[med-svn] [r-cran-igraph] 01/02: Imported Upstream version 1.0.1

Andreas Tille tille at debian.org
Wed Apr 6 07:41:09 UTC 2016


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-igraph.

commit ed939d64934385500e39247f1db389dfaf7d0162
Author: Andreas Tille <tille at debian.org>
Date:   Wed Apr 6 09:39:07 2016 +0200

    Imported Upstream version 1.0.1
---
 AUTHORS                                            |  133 -
 DESCRIPTION                                        |   36 +-
 MD5                                                | 1797 ++--
 NAMESPACE                                          | 1268 ++-
 NEWS                                               | 1036 ---
 R/adjacency.R                                      |  400 +
 R/assortativity.R                                  |  113 +
 R/attributes.R                                     |  790 +-
 R/auto.R                                           | 1317 ++-
 R/basic.R                                          |   70 +-
 R/bipartite.R                                      |  130 +-
 R/centrality.R                                     |  683 +-
 R/centralization.R                                 |  345 +
 R/cliques.R                                        |  242 +-
 R/cocitation.R                                     |   55 +-
 R/cohesive.blocks.R                                |  302 +-
 R/community.R                                      | 1599 +++-
 R/components.R                                     |  134 +-
 R/console.R                                        |  154 +-
 R/conversion.R                                     |  615 +-
 R/data_frame.R                                     |  254 +
 R/decomposition.R                                  |   62 +-
 R/degseq.R                                         |   89 +
 R/demo.R                                           |  106 +-
 R/embedding.R                                      |  347 +
 R/epi.R                                            |   64 +-
 R/fit.R                                            |  119 +-
 R/flow.R                                           |  639 +-
 R/foreign.R                                        |  206 +-
 R/games.R                                          | 1423 ++-
 R/glet.R                                           |   99 +-
 R/hrg.R                                            |  472 +-
 R/igraph-package.R                                 |  190 +
 R/incidence.R                                      |  242 +
 R/indexing.R                                       |  234 +-
 R/interface.R                                      |  415 +-
 R/iterators.R                                      | 1603 +++-
 R/layout.R                                         | 2534 ++++--
 R/layout_drl.R                                     |  275 +
 R/lazyeval.R                                       |  244 +
 R/make.R                                           | 1563 ++++
 R/mgclust.R                                        |  168 +
 R/minimum.spanning.tree.R                          |   47 +-
 R/motifs.R                                         |  172 +-
 R/nexus.R                                          |  214 +-
 R/operators.R                                      |  780 +-
 R/other.R                                          |   98 +-
 R/package.R                                        |    9 -
 R/palette.R                                        |  210 +
 R/par.R                                            |  122 +-
 R/paths.R                                          |  231 +
 R/plot.R                                           |  154 +-
 R/plot.common.R                                    |   83 +-
 R/plot.shapes.R                                    |  268 +-
 R/pp.R                                             |   25 +
 R/print.R                                          |  440 +-
 R/printr.R                                         |  189 +
 R/random_walk.R                                    |   53 +
 R/revolver.R                                       |  493 -
 R/rewire.R                                         |  142 +
 R/scan.R                                           |  424 +
 R/scg.R                                            |  539 +-
 R/sgm.R                                            |  138 +
 R/similarity.R                                     |   65 +
 R/simple.R                                         |   70 +
 R/sir.R                                            |  103 +
 R/socnet.R                                         | 1061 +--
 R/sparsedf.R                                       |    6 +
 R/structural.properties.R                          | 2067 ++++-
 R/structure.generators.R                           |  883 --
 R/structure.info.R                                 |   30 +-
 R/test.R                                           |   50 +-
 R/tkplot.R                                         |  683 +-
 R/topology.R                                       |  895 +-
 R/triangles.R                                      |   73 +
 R/utils.R                                          |   99 +
 R/uuid.R                                           |   13 +
 R/versions.R                                       |  120 +
 R/weakref.R                                        |   41 +
 R/zzz-deprecate.R                                  |  610 ++
 configure                                          |  115 +-
 configure.ac                                       |  146 +
 configure.in                                       |  119 -
 demo/centrality.R                                  |   62 +-
 demo/cohesive.R                                    |   14 +-
 demo/community.R                                   |   66 +-
 demo/crashR.R                                      |   52 +-
 demo/hrg.R                                         |   30 +-
 demo/smallworld.R                                  |   54 +-
 inst/AUTHORS                                       |    5 +
 inst/NEWS.md                                       | 1034 +++
 inst/README.md                                     |   32 +
 inst/benchmarks/correlated.R                       |    8 +
 inst/benchmarks/local.scan.R                       |   57 +
 inst/benchmarks/time_dirSelect.R                   |    7 +
 inst/benchmarks/time_fr_layout.R                   |   12 +
 inst/benchmarks/time_kk_layout.R                   |   17 +
 inst/benchmarks/time_print.R                       |   54 +
 inst/benchmarks/time_sgm.R                         |   11 +
 inst/benchmarks/time_sir.R                         |    2 +-
 inst/tests/dyad.census.R                           |   20 +-
 inst/tests/test-constructor-modifiers.R            |  116 +
 inst/tests/test-index-es.R                         |   40 +
 inst/tests/test-isomorphism.R                      |  121 +
 inst/tests/test-make.R                             |   61 +
 inst/tests/test-make_graph.R                       |   57 +
 inst/tests/test-new-layout-api.R                   |   59 +
 inst/tests/test-notable.R                          |   38 +
 inst/tests/test-old-data-type.R                    |   68 +
 inst/tests/test-random_walk.R                      |   28 +
 inst/tests/test-version.R                          |   20 +
 inst/tests/test-versions.R                         |   25 +
 inst/tests/test-vs-es-printing.R                   |   88 +
 inst/tests/test-vs-es-quirks.R                     |   32 +
 inst/tests/test-vs-es.R                            |  272 +
 inst/tests/test-vs-indexing-lapply.R               |   11 +
 inst/tests/test-vs-operators.R                     |  651 ++
 inst/tests/test-weakref.R                          |  106 +
 inst/tests/test_add.edges.R                        |   43 +-
 inst/tests/test_add.vertices.R                     |   16 +-
 inst/tests/test_adjacency.spectral.embedding.R     |  234 +
 inst/tests/test_all.st.cuts.R                      |   26 +-
 inst/tests/test_alpha.centrality.R                 |   53 +-
 inst/tests/test_are.connected.R                    |   28 +-
 inst/tests/test_arpack.R                           |    2 +-
 inst/tests/test_articulation.points.R              |   12 +-
 inst/tests/test_as.directed.R                      |    8 +-
 inst/tests/test_as.undirected.R                    |    8 +-
 inst/tests/test_assortativity.R                    |   18 +-
 inst/tests/test_attributes.R                       |  164 +-
 inst/tests/test_authority.score.R                  |   34 +-
 inst/tests/test_average.path.length.R              |   28 +-
 inst/tests/test_ba.game.R                          |   50 +-
 inst/tests/test_betweenness.R                      |    6 +-
 inst/tests/test_biconnected.components.R           |   15 +-
 inst/tests/test_bipartite.projection.R             |   78 +-
 inst/tests/test_bipartite.random.game.R            |   40 +-
 inst/tests/test_bonpow.R                           |   12 +-
 inst/tests/test_bug-1019624.R                      |    4 +-
 inst/tests/test_bug-1032819.R                      |    6 +-
 inst/tests/test_bug-1033045.R                      |    6 +-
 inst/tests/test_bug-1073705-indexing.R             |   10 +-
 inst/tests/test_bug-1073800-clique.R               |    7 +-
 inst/tests/test_callbacks.R                        |    2 +-
 inst/tests/test_canonical.permutation.R            |   20 +-
 inst/tests/test_cliques.R                          |   12 +-
 inst/tests/test_closeness.R                        |   42 +-
 inst/tests/test_clusters.R                         |   40 +-
 inst/tests/test_communities.R                      |   52 +-
 inst/tests/test_constraint.R                       |    6 +-
 inst/tests/test_contract.vertices.R                |    8 +-
 inst/tests/test_correlated.R                       |   79 +
 inst/tests/test_count.multiple.R                   |   16 +-
 inst/tests/test_decompose.graph.R                  |   34 +-
 inst/tests/test_degree.R                           |    8 +-
 inst/tests/test_degree.sequence.game.R             |   26 +-
 inst/tests/test_delete.edges.R                     |    8 +-
 inst/tests/test_delete.vertices.R                  |   10 +-
 inst/tests/test_diameter.R                         |   20 +-
 inst/tests/test_dimSelect.R                        |   33 +
 inst/tests/test_dominator.tree.R                   |   16 +-
 inst/tests/test_dot.product.game.R                 |   46 +
 inst/tests/test_dyad.census.R                      |   10 +-
 inst/tests/test_edge.betweenness.R                 |   28 +-
 inst/tests/test_edge.betweenness.community.R       |   19 +-
 inst/tests/test_edge.connectivity.R                |   42 +-
 inst/tests/test_edgenames.R                        |   26 +-
 inst/tests/test_evcent.R                           |   32 +-
 inst/tests/test_fartherst.nodes.R                  |   34 +-
 inst/tests/test_fastgreedy.community.R             |   19 +-
 inst/tests/test_forestfire.R                       |    6 +-
 inst/tests/test_get.adjacency.R                    |   24 +-
 inst/tests/test_get.adjlist.R                      |   36 +-
 inst/tests/test_get.all.shortest.paths.R           |   13 +-
 inst/tests/test_get.diameter.R                     |   14 +-
 inst/tests/test_get.edge.R                         |    8 +-
 inst/tests/test_get.edgelist.R                     |    8 +-
 inst/tests/test_get.incidence.R                    |   10 +-
 inst/tests/test_get.shortest.paths.R               |   12 +-
 inst/tests/test_girth.R                            |    8 +-
 inst/tests/test_graph.adhesion.R                   |   70 +-
 inst/tests/test_graph.adjacency.R                  |   66 +-
 inst/tests/test_graph.adjlist.R                    |   16 +-
 inst/tests/test_graph.bfs.R                        |   10 +-
 inst/tests/test_graph.bipartite.R                  |   10 +-
 inst/tests/test_graph.complementer.R               |   10 +-
 inst/tests/test_graph.compose.R                    |   10 +-
 inst/tests/test_graph.coreness.R                   |   10 +-
 inst/tests/test_graph.data.frame.R                 |   18 +-
 inst/tests/test_graph.de.bruijn.R                  |   10 +-
 inst/tests/test_graph.density.R                    |   12 +-
 inst/tests/test_graph.edgelist.R                   |   22 +-
 inst/tests/test_graph.eigen.R                      |   10 +-
 inst/tests/test_graph.formula.R                    |    6 +-
 inst/tests/test_graph.isoclass.R                   |   14 +-
 inst/tests/test_graph.kautz.R                      |    8 +-
 inst/tests/test_graph.knn.R                        |   24 +-
 inst/tests/test_graph.maxflow.R                    |   16 +-
 inst/tests/test_graph.mincut.R                     |   12 +-
 inst/tests/test_graph.subisomorphic.lad.R          |   67 +-
 inst/tests/test_graph.subisomorphic.vf2.R          |    4 +-
 inst/tests/test_graphNEL.R                         |   14 +-
 inst/tests/test_graphlets.R                        |   39 +-
 inst/tests/test_hrg.R                              |    6 +-
 inst/tests/test_hsbm.R                             |  113 +
 inst/tests/test_igraph.options.R                   |   12 +-
 inst/tests/test_independent.vertex.sets.R          |   10 +-
 inst/tests/test_indexing.R                         |  111 +-
 inst/tests/test_indexing2.R                        |   14 +-
 inst/tests/test_indexing3.R                        |   10 +
 inst/tests/test_is.bipartite.R                     |   12 +-
 inst/tests/test_is.chordal.R                       |   27 +-
 inst/tests/test_iterators.R                        |   40 +-
 inst/tests/test_label.propagation.community.R      |    8 +-
 inst/tests/test_laplacian.spectral.embedding.R     |  442 +
 inst/tests/test_largest.cliques.R                  |   10 +-
 inst/tests/test_largest.independent.vertex.sets.R  |   12 +-
 inst/tests/test_layout.fr.R                        |   25 +
 inst/tests/test_layout.gem.R                       |   12 +
 inst/tests/test_layout.kk.R                        |   53 +
 inst/tests/test_layout.mds.R                       |   18 +-
 inst/tests/test_layout.merge.R                     |   14 +-
 inst/tests/test_leading.eigenvector.community.R    |   27 +-
 inst/tests/test_maximal_cliques.R                  |   30 +-
 inst/tests/test_minimal.st.separators.R            |   10 +-
 inst/tests/test_minimum.size.separators.R          |   32 +-
 inst/tests/test_modularity_matrix.R                |   12 +-
 inst/tests/test_motifs.R                           |   32 +-
 inst/tests/test_multilevel.community.R             |   10 +-
 inst/tests/test_neighborhood.R                     |   52 +-
 inst/tests/test_neighbors.R                        |    6 +-
 inst/tests/test_operators.R                        |   45 +-
 inst/tests/test_operators3.R                       |   16 +-
 inst/tests/test_operators4.R                       |   98 +-
 inst/tests/test_optimal.community.R                |   16 +-
 inst/tests/test_pajek.R                            |    4 +-
 inst/tests/test_print.R                            |   25 +-
 inst/tests/test_sample.R                           |   29 +
 inst/tests/test_sbm.game.R                         |   16 +-
 inst/tests/test_scan.R                             |  188 +
 inst/tests/test_scg.R                              |    6 +-
 inst/tests/test_sdf.R                              |    7 +-
 inst/tests/test_sgm.R                              |   48 +
 inst/tests/test_sir.R                              |    2 +-
 inst/tests/test_sphere.R                           |   40 +
 inst/tests/test_transitivity.R                     |   12 +-
 inst/tests/test_triangles.R                        |   39 +
 inst/tests/test_unfold.tree.R                      |   10 +-
 inst/tests/test_walktrap.community.R               |   19 +-
 inst/tests/test_watts.strogatz.game.R              |    8 +-
 man/E.Rd                                           |  100 +
 man/SCGintro.Rd                                    |  156 -
 man/V.Rd                                           |   93 +
 man/aaa-igraph-package.Rd                          |   69 +-
 man/add_edges.Rd                                   |   55 +
 man/add_layout_.Rd                                 |   69 +
 man/add_vertices.Rd                                |   50 +
 man/adjacent.triangles.Rd                          |   36 -
 man/adjacent_vertices.Rd                           |   41 +
 man/aging.prefatt.game.Rd                          |  120 -
 man/all.st.cuts.Rd                                 |   51 -
 man/all.st.mincuts.Rd                              |   63 -
 man/all_simple_paths.Rd                            |   47 +
 man/alpha.centrality.Rd                            |   73 -
 man/alpha_centrality.Rd                            |   88 +
 man/are_adjacent.Rd                                |   48 +
 man/arpack.Rd                                      |  393 +-
 man/articulation.points.Rd                         |   33 -
 man/articulation_points.Rd                         |   43 +
 man/as.directed.Rd                                 |  104 +-
 man/as.igraph.Rd                                   |   41 +-
 man/as_adj_list.Rd                                 |   50 +
 man/as_adjacency_matrix.Rd                         |   73 +
 man/as_edgelist.Rd                                 |   38 +
 man/as_graphnel.Rd                                 |   52 +
 man/as_ids.Rd                                      |   44 +
 man/as_incidence_matrix.Rd                         |   58 +
 man/as_long_data_frame.Rd                          |   32 +
 man/as_membership.Rd                               |   29 +
 man/assortativity.Rd                               |  173 +-
 man/attribute.combination.Rd                       |  144 -
 man/attributes.Rd                                  |  183 -
 man/authority_score.Rd                             |   67 +
 man/autocurve.edges.Rd                             |   43 -
 man/automorphisms.Rd                               |   63 +
 man/ba.game.Rd                                     |  108 -
 man/betweenness.Rd                                 |  163 +-
 man/bfs.Rd                                         |  116 +
 man/biconnected.components.Rd                      |   48 -
 man/biconnected_components.Rd                      |   52 +
 man/bipartite.projection.Rd                        |   83 -
 man/bipartite.random.game.Rd                       |   58 -
 man/bipartite_mapping.Rd                           |   57 +
 man/bipartite_projection.Rd                        |   87 +
 man/bonpow.Rd                                      |  117 -
 man/c.igraph.es.Rd                                 |   47 +
 man/c.igraph.vs.Rd                                 |   47 +
 man/canonical.permutation.Rd                       |   88 -
 man/canonical_permutation.Rd                       |   86 +
 man/categorical_pal.Rd                             |   43 +
 man/centr_betw.Rd                                  |   61 +
 man/centr_betw_tmax.Rd                             |   53 +
 man/centr_clo.Rd                                   |   57 +
 man/centr_clo_tmax.Rd                              |   54 +
 man/centr_degree.Rd                                |   61 +
 man/centr_degree_tmax.Rd                           |   55 +
 man/centr_eigen.Rd                                 |   71 +
 man/centr_eigen_tmax.Rd                            |   57 +
 man/centralization.Rd                              |  156 -
 man/centralize.Rd                                  |   89 +
 man/cliques.Rd                                     |  143 +-
 man/closeness.Rd                                   |  114 +-
 man/cluster_edge_betweenness.Rd                    |  102 +
 man/cluster_fast_greedy.Rd                         |   66 +
 man/cluster_infomap.Rd                             |   70 +
 man/cluster_label_prop.Rd                          |   72 +
 man/cluster_leading_eigen.Rd                       |  116 +
 man/cluster_louvain.Rd                             |   70 +
 man/cluster_optimal.Rd                             |   75 +
 man/cluster_spinglass.Rd                           |  146 +
 man/cluster_walktrap.Rd                            |   67 +
 man/clusters.Rd                                    |   73 -
 man/cocitation.Rd                                  |   61 +-
 man/cohesive.blocks.Rd                             |  269 -
 man/cohesive_blocks.Rd                             |  282 +
 man/communities.Rd                                 |  465 +-
 man/community.edge.betweenness.Rd                  |   96 -
 man/community.structure.Rd                         |   44 -
 man/compare.Rd                                     |   73 +
 man/compare.communities.Rd                         |   75 -
 man/complementer.Rd                                |   46 +
 man/component_wise.Rd                              |   67 +
 man/components.Rd                                  |  102 +-
 man/compose.Rd                                     |   76 +
 man/consensus_tree.Rd                              |   54 +
 man/console.Rd                                     |   35 +
 man/constraint.Rd                                  |   83 +-
 man/contract.Rd                                    |   49 +
 man/contract.vertices.Rd                           |   51 -
 man/conversion.Rd                                  |   82 -
 man/convex.hull.Rd                                 |   34 -
 man/convex_hull.Rd                                 |   36 +
 man/coreness.Rd                                    |   53 +
 man/count_isomorphisms.Rd                          |   67 +
 man/count_motifs.Rd                                |   43 +
 man/count_subgraph_isomorphisms.Rd                 |  100 +
 man/count_triangles.Rd                             |   63 +
 man/curve_multiple.Rd                              |   49 +
 man/decompose.Rd                                   |   48 +
 man/decompose.graph.Rd                             |   40 -
 man/degree.Rd                                      |   77 +-
 man/degree.sequence.game.Rd                        |   86 -
 man/delete_edge_attr.Rd                            |   70 +
 man/delete_edges.Rd                                |   40 +
 man/delete_graph_attr.Rd                           |   69 +
 man/delete_vertex_attr.Rd                          |   70 +
 man/delete_vertices.Rd                             |   42 +
 man/dendPlot.Rd                                    |   24 -
 man/dendPlot.communities.Rd                        |   95 -
 man/dendPlot.igraphHRG.Rd                          |   94 -
 man/dfs.Rd                                         |  109 +
 man/diameter.Rd                                    |   85 +-
 man/difference.Rd                                  |   24 +
 man/difference.igraph.Rd                           |   64 +
 man/difference.igraph.es.Rd                        |   52 +
 man/difference.igraph.vs.Rd                        |   52 +
 man/dim_select.Rd                                  |   72 +
 man/disjoint_union.Rd                              |   57 +
 man/distances.Rd                                   |  207 +
 man/diverging_pal.Rd                               |   53 +
 man/diversity.Rd                                   |   58 +
 man/dominator.tree.Rd                              |   75 -
 man/dominator_tree.Rd                              |   69 +
 man/dyad.census.Rd                                 |   38 -
 man/dyad_census.Rd                                 |   44 +
 man/each_edge.Rd                                   |   41 +
 man/eccentricity.Rd                                |   73 +-
 man/edge.Rd                                        |   63 +
 man/edge.connectivity.Rd                           |   80 -
 man/edge_attr-set.Rd                               |   79 +
 man/edge_attr.Rd                                   |   75 +
 man/edge_attr_names.Rd                             |   67 +
 man/edge_connectivity.Rd                           |   86 +
 man/edge_density.Rd                                |   53 +
 man/ego.Rd                                         |   92 +
 man/eigen_centrality.Rd                            |   85 +
 man/embed_adjacency_matrix.Rd                      |   88 +
 man/embed_laplacian_matrix.Rd                      |  100 +
 man/ends.Rd                                        |   40 +
 man/erdos.renyi.game.Rd                            |   88 +-
 man/evcent.Rd                                      |   76 -
 man/evolver.Rd                                     |  243 -
 man/fastgreedy.community.Rd                        |   63 -
 man/fit_hrg.Rd                                     |   90 +
 man/fit_power_law.Rd                               |  119 +
 man/forest.fire.game.Rd                            |   79 -
 man/gclust.app.Rd                                  |   29 +
 man/gclust.rsvt.Rd                                 |   33 +
 man/get.adjlist.Rd                                 |   41 -
 man/get.edge.ids.Rd                                |   85 +-
 man/get.incidence.Rd                               |   48 -
 man/getAICc.Rd                                     |   28 +
 man/girth.Rd                                       |   64 +-
 man/gorder.Rd                                      |   35 +
 man/graph.adjacency.Rd                             |  156 -
 man/graph.adjlist.Rd                               |   62 -
 man/graph.automorphisms.Rd                         |   58 -
 man/graph.bfs.Rd                                   |  113 -
 man/graph.bipartite.Rd                             |   54 -
 man/graph.complementer.Rd                          |   40 -
 man/graph.compose.Rd                               |   72 -
 man/graph.constructors.Rd                          |  176 -
 man/graph.data.frame.Rd                            |  110 -
 man/graph.de.bruijn.Rd                             |   38 -
 man/graph.density.Rd                               |   44 -
 man/graph.dfs.Rd                                   |  102 -
 man/graph.difference.Rd                            |   55 -
 man/graph.disjoint.union.Rd                        |   49 -
 man/graph.diversity.Rd                             |   57 -
 man/graph.eigen.Rd                                 |   81 -
 man/graph.famous.Rd                                |  133 -
 man/graph.formula.Rd                               |  125 -
 man/graph.full.bipartite.Rd                        |   39 -
 man/graph.graphdb.Rd                               |   78 -
 man/graph.incidence.Rd                             |   73 -
 man/graph.intersection.Rd                          |   56 -
 man/graph.isomorphism.Rd                           |  329 -
 man/graph.kautz.Rd                                 |   34 -
 man/graph.kcores.Rd                                |   42 -
 man/graph.knn.Rd                                   |   63 -
 man/graph.laplacian.Rd                             |   49 -
 man/graph.lcf.Rd                                   |   31 -
 man/graph.maxflow.Rd                               |  128 -
 man/graph.motifs.Rd                                |   62 -
 man/graph.strength.Rd                              |   44 -
 man/graph.structure.Rd                             |  351 -
 man/graph.union.Rd                                 |   54 -
 man/graphNEL.Rd                                    |   71 -
 man/graph_.Rd                                      |   23 +
 man/graph_attr-set.Rd                              |   76 +
 man/graph_attr.Rd                                  |   70 +
 man/graph_attr_names.Rd                            |   66 +
 man/graph_from_adj_list.Rd                         |   70 +
 man/graph_from_adjacency_matrix.Rd                 |  150 +
 man/graph_from_atlas.Rd                            |   74 +
 man/graph_from_data_frame.Rd                       |  124 +
 man/graph_from_edgelist.Rd                         |   70 +
 man/graph_from_graphdb.Rd                          |   93 +
 man/graph_from_graphnel.Rd                         |   67 +
 man/graph_from_incidence_matrix.Rd                 |   85 +
 man/graph_from_isomorphism_class.Rd                |   50 +
 man/graph_from_lcf.Rd                              |   42 +
 man/graph_from_literal.Rd                          |  153 +
 man/graph_version.Rd                               |   32 +
 man/graphlet_basis.Rd                              |   99 +
 man/graphlets.Rd                                   |  100 -
 man/grg.game.Rd                                    |   39 -
 man/groups.Rd                                      |   43 +
 man/growing.random.game.Rd                         |   35 -
 man/gsize.Rd                                       |   40 +
 man/head_of.Rd                                     |   34 +
 man/hrg-methods.Rd                                 |   39 +
 man/hrg.Rd                                         |  241 +-
 man/hrg_tree.Rd                                    |   29 +
 man/hub_score.Rd                                   |   64 +
 man/identical_graphs.Rd                            |   20 +
 man/igraph-attribute-combination.Rd                |  109 +
 man/igraph-dollar.Rd                               |   73 +
 man/igraph-es-attributes.Rd                        |  117 +
 man/igraph-es-indexing.Rd                          |  154 +
 man/igraph-es-indexing2.Rd                         |   85 +
 man/igraph-minus.Rd                                |   69 +
 man/igraph-vs-attributes.Rd                        |  133 +
 man/igraph-vs-indexing.Rd                          |  167 +
 man/igraph-vs-indexing2.Rd                         |   86 +
 man/igraph.console.Rd                              |   28 -
 man/igraph.par.Rd                                  |  108 -
 man/igraph.sample.Rd                               |   29 -
 man/igraph.version.Rd                              |   30 -
 man/igraph.vertex.shapes.Rd                        |  257 -
 man/igraph_demo.Rd                                 |   42 +
 man/igraph_options.Rd                              |  106 +
 man/igraph_test.Rd                                 |   29 +
 man/igraph_version.Rd                              |   34 +
 man/igraphdemo.Rd                                  |   33 -
 man/igraphtest.Rd                                  |   22 -
 man/incident.Rd                                    |   42 +
 man/incident_edges.Rd                              |   41 +
 man/independent.sets.Rd                            |   76 -
 man/infomap.Rd                                     |   64 -
 man/interconnected.islands.Rd                      |   33 -
 man/intersection.Rd                                |   24 +
 man/intersection.igraph.Rd                         |   63 +
 man/intersection.igraph.es.Rd                      |   48 +
 man/intersection.igraph.vs.Rd                      |   48 +
 man/is.bipartite.Rd                                |   56 -
 man/is.chordal.Rd                                  |   71 -
 man/is.dag.Rd                                      |   28 -
 man/is.degree.sequence.Rd                          |   55 -
 man/is.graph.Rd                                    |   24 -
 man/is.multiple.Rd                                 |   76 -
 man/is.mutual.Rd                                   |   39 -
 man/is.named.Rd                                    |   35 -
 man/is.separator.Rd                                |   69 -
 man/is.weighted.Rd                                 |   33 -
 man/is_chordal.Rd                                  |   77 +
 man/is_dag.Rd                                      |   36 +
 man/is_degseq.Rd                                   |   49 +
 man/is_directed.Rd                                 |   38 +
 man/is_graphical.Rd                                |   45 +
 man/is_igraph.Rd                                   |   29 +
 man/is_min_separator.Rd                            |   63 +
 man/is_named.Rd                                    |   44 +
 man/is_separator.Rd                                |   36 +
 man/is_weighted.Rd                                 |   42 +
 man/isomorphic.Rd                                  |  150 +
 man/isomorphism_class.Rd                           |   56 +
 man/isomorphisms.Rd                                |   49 +
 man/iterators.Rd                                   |  234 -
 man/ivs.Rd                                         |   90 +
 man/k.regular.game.Rd                              |   51 -
 man/keeping_degseq.Rd                              |   43 +
 man/kleinberg.Rd                                   |   65 -
 man/knn.Rd                                         |   70 +
 man/label.propagation.community.Rd                 |   70 -
 man/laplacian_matrix.Rd                            |   58 +
 man/layout.Rd                                      |  324 -
 man/layout.bipartite.Rd                            |   48 -
 man/layout.deprecated.Rd                           |   35 +
 man/layout.drl.Rd                                  |  103 -
 man/layout.fruchterman.reingold.grid.Rd            |   20 +
 man/layout.grid.Rd                                 |   47 -
 man/layout.mds.Rd                                  |   52 -
 man/layout.merge.Rd                                |   58 -
 man/layout.spring.Rd                               |   20 +
 man/layout.star.Rd                                 |   36 -
 man/layout.sugiyama.Rd                             |  195 -
 man/layout.svd.Rd                                  |   20 +
 man/layout_.Rd                                     |  107 +
 man/layout_as_bipartite.Rd                         |  104 +
 man/layout_as_star.Rd                              |   90 +
 man/layout_as_tree.Rd                              |  119 +
 man/layout_in_circle.Rd                            |   88 +
 man/layout_nicely.Rd                               |   86 +
 man/layout_on_grid.Rd                              |   99 +
 man/layout_on_sphere.Rd                            |   75 +
 man/layout_randomly.Rd                             |   75 +
 man/layout_with_dh.Rd                              |  173 +
 man/layout_with_drl.Rd                             |  116 +
 man/layout_with_fr.Rd                              |  146 +
 man/layout_with_gem.Rd                             |  105 +
 man/layout_with_graphopt.Rd                        |  108 +
 man/layout_with_kk.Rd                              |  134 +
 man/layout_with_lgl.Rd                             |   94 +
 man/layout_with_mds.Rd                             |  103 +
 man/layout_with_sugiyama.Rd                        |  242 +
 man/leading.eigenvector.Rd                         |  133 -
 man/line.graph.Rd                                  |   38 -
 man/local_scan.Rd                                  |   99 +
 man/make_.Rd                                       |   48 +
 man/make_bipartite_graph.Rd                        |   68 +
 man/make_chordal_ring.Rd                           |   70 +
 man/make_clusters.Rd                               |   35 +
 man/make_de_bruijn_graph.Rd                        |   54 +
 man/make_empty_graph.Rd                            |   63 +
 man/make_full_bipartite_graph.Rd                   |   54 +
 man/make_full_citation_graph.Rd                    |   60 +
 man/make_full_graph.Rd                             |   65 +
 man/make_graph.Rd                                  |  211 +
 man/make_kautz_graph.Rd                            |   49 +
 man/make_lattice.Rd                                |   83 +
 man/make_line_graph.Rd                             |   48 +
 man/make_ring.Rd                                   |   69 +
 man/make_star.Rd                                   |   71 +
 man/make_tree.Rd                                   |   71 +
 man/match_vertices.Rd                              |   80 +
 man/matching.Rd                                    |  156 +-
 man/max_cardinality.Rd                             |   58 +
 man/max_flow.Rd                                    |   77 +
 man/maximum.cardinality.search.Rd                  |   49 -
 man/merge_coords.Rd                                |  106 +
 man/min_cut.Rd                                     |   81 +
 man/min_separators.Rd                              |   81 +
 man/min_st_separators.Rd                           |   48 +
 man/minimal.st.separators.Rd                       |   43 -
 man/minimum.size.separators.Rd                     |   78 -
 man/minimum.spanning.tree.Rd                       |   47 -
 man/modularity.Rd                                  |   79 -
 man/modularity.igraph.Rd                           |   85 +
 man/motifs.Rd                                      |   49 +
 man/mst.Rd                                         |   56 +
 man/multilevel.community.Rd                        |   70 -
 man/neighborhood.Rd                                |   77 -
 man/neighbors.Rd                                   |   43 +
 man/nexus.Rd                                       |  345 +-
 man/norm_coords.Rd                                 |   77 +
 man/normalize.Rd                                   |   66 +
 man/optimal.community.Rd                           |   70 -
 man/page.rank.Rd                                   |  130 -
 man/page_rank.Rd                                   |  142 +
 man/path.Rd                                        |   58 +
 man/permute.Rd                                     |   55 +
 man/permute.vertices.Rd                            |   46 -
 man/pipe.Rd                                        |   28 +
 man/plot.common.Rd                                 |   67 +-
 man/plot.graph.Rd                                  |   64 -
 man/plot.igraph.Rd                                 |   82 +
 man/plot.sir.Rd                                    |  110 +-
 man/plot_dendrogram.communities.Rd                 |  100 +
 man/plot_dendrogram.igraphHRG.Rd                   |   92 +
 man/plus-.igraph.Rd                                |  117 +
 man/power.law.fit.Rd                               |  116 -
 man/power_centrality.Rd                            |  131 +
 man/predict_edges.Rd                               |   85 +
 man/preference.game.Rd                             |   62 -
 man/print.graph.Rd                                 |   82 -
 man/print.igraph.Rd                                |   97 +
 man/print.igraph.es.Rd                             |   83 +
 man/print.igraph.vs.Rd                             |   81 +
 man/print.igraphHRG.Rd                             |   66 +
 man/print.igraphHRGConsensus.Rd                    |   36 +
 man/r_pal.Rd                                       |   24 +
 man/radius.Rd                                      |   49 +
 man/random_walk.Rd                                 |   48 +
 man/read.graph.Rd                                  |  343 -
 man/read_graph.Rd                                  |   60 +
 man/reciprocity.Rd                                 |   63 +-
 man/rep.igraph.Rd                                  |   31 +
 man/rev.igraph.es.Rd                               |   44 +
 man/rev.igraph.vs.Rd                               |   43 +
 man/rewire.Rd                                      |   48 +-
 man/rewire.edges.Rd                                |   33 -
 man/rglplot.Rd                                     |   49 +-
 man/running.mean.Rd                                |   28 -
 man/running_mean.Rd                                |   36 +
 man/sample_.Rd                                     |   30 +
 man/sample_bipartite.Rd                            |   74 +
 man/sample_correlated_gnp.Rd                       |   53 +
 man/sample_correlated_gnp_pair.Rd                  |   54 +
 man/sample_degseq.Rd                               |   99 +
 man/sample_dirichlet.Rd                            |   38 +
 man/sample_dot_product.Rd                          |   58 +
 man/sample_fitness.Rd                              |   79 +
 man/sample_fitness_pl.Rd                           |   86 +
 man/sample_forestfire.Rd                           |   79 +
 man/sample_gnm.Rd                                  |   52 +
 man/sample_gnp.Rd                                  |   51 +
 man/sample_grg.Rd                                  |   53 +
 man/sample_growing.Rd                              |   49 +
 man/sample_hierarchical_sbm.Rd                     |   60 +
 man/sample_hrg.Rd                                  |   30 +
 man/sample_islands.Rd                              |   39 +
 man/sample_k_regular.Rd                            |   54 +
 man/sample_last_cit.Rd                             |   71 +
 man/sample_motifs.Rd                               |   51 +
 man/sample_pa.Rd                                   |  122 +
 man/sample_pa_age.Rd                               |  135 +
 man/sample_pref.Rd                                 |   87 +
 man/sample_sbm.Rd                                  |   57 +
 man/sample_seq.Rd                                  |   42 +
 man/sample_smallworld.Rd                           |   61 +
 man/sample_sphere_surface.Rd                       |   43 +
 man/sample_sphere_volume.Rd                        |   43 +
 man/sample_traits_callaway.Rd                      |   73 +
 man/sbm.game.Rd                                    |   43 -
 man/scan_stat.Rd                                   |   64 +
 man/scg-method.Rd                                  |   52 +
 man/scg.Rd                                         |  293 +-
 man/scg.grouping.Rd                                |  127 -
 man/scg_eps.Rd                                     |   59 +
 man/scg_extra.Rd                                   |   51 -
 man/scg_group.Rd                                   |  133 +
 man/scg_semi_proj.Rd                               |  100 +
 man/semiProjectors.Rd                              |   92 -
 man/sequential_pal.Rd                              |   41 +
 man/set_edge_attr.Rd                               |   75 +
 man/set_graph_attr.Rd                              |   71 +
 man/set_vertex_attr.Rd                             |   75 +
 man/shapes.Rd                                      |  261 +
 man/shortest.paths.Rd                              |  196 -
 man/similarity.Rd                                  |  109 +-
 man/simplified.Rd                                  |   22 +
 man/simplify.Rd                                    |   81 +-
 man/sir.Rd                                         |  172 +-
 man/spectrum.Rd                                    |   79 +
 man/spinglass.community.Rd                         |  144 -
 man/split_join_distance.Rd                         |   44 +
 man/srand.Rd                                       |   35 +-
 man/st_cuts.Rd                                     |   56 +
 man/st_min_cuts.Rd                                 |   66 +
 man/static.fitness.game.Rd                         |   73 -
 man/static.power.law.game.Rd                       |   78 -
 man/stochasticMatrix.Rd                            |   49 -
 man/stochastic_matrix.Rd                           |   55 +
 man/strength.Rd                                    |   56 +
 man/structure.info.Rd                              |   88 -
 man/sub-.igraph.Rd                                 |  130 +
 man/sub-sub-.igraph.Rd                             |   86 +
 man/subcomponent.Rd                                |   44 +
 man/subgraph.Rd                                    |   96 +-
 man/subgraph.centrality.Rd                         |   45 -
 man/subgraph_centrality.Rd                         |   51 +
 man/subgraph_isomorphic.Rd                         |  128 +
 man/subgraph_isomorphisms.Rd                       |   89 +
 man/tail_of.Rd                                     |   34 +
 man/tkigraph.Rd                                    |   29 +-
 man/tkplot.Rd                                      |  288 +-
 man/topo_sort.Rd                                   |   42 +
 man/topological.sort.Rd                            |   39 -
 man/traits.Rd                                      |   53 -
 man/transitivity.Rd                                |  169 +-
 man/triad.census.Rd                                |   56 -
 man/triad_census.Rd                                |   55 +
 man/undocumented.Rd                                |   40 -
 man/unfold.tree.Rd                                 |   48 -
 man/unfold_tree.Rd                                 |   48 +
 man/union.Rd                                       |   24 +
 man/union.igraph.Rd                                |   59 +
 man/union.igraph.es.Rd                             |   49 +
 man/union.igraph.vs.Rd                             |   49 +
 man/unique.igraph.es.Rd                            |   48 +
 man/unique.igraph.vs.Rd                            |   48 +
 man/upgrade_graph.Rd                               |   32 +
 man/vertex.Rd                                      |   50 +
 man/vertex.connectivity.Rd                         |   86 -
 man/vertex.shape.pie.Rd                            |    2 +-
 man/vertex_attr-set.Rd                             |   79 +
 man/vertex_attr.Rd                                 |   76 +
 man/vertex_attr_names.Rd                           |   68 +
 man/vertex_connectivity.Rd                         |  101 +
 man/walktrap.community.Rd                          |   60 -
 man/watts.strogatz.game.Rd                         |   44 -
 man/which_multiple.Rd                              |   82 +
 man/which_mutual.Rd                                |   47 +
 man/with_edge_.Rd                                  |   28 +
 man/with_graph_.Rd                                 |   24 +
 man/with_vertex_.Rd                                |   29 +
 man/without_attr.Rd                                |   25 +
 man/without_loops.Rd                               |   23 +
 man/without_multiples.Rd                           |   22 +
 man/write.graph.Rd                                 |  194 -
 man/write_graph.Rd                                 |   53 +
 src/AMD/Include/amd.h                              |  411 +
 src/AMD/Include/amd_internal.h                     |  347 +
 src/AMD/Makefile                                   |   73 +
 src/AMD/README.txt                                 |  213 +
 src/AMD/Source/amd.f                               | 1214 +++
 src/AMD/Source/amd_1.c                             |  180 +
 src/AMD/Source/amd_2.c                             | 1842 ++++
 src/AMD/Source/amd_aat.c                           |  184 +
 src/AMD/Source/amd_control.c                       |   63 +
 src/AMD/Source/amd_defaults.c                      |   37 +
 src/AMD/Source/amd_dump.c                          |  179 +
 src/AMD/Source/amd_global.c                        |   83 +
 src/AMD/Source/amd_info.c                          |  119 +
 src/AMD/Source/amd_order.c                         |  199 +
 src/AMD/Source/amd_post_tree.c                     |  120 +
 src/AMD/Source/amd_postorder.c                     |  206 +
 src/AMD/Source/amd_preprocess.c                    |  118 +
 src/AMD/Source/amd_valid.c                         |   92 +
 src/AMD/Source/amdbar.f                            | 1206 +++
 src/CHOLMOD.diff                                   |   89 +
 src/CHOLMOD/Check/License.txt                      |   24 +
 src/CHOLMOD/Check/cholmod_check.c                  | 2709 ++++++
 src/CHOLMOD/Check/cholmod_read.c                   | 1319 +++
 src/CHOLMOD/Check/cholmod_write.c                  |  744 ++
 src/CHOLMOD/Check/lesser.txt                       |  504 ++
 src/CHOLMOD/Cholesky/License.txt                   |   24 +
 src/CHOLMOD/Cholesky/cholmod_amd.c                 |  211 +
 src/CHOLMOD/Cholesky/cholmod_analyze.c             |  942 ++
 src/CHOLMOD/Cholesky/cholmod_colamd.c              |  209 +
 src/CHOLMOD/Cholesky/cholmod_etree.c               |  226 +
 src/CHOLMOD/Cholesky/cholmod_factorize.c           |  428 +
 src/CHOLMOD/Cholesky/cholmod_postorder.c           |  291 +
 src/CHOLMOD/Cholesky/cholmod_rcond.c               |  160 +
 src/CHOLMOD/Cholesky/cholmod_resymbol.c            |  608 ++
 src/CHOLMOD/Cholesky/cholmod_rowcolcounts.c        |  536 ++
 src/CHOLMOD/Cholesky/cholmod_rowfac.c              |  735 ++
 src/CHOLMOD/Cholesky/cholmod_solve.c               | 1684 ++++
 src/CHOLMOD/Cholesky/cholmod_spsolve.c             |  396 +
 src/CHOLMOD/Cholesky/lesser.txt                    |  504 ++
 src/CHOLMOD/Cholesky/t_cholmod_lsolve.c            |  850 ++
 src/CHOLMOD/Cholesky/t_cholmod_ltsolve.c           |  849 ++
 src/CHOLMOD/Cholesky/t_cholmod_rowfac.c            |  457 +
 src/CHOLMOD/Cholesky/t_cholmod_solve.c             |  177 +
 src/CHOLMOD/Core/License.txt                       |   25 +
 src/CHOLMOD/Core/cholmod_aat.c                     |  301 +
 src/CHOLMOD/Core/cholmod_add.c                     |  281 +
 src/CHOLMOD/Core/cholmod_band.c                    |  373 +
 src/CHOLMOD/Core/cholmod_change_factor.c           | 1226 +++
 src/CHOLMOD/Core/cholmod_common.c                  |  701 ++
 src/CHOLMOD/Core/cholmod_complex.c                 |  549 ++
 src/CHOLMOD/Core/cholmod_copy.c                    |  406 +
 src/CHOLMOD/Core/cholmod_dense.c                   |  701 ++
 src/CHOLMOD/Core/cholmod_error.c                   |   79 +
 src/CHOLMOD/Core/cholmod_factor.c                  |  936 ++
 src/CHOLMOD/Core/cholmod_memory.c                  |  575 ++
 src/CHOLMOD/Core/cholmod_sparse.c                  |  651 ++
 src/CHOLMOD/Core/cholmod_transpose.c               | 1138 +++
 src/CHOLMOD/Core/cholmod_triplet.c                 |  772 ++
 src/CHOLMOD/Core/cholmod_version.c                 |   37 +
 src/CHOLMOD/Core/lesser.txt                        |  504 ++
 src/CHOLMOD/Core/t_cholmod_change_factor.c         |  660 ++
 src/CHOLMOD/Core/t_cholmod_dense.c                 |  265 +
 src/CHOLMOD/Core/t_cholmod_transpose.c             |  317 +
 src/CHOLMOD/Core/t_cholmod_triplet.c               |  175 +
 src/CHOLMOD/Include/License.txt                    |    8 +
 src/CHOLMOD/Include/README.txt                     |   25 +
 src/CHOLMOD/Include/cholmod.h                      |  125 +
 src/CHOLMOD/Include/cholmod_blas.h                 |  455 +
 src/CHOLMOD/Include/cholmod_camd.h                 |  102 +
 src/CHOLMOD/Include/cholmod_check.h                |  427 +
 src/CHOLMOD/Include/cholmod_cholesky.h             |  565 ++
 src/CHOLMOD/Include/cholmod_complexity.h           |  264 +
 src/CHOLMOD/Include/cholmod_config.h               |   85 +
 src/CHOLMOD/Include/cholmod_core.h                 | 2395 +++++
 src/CHOLMOD/Include/cholmod_internal.h             |  404 +
 src/CHOLMOD/Include/cholmod_io64.h                 |   45 +
 src/CHOLMOD/Include/cholmod_matrixops.h            |  237 +
 src/CHOLMOD/Include/cholmod_modify.h               |  306 +
 src/CHOLMOD/Include/cholmod_partition.h            |  166 +
 src/CHOLMOD/Include/cholmod_supernodal.h           |  172 +
 src/CHOLMOD/Include/cholmod_template.h             |  238 +
 src/CHOLMOD/Makefile                               |   75 +
 src/CHOLMOD/MatrixOps/License.txt                  |   25 +
 src/CHOLMOD/MatrixOps/cholmod_drop.c               |  183 +
 src/CHOLMOD/MatrixOps/cholmod_horzcat.c            |  203 +
 src/CHOLMOD/MatrixOps/cholmod_norm.c               |  452 +
 src/CHOLMOD/MatrixOps/cholmod_scale.c              |  217 +
 src/CHOLMOD/MatrixOps/cholmod_sdmult.c             |  149 +
 src/CHOLMOD/MatrixOps/cholmod_ssmult.c             |  487 +
 src/CHOLMOD/MatrixOps/cholmod_submatrix.c          |  425 +
 src/CHOLMOD/MatrixOps/cholmod_symmetry.c           |  488 +
 src/CHOLMOD/MatrixOps/cholmod_vertcat.c            |  201 +
 src/CHOLMOD/MatrixOps/gpl.txt                      |  340 +
 src/CHOLMOD/MatrixOps/t_cholmod_sdmult.c           |  726 ++
 src/CHOLMOD/Modify/License.txt                     |   25 +
 src/CHOLMOD/Modify/cholmod_rowadd.c                |  678 ++
 src/CHOLMOD/Modify/cholmod_rowdel.c                |  461 +
 src/CHOLMOD/Modify/cholmod_updown.c                | 1570 ++++
 src/CHOLMOD/Modify/gpl.txt                         |  340 +
 src/CHOLMOD/Modify/t_cholmod_updown.c              |  214 +
 src/CHOLMOD/Modify/t_cholmod_updown_numkr.c        |  746 ++
 src/CHOLMOD/Partition/License.txt                  |   25 +
 src/CHOLMOD/Partition/cholmod_camd.c               |  231 +
 src/CHOLMOD/Partition/cholmod_ccolamd.c            |  208 +
 src/CHOLMOD/Partition/cholmod_csymamd.c            |  144 +
 src/CHOLMOD/Partition/cholmod_metis.c              |  795 ++
 src/CHOLMOD/Partition/cholmod_nesdis.c             | 2168 +++++
 src/CHOLMOD/Partition/lesser.txt                   |  504 ++
 src/CHOLMOD/README.txt                             |   81 +
 src/CHOLMOD/Supernodal/License.txt                 |   25 +
 src/CHOLMOD/Supernodal/cholmod_super_numeric.c     |  307 +
 src/CHOLMOD/Supernodal/cholmod_super_solve.c       |  217 +
 src/CHOLMOD/Supernodal/cholmod_super_symbolic.c    |  862 ++
 src/CHOLMOD/Supernodal/gpl.txt                     |  340 +
 src/CHOLMOD/Supernodal/t_cholmod_gpu.c             |  972 ++
 src/CHOLMOD/Supernodal/t_cholmod_super_numeric.c   |  912 ++
 src/CHOLMOD/Supernodal/t_cholmod_super_solve.c     |  450 +
 src/COLAMD/Include/colamd.h                        |  251 +
 src/COLAMD/Makefile                                |   56 +
 src/COLAMD/README.txt                              |  118 +
 src/COLAMD/Source/colamd.c                         | 3604 ++++++++
 src/COLAMD/Source/colamd_global.c                  |   24 +
 src/Makevars.in                                    |   10 +-
 src/Makevars.win                                   |    7 +-
 src/SuiteSparse_config/Makefile                    |   43 +
 src/SuiteSparse_config/README.txt                  |   48 +
 src/SuiteSparse_config/SuiteSparse_config.c        |  191 +
 src/SuiteSparse_config/SuiteSparse_config.h        |  202 +
 src/SuiteSparse_config/SuiteSparse_config.mk       |  393 +
 src/SuiteSparse_config/SuiteSparse_config_GPU.mk   |  393 +
 src/SuiteSparse_config/SuiteSparse_config_Mac.mk   |  395 +
 src/adjlist.c                                      |   44 +-
 src/bigint.c                                       |    6 -
 src/blas.c                                         |    6 +
 src/cattributes.c                                  |  502 +-
 src/centrality.c                                   |   48 +-
 src/community.c                                    |   48 +-
 src/components.c                                   |   91 +-
 src/config.h.in                                    |   32 +-
 src/{ => cs}/cs_add.c                              |    0
 src/{ => cs}/cs_amd.c                              |    0
 src/{ => cs}/cs_chol.c                             |    0
 src/{ => cs}/cs_cholsol.c                          |    0
 src/{ => cs}/cs_compress.c                         |    0
 src/{ => cs}/cs_counts.c                           |    0
 src/{ => cs}/cs_cumsum.c                           |    0
 src/{ => cs}/cs_dfs.c                              |    0
 src/{ => cs}/cs_dmperm.c                           |    0
 src/{ => cs}/cs_droptol.c                          |    0
 src/{ => cs}/cs_dropzeros.c                        |    0
 src/{ => cs}/cs_dupl.c                             |    0
 src/{ => cs}/cs_entry.c                            |    0
 src/{ => cs}/cs_ereach.c                           |    0
 src/{ => cs}/cs_etree.c                            |    0
 src/{ => cs}/cs_fkeep.c                            |    0
 src/{ => cs}/cs_gaxpy.c                            |    0
 src/{ => cs}/cs_happly.c                           |    0
 src/{ => cs}/cs_house.c                            |    0
 src/{ => cs}/cs_ipvec.c                            |    0
 src/{ => cs}/cs_leaf.c                             |    0
 src/{ => cs}/cs_load.c                             |    0
 src/{ => cs}/cs_lsolve.c                           |    0
 src/{ => cs}/cs_ltsolve.c                          |    0
 src/{ => cs}/cs_lu.c                               |    0
 src/{ => cs}/cs_lusol.c                            |    0
 src/{ => cs}/cs_malloc.c                           |    0
 src/{ => cs}/cs_maxtrans.c                         |    0
 src/{ => cs}/cs_multiply.c                         |    0
 src/{ => cs}/cs_norm.c                             |    0
 src/{ => cs}/cs_permute.c                          |    0
 src/{ => cs}/cs_pinv.c                             |    0
 src/{ => cs}/cs_post.c                             |    0
 src/{ => cs}/cs_print.c                            |    0
 src/{ => cs}/cs_pvec.c                             |    0
 src/{ => cs}/cs_qr.c                               |    0
 src/{ => cs}/cs_qrsol.c                            |    0
 src/cs/cs_randperm.c                               |   49 +
 src/{ => cs}/cs_reach.c                            |    0
 src/{ => cs}/cs_scatter.c                          |    0
 src/{ => cs}/cs_scc.c                              |    0
 src/{ => cs}/cs_schol.c                            |    0
 src/{ => cs}/cs_spsolve.c                          |    0
 src/{ => cs}/cs_sqr.c                              |    0
 src/{ => cs}/cs_symperm.c                          |    0
 src/{ => cs}/cs_tdfs.c                             |    0
 src/{ => cs}/cs_transpose.c                        |    0
 src/{ => cs}/cs_updown.c                           |    0
 src/{ => cs}/cs_usolve.c                           |    0
 src/{ => cs}/cs_util.c                             |    0
 src/{ => cs}/cs_utsolve.c                          |    0
 src/cs_randperm.c                                  |   44 -
 src/dotproduct.c                                   |  276 +
 src/dqueue.c                                       |    6 +
 src/dqueue.pmt                                     |    1 -
 src/drl_layout.cpp                                 |    2 +-
 src/embedding.c                                    | 1116 +++
 src/evolver_cit.c                                  |  179 -
 src/f2c.h                                          |  230 -
 src/f2c_dummy.c                                    |   25 -
 src/flow.c                                         |   16 +-
 src/foreign-dl-lexer.c                             |   58 +-
 src/foreign-dl-parser.c                            |  116 +-
 src/foreign-dl-parser.h                            |    2 +-
 src/foreign-gml-lexer.c                            |   28 +-
 src/foreign-gml-parser.c                           |   38 +-
 src/foreign-gml-parser.h                           |    2 +-
 src/foreign-graphml.c                              |  600 +-
 src/foreign-lgl-lexer.c                            |   20 +-
 src/foreign-lgl-parser.c                           |   16 +-
 src/foreign-lgl-parser.h                           |    2 +-
 src/foreign-ncol-lexer.c                           |   18 +-
 src/foreign-ncol-parser.c                          |   14 +-
 src/foreign-ncol-parser.h                          |    2 +-
 src/foreign-pajek-lexer.c                          |  104 +-
 src/foreign-pajek-parser.c                         |  176 +-
 src/foreign-pajek-parser.h                         |    2 +-
 src/foreign.c                                      |   16 +-
 src/games.c                                        |  270 +-
 src/gengraph_box_list.h                            |    2 +
 src/gengraph_definitions.h                         |    4 +
 src/gengraph_graph_molloy_hash.cpp                 |    4 +-
 src/gengraph_graph_molloy_optimized.cpp            |   16 +-
 src/gengraph_qsort.h                               |    4 +
 src/gengraph_vertex_cover.h                        |    4 +
 src/glpenv01.c                                     |  234 -
 src/glpk/COPYING                                   |  676 ++
 src/glpk/README                                    |   39 +
 src/glpk/amd/COPYING                               |  502 ++
 src/glpk/amd/README                                |   58 +
 src/{ => glpk/amd}/amd_1.c                         |    0
 src/{ => glpk/amd}/amd_2.c                         |    0
 src/{ => glpk/amd}/amd_aat.c                       |    0
 src/{ => glpk/amd}/amd_control.c                   |    0
 src/{ => glpk/amd}/amd_defaults.c                  |    0
 src/{ => glpk/amd}/amd_dump.c                      |    0
 src/{ => glpk/amd}/amd_info.c                      |    0
 src/{ => glpk/amd}/amd_order.c                     |    0
 src/{ => glpk/amd}/amd_post_tree.c                 |    0
 src/{ => glpk/amd}/amd_postorder.c                 |    0
 src/{ => glpk/amd}/amd_preprocess.c                |    0
 src/{ => glpk/amd}/amd_valid.c                     |    0
 src/glpk/colamd/COPYING                            |  502 ++
 src/glpk/colamd/README                             |   98 +
 src/{ => glpk/colamd}/colamd.c                     |    0
 src/{ => glpk}/glpapi01.c                          |    0
 src/{ => glpk}/glpapi02.c                          |    0
 src/{ => glpk}/glpapi03.c                          |    0
 src/{ => glpk}/glpapi04.c                          |    0
 src/{ => glpk}/glpapi05.c                          |    0
 src/{ => glpk}/glpapi06.c                          |    0
 src/{ => glpk}/glpapi07.c                          |    0
 src/{ => glpk}/glpapi08.c                          |    0
 src/{ => glpk}/glpapi09.c                          |    0
 src/{ => glpk}/glpapi10.c                          |    0
 src/{ => glpk}/glpapi11.c                          |    0
 src/{ => glpk}/glpapi12.c                          |    0
 src/{ => glpk}/glpapi13.c                          |    0
 src/{ => glpk}/glpapi14.c                          |    0
 src/{ => glpk}/glpapi15.c                          |    0
 src/{ => glpk}/glpapi16.c                          |    0
 src/{ => glpk}/glpapi17.c                          |    0
 src/{ => glpk}/glpapi18.c                          |    0
 src/{ => glpk}/glpapi19.c                          |    0
 src/{ => glpk}/glpavl.c                            |    0
 src/{ => glpk}/glpbfd.c                            |    0
 src/{ => glpk}/glpbfx.c                            |    0
 src/{ => glpk}/glpcpx.c                            |    0
 src/{ => glpk}/glpdmp.c                            |    0
 src/{ => glpk}/glpdmx.c                            |    0
 src/glpk/glpenv01.c                                |  238 +
 src/{ => glpk}/glpenv02.c                          |    0
 src/{ => glpk}/glpenv03.c                          |    0
 src/{ => glpk}/glpenv04.c                          |    0
 src/{ => glpk}/glpenv05.c                          |    0
 src/{ => glpk}/glpenv06.c                          |    0
 src/{ => glpk}/glpenv07.c                          |    0
 src/{ => glpk}/glpenv08.c                          |    0
 src/{ => glpk}/glpfhv.c                            |    0
 src/{ => glpk}/glpgmp.c                            |    0
 src/{ => glpk}/glphbm.c                            |    0
 src/{ => glpk}/glpini01.c                          |    0
 src/{ => glpk}/glpini02.c                          |    0
 src/{ => glpk}/glpios01.c                          |    0
 src/{ => glpk}/glpios02.c                          |    0
 src/{ => glpk}/glpios03.c                          |    0
 src/{ => glpk}/glpios04.c                          |    0
 src/{ => glpk}/glpios05.c                          |    0
 src/{ => glpk}/glpios06.c                          |    0
 src/{ => glpk}/glpios07.c                          |    0
 src/{ => glpk}/glpios08.c                          |    0
 src/{ => glpk}/glpios09.c                          |    0
 src/{ => glpk}/glpios10.c                          |    0
 src/{ => glpk}/glpios11.c                          |    0
 src/{ => glpk}/glpios12.c                          |    0
 src/{ => glpk}/glpipm.c                            |    0
 src/glpk/glpk.inc                                  |    1 +
 src/{ => glpk}/glplib01.c                          |    0
 src/{ => glpk}/glplib02.c                          |    0
 src/{ => glpk}/glplib03.c                          |    0
 src/{ => glpk}/glplpf.c                            |    0
 src/{ => glpk}/glplpx01.c                          |    0
 src/{ => glpk}/glplpx02.c                          |    0
 src/{ => glpk}/glplpx03.c                          |    0
 src/{ => glpk}/glpluf.c                            |    0
 src/{ => glpk}/glplux.c                            |    0
 src/{ => glpk}/glpmat.c                            |    0
 src/{ => glpk}/glpmpl01.c                          |    0
 src/{ => glpk}/glpmpl02.c                          |    0
 src/{ => glpk}/glpmpl03.c                          |    0
 src/{ => glpk}/glpmpl04.c                          |    0
 src/{ => glpk}/glpmpl05.c                          |    0
 src/{ => glpk}/glpmpl06.c                          |    0
 src/{ => glpk}/glpmps.c                            |    0
 src/{ => glpk}/glpnet01.c                          |    0
 src/{ => glpk}/glpnet02.c                          |    0
 src/{ => glpk}/glpnet03.c                          |    0
 src/{ => glpk}/glpnet04.c                          |    0
 src/{ => glpk}/glpnet05.c                          |    0
 src/{ => glpk}/glpnet06.c                          |    0
 src/{ => glpk}/glpnet07.c                          |    0
 src/{ => glpk}/glpnet08.c                          |    0
 src/{ => glpk}/glpnet09.c                          |    0
 src/{ => glpk}/glpnpp01.c                          |    0
 src/{ => glpk}/glpnpp02.c                          |    0
 src/{ => glpk}/glpnpp03.c                          |    0
 src/{ => glpk}/glpnpp04.c                          |    0
 src/{ => glpk}/glpnpp05.c                          |    0
 src/{ => glpk}/glpqmd.c                            |    0
 src/{ => glpk}/glprgr.c                            |    0
 src/{ => glpk}/glprng01.c                          |    0
 src/{ => glpk}/glprng02.c                          |    0
 src/{ => glpk}/glpscf.c                            |    0
 src/{ => glpk}/glpscl.c                            |    0
 src/{ => glpk}/glpsdf.c                            |    0
 src/{ => glpk}/glpspm.c                            |    0
 src/{ => glpk}/glpspx01.c                          |    0
 src/{ => glpk}/glpspx02.c                          |    0
 src/{ => glpk}/glpsql.c                            |    0
 src/{ => glpk}/glpssx01.c                          |    0
 src/{ => glpk}/glpssx02.c                          |    0
 src/{ => glpk}/glptsp.c                            |    0
 src/heap.pmt                                       |    1 -
 src/igraph.h                                       |   97 -
 src/igraph_adjlist.h                               |  238 -
 src/igraph_blas.h                                  |   72 -
 src/igraph_blas_internal.h                         |   10 +
 src/igraph_constants.h                             |  159 -
 src/igraph_dqueue.h                                |   76 -
 src/igraph_eigen.h                                 |  118 -
 src/igraph_error.h                                 |  721 --
 src/igraph_games.h                                 |  194 -
 src/igraph_lapack.h                                |  118 -
 src/igraph_lapack_internal.h                       |    6 +
 src/igraph_layout.h                                |  253 -
 src/igraph_math.h                                  |    4 +
 src/igraph_matrix.h                                |  107 -
 src/igraph_matrix_pmt.h                            |  234 -
 src/igraph_motifs.h                                |  104 -
 src/igraph_neighborhood.h                          |   51 -
 src/igraph_paths.h                                 |  135 -
 src/igraph_pmt.h                                   |  142 -
 src/igraph_random.h                                |  129 -
 src/igraph_revolver.h                              | 1200 ---
 src/igraph_sparsemat.h                             |  264 -
 src/igraph_stack.c                                 |    6 +
 src/igraph_stack.h                                 |   82 -
 src/igraph_vector.h                                |  174 -
 src/igraph_version.h                               |    6 +-
 src/include/igraph.h                               |   99 +
 src/include/igraph_adjlist.h                       |  238 +
 src/{ => include}/igraph_arpack.h                  |    0
 src/{ => include}/igraph_array.h                   |    0
 src/{ => include}/igraph_array_pmt.h               |    0
 src/{ => include}/igraph_attributes.h              |    0
 src/{ => include}/igraph_bipartite.h               |    0
 src/include/igraph_blas.h                          |   74 +
 src/{ => include}/igraph_centrality.h              |    0
 src/{ => include}/igraph_cliques.h                 |    0
 src/{ => include}/igraph_cocitation.h              |    0
 src/{ => include}/igraph_cohesive_blocks.h         |    0
 src/{ => include}/igraph_community.h               |    0
 src/{ => include}/igraph_complex.h                 |    0
 src/{ => include}/igraph_components.h              |    0
 src/include/igraph_constants.h                     |  167 +
 src/{ => include}/igraph_constructors.h            |    0
 src/{ => include}/igraph_conversion.h              |    0
 src/{ => include}/igraph_datatype.h                |    0
 src/include/igraph_dqueue.h                        |   82 +
 src/{ => include}/igraph_dqueue_pmt.h              |    0
 src/include/igraph_eigen.h                         |  119 +
 src/include/igraph_embedding.h                     |   77 +
 src/{ => include}/igraph_epidemics.h               |    0
 src/include/igraph_error.h                         |  723 ++
 src/{ => include}/igraph_flow.h                    |    0
 src/{ => include}/igraph_foreign.h                 |    0
 src/include/igraph_games.h                         |  235 +
 src/{ => include}/igraph_graphlets.h               |    0
 src/{ => include}/igraph_heap.h                    |    0
 src/{ => include}/igraph_heap_pmt.h                |    0
 src/{ => include}/igraph_hrg.h                     |    0
 src/{ => include}/igraph_interface.h               |    0
 src/{ => include}/igraph_interrupt.h               |    0
 src/{ => include}/igraph_iterators.h               |    0
 src/include/igraph_lapack.h                        |  121 +
 src/include/igraph_layout.h                        |  258 +
 src/include/igraph_lsap.h                          |   12 +
 src/{ => include}/igraph_matching.h                |    0
 src/include/igraph_matrix.h                        |  109 +
 src/include/igraph_matrix_pmt.h                    |  243 +
 src/{ => include}/igraph_memory.h                  |    0
 src/{ => include}/igraph_microscopic_update.h      |    0
 src/{ => include}/igraph_mixing.h                  |    0
 src/include/igraph_motifs.h                        |  106 +
 src/include/igraph_neighborhood.h                  |   52 +
 src/{ => include}/igraph_nongraph.h                |    0
 src/{ => include}/igraph_operators.h               |    0
 src/include/igraph_paths.h                         |  147 +
 src/include/igraph_pmt.h                           |  150 +
 src/{ => include}/igraph_pmt_off.h                 |    0
 src/{ => include}/igraph_progress.h                |    0
 src/{ => include}/igraph_psumtree.h                |    0
 src/{ => include}/igraph_qsort.h                   |    0
 src/include/igraph_random.h                        |  142 +
 src/include/igraph_scan.h                          |   78 +
 src/{ => include}/igraph_scg.h                     |    0
 src/{ => include}/igraph_separators.h              |    0
 src/include/igraph_sparsemat.h                     |  281 +
 src/{ => include}/igraph_spmatrix.h                |    0
 src/include/igraph_stack.h                         |   88 +
 src/{ => include}/igraph_stack_pmt.h               |    0
 src/{ => include}/igraph_statusbar.h               |    0
 src/{ => include}/igraph_structural.h              |    0
 src/{ => include}/igraph_strvector.h               |    0
 src/include/igraph_threading.h.in                  |   51 +
 src/{ => include}/igraph_topology.h                |    0
 src/{ => include}/igraph_transitivity.h            |    0
 src/{ => include}/igraph_types.h                   |    0
 src/include/igraph_vector.h                        |  188 +
 src/{ => include}/igraph_vector_pmt.h              |    0
 src/{ => include}/igraph_vector_ptr.h              |    0
 src/{ => include}/igraph_vector_type.h             |    0
 src/include/igraph_version.h.in                    |   40 +
 src/{ => include}/igraph_visitor.h                 |    0
 src/lad.c                                          |   48 +-
 src/lapack.c                                       |   17 +
 src/layout.c                                       |  993 +--
 src/layout_dh.c                                    |  399 +
 src/layout_fr.c                                    |  677 ++
 src/layout_gem.c                                   |  241 +
 src/layout_kk.c                                    |  597 ++
 src/lazyeval.c                                     |  173 +
 src/lsap.c                                         |  614 ++
 src/matching.c                                     |   12 +-
 src/matrix.c                                       |   30 +-
 src/matrix.pmt                                     |   11 +
 src/operators.c                                    |    8 +-
 src/other.c                                        |   81 +-
 src/paths.c                                        |  159 +
 src/{ => plfit}/error.c                            |    0
 src/{ => plfit}/gss.c                              |    0
 src/{ => plfit}/kolmogorov.c                       |    0
 src/{ => plfit}/lbfgs.c                            |    0
 src/{ => plfit}/options.c                          |    0
 src/{ => plfit}/plfit.c                            |    0
 src/plfit/plfit.inc                                |    9 +
 src/{ => plfit}/zeta.c                             |    0
 src/prpack.cpp                                     |    2 +-
 src/prpack/prpack.inc                              |   23 +
 src/{ => prpack}/prpack_base_graph.cpp             |    0
 src/{ => prpack}/prpack_igraph_graph.cpp           |    0
 src/{ => prpack}/prpack_preprocessed_ge_graph.cpp  |    0
 src/{ => prpack}/prpack_preprocessed_gs_graph.cpp  |    0
 src/{ => prpack}/prpack_preprocessed_scc_graph.cpp |    0
 .../prpack_preprocessed_schur_graph.cpp            |    0
 src/{ => prpack}/prpack_result.cpp                 |    0
 src/prpack/prpack_solver.cpp                       |  879 ++
 src/prpack/prpack_utils.cpp                        |   60 +
 src/prpack_solver.cpp                              |  877 --
 src/prpack_utils.cpp                               |   61 -
 src/random.c                                       |  339 +
 src/random_walk.c                                  |  113 +
 src/revolver_cit.c                                 | 6479 --------------
 src/revolver_grow.c                                | 1284 ---
 src/revolver_ml_cit.c                              | 3548 --------
 src/rinterface.c                                   | 9398 ++++++++------------
 src/rinterface.h                                   |    6 +
 src/rinterface_extra.c                             |  115 +-
 src/sbm.c                                          |  387 +
 src/scan.c                                         |  859 ++
 src/{ => simpleraytracer}/Color.cpp                |    0
 src/{ => simpleraytracer}/Color.h                  |    0
 src/{ => simpleraytracer}/Light.cpp                |    0
 src/{ => simpleraytracer}/Light.h                  |    0
 src/{ => simpleraytracer}/Point.cpp                |    0
 src/{ => simpleraytracer}/Point.h                  |    0
 src/{ => simpleraytracer}/RIgraphRay.cpp           |    0
 src/{ => simpleraytracer}/Ray.cpp                  |    0
 src/{ => simpleraytracer}/Ray.h                    |    0
 src/{ => simpleraytracer}/RayTracer.cpp            |    0
 src/{ => simpleraytracer}/RayTracer.h              |    0
 src/{ => simpleraytracer}/RayVector.cpp            |    0
 src/{ => simpleraytracer}/RayVector.h              |    0
 src/{ => simpleraytracer}/Shape.cpp                |    0
 src/{ => simpleraytracer}/Shape.h                  |    0
 src/{ => simpleraytracer}/Sphere.cpp               |    0
 src/{ => simpleraytracer}/Sphere.h                 |    0
 src/{ => simpleraytracer}/Triangle.cpp             |    0
 src/{ => simpleraytracer}/Triangle.h               |    0
 src/{ => simpleraytracer}/unit_limiter.cpp         |    0
 src/{ => simpleraytracer}/unit_limiter.h           |    0
 src/sparsemat.c                                    |  317 +
 src/stack.pmt                                      |    1 -
 src/structural_properties.c                        |   71 +-
 src/triangles.c                                    |   52 +-
 src/triangles_template.h                           |   21 +-
 src/triangles_template1.h                          |   12 +-
 src/type_indexededgelist.c                         |   33 +-
 src/uuid/COPYING                                   |   28 +
 src/uuid/Makevars.in                               |    2 +
 src/uuid/Makevars.win                              |    1 +
 src/uuid/R.c                                       |   25 +
 src/uuid/clear.c                                   |   43 +
 src/uuid/compare.c                                 |   55 +
 src/uuid/config.h.in                               |   82 +
 src/uuid/copy.c                                    |   45 +
 src/uuid/gen_uuid.c                                |  575 ++
 src/uuid/isnull.c                                  |   48 +
 src/uuid/pack.c                                    |   69 +
 src/uuid/parse.c                                   |   79 +
 src/uuid/unpack.c                                  |   63 +
 src/uuid/unparse.c                                 |   76 +
 src/uuid/uuid.h                                    |  104 +
 src/uuid/uuidP.h                                   |   63 +
 src/uuid/uuidd.h                                   |   54 +
 src/uuid/win32/config.h                            |   84 +
 src/vector.c                                       |  100 +-
 src/visitors.c                                     |    5 +-
 1279 files changed, 137557 insertions(+), 48676 deletions(-)

diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index aeb346c..0000000
--- a/AUTHORS
+++ /dev/null
@@ -1,133 +0,0 @@
-
-igraph authors, in alphabetical order:
---------------------------------------
-
-Patrick R. Amestoy	AMD library
-Adelchi Azzalini	igraph.options based on the sm package
-Tamas Badics		GLPK
-Gregory Benison		Minimum cut calculation
-Adrian Bowman		igraph.options based on the sm package
-Keith Briggs		Parts from the Very Nauty Graph Library
-      			Geometric random graphs
-			Girth
-      			Various patches and bug fixes
-Jeroen Bruggeman	spinglass community detection
-       			Burt's constraints
-Juergen Buchmueller	Big number math implementation
-Carter T. Butts		Some layout algorithms from the SNA R package
-       	  		bonpow function in the SNA R package
-			Some R manual pages, from the SNA R package
-Aaron Clauset		Hierarchical random graphs
-J.T. Conklin		logbl function
-Topher Cooper		GSL random number generators (not used in R)
-Gabor Csardi		Most of igraph
-Trevor Croft		simpleraytracer
-Peter DalGaard		zeroin root finder
-Timothy A Davis		CXSPARSE: a Concise Sparse Matrix package - Extended
-	  		AMD library
-	  		Sparse matrix column ordering
-Laurent Deniau		Bits of the error handling system
-Ulrich Drepper		logbl function
-Iain S. Duff		AMD library
-     			GLPK
-S.I. Feldman		f2c
-David Firth		Display data frame in Tk, from relimp package
-P. Foggia		VF2 graph isomorphism algorithm
-John Fox		R: suppressing X11 warnings
-Alan George   		GLPK
-John Gilbert		Sparse matrix column ordering
-D.Goldfarb		GLPK
-Brian Gough		GSL random number generators (not used in R)
-Tom Gregorovic		Multilevel community detection
-M.Grigoriadis		GLPK
-Oscar Gustafsson	GLPK
-Paul Hsieh		pstdint.h
-Ross Ihaka		Some random number generators (not used in R)
-Tommi Junttila		BLISS graph isomorphism library
-Petteri Kaski		BLISS graph isomorphism library
-Oleg Keselyov		zeroin root finder
-Darwin Klingman		GLPK
-Donald E. Knuth		GLPK
-Stefan I. Larimore	Sparse matrix column ordering
-Yusin Lee 		GLPK
-Richard Lehoucq		ARPACK
-Rene Locher		R arrow drawing function, from IDPmisc package
-J.C. Nash		BFGS optimizer
-Joseph W-H Liu		GLPK
-Makoto Matsumoto	GSL random number generators (not used in R)
-Vincent Matossian	Graph laplacian
-			igraph_neighborhood_graphs
-			Line graphs
-Peter McMahan		Cohesive blocking
-Andrew Makhorin		GLPK
-David Morton de Lachapelle	Spectral coarse graining
-Laurence Muller		Fixes for compilation on MS Visual Studio
-Fionn Murtagh		Order a hierarchical clustering
-Emmanuel Navarro	infomap community detection
-	 		Various fixes and patches
-Tamas Nepusz		Most of igraph
-Esmond Ng 		Sparse matrix column ordering
-Kevin O'Neill		Maximal independent vertex sets
-Takuji Nishimura	GSL random number generators (not used in R)
-Jim Orlin		GLPK
-Patric Ostergard	GLPK
-Elliot Paquette		psumtree data type
-Pascal Pons		walktrap community detection
-Joerg Reichardt		spinglass community detection
-Marc Rieffel		GSL random number generators (not used in R)
-B.D. Ripley		igraph.options based on the sm package
-     			BFGS optimizer
-			Various bug fixes
-Martin Rosvall		infomap community detection
-Andreas Ruckstuhl	R arrow drawing function, from IDPmisc package
-Heinrich Schuchardt	GLPK
-J.K. Reid 		GLPK
-C. Sansone		VF2 graph isomorphism algorithm
-Michael Schmuhl		The graphopt layout generator
-Christine Solnon	LAD graph isomorphism library
-Danny Sorensen		ARPACK
-James Theiler		GSL random number generators (not used in R)
-Samuel Thiriot		Interconnected islands graph generator
-Vincent A. Traag	spinglass community detection
-Magnus Torfason		R operators that work by name
-Minh Van Nguyen		Microscopic update rules
-     	 		Various test cases
-     	 		Many documentation and other fixes
-M. Vento		VF2 graph isomorphism algorithm
-Fabien Viger		gengraph graph generator
-Phuong Vu		ARPACK
-P.J. Weinberger		f2c
-Garrett A. Wollman	qsort
-B.N. Wylie 		DrL layout generator
-Chao Yang		ARPACK
-
-Institutional copyright owners:
--------------------------------
-
-Free Software Foundation, Inc	Code generated by bison
-Sandia Corporation	  	DrL layout generator
-The R Development Core Team 	Some random number generators (not used in R)
-      		       		R: as.dendrogram from stats package
-The Regents of the University of California	qsort
-Xerox PARC		      	Sparse matrix column ordering
-
-Other contributors
-------------------
-
-Neal Becker		Patches to compile with gcc 4.4
-Richard Bowman		R patches
-Alex Chen		Patch to compile on Intel compilers
-Daniel Cordeiro 	Patches
-Tom Gregorovic		Bug fixes
-Mayank Lahiri		Forest fire game fix
-John Lapeyre 		Patches
-Christopher Lu		Various fixes and patches
-André Panisson		R patches
-Bob Pap 		Bug fixes
-Keith Ponting		R package bug fixes
-Martin J Reed		Bug fixes
-Elena Tea Russo		Bug fixes
-KennyTM			Bug fixes
-Jordi Torrents		Patches
-Matthew Walker		Various patches
-Kai Willadsen		Arrow size support in Python
diff --git a/DESCRIPTION b/DESCRIPTION
index c32b06d..b6e46c8 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,20 +1,36 @@
 Package: igraph
-Version: 0.7.1
-Date: 2014-04-22
-Title: Network analysis and visualization
+Version: 1.0.1
+Title: Network Analysis and Visualization
 Author: See AUTHORS file.
 Maintainer: Gabor Csardi <csardi.gabor at gmail.com>
-Description: Routines for simple graphs and network analysis. igraph can
-  handle large graphs very well and provides functions for generating random
-  and regular graphs, graph visualization, centrality indices and much more.
+Description: Routines for simple graphs and network analysis. It can
+    handle large graphs very well and provides functions for generating random
+    and regular graphs, graph visualization, centrality methods and much more.
 Depends: methods
-Imports: Matrix
-Suggests: igraphdata, stats4, rgl, tcltk, graph, ape
+Imports: Matrix, magrittr, NMF, irlba
+Suggests: igraphdata, stats4, rgl, tcltk, graph, ape, scales
 License: GPL (>= 2)
 URL: http://igraph.org
 SystemRequirements: gmp, libxml2
 BugReports: https://github.com/igraph/igraph/issues
-Packaged: 2014-04-22 18:00:26 UTC; gaborcsardi
+Collate: 'adjacency.R' 'auto.R' 'assortativity.R' 'attributes.R'
+        'basic.R' 'bipartite.R' 'centrality.R' 'centralization.R'
+        'cliques.R' 'cocitation.R' 'cohesive.blocks.R' 'printr.R'
+        'community.R' 'components.R' 'console.R' 'conversion.R'
+        'data_frame.R' 'decomposition.R' 'degseq.R' 'demo.R'
+        'embedding.R' 'epi.R' 'fit.R' 'flow.R' 'foreign.R' 'games.R'
+        'glet.R' 'hrg.R' 'igraph-package.R' 'incidence.R' 'indexing.R'
+        'interface.R' 'iterators.R' 'layout.R' 'layout_drl.R'
+        'lazyeval.R' 'make.R' 'mgclust.R' 'minimum.spanning.tree.R'
+        'motifs.R' 'nexus.R' 'operators.R' 'other.R' 'package.R'
+        'palette.R' 'par.R' 'paths.R' 'plot.R' 'plot.common.R'
+        'plot.shapes.R' 'pp.R' 'print.R' 'random_walk.R' 'rewire.R'
+        'scan.R' 'scg.R' 'sgm.R' 'similarity.R' 'simple.R' 'sir.R'
+        'socnet.R' 'sparsedf.R' 'structural.properties.R'
+        'structure.info.R' 'test.R' 'tkplot.R' 'topology.R'
+        'triangles.R' 'utils.R' 'uuid.R' 'versions.R' 'weakref.R'
+        'zzz-deprecate.R'
 NeedsCompilation: yes
+Packaged: 2015-06-26 01:04:44 UTC; gaborcsardi
 Repository: CRAN
-Date/Publication: 2014-04-22 23:08:29
+Date/Publication: 2015-06-26 11:13:24
diff --git a/MD5 b/MD5
index 84201f3..5ea643c 100644
--- a/MD5
+++ b/MD5
@@ -1,425 +1,751 @@
-99b8be64f349b103adc8cb859338b1ca *AUTHORS
-bc5a02c974ba8f35a3d5753a4c841ae5 *DESCRIPTION
-16c0850ef35f8fdea0c5409562fb5069 *NAMESPACE
-f435d6ed602b117d12286c24f6bb9047 *NEWS
-5296a012c71b4692c4eafbc82b0d8a57 *R/attributes.R
-8c383a3f7515998e5351efc574acb3e2 *R/auto.R
+2c5e42dcbba6017e93ab51bf81b4f20a *DESCRIPTION
+50bafc0417326064ab29ea6a4644c220 *NAMESPACE
+55dd90c46ae68e431233c74c70817915 *R/adjacency.R
+ba96cdf262f284a91629bcc81958464a *R/assortativity.R
+871276e16f6aeb7b9206f14d18706dbc *R/attributes.R
+7625f16ec000d67fba004b5527af4d0f *R/auto.R
 d41d8cd98f00b204e9800998ecf8427e *R/auto.R.in
-99b409e71bd977062cbd91aec4c15e2f *R/basic.R
-f527380a4b278b4f0ca91f1334692268 *R/bipartite.R
-da58f707c3559bda253777edf5e23995 *R/centrality.R
-d1673cd562b2af755729006c6ce3d814 *R/cliques.R
-e361e9c71f18f8a9adb41beaca81ccc8 *R/cocitation.R
-7bdd13dfb755b3284bce50ef437d4cc2 *R/cohesive.blocks.R
-63c2288e562bf2cd6975c2091f2f414d *R/community.R
-d13e1846bbb660dd08b8965a600c4211 *R/components.R
-e1d90db3a6516c67633ef9e8ea210053 *R/console.R
-3ab675564f4d53c736fb80a8b1da4183 *R/conversion.R
-4bb32ac02f1f75c66028845f53f6d950 *R/decomposition.R
-238adf54a30725ce601625e44766fa96 *R/demo.R
-b2fba3f8858d4d96d2f44c53aa06bf84 *R/epi.R
-c77c162cd280ab90988de2e85150e249 *R/fit.R
-c5804dc24c3091d1c5b2a5f1c72b0fc5 *R/flow.R
-e666b6d8c7368a0ca4aab432bef3f5fb *R/foreign.R
-d2de1cf3c8681cb56aa76a062fa08d21 *R/games.R
-9bb72b81a8881a9bb3edda3284391f3d *R/glet.R
-1482c9aba048986332e830a0a6e6022d *R/hrg.R
-3ec59ac2bbceb42302d9e382e4601f11 *R/indexing.R
-1d2e8b3184b251ca8f35f6201b818bfc *R/interface.R
-a61ca8680ccdf5e3c7e761ebb5ecc0bc *R/iterators.R
-76dee45ded697e86b4a3de83a88e9731 *R/layout.R
-7423ba2fe38652b9a4e16a2e0375cfe2 *R/minimum.spanning.tree.R
-0a427902da9281722a41fb6053ba259b *R/motifs.R
-a894950219f4b721ba0b276aefbc6022 *R/nexus.R
-79816363395853ad7da863c1b6dc615d *R/operators.R
-db590b82e87c2d39aa69bfe2d1c42ad0 *R/other.R
-187d948faa58e01dc56bcc8b1f6ac0fb *R/package.R
-36ba81d919ae2550997665b94f72bcf3 *R/par.R
-dfd92782b7c109dc78cafd1093149f9e *R/plot.R
-9acf307c396d4883fed103825a780fa9 *R/plot.common.R
-cc3648a20be58b52519d515a49a64b09 *R/plot.shapes.R
-0833171a8c2eaf76a0e8e57c8bbfaec0 *R/print.R
-c376415cd72d4ef2d3617e156976a704 *R/revolver.R
-4edd8637f3529608c8230be1b637f598 *R/scg.R
-1198418ab2a1d9e8f611eaeb04967650 *R/socnet.R
-fa788f7f9a26d053131e76c740d365db *R/sparsedf.R
-f2701fc19142703f08279dbbd1466e86 *R/structural.properties.R
-f2de94e2a540bd58cd3b1dd9e36fc29c *R/structure.generators.R
-5e3734f8f19d4c68b53fee8943f3421e *R/structure.info.R
-b48350454f84ceede2793510bbc42df7 *R/test.R
-6c4111c900e2f45486aa982d981d4033 *R/tkplot.R
-570b94fbf8b9cb6846f0363107e61dfa *R/topology.R
-85236ab7181493ccea9cdfc495587a89 *configure
-86216451555b0f3a4e50740d9c51c4fd *configure.in
+2aa7eb58f202fd133c29004b0f600615 *R/basic.R
+955c7998cfc2dd457548cbed16601a56 *R/bipartite.R
+61c7fd410ddf9e53528a33b384d07de2 *R/centrality.R
+249b7f6fb9165564b81c3bf5df932290 *R/centralization.R
+535a949047902b37cf4f1b4b4659425d *R/cliques.R
+6c503afbcde5732d2070df77b7712f9f *R/cocitation.R
+bc9b293f380e0a87c33775da13707e56 *R/cohesive.blocks.R
+9200a81d3cd06c4970779c3d01851ce2 *R/community.R
+4767ee8bfdeacb4dbd4acf70715f560b *R/components.R
+21dccc6b3725cb86825cbe4bcf9ecefc *R/console.R
+845e3474688180d66cb87de42e14d279 *R/conversion.R
+f60154d5c769713e6694ab0c8b287a43 *R/data_frame.R
+46360b04298b2abf673c195277e554f4 *R/decomposition.R
+d20ec0854628e7d0173998343b9d9271 *R/degseq.R
+4206d088dc2e5cad5568d5b0b19cb103 *R/demo.R
+1c0051d5d333d64c534f7a90faf209c9 *R/embedding.R
+2aedcb15df7d1d6f577bde625eae9fd3 *R/epi.R
+7270bb6cdce7f4a9438949e21a3874d1 *R/fit.R
+7b50f4ec4636d2d5057e0d6e45cacb7a *R/flow.R
+0f6515a1a6c8d79b90b86078b64a216f *R/foreign.R
+e7e7ff124f1f515371c9fb791749d933 *R/games.R
+e243b3f2cb3334a5cf2bb51103b66226 *R/glet.R
+fd6c3972a93a933d35144ff7b1b8b8fa *R/hrg.R
+6ac57bf5bf50c5affb5d2aed29f93d40 *R/igraph-package.R
+43d173fd8b57715003d60790c7c2c560 *R/incidence.R
+b1715dfef456137328a00ff9b770545d *R/indexing.R
+b3a77c85e9f5cad37d6c9a0d8899b0e8 *R/interface.R
+019d1060cdccc33575ed954bdbae388f *R/iterators.R
+1045c427da4eb100b63b72eb9f734b92 *R/layout.R
+5ff011b96c1871c3d2736fef68a772b8 *R/layout_drl.R
+f011488c4fade0c2e917568dfbd3dbbf *R/lazyeval.R
+6228a94a52c828fe939bafba779a2987 *R/make.R
+4b1b30ee58dbfbbcf3e0b99d72d385ba *R/mgclust.R
+bfe6df5c0c275a6998e26c3e07b7f794 *R/minimum.spanning.tree.R
+a72970cff239d026a39a8d970e96adac *R/motifs.R
+a294ea37054111ecd15408227ae68615 *R/nexus.R
+681e9b187ce729c6f8bd9434d9977fa1 *R/operators.R
+33503344e3c5008937834887aee6848f *R/other.R
+0f8808bb3fd91c593d6ab9220e06bcc5 *R/package.R
+f965e97b2bf1fdfbab7c5c60ee180cee *R/palette.R
+266a2e11ff674a80dce3b5e0668425a2 *R/par.R
+ef9eb5604ee9485c5e1f95b1e6ebb42c *R/paths.R
+6a0c88a56b8b284a1862064aba1b66ef *R/plot.R
+7c6cdfaa48271ee61543e21d82561521 *R/plot.common.R
+2219bdd7cf551776413f8e8f775110a3 *R/plot.shapes.R
+173dc6c730cf0702ad1fe1dd8a5a9692 *R/pp.R
+480aa14d1bddc436db66b7763dbb9b57 *R/print.R
+aebe5923d9e5ed95bad7edb63f51d411 *R/printr.R
+746a4da766b543cea185baf5375a2cd6 *R/random_walk.R
+7ecfdd3a6d588af525da6a4a8e27554b *R/rewire.R
+774a74900a27b0b69fe2618f14a2a08e *R/scan.R
+d31407a7b29796b72a7a3c2a6eafc313 *R/scg.R
+d2d42ed1f409f616a8fa9dcda5ec12d4 *R/sgm.R
+ba463b11d0c2f3b7cf1781cdeb34d5a3 *R/similarity.R
+296a4b11587d8311ab9ed05836b72f01 *R/simple.R
+db7f41f5186a1dd4561c2464b2acdc07 *R/sir.R
+43a3a2dccadcb247801102866e33dbc2 *R/socnet.R
+1ba5d03fdff8d5e714320cc47f332d1d *R/sparsedf.R
+24e25af5a04efb4d7d82176e6bbf009c *R/structural.properties.R
+d4a76d483bb8afa8716c1ce5340c8cd2 *R/structure.info.R
+441eea32a286eefc85a22e432c3d11b4 *R/test.R
+fe4ab338c2ee6498660eeef229a60106 *R/tkplot.R
+738c84e875b277b2d82da30f5cd710ef *R/topology.R
+d1834d2fffb6a383c6f2ce7b216df3f6 *R/triangles.R
+09c6021900b34101393a17aaf640e920 *R/utils.R
+7cad85ba458be835fa73e70f548b2ee7 *R/uuid.R
+41bcc0ef061e37371ae6203464fb0687 *R/versions.R
+a6102f385771f3b6023b5f83ec872c0d *R/weakref.R
+0ecc144bf3508ed2d4c65e2dbc81c4a2 *R/zzz-deprecate.R
+6e989e75e989389ee4c508d0e37d0d51 *configure
+02637ad0af99df6d0c92b8aa5d2fc8fc *configure.ac
 d41d8cd98f00b204e9800998ecf8427e *configure.win
 f6d91efbe9a92d9da367b19ae2b77d48 *demo/00Index
-1b36208ff2a1e5ff5251d56bb592a3bf *demo/centrality.R
-8885f3a265bf4d3b61ead4fa8c8baaa4 *demo/cohesive.R
-00cfe20fc1f83f6a06d6ae5a513da990 *demo/community.R
-c02d2d3f119cb3f083b057b8e8662bec *demo/crashR.R
-8b40827212837f6f3950b23dfb78798a *demo/hrg.R
-222af9cf74ba2a4e7bfc2d44f2d4e6df *demo/smallworld.R
-99b8be64f349b103adc8cb859338b1ca *inst/AUTHORS
+594342a01208503fbaac63fa9b1f24fa *demo/centrality.R
+66b983548b89ca5c7cf63df0e7a72fe3 *demo/cohesive.R
+4ed3fb8087e8c142cdbc5932c44b363a *demo/community.R
+54f8ab308700e80de829711f2eeab719 *demo/crashR.R
+faf3ffd01e590fd13b34efb775f173eb *demo/hrg.R
+771ca356197ee2b54c40ceccb4c2419c *demo/smallworld.R
+63f74b06a17d02a00dac03fb54a07b54 *inst/AUTHORS
 5cc5f3e2c4239fe9a47bfefdbb923dd0 *inst/CITATION
+b1f7ddce29fbf876cc9b6ef5120df8c2 *inst/NEWS.md
+cf9b9fcdfbc6a08f71bbdcd384312e1b *inst/README.md
+9318bc2aeb60f4f79eac2357da0d9b84 *inst/benchmarks/correlated.R
+4f938e92ca259e3259a5223e87e51bb0 *inst/benchmarks/local.scan.R
 be1c160f903340c69231c009998d9c11 *inst/benchmarks/time_call.R
-e9b385aab8ca83ec08312329dc2a6a0c *inst/benchmarks/time_sir.R
+5ad213883678196238e964be02ae0585 *inst/benchmarks/time_dirSelect.R
+edff9359ac1cb8957676283032452e3c *inst/benchmarks/time_fr_layout.R
+ebf0471b513b73423273265c2fe2a663 *inst/benchmarks/time_kk_layout.R
+f864ca3d5dcd66af6f75b31fd00223a4 *inst/benchmarks/time_print.R
+eae286de8f64912cf4b2ac317bc5e67b *inst/benchmarks/time_sgm.R
+56cacf3291bedc3596f2af9f2e664fa9 *inst/benchmarks/time_sir.R
 9f15757aae0fc33c5e1c8fd7546173a1 *inst/html_library.license.terms
 9a1b851f5373287728fa8fbe7b3f67f0 *inst/html_library.tcl
 4fb9f93f54eeef966f8259609247a787 *inst/igraph.gif
 c07ee84ac019e590ef906200e5183ea2 *inst/igraph2.gif
 87bc6231efc284995f9d609715ea4d2f *inst/my_html_library.tcl
 3a5ec4e3cc8d87587b31237c5541f86e *inst/tests/celegansneural.gml.gz
-4e7cca203677fa3cb785b3f19092ccae *inst/tests/dyad.census.R
+28cd0567bf26075c39c14d11c4c829aa *inst/tests/dyad.census.R
 34d03342fd57be47bdcf3079baea1efa *inst/tests/football.gml.gz
 157659d4b0f46abf1b2893b2e52a9fc1 *inst/tests/power.gml.gz
-d31d406a0437314ee55bcfdc1ce329b1 *inst/tests/test_add.edges.R
-92b1309d632744e902b344e0cf844afd *inst/tests/test_add.vertices.R
-e20404df1236cbc6b197a7625d3955ef *inst/tests/test_all.st.cuts.R
-4b654460652b989dadcb8414572be41f *inst/tests/test_alpha.centrality.R
-344c79c5412c6f0034e6c34fe2f01777 *inst/tests/test_are.connected.R
-2c7d3db034f04519e6645a94ac05cd78 *inst/tests/test_arpack.R
-bb7f261a4c2f80c8119bb826e3229190 *inst/tests/test_articulation.points.R
-168eb57ca4b9e4f5acbb5f39023bad70 *inst/tests/test_as.directed.R
-195fe109313388d97342ff6c4f029072 *inst/tests/test_as.undirected.R
-c25d797aa0a639d42f11c929a14a0acd *inst/tests/test_assortativity.R
-7fa4f73022e6e9d69a39b65f1eec62a3 *inst/tests/test_attributes.R
-338afca5b3a3b295dd28d39d42a8129b *inst/tests/test_authority.score.R
-4e5736a68e3f63c407ebdfaecdfb5962 *inst/tests/test_average.path.length.R
-b9a6f87f9fb6ce050b033d81e07d182a *inst/tests/test_ba.game.R
-bf992a5333d87b2167909dd241122405 *inst/tests/test_betweenness.R
-2e7e4b60e4a660159f12d3aaa6b2d527 *inst/tests/test_biconnected.components.R
-a1539c6a9fb97f13004172a0cecb4892 *inst/tests/test_bipartite.projection.R
-543e658b701f078e4d5df9459afa7f4a *inst/tests/test_bipartite.random.game.R
-aaf49d751e5b3f9f309c8abb41f760b8 *inst/tests/test_bonpow.R
-09dffc611cdd0e4d032d72d0a6cd7e1e *inst/tests/test_bug-1019624.R
-bf5025d43c2e00b64664512739fcc48d *inst/tests/test_bug-1032819.R
-4b3e78e53d1791833f32768b4cfac5b5 *inst/tests/test_bug-1033045.R
-efe6e3f58002704896e364ecd4d8f693 *inst/tests/test_bug-1073705-indexing.R
-43ff7cc288aac3bf6a177299a6dce4c7 *inst/tests/test_bug-1073800-clique.R
-298abe140033edb6f42098cff366b810 *inst/tests/test_callbacks.R
-ccfa3a1bab225fa5c485c315166b8477 *inst/tests/test_canonical.permutation.R
-2125354fe142cfac984704d2de89a647 *inst/tests/test_cliques.R
-1f76b5fab1c5e3cdb562fcd564bbfe34 *inst/tests/test_closeness.R
-6c38899d657a98820a069c9d4f7e8cc7 *inst/tests/test_clusters.R
-dc291e1bc4fc120ad1cfbdf55d335044 *inst/tests/test_communities.R
-039ed2f30198a5e14a062ff8358750bc *inst/tests/test_constraint.R
-0ae5c465092f6fb1a24cdc66882b0e2b *inst/tests/test_contract.vertices.R
-80c5de9b0a8e14071965892dc346c722 *inst/tests/test_count.multiple.R
-5cb21068d61ea3ea54db0fa60e7031b3 *inst/tests/test_decompose.graph.R
-dae8990a3234284931b15cda42742d93 *inst/tests/test_degree.R
-604e38fc4c00f8dee757342b186dbd76 *inst/tests/test_degree.sequence.game.R
-9e95da90e0ef279b01ceb60fdf2f0924 *inst/tests/test_delete.edges.R
-119c85d94d9b5fe56999cca1f349699d *inst/tests/test_delete.vertices.R
-bccf336aef04efe0df1c4420b8f6b4ec *inst/tests/test_diameter.R
-87b65f39adf2e302ba41ee8c6926be2c *inst/tests/test_dominator.tree.R
-fe8993633f7bfff4c992e22275194265 *inst/tests/test_dyad.census.R
-e6220f3a324286fb9c0feb98eb5d3ccb *inst/tests/test_edge.betweenness.R
-6bd7e827ce0cdb40eb04689c32956990 *inst/tests/test_edge.betweenness.community.R
-5c58d100384eab89fd2a9e92130eb98c *inst/tests/test_edge.connectivity.R
-0b33f65818398701019aa1a75fb48399 *inst/tests/test_edgenames.R
-39d23cce35206c1c511132d9a94421c1 *inst/tests/test_evcent.R
-550b55509c1fbb72cc8a839c22c58452 *inst/tests/test_fartherst.nodes.R
-72dc7605af2bc9ad725d90117f95cad6 *inst/tests/test_fastgreedy.community.R
-c149cb204bd0d601fee3c51952597874 *inst/tests/test_forestfire.R
-f56a4d780b739b85f63ab42afc5fa543 *inst/tests/test_get.adjacency.R
-45d06dee3e4b3f53287c0bf0f2cc6ae0 *inst/tests/test_get.adjlist.R
-d71f19e9c211368a5d9e266c698c293d *inst/tests/test_get.all.shortest.paths.R
-ed0a610924d15a6fc9896186da532ee9 *inst/tests/test_get.diameter.R
-7d58dc19fcbe87981f4c4e0388eeafba *inst/tests/test_get.edge.R
-d196bde121b88bb853af41965d9a7c7c *inst/tests/test_get.edgelist.R
-ee55e35eaa74ce819bccff8eb11e2f85 *inst/tests/test_get.incidence.R
-57457d94d1faa7326b14afab5587fd44 *inst/tests/test_get.shortest.paths.R
-04afa867bee1c9f411c914f5cc883744 *inst/tests/test_girth.R
-8e5983e030da6871765e3566ce833912 *inst/tests/test_graph.adhesion.R
-c555ea15e5dfac6bd814096b52858e75 *inst/tests/test_graph.adjacency.R
-05a2e3cdeb95b210145ae701a7b98e8d *inst/tests/test_graph.adjlist.R
+d44acbb3efd8c507e3dbb2004a4dc52f *inst/tests/test-constructor-modifiers.R
+e6b10c3c036376304dd0a6866a8f3926 *inst/tests/test-index-es.R
+4788e269746f1dab1c81dd3c451e25ba *inst/tests/test-isomorphism.R
+72eaaa03dc1634f01b6627dc4b579331 *inst/tests/test-make.R
+69b30e1a71abb8ba4183e53802995c5a *inst/tests/test-make_graph.R
+22c63ccc32ad7bcc1ca5858e1f7682f1 *inst/tests/test-new-layout-api.R
+3c946c65dbee1987ac5fd0991ab4cbdd *inst/tests/test-notable.R
+7687fdcb891047a342172e1feab863b5 *inst/tests/test-old-data-type.R
+f4383004c3666fcdda76b140c9be5f91 *inst/tests/test-random_walk.R
+9611d2c9cb947b58c40443fe2368bbc3 *inst/tests/test-version.R
+ec4d2c7247fdbb3cb6e5f8299d51925d *inst/tests/test-versions.R
+fee32de1be74da0b925a367eeef58ece *inst/tests/test-vs-es-printing.R
+89c1da084e2516de1600992f2c91adbc *inst/tests/test-vs-es-quirks.R
+ad17a2d0bfa04974980731e8824e66e8 *inst/tests/test-vs-es.R
+a7de50a9ec007b0ec6bd4ba043b8ce0c *inst/tests/test-vs-indexing-lapply.R
+b0783b265ed1ce213fc45bfc8ef0abf6 *inst/tests/test-vs-operators.R
+4c1ba73219c8dfd973fc878c0e2ed3b7 *inst/tests/test-weakref.R
+85ec5222dcf11a56e1c119cefcd8c9d1 *inst/tests/test_add.edges.R
+9d640d7ac3411dad252fa61e191968fd *inst/tests/test_add.vertices.R
+13cae003d2c04d379736320d7dac41f9 *inst/tests/test_adjacency.spectral.embedding.R
+b93a3944e3c6b752dac2e225ce10d2ea *inst/tests/test_all.st.cuts.R
+542a9710d4d20713093a35d9b5000c7a *inst/tests/test_alpha.centrality.R
+505493c56ee9fd269286cf68a3701fd7 *inst/tests/test_are.connected.R
+1186c6125dd7536cc593a14912cacb2a *inst/tests/test_arpack.R
+e282694af0f688cb034709e529f70ea2 *inst/tests/test_articulation.points.R
+8979b7079adec68a4eebc1fdcfec25b8 *inst/tests/test_as.directed.R
+e48a4e35ddf3d28d072f439de1eb0499 *inst/tests/test_as.undirected.R
+3d24bf6e4a3f12e23306a6075f786b84 *inst/tests/test_assortativity.R
+795eb9d342b6953248fd9578ad6f4868 *inst/tests/test_attributes.R
+8b60ef73553267334628adff510abcb0 *inst/tests/test_authority.score.R
+3809cd4a3febab2fe0a453bc8cabc030 *inst/tests/test_average.path.length.R
+6b49e3650ff1719aa1f44db76b47ba4d *inst/tests/test_ba.game.R
+0a5a3daca2a7c84fcebfbe44f771f794 *inst/tests/test_betweenness.R
+4f381a3bdebfbf215316ec09037f3c02 *inst/tests/test_biconnected.components.R
+5082b11e39d7b485770e6400656841e7 *inst/tests/test_bipartite.projection.R
+0137a8f814a670f45fb8678a74a0ac30 *inst/tests/test_bipartite.random.game.R
+8582a01c00fe03d6cc8336be5ea1555d *inst/tests/test_bonpow.R
+3a8a8485e09a9be56b8aa61943d1b2cf *inst/tests/test_bug-1019624.R
+a0f71df068480720e927de8b86f061d9 *inst/tests/test_bug-1032819.R
+6de97cc0e6c5f0eccb17bcebed244070 *inst/tests/test_bug-1033045.R
+254a3cf2d08007ad5803d244a99abdfb *inst/tests/test_bug-1073705-indexing.R
+8eb54ffc45a7662db609689ab1da7ee2 *inst/tests/test_bug-1073800-clique.R
+cda7097f73b9ef8be8bfe6662d3399d6 *inst/tests/test_callbacks.R
+2c96af4031e6a3b8b018a8ce8735eb07 *inst/tests/test_canonical.permutation.R
+f254ac34fc9203ce26ad62ed19d30976 *inst/tests/test_cliques.R
+ac1d66133bea5969e51bd75e13c354d8 *inst/tests/test_closeness.R
+c45762e40c0ee3cb70d305d06db47f0d *inst/tests/test_clusters.R
+8d2c03d0914792d2f1679d3909be2a18 *inst/tests/test_communities.R
+4a2a8e80da2d290077446c5cccca7998 *inst/tests/test_constraint.R
+2786c19359b36de1d6c2d90c305fde9e *inst/tests/test_contract.vertices.R
+a4762ac8213e2d36626defccac985e1a *inst/tests/test_correlated.R
+df25b65676954132724105f0c45d76fc *inst/tests/test_count.multiple.R
+401b5276d52c308093b1d9ebf252ec66 *inst/tests/test_decompose.graph.R
+3bce5671201a06ebd58d90ad350a01a8 *inst/tests/test_degree.R
+5512dce75135fa587c083313a70c6b19 *inst/tests/test_degree.sequence.game.R
+8ceeede3d4b00fd625b2f111a1ce60af *inst/tests/test_delete.edges.R
+a2667985a9407d55df61cd8b56c58b5d *inst/tests/test_delete.vertices.R
+6fef9d7dba6ac8269458d0d5764e0052 *inst/tests/test_diameter.R
+c5526915b4f853835809c7fb5898822f *inst/tests/test_dimSelect.R
+94f8ad23a61bb3dc9d46ff310b712611 *inst/tests/test_dominator.tree.R
+541d7ff02723427f2026be1a0eb7a737 *inst/tests/test_dot.product.game.R
+5d9a8a58619b8bb5c7645e2a4dbbc309 *inst/tests/test_dyad.census.R
+372dee80f0212ec9fb38200aa25b6d1d *inst/tests/test_edge.betweenness.R
+82fe00c577b8f8ec3430f7848f2c2fd8 *inst/tests/test_edge.betweenness.community.R
+078a1606ee3392ef9d8408b2b146ab60 *inst/tests/test_edge.connectivity.R
+fecffc869c851602342b441a3a418b77 *inst/tests/test_edgenames.R
+4781c4417c2f526009605d601b832ba6 *inst/tests/test_evcent.R
+85edbfa6a1db6972776e62292a19dc8b *inst/tests/test_fartherst.nodes.R
+80cf1f5676bd09a700e490ed4b439cfb *inst/tests/test_fastgreedy.community.R
+542aafbf6ff22a659f339ea8ffff8276 *inst/tests/test_forestfire.R
+36eccc1dd3d999a3941e7d034d1e6d17 *inst/tests/test_get.adjacency.R
+70b7391ff74607bee1c8936f578c335d *inst/tests/test_get.adjlist.R
+51873b120dd3fd8fba64430e3a5daec8 *inst/tests/test_get.all.shortest.paths.R
+849cff0f46c9170797641ba66cba5595 *inst/tests/test_get.diameter.R
+c4ba0a587f9530519bf13ea2acb58843 *inst/tests/test_get.edge.R
+f9249efa32145fc1c8c12a36f945cbdf *inst/tests/test_get.edgelist.R
+ded360a0009f7c4f67dc2b0352a0fb8a *inst/tests/test_get.incidence.R
+713863c8a73e169cd24293f85d08fc74 *inst/tests/test_get.shortest.paths.R
+03b481f55a65183b3b0e8ad203897960 *inst/tests/test_girth.R
+f2214f9cf209e9878e4da3c57232f17f *inst/tests/test_graph.adhesion.R
+6616d546c5d1fc6e253cde6c4fdee6db *inst/tests/test_graph.adjacency.R
+f7f7d009ae1a05610d9410b8bcc9d3a5 *inst/tests/test_graph.adjlist.R
 9ba1d7ad6342b0bef83bf1aaa52aae50 *inst/tests/test_graph.atlas.R
-7b2b92d896ca4a0d29460d53dacf8f9d *inst/tests/test_graph.bfs.R
-9f7cda832318e117e4d721c155dbd8ed *inst/tests/test_graph.bipartite.R
-f31c3eb5335f68d2bd8bbe924ca1a383 *inst/tests/test_graph.complementer.R
-a491210160c084f705849ae4bcf90a5c *inst/tests/test_graph.compose.R
-6367eea35161330f9b1ecefc7f36bbc8 *inst/tests/test_graph.coreness.R
-e2d388583de8f401529d0e873249b8b0 *inst/tests/test_graph.data.frame.R
-f8906cacaf642693784fde7450cfc61e *inst/tests/test_graph.de.bruijn.R
-f17e8a4d137c862a3aa739b95b79b9e5 *inst/tests/test_graph.density.R
-7a008546216365c194fe810dfbd8096a *inst/tests/test_graph.edgelist.R
-c3ec8547742438391412972e60e790e1 *inst/tests/test_graph.eigen.R
-7814cb971ce14d84b3eb376cab11f9c6 *inst/tests/test_graph.formula.R
-e0f44e4581e777f7d80c5a518808434f *inst/tests/test_graph.isoclass.R
-9ef58fbedec877449ea7d1701cea9713 *inst/tests/test_graph.kautz.R
-076362c5d606b06989a6213c88510c94 *inst/tests/test_graph.knn.R
-cec9f04f82187c5b4ad58349426c5699 *inst/tests/test_graph.maxflow.R
-4214d39292af7c09dded667eb04f6c74 *inst/tests/test_graph.mincut.R
-d9514f94fb33a8c1cb20ab6360a2ebfd *inst/tests/test_graph.subisomorphic.lad.R
-40249e1c6bc0f92005a4cd0398ea3d3a *inst/tests/test_graph.subisomorphic.vf2.R
-88d077e7f4fd460fd1a5fd4666897221 *inst/tests/test_graphNEL.R
-3b881412a68838d077433f9b8fc141b4 *inst/tests/test_graphlets.R
-c4c1dc078239cf57d31d2e93a152c7e5 *inst/tests/test_hrg.R
-ce2cf585ab05171852750dc56ee6b215 *inst/tests/test_igraph.options.R
-7e613d55a1d6432ed49f30b2483600f8 *inst/tests/test_independent.vertex.sets.R
-6024f685d222d59eb7ec1914eba0a7e8 *inst/tests/test_indexing.R
-75680864fda91a0e688eca440e3205a0 *inst/tests/test_indexing2.R
-0e4d57dbc7ce7ac7eec5cec1e4c93079 *inst/tests/test_is.bipartite.R
-5e0efc89b358f7c01d5dc9168c4f88db *inst/tests/test_is.chordal.R
-c34c21011d44938e3fd4086a01e92555 *inst/tests/test_iterators.R
-8957faf40bf0e046e585ed3a3cbf9332 *inst/tests/test_label.propagation.community.R
-04fd308d6a7daeefb0cd5d49ecd376cd *inst/tests/test_largest.cliques.R
-24b9cf59e40c52490bfb5116f0fb9237 *inst/tests/test_largest.independent.vertex.sets.R
-93a2aabed97712862e9463458b464244 *inst/tests/test_layout.mds.R
-a7a5593903397253275e6279b015a608 *inst/tests/test_layout.merge.R
-ea94d80fada25fccafc16102c39694f6 *inst/tests/test_leading.eigenvector.community.R
-bbd2ed78ca4760d764865fabd1f80924 *inst/tests/test_maximal_cliques.R
-0ba3066de2bd850da7d6215924d0b718 *inst/tests/test_minimal.st.separators.R
-2696f5672ca0a5d073c6ad11c2f66a1e *inst/tests/test_minimum.size.separators.R
-697b0e3793cdf91fbdb7d93200503f69 *inst/tests/test_modularity_matrix.R
-91d2b6f3de45f27700c0ebb4ec9a9e2b *inst/tests/test_motifs.R
-25cec45c57960f0ad8b18575d4802e53 *inst/tests/test_multilevel.community.R
-2695c3e58891d31786d82a39b80f3e27 *inst/tests/test_neighborhood.R
-238412bcc9a6f6276f36f00ee5af64a0 *inst/tests/test_neighbors.R
-fd7b4045a32f44c6ed86c6ff35703474 *inst/tests/test_operators.R
-e2053cd8e5fe548a3f52b62cc64c2d17 *inst/tests/test_operators3.R
-4a6fc11bf464763d6423bdbc1f0b5b5e *inst/tests/test_operators4.R
-b3dbbd6857e5669268fafab10b5de9e3 *inst/tests/test_optimal.community.R
-61197f2d34abcdf1d90ad312a846575b *inst/tests/test_pajek.R
-2f2bd04fc787c8a03aa62ec2a5e1ae96 *inst/tests/test_print.R
+849ce84a24fb61e09ed729bba98d4d7f *inst/tests/test_graph.bfs.R
+499b455adea86ee71817783a4a65f577 *inst/tests/test_graph.bipartite.R
+879c434fba2bfd905c539be92ebe91fa *inst/tests/test_graph.complementer.R
+c13bf09188f949377f0eac6d68a84042 *inst/tests/test_graph.compose.R
+2aa42f162d1bcb6b9582281130432efb *inst/tests/test_graph.coreness.R
+5f4e9c1eb0d4699236654074358b5115 *inst/tests/test_graph.data.frame.R
+68161b1dacafdfeef13eccd9efd7ae5f *inst/tests/test_graph.de.bruijn.R
+8723a905ccf9bd8987926a579d0442a5 *inst/tests/test_graph.density.R
+de6d23c1d3d6e7b16d3159f56185e434 *inst/tests/test_graph.edgelist.R
+df43bbc9223f5d6496e5715f1881abd6 *inst/tests/test_graph.eigen.R
+f894160c868e9392d2727cf9a6dc5af6 *inst/tests/test_graph.formula.R
+e2efb24c4db5b274ac18017ed480d2d9 *inst/tests/test_graph.isoclass.R
+6f3d4507996dbcc43920adce657a738f *inst/tests/test_graph.kautz.R
+0a80082ebc39ec4cdca090a3e1c11c67 *inst/tests/test_graph.knn.R
+9d869da1cc161a645c293d10dc341590 *inst/tests/test_graph.maxflow.R
+1159c879ec2285bbaa08209a1d2c5add *inst/tests/test_graph.mincut.R
+530fba9e8d790c38aca699b1a568de00 *inst/tests/test_graph.subisomorphic.lad.R
+eb55c1cd65d26a7530d9460ec396dfb2 *inst/tests/test_graph.subisomorphic.vf2.R
+ae031d23ec08cade48a2d03721dac0c7 *inst/tests/test_graphNEL.R
+65da974174ee936968ff534d50d35b93 *inst/tests/test_graphlets.R
+3e58a33bfda76293340465d7aac08c86 *inst/tests/test_hrg.R
+a570ca5f125efa4d98d030585f2004d2 *inst/tests/test_hsbm.R
+5448ef099cc050671cda697846fe042c *inst/tests/test_igraph.options.R
+026f3752506a2ec286066504e9d37a85 *inst/tests/test_independent.vertex.sets.R
+e466a39d382b5505b953292b62c50366 *inst/tests/test_indexing.R
+ff070d086e04573751eb22de047f4b7c *inst/tests/test_indexing2.R
+c78a920d52351d67639476e2aac25a8d *inst/tests/test_indexing3.R
+7748209eb0003b8d2c5d4ee90606878e *inst/tests/test_is.bipartite.R
+d501b567e3e573c4d999ac1ace4bb665 *inst/tests/test_is.chordal.R
+52138bea453eda91c667da3742007912 *inst/tests/test_iterators.R
+764d5cb76819f0a268562b2f6f59f82b *inst/tests/test_label.propagation.community.R
+c8c475e2e86016609574169e78c716ea *inst/tests/test_laplacian.spectral.embedding.R
+418d9fcc91a880b0fb839eb0fe002a41 *inst/tests/test_largest.cliques.R
+fce5463a31d7da19e21761e1d3bfbe9d *inst/tests/test_largest.independent.vertex.sets.R
+3f461a4ed6ed74da672f44761a2de349 *inst/tests/test_layout.fr.R
+f3caf46d387b7fecd5e28826fd753c7d *inst/tests/test_layout.gem.R
+bfeeecbfd9aeea87ba0c0b2cae9f627c *inst/tests/test_layout.kk.R
+6a2aed874635751a944a0f28f08f2c9a *inst/tests/test_layout.mds.R
+7e921347ce3b1b198f167e574067d1db *inst/tests/test_layout.merge.R
+dea0f7483ea375c42c7a00e6217a09eb *inst/tests/test_leading.eigenvector.community.R
+b373b6fd97fabb47114c76e104fa86bb *inst/tests/test_maximal_cliques.R
+751e142d0005412034ca097b97c9a153 *inst/tests/test_minimal.st.separators.R
+e376dbc01376d61de29507390ea4a4a0 *inst/tests/test_minimum.size.separators.R
+27b029baf39ed4c32ba0d69d5f7ed5a0 *inst/tests/test_modularity_matrix.R
+76e7ce19e8352b279c775ebed2f69153 *inst/tests/test_motifs.R
+993e177c45db6a718a6784b34330c659 *inst/tests/test_multilevel.community.R
+46d54173d41a303f3390ca543721ccb5 *inst/tests/test_neighborhood.R
+9f34f2b64e709ee9d3d3069464f88c15 *inst/tests/test_neighbors.R
+24cbc821daf29547b37847071891286a *inst/tests/test_operators.R
+46c39f7c2bed29cc43dc7ce9cfefa10b *inst/tests/test_operators3.R
+b45cd48a81d66aec4e4c28a9bd9da016 *inst/tests/test_operators4.R
+de9a71750cfede9c47f11418dd2bd351 *inst/tests/test_optimal.community.R
+560990b6b9e50c3585297bbea2a8313b *inst/tests/test_pajek.R
+823610533e3068fd474e770d7decc725 *inst/tests/test_print.R
 aff3f8aee89ec2151834aef5a203125f *inst/tests/test_psumtree.R
-8b85d86e270b64291868a4cbb9e0f9a8 *inst/tests/test_sbm.game.R
-9691d0d61689818c880138630bc1ce8f *inst/tests/test_scg.R
-e7a3fbd5a979efeb9279505dc836316d *inst/tests/test_sdf.R
-054fea42e0dc8d2c724181d64a222535 *inst/tests/test_sir.R
-dbf59cf415e1b750481f1d594afe8a10 *inst/tests/test_transitivity.R
-ccb4118a2fc7ce8921ad7c2d0833c57d *inst/tests/test_unfold.tree.R
-0070fa164ebeba8f1e241aa02a35161b *inst/tests/test_walktrap.community.R
-a1c8fe35ba8ee6dc6cb8243fe3edb069 *inst/tests/test_watts.strogatz.game.R
+c16adef7ce46505194e165e819a6ee7f *inst/tests/test_sample.R
+071bf3fb054279e535ccb9936ecb1944 *inst/tests/test_sbm.game.R
+5996191f90b8e86be20a5840a2089aa1 *inst/tests/test_scan.R
+2c945b5acdbb1e4c85b3112a67be04f6 *inst/tests/test_scg.R
+9274bc5af61b2058a08fe4d377aedab0 *inst/tests/test_sdf.R
+307c4bdb58bd0229816f4363a5b12186 *inst/tests/test_sgm.R
+7078a546e96ccb8b0dab099b9b451487 *inst/tests/test_sir.R
+1f919061ff9d5f2c9f8c771b5b9ca873 *inst/tests/test_sphere.R
+3fa33f48dc6393aa2915845a2813339b *inst/tests/test_transitivity.R
+59b470781b4cbb8184b85b2f292cc9a0 *inst/tests/test_triangles.R
+7f8ca4c58a09baf998e26774fc6a6290 *inst/tests/test_unfold.tree.R
+2426bc82153054e1f00534d6c81e47b9 *inst/tests/test_walktrap.community.R
+d8d7a03abfc121b96fad591afb9fbca7 *inst/tests/test_watts.strogatz.game.R
 2521dfd3cdd6457b8947f9bd78094b48 *inst/tkigraph_help/communities.html
 b836ba1ad253b94013d430cf0ba3e7c2 *inst/tkigraph_help/index.html
 11db5e3c8a97b9b22418aecf954b961a *inst/tkigraph_help/style.css
 4cbf1010c7a8edb8b8576853eb8898d6 *inst/tkigraph_help/tkigraph-main.gif
-490e59e4c25b5d1117d496e45360f7a5 *man/SCGintro.Rd
-0113551b0eda6a6798ff87c2cbd3f4a6 *man/aaa-igraph-package.Rd
-acc8922a7d352edde749e9c70d5a0ebe *man/adjacent.triangles.Rd
-c2b28b9762e007731552029cf28b534a *man/aging.prefatt.game.Rd
-09245948cf7622f1d8fce75dd904f644 *man/all.st.cuts.Rd
-fb3c3ca851721dbcd8e07eab5d9c4803 *man/all.st.mincuts.Rd
-a991620f8a233c0a4825c264f5af64e2 *man/alpha.centrality.Rd
-b7bac114fce81d2283e85b6cded01a36 *man/arpack.Rd
-e34d1c3782098341b133161a938ec14f *man/articulation.points.Rd
-f24e48da6348b734da938856ca6d1100 *man/as.directed.Rd
-8d3bb408a3c0d29df5341c113cc4c5b6 *man/as.igraph.Rd
-cd28abd98686de539361bd269bffd446 *man/assortativity.Rd
-9ec098103489e86877ceabf3a71a699b *man/attribute.combination.Rd
-b0fa4ce312607473d91fdbe3e6bdb821 *man/attributes.Rd
-f5bde797cf09b2c401dd32f111ad85e2 *man/autocurve.edges.Rd
-4354d5df9f52e6fbc69ec249e402e4a5 *man/ba.game.Rd
-46e4de4c7fba89dff11b32364ab3beea *man/betweenness.Rd
-1d2fbdf761aae74bb37b7bab64f5e182 *man/biconnected.components.Rd
-3c9265632a81a664f3bf3d90a7f8e26a *man/bipartite.projection.Rd
-07232859d44dd80d2539177d11c9a3f5 *man/bipartite.random.game.Rd
-44717817da10707585703923d9e80fb2 *man/bonpow.Rd
-7f34f8c90526469b80f4954be778da38 *man/canonical.permutation.Rd
-0a4cf8835c11767fec9b683e3a27f958 *man/centralization.Rd
-06c415a0840c9beac51fa27db0826b01 *man/cliques.Rd
-9ee6a34b3a9d625396d53a38b353ad17 *man/closeness.Rd
-4ea4827d8f9120e66dc459f204135c32 *man/clusters.Rd
-62ffba3e1c39a99270d5c3a3b5cd9c7e *man/cocitation.Rd
-993b89ee61989b1673c3b335f87218ae *man/cohesive.blocks.Rd
-4073dc3d5bf31010638608e8ce4bfc4e *man/communities.Rd
-8b79265c9f5a14989606ebc0ad804845 *man/community.edge.betweenness.Rd
-e22a859e7d9e48dca8d07e6d6378a283 *man/community.structure.Rd
-c3f6f238760ca3b9a059d9581e520ace *man/compare.communities.Rd
-908778aa0d5994f377306caa1408f090 *man/components.Rd
-1590bd8ff482d89faf8e014a38976109 *man/constraint.Rd
-86577a79e646341d55d357b29b2c72ab *man/contract.vertices.Rd
-438df04d7dc69a768a9817535ca287e8 *man/conversion.Rd
-22358ede3d6f988629f1beb8a8ee6828 *man/convex.hull.Rd
-fba08b66e8506b092a6b55858d4532b7 *man/decompose.graph.Rd
-ff7928f64c74493af5ec121faafb5076 *man/degree.Rd
-b708da4742c6f8eff8a303d10f83b6a0 *man/degree.sequence.game.Rd
-32174a837eb0a219ca36c7eb7b5f11e7 *man/dendPlot.Rd
-c805d22b79e24625a6c367742a64ea49 *man/dendPlot.communities.Rd
-ca95ec72c1fe4f41b7ef4cb3115ab00f *man/dendPlot.igraphHRG.Rd
-0be9392f822f6216444317f74f5ce3e7 *man/diameter.Rd
-71524ce77088cfcd7d9056483be0f508 *man/dominator.tree.Rd
-a52ef84d749ac079f82e1ca08ce8d699 *man/dyad.census.Rd
-22cad0ed8f6ac4610066ac305d4ad870 *man/eccentricity.Rd
-b16ce3410809a4147d6f24b3241d1ddf *man/edge.connectivity.Rd
-a05ddd762855b8abe5a36f628c99e5e0 *man/erdos.renyi.game.Rd
-53b55c90c42137ba6288d972bef78776 *man/evcent.Rd
-3b1106d3592ca518754c952b031f6129 *man/evolver.Rd
-31da869fc76ffbde2d38e295ef6b833f *man/fastgreedy.community.Rd
-d5c7d58e5b700a33b3350426bd68107f *man/forest.fire.game.Rd
-f217e124bd51f125eda133685863d207 *man/get.adjlist.Rd
-bcc35fc622c4deffb1d0c80e9c994db3 *man/get.edge.ids.Rd
-f26ceb99f240c3639d1990fee544611c *man/get.incidence.Rd
-7bcba0893e491f89658fc5d4a088e37b *man/girth.Rd
-8e71d93212eb276333fa49122fba6962 *man/graph.adjacency.Rd
-fd1e9140bc3a05dd9a798fb2af0e372d *man/graph.adjlist.Rd
-01aa54eb9c9ce6ebd248fef4a180109d *man/graph.automorphisms.Rd
-6703b7e69298233f17ff00ed119552ea *man/graph.bfs.Rd
-9233c293d35c2d67ad468681190c0244 *man/graph.bipartite.Rd
-1a6954216d4c3f51102b9ae14dc31a58 *man/graph.complementer.Rd
-999533f3e566009237a4192b159f9645 *man/graph.compose.Rd
-1fae7916c9207e10e666a486eb1da27c *man/graph.constructors.Rd
-5a74dbf9027ea59b88f1d471ba2fd3c9 *man/graph.data.frame.Rd
-2f9dca685fdf7c4bf4cecbd6c834843c *man/graph.de.bruijn.Rd
-4aa7ba2d0be3d6f76e9edbd3e5e1b21c *man/graph.density.Rd
-fc4a39e6adbd5b47530150a3a36bd4e6 *man/graph.dfs.Rd
-63857044820f4d4b9304b562eb3e14a6 *man/graph.difference.Rd
-cc3b2c1d3af65543a55339a199f82535 *man/graph.disjoint.union.Rd
-7a0ba30d43312e489f59bf7ac24ce8cf *man/graph.diversity.Rd
-b6223d79764a2a392818d553cec7e2b1 *man/graph.eigen.Rd
-b2c65bb8ffa89b27a8d3ed715951da77 *man/graph.famous.Rd
-678fcd111352b7755b544ad854478583 *man/graph.formula.Rd
-737f1b74fa5d9645f8dc4642ad480be7 *man/graph.full.bipartite.Rd
-00d2fcf4e8f9a70c11abfa0131a9b417 *man/graph.graphdb.Rd
-64c8830f9eeb9c16f8b6cc6857a2e0ce *man/graph.incidence.Rd
-a9bb06285b3fb1dd1180cd881f173db7 *man/graph.intersection.Rd
-a58924281b2ee65e8753f8610c1b08dc *man/graph.isomorphism.Rd
-16564b70c1f7d0f42e25c78885ee4fac *man/graph.kautz.Rd
-94c9486e89c543296874572edc63c825 *man/graph.kcores.Rd
-795059f08a847efb459f5def06ec61b7 *man/graph.knn.Rd
-687e881b37044914d3d6000ef9764ed9 *man/graph.laplacian.Rd
-1983f5ad22f00b21fc4d50c996e02496 *man/graph.lcf.Rd
-9ad24c3a74a39bc11d5569c6940c5091 *man/graph.maxflow.Rd
-95020ecaf81290a8b1dd943ee54fdb84 *man/graph.motifs.Rd
-119a74bc57ed38322380c56a866ce3bc *man/graph.strength.Rd
-8308256a1ade3ab6997801297bb13652 *man/graph.structure.Rd
-d91b16919bead07805c5ea80995c7ba9 *man/graph.union.Rd
-99a1a3f17338172c65a89c0d33925f58 *man/graphNEL.Rd
-984f9aa7375b5711a8aab5281b6d9077 *man/graphlets.Rd
-a9cb025e4eb3379ba88aeb62fee2bf3a *man/grg.game.Rd
-4c61d41f4560b7eedaa05aacfbedc387 *man/growing.random.game.Rd
-c61a5eeb50205147a45e629d6a252171 *man/hrg.Rd
-c3cc06fcff62664939e29d6e480fef22 *man/igraph.console.Rd
-9748f1acad017fe19c86313f2b27c73e *man/igraph.par.Rd
-59fa45e754df67baff9e59e047d176b6 *man/igraph.sample.Rd
-221ee11aa9ed0250d6cc653b6ef03f90 *man/igraph.version.Rd
-129c263e141dd36fc2f0f3960a0ededa *man/igraph.vertex.shapes.Rd
-d03bd59be3c1ea2762f726250fd659c1 *man/igraphdemo.Rd
-29a8baed67540673caaa8c83cb37b2eb *man/igraphtest.Rd
-bec1565476a4fd6b341390673df536ff *man/independent.sets.Rd
-eaba27a168cbc50a031e7c651761f11c *man/infomap.Rd
-7e64749dd773129c2ab536c7c46fcd01 *man/interconnected.islands.Rd
-6be427a7a1acdb14f2532900249c3ca7 *man/is.bipartite.Rd
-08403ce9e5ddf172669ce3601ee2f834 *man/is.chordal.Rd
-f93eb0c15fad1c3d46f842889bef764b *man/is.dag.Rd
-00191dad9c675a906eee5f413db2ce2f *man/is.degree.sequence.Rd
-9cf012f43a340967e4be995cea0d5ce5 *man/is.graph.Rd
-6d019435258e40157a1b65a1c9c7570e *man/is.multiple.Rd
-6743daccfdc2222d9ecd2811d5072356 *man/is.mutual.Rd
-c0691c04238439c9a1bd2a918421d854 *man/is.named.Rd
-f9ffb5c80cdd2e34e059ebfaab1b614e *man/is.separator.Rd
-5e20d1fc01c29cc4c85e988f5c051aca *man/is.weighted.Rd
-273b4fa0739aa8e31cccb3f256f98da9 *man/iterators.Rd
-82e94991ac7d85ea10dc0f6fa64f7afc *man/k.regular.game.Rd
-81cef44a4887b1eeb367fefcfd36dcbe *man/kleinberg.Rd
-57c6f91a6f4ef7de8bbb552e81335947 *man/label.propagation.community.Rd
-c68dab75e67ec060291ef25f3a0d59f7 *man/layout.Rd
-d7c813bba7dfe1fa64a9a535e89b9311 *man/layout.bipartite.Rd
-7f1debc3cb710724d7509cb38319a267 *man/layout.drl.Rd
-4eeb14a71b7740d8969248d5b89a7665 *man/layout.grid.Rd
-abf2f5674abc7c049f74baba093d7822 *man/layout.mds.Rd
-449b8cdd626361e2e5b3b86378d5a6fc *man/layout.merge.Rd
-abd58c7f5864e9b7d0b6f8ec256a6216 *man/layout.star.Rd
-58e7a514dbe8ca8077cf1f53757d96b9 *man/layout.sugiyama.Rd
-a7e85e5a0714ab6cba57af818310a119 *man/leading.eigenvector.Rd
-f2f70629a861eb66d4c205bee1c503b1 *man/line.graph.Rd
-78b1b429c7c1a7c333619b2483633904 *man/matching.Rd
-60a0337a59ae28708a3d78c48c5c64a1 *man/maximum.cardinality.search.Rd
-89e5c3eef4457aaa932aeee9b032f2e3 *man/minimal.st.separators.Rd
-842a32dbc4cb921897f6d9bcac0b9255 *man/minimum.size.separators.Rd
-52ee27b0f5bf3e04e7be9e878725a2cf *man/minimum.spanning.tree.Rd
-52c8ab132a6966739bef8ee2f8981756 *man/modularity.Rd
-f560cf7c63099dfdd3b0a674275e316e *man/multilevel.community.Rd
-7900bed1b0940ccc7776d3dec5eaf8b3 *man/neighborhood.Rd
-1ec57ad12a1927136903ec84dece1d8e *man/nexus.Rd
-299d7851220ad2eb4ced185feea58a70 *man/optimal.community.Rd
-4d2f3c8e437282aa798c8066943d869a *man/page.rank.Rd
-288a40186ba8f7078d043476237c05be *man/permute.vertices.Rd
-358552108b31e3d75f36bd12a184cb5f *man/plot.common.Rd
-aeb9b7b19f32c2b8c00c366ef1cd03b1 *man/plot.graph.Rd
-d24bd1f85b5dff80683020d660d86624 *man/plot.sir.Rd
-7c219a4fc350e53ef87bcc0c042c9234 *man/power.law.fit.Rd
-5d6296b70d49f683d351b458d70f8943 *man/preference.game.Rd
-cd164cdfbcf792e4fc29a6a45228640d *man/print.graph.Rd
-1383336495f05be66550a63cf583ec55 *man/read.graph.Rd
-77e606ba497c192295bb2ad7515e5e9a *man/reciprocity.Rd
-b1f605b0ec7c78115abe2b0a87d3eedc *man/rewire.Rd
-434d161208d569515f7a42a6148f6574 *man/rewire.edges.Rd
-39a855aeb28eb15d3b3f2ab3fa9d1eb0 *man/rglplot.Rd
-952c0bfb97bd3832323ccdbfad724d35 *man/running.mean.Rd
-92b9c05fdd87fd53d127f437b6bce8be *man/sbm.game.Rd
-d63bd966921d98f2c4965dd169d66b59 *man/scg.Rd
-ad681e1cc6ffad6b7dc81716f83e8ff5 *man/scg.grouping.Rd
-59d41f382e4326c1292b15e4847cf9be *man/scg_extra.Rd
-db1c37e60a394104fb771cb4096ec635 *man/semiProjectors.Rd
-f70e82a7d81dfa5b609ceb5419dbc3f1 *man/shortest.paths.Rd
-a679be4e396aa6c03503e4ffb9c0ccd8 *man/similarity.Rd
-a01c751a108c457f3760db1038ad204a *man/simplify.Rd
-a2641565bc5a23b767234cf5292a17f1 *man/sir.Rd
-882887a6ce4a57d7934bd32121a95bb2 *man/spinglass.community.Rd
-4cca0ec13649f704220ddb041ecbb6cc *man/srand.Rd
-3bdfb6457757014caaf1d85cc9b8cea8 *man/static.fitness.game.Rd
-b6398eb1622f9521f71b32b880964f1d *man/static.power.law.game.Rd
-de8724b8505aec8c7a81cd821d53cb77 *man/stochasticMatrix.Rd
-a203c69759d100b84cf3afea2ea8bf47 *man/structure.info.Rd
-e9e0874c3509e622902d9b64a6c16ee2 *man/subgraph.Rd
-56e5286d57cbb4daf39e353a90d42a3b *man/subgraph.centrality.Rd
-b0248ac705603d8eca7e256bb54f9c5f *man/tkigraph.Rd
-d20eee7198ad87986ff574b6c6d27857 *man/tkplot.Rd
-7c42e19c656b1139263d4ffaef34ed36 *man/topological.sort.Rd
-dd16887c31810542bd53c00c2deee88b *man/traits.Rd
-98fee1818998ec54602d511b3a09ffd3 *man/transitivity.Rd
-6d76bb6086d6d6df07d117f862006598 *man/triad.census.Rd
-c7c363024814476cd2d56289bbbf9a0a *man/undocumented.Rd
-61076d6735b29e2fc094b02a6d767673 *man/unfold.tree.Rd
-3cacf42c3bfaca2bd7252076c56bd9e6 *man/vertex.connectivity.Rd
-9ac174cab048d5b9bb865bf3621862c3 *man/vertex.shape.pie.Rd
-c3dacc31658bd53c75b5cd77b9a634d8 *man/walktrap.community.Rd
-317908ae26b0bd17a7300d2d8d1a0a58 *man/watts.strogatz.game.Rd
-184e95f181ede0924a808e7e79316109 *man/write.graph.Rd
-af447f07a45af2b4f7edaee5d0a877a7 *src/Color.cpp
-be39147aa9a658a401d5d8e304bfbb68 *src/Color.h
+42c1278ae6f22de279f3ddc9ed26fe28 *man/E.Rd
+3f3ac164c20cdd057b07edfe481b4655 *man/V.Rd
+820f2d1b9be71a7060609c4fed5676fa *man/aaa-igraph-package.Rd
+16cadea42418126237df23b69083f7d0 *man/add_edges.Rd
+1f7a2c8b6ae4eca77770eaa2f5adcbe4 *man/add_layout_.Rd
+5ce3b4c2874535ac07cce4b033902ad9 *man/add_vertices.Rd
+1c77e11700e3c830d602d58974f0948f *man/adjacent_vertices.Rd
+ed8b296fbab3bb09d4f8e1693fa18dfd *man/all_simple_paths.Rd
+3f115e30d70b57a85dd0bb86ee858e6f *man/alpha_centrality.Rd
+593e85eda7a2355a70bd13d3a9280260 *man/are_adjacent.Rd
+c35a0ae551bc338162ed2365a1c44c32 *man/arpack.Rd
+6674c22d07aa391dedf759f6230c40a5 *man/articulation_points.Rd
+72e51eca9b31ed0802757b2ba90b43d8 *man/as.directed.Rd
+ce1904d04c4dea1fe6ca733be2f11c4b *man/as.igraph.Rd
+f50b14b832c15b59a92d0332bcc89ccf *man/as_adj_list.Rd
+c806cd2c9c54293c378cf3c60bad100b *man/as_adjacency_matrix.Rd
+adadf7f7c32cd962cd782caf6a9d6cf3 *man/as_edgelist.Rd
+553979df54450f9fdeb74992f16e1d7f *man/as_graphnel.Rd
+be123be50bf38ec0b4b8ed1b30ff0ca2 *man/as_ids.Rd
+b47be078d27a0ecc33094bb13fcdb77d *man/as_incidence_matrix.Rd
+b1cb9a66612beaee4a34d607d8ff278b *man/as_long_data_frame.Rd
+ccd0d0339e4b242c1442ca31d7b92e30 *man/as_membership.Rd
+e5510800ad5bbca2061a8c1496d49b1b *man/assortativity.Rd
+94896983d098792b003cf4a7b28fd262 *man/authority_score.Rd
+d5dc0579c91dac3bcdd0a6a4644cd141 *man/automorphisms.Rd
+8ee4fb751ff6d43c2180160321a5b40d *man/betweenness.Rd
+7eb787039b97a218dfe970e011d7c79d *man/bfs.Rd
+11e3fc1351df6dfa17486eadb8ddc292 *man/biconnected_components.Rd
+a6bfcf76e2146eccf273aab86500c5ee *man/bipartite_mapping.Rd
+1a068022bde7e4d489a528d86d0d723d *man/bipartite_projection.Rd
+e5faacfc659013aa966dd01b252338a2 *man/c.igraph.es.Rd
+1a84493af7864d878ba3dcdbd7cd6bcc *man/c.igraph.vs.Rd
+dfaf157b403f341ee0f7fff041c9fa3d *man/canonical_permutation.Rd
+618c5eca9051b733581259943ba4b896 *man/categorical_pal.Rd
+581113912e2e3f6d41cc30323f1d3c21 *man/centr_betw.Rd
+a030cd80299a5e65507dcf99f5a2ec4c *man/centr_betw_tmax.Rd
+7bed7a172c2ea0da3d80dc86ea211584 *man/centr_clo.Rd
+ce2fac46632fa55176d18c5a3de1a8e7 *man/centr_clo_tmax.Rd
+87ea150584120535700e8c891bc7ab6e *man/centr_degree.Rd
+68a931c8ed757c098465abafeae723de *man/centr_degree_tmax.Rd
+c05a22aebdbd1fe1913280dc8cf921a3 *man/centr_eigen.Rd
+521a6a801c97a8348c43e7af5c117dd6 *man/centr_eigen_tmax.Rd
+40fbbc993bfa698a22c4b0b88d4605f8 *man/centralize.Rd
+720d7dfb2654ecb33d227c0bf87d0dff *man/cliques.Rd
+f20851702be457b76933b0473ad2014e *man/closeness.Rd
+853ea7bcc0d09991bd222dc649f29a97 *man/cluster_edge_betweenness.Rd
+f2e1654f3bf33206891b23bac01d87a6 *man/cluster_fast_greedy.Rd
+7d3a1c1d34ffd76051d4120c98c3572e *man/cluster_infomap.Rd
+450ce83fc207203efc551d704a219cac *man/cluster_label_prop.Rd
+a92d4850db4c32e8527a93ded86fcf11 *man/cluster_leading_eigen.Rd
+1b1c7382bc342cac0c7b6a0264479222 *man/cluster_louvain.Rd
+32631022f52b45b5877e11fce7615621 *man/cluster_optimal.Rd
+7be2c4600e453c1b1d2c196dca9e20cb *man/cluster_spinglass.Rd
+85835158e45b3cb08e3862febabd351c *man/cluster_walktrap.Rd
+31f676c711d9807d0153e790c574cd89 *man/cocitation.Rd
+0aa629efee730064061f2ef0c7e3cb3d *man/cohesive_blocks.Rd
+28170705450784257bff8a0a8338caa1 *man/communities.Rd
+694aab9fa9475d4f3de2f9ccb39666ab *man/compare.Rd
+39457167b31ab972e173cf9c4ed448e4 *man/complementer.Rd
+eb9237e69899642b8aa6b1df2347ca44 *man/component_wise.Rd
+dafb78dbeb15cda02db23570186f4681 *man/components.Rd
+07d446402fa23a221f2a1d747175acd7 *man/compose.Rd
+29f939daa99e37681803250021bbfefc *man/consensus_tree.Rd
+81d65bf9d19be8973ea34dbbac7bd48e *man/console.Rd
+9edf36b2d7ad2e59fae80c92d3e65368 *man/constraint.Rd
+8975e669758a2fbbe6af5c9ed2597b7a *man/contract.Rd
+32c5b3b636e949bdc7500edf2ac08ad0 *man/convex_hull.Rd
+e685b2e07e639f23583ffc29053a9ccd *man/coreness.Rd
+ad7ae4c446fd85e7a4fe2c1a9a109033 *man/count_isomorphisms.Rd
+e97bda4f31ca00ec8baa0d2bfe29b15a *man/count_motifs.Rd
+0bcee3f3c8bf4dc244763d4a3444eaf6 *man/count_subgraph_isomorphisms.Rd
+5b8dfc677d8881bc998f95d7767ab686 *man/count_triangles.Rd
+9e53a4cfce7b1cb32b35f46bf14f4675 *man/curve_multiple.Rd
+77b4c935af70b2317fc364532a5b590c *man/decompose.Rd
+d130e862deb252b1da4febfd6e95c123 *man/degree.Rd
+2ed62693c6a16d84fada9fc20fd889be *man/delete_edge_attr.Rd
+7680628420f914eee2c97a4be6058a13 *man/delete_edges.Rd
+14b1696fdc471c3c5bb693b102271aaa *man/delete_graph_attr.Rd
+f894633052e956e40bf6a958d3c8f2e2 *man/delete_vertex_attr.Rd
+c3e5b2a63f48feb3ede390b61fc6c8aa *man/delete_vertices.Rd
+639babe2082d25cfa7826243295e9b62 *man/dfs.Rd
+19f8468e2239f50570ab4ba031ff74e4 *man/diameter.Rd
+647fb341144f2510dc854c33a2548502 *man/difference.Rd
+0dbc896fad5e6dbbb8e4351ca4eeeecb *man/difference.igraph.Rd
+b5c15780d2a52e92c3f51a67d33a488f *man/difference.igraph.es.Rd
+c130e348b16235400a7686cb64e6bc3a *man/difference.igraph.vs.Rd
+0b8c38e7dc7b03a6cb650a4eba0c15c0 *man/dim_select.Rd
+87213fb94ed3f4677ff653b879d9a529 *man/disjoint_union.Rd
+adc4fe47551956348269bf88cd3cddf5 *man/distances.Rd
+347159fec595675b3defc2f9a341c091 *man/diverging_pal.Rd
+dbcc4cc78b8be60c6af754234225adba *man/diversity.Rd
+012fd6d56cf19d9d7a5173b82aad3407 *man/dominator_tree.Rd
+4f7cbb04e3894a4debe1827cb383916a *man/dyad_census.Rd
+3d1e4cf9bb2a1ee538555f126a25ad36 *man/each_edge.Rd
+08825c5e095e796765c52865ebbdcd64 *man/eccentricity.Rd
+b63be8edd87ffb5945f407fdc0488c87 *man/edge.Rd
+674e1311beca10e0bc989016cf00c955 *man/edge_attr-set.Rd
+7dc0f500697f55abf00ef45b479a4ece *man/edge_attr.Rd
+15c0ba433decb07d4ab33992ce75810b *man/edge_attr_names.Rd
+607c683e8e7814f82cc6db63c58d2beb *man/edge_connectivity.Rd
+bb562ba01abd97d07b231fe2e88bc7e1 *man/edge_density.Rd
+bd6e630a76ee6e65756059a9640540f6 *man/ego.Rd
+d63adaba5e10e2c5c87e415234eae4b6 *man/eigen_centrality.Rd
+59b771162e183b433f8e9b003d09de31 *man/embed_adjacency_matrix.Rd
+d616eef787d4c0e7f6f6d5d0853e6fa7 *man/embed_laplacian_matrix.Rd
+d87115d0d20a0642ec5f967736324fca *man/ends.Rd
+fa0900f5a1e35fb9e3041b44c7423c3a *man/erdos.renyi.game.Rd
+8658562750b9627a0f0a632a49034205 *man/fit_hrg.Rd
+56a434f03c82e835dd31f87292f5a71d *man/fit_power_law.Rd
+74b968133daf808e2f5c631cc2654c22 *man/gclust.app.Rd
+b4178b60ef1c7a22cddebb32f76a21c0 *man/gclust.rsvt.Rd
+8548a3561438dcf553a615a62294a9aa *man/get.edge.ids.Rd
+dfb58aae066baf7dfae2f04674e5fb4b *man/getAICc.Rd
+0fbd30c6367ec7fbc10b9f3542f7c82e *man/girth.Rd
+d614b4ef4c9666b99087165b5f5419ef *man/gorder.Rd
+22af0feb4a59ccb57933f1748dde3ac1 *man/graph_.Rd
+d5b7e02fa71cca864f78d9858dddc0ac *man/graph_attr-set.Rd
+87e28cc96a013b72b9e20e12a00f7a3b *man/graph_attr.Rd
+fe0d99ff560eb2cd8f3c60b04649e965 *man/graph_attr_names.Rd
+0bd6eab2c2f2a29d77db42d09547e081 *man/graph_from_adj_list.Rd
+5fc78dbb1fa7a0dc9f635d30e08540ea *man/graph_from_adjacency_matrix.Rd
+f7a1dd6a5a341d4f9357a53b57add309 *man/graph_from_atlas.Rd
+06f3df86bad345b1c0b68442b4900f3e *man/graph_from_data_frame.Rd
+02c4641de052aa4d17ceb29485915bd9 *man/graph_from_edgelist.Rd
+be4047c1cf53cf45594b3dd94bad9e1d *man/graph_from_graphdb.Rd
+fd177c1244b8978a91a30530032e1271 *man/graph_from_graphnel.Rd
+a2cd741b195ce0ef54e62b52d90b694b *man/graph_from_incidence_matrix.Rd
+8d56abb3af392c4f71fe01e48edfff4a *man/graph_from_isomorphism_class.Rd
+de1b97cf645144302976c33e7993fef3 *man/graph_from_lcf.Rd
+d89a32a2f29beea3a77c648a3d323346 *man/graph_from_literal.Rd
+d9d5a401cab3a0c711170694e9e17d86 *man/graph_version.Rd
+a2323638f43d17d2542b59cb3303d991 *man/graphlet_basis.Rd
+2124a938a31648509028900f8fb17cf7 *man/groups.Rd
+3702ff90113cf5b7e9827c3e7545ce04 *man/gsize.Rd
+d7c3adc0ec9dbd8ea1c0f6a96bea225a *man/head_of.Rd
+91e55f6daa7a105dfc4d2b13504f4029 *man/hrg-methods.Rd
+47d7c68cc34318f9aa13a7746a010eae *man/hrg.Rd
+4c644dc8799db286764bb278a0811191 *man/hrg_tree.Rd
+6c40bbe78748414c56fcb2dd9e5fd8ed *man/hub_score.Rd
+d47552e7d68be057350306b8381b6919 *man/identical_graphs.Rd
+f5bfbeb9c8a3af8c136cd6aa72f108db *man/igraph-attribute-combination.Rd
+7f5da4ceaba7c96ef11d626f442c4ddf *man/igraph-dollar.Rd
+54acc64cc203f0661333e5257f7b51d1 *man/igraph-es-attributes.Rd
+5d2f8a7978b61bf8e1b1c6ba1cfdc011 *man/igraph-es-indexing.Rd
+afa8858090ee79dfba9aaa53ae21d108 *man/igraph-es-indexing2.Rd
+f12ff62050aba45a402fcb1e35be5227 *man/igraph-minus.Rd
+da7358d3713a59db241f1718a6d9527b *man/igraph-vs-attributes.Rd
+cf8c0956ec3ddda21ef76c137e1c3024 *man/igraph-vs-indexing.Rd
+eba1f7a15965cdae12ec5ac57a1efee0 *man/igraph-vs-indexing2.Rd
+9b8a6e97ae99b1ddc9a98a0b56553f5a *man/igraph_demo.Rd
+93517397d8b95a2681fb6191d392a90a *man/igraph_options.Rd
+e43a53dc076854140d1d0f7a48e3d4a6 *man/igraph_test.Rd
+a55b5466e0b979519b64835cd0a3c029 *man/igraph_version.Rd
+2d3f8486853c1ede38d26d28ec8c1a95 *man/incident.Rd
+03031f83b10a7a89d280fdcc62ca5c32 *man/incident_edges.Rd
+e83e036237832d65ab2cc4d65034a18b *man/intersection.Rd
+b001cba054b2743a131e4c8b77fabd4f *man/intersection.igraph.Rd
+4dc1bb8369c6ed43e51d55c347425027 *man/intersection.igraph.es.Rd
+83344ec591ef1ca339d84d08d5990e9b *man/intersection.igraph.vs.Rd
+4dfc8e3a5f3d777e55d47532f5875707 *man/is_chordal.Rd
+4f8875de0fcce429f3b371caefc892a8 *man/is_dag.Rd
+452cead424aa28544027144724321f60 *man/is_degseq.Rd
+a21b97cccaf40542c570be0c1288b465 *man/is_directed.Rd
+8e7ace8cbb9c9837b3ec758dbe097c37 *man/is_graphical.Rd
+05bcf0120965dbbfd561b29b58db76e8 *man/is_igraph.Rd
+b292b5608efb9384200b1d0f2f7c7fb4 *man/is_min_separator.Rd
+37cb14c551976936ca992a0a84fccb9c *man/is_named.Rd
+6a4a7f4d8e97368dac68a0f48c455a27 *man/is_separator.Rd
+e9ed66f532a25933daf45b1702b6cd3a *man/is_weighted.Rd
+71cb5f6ea28168c96188a77552ff546e *man/isomorphic.Rd
+ea956f4179bec462125cdb8ff4f2a717 *man/isomorphism_class.Rd
+fd50445a0f3ca0bad4d7ecc2164aec78 *man/isomorphisms.Rd
+b91f032838ce4df0ce874f9fd39828ff *man/ivs.Rd
+2b84fcff11e8d6b5f03f678ff45c3314 *man/keeping_degseq.Rd
+8925a2d061eb6df46e925a0721ad90ba *man/knn.Rd
+33aabf13f50e08ac82c99a41375b74b0 *man/laplacian_matrix.Rd
+9d6ae85fdc9ecbbe1bf27ca0dcab4250 *man/layout.deprecated.Rd
+52748dac68c0bf40a1e04550ee37f6d5 *man/layout.fruchterman.reingold.grid.Rd
+43268bf9eeac08ae46d09da4db6b57a3 *man/layout.spring.Rd
+2ea15460bf78ea00e48db1738055c0e5 *man/layout.svd.Rd
+fee83b0eb69d88faf916b2728d121cef *man/layout_.Rd
+9f8e2ddafc1cfdc24b693c123e8ce8ed *man/layout_as_bipartite.Rd
+54535e6409eba0bf2ab83d6f77e927b5 *man/layout_as_star.Rd
+593d4dae6aebd82bcf7d8396312ec7e2 *man/layout_as_tree.Rd
+e2cd455dc3b7dd627a595d5b96250e32 *man/layout_in_circle.Rd
+64ae8a405c850689756f180ee8982a51 *man/layout_nicely.Rd
+5bb6e898eea6bb5e407ee5867f5fdfb5 *man/layout_on_grid.Rd
+e592c443769d1a1a0297f1fc74345a0a *man/layout_on_sphere.Rd
+f65597ec9ae8da96bd50aff1c03df82e *man/layout_randomly.Rd
+9c704c34de38dcc7bedcc1084ba3f438 *man/layout_with_dh.Rd
+05220a521782937b617c1729b49a585e *man/layout_with_drl.Rd
+091f9c2f094b0e7aa160af0956549141 *man/layout_with_fr.Rd
+6393aa28d0a9de7f0d70e69c74b4a33a *man/layout_with_gem.Rd
+1e8c7441116449150dff1eb5c72d85c9 *man/layout_with_graphopt.Rd
+9741a391a852f6838e657079abdfb6cc *man/layout_with_kk.Rd
+2be543edb81ab164aa198f56f7b793c6 *man/layout_with_lgl.Rd
+2cb70129a7f35b5ef7a77ee5bfa8d8a1 *man/layout_with_mds.Rd
+feaa1135c7fc72bc1bda872584eded61 *man/layout_with_sugiyama.Rd
+578f44c6a20b7f2536d885e4c9a4e590 *man/local_scan.Rd
+20079a3b6002e90c4ca917df63a44b52 *man/make_.Rd
+16d14883b0678f2846dda3938fb68327 *man/make_bipartite_graph.Rd
+f0e5ea424809203ce113d256f9b9e20c *man/make_chordal_ring.Rd
+5db3d3730f04ae17efb279153118a9b9 *man/make_clusters.Rd
+39507e56a91cfba479508cae57ff1d8c *man/make_de_bruijn_graph.Rd
+d528bc8f5be5c1e8fbc68a954aac90dc *man/make_empty_graph.Rd
+6f81272db67b4fc23f66cf53797ebafb *man/make_full_bipartite_graph.Rd
+d0bc61da7952b2e4a76571c6d9954d2f *man/make_full_citation_graph.Rd
+3b62b8c1c5a054c923b44dd63478208d *man/make_full_graph.Rd
+164e0541cc25c3f613d9c0cd5cb15006 *man/make_graph.Rd
+936434f82ceb6e068d893c50a7a657f5 *man/make_kautz_graph.Rd
+13f0a8773a633b880924c1ded4a75cf7 *man/make_lattice.Rd
+f22a1d4cff51583e81679b1f7f27d627 *man/make_line_graph.Rd
+afeb6f173f1d7cab539e5aeb31468458 *man/make_ring.Rd
+e1b6288f1a7e3b28c075ced81b8fae61 *man/make_star.Rd
+3072bf647a5705f3f3891bc72eb228c8 *man/make_tree.Rd
+5e583097c858a8f02f81965fd0d95719 *man/match_vertices.Rd
+24e372c1b19ee62816b5d9e7096d4fd6 *man/matching.Rd
+d6ebfebc4087908306b2b94b08074d0d *man/max_cardinality.Rd
+9602c5aefcb2043d39b982f0340c3a6f *man/max_flow.Rd
+ef4273a5c4ae18aae0d99cfa9cfbb790 *man/merge_coords.Rd
+dc910ee178905057e1fd3706ef647270 *man/min_cut.Rd
+6c1dc0728374b210301f8405f51dc5a5 *man/min_separators.Rd
+60d1f362bf1bc9ae41e8ee10ca377c61 *man/min_st_separators.Rd
+1984779bdf14207798047ea855f411c6 *man/modularity.igraph.Rd
+c4fba7b6861ec7d12657fe44845046eb *man/motifs.Rd
+d5f5bd1708f65205548f714cce6a1812 *man/mst.Rd
+c77e5015482de8b1aec7423c08cbf6bd *man/neighbors.Rd
+f2cc5d52ed6be064971beaeef93ad647 *man/nexus.Rd
+1b748689d19e832426007937948faa80 *man/norm_coords.Rd
+9640a8fca94c9320bba0b34c799e149b *man/normalize.Rd
+5ecfd31475fbe1642438b5faba99c5a0 *man/page_rank.Rd
+be4d99ce100b571628564f13e16a47cc *man/path.Rd
+9480f29b2c3d7cb825d147a965a6574e *man/permute.Rd
+4c94ba42c4bd6661971d62cd020f9f12 *man/pipe.Rd
+c74527bbb90ac46e47197a4a587435eb *man/plot.common.Rd
+cad87735f8a44423b46d8ea742dfc29a *man/plot.igraph.Rd
+dfa9f590f9f2ffb747df7aa91becce2f *man/plot.sir.Rd
+225e47ae770110ff85bf4d095682f4ee *man/plot_dendrogram.communities.Rd
+f00a7c8ebe851a4d54ea0ec0b1b22c33 *man/plot_dendrogram.igraphHRG.Rd
+473d2eb8d9cbe5407f71ba46bdac2d64 *man/plus-.igraph.Rd
+448866d911307690e368c5efb2ae01c9 *man/power_centrality.Rd
+b62370232f5becf5075014b5fdc26b38 *man/predict_edges.Rd
+615b4d4dd7531267ac4eb75d87eab020 *man/print.igraph.Rd
+d57f0f6c5d19af3ba6ac2e790f864019 *man/print.igraph.es.Rd
+a31b0f570d61eb10f9e37a6fce51fa4f *man/print.igraph.vs.Rd
+0e1d65b2b7aed4cabafa756829fe85c2 *man/print.igraphHRG.Rd
+d59b8d1a95a6f3704577a0028417cb10 *man/print.igraphHRGConsensus.Rd
+34ee0e22dbd736c5920964732c768cae *man/r_pal.Rd
+faa7b61a3a9a896fbba69456a2c7c8b5 *man/radius.Rd
+ef10cb0c51b3b357eca15e50fdd07b8a *man/random_walk.Rd
+062f052f27b8cf583a2555be5cb44b39 *man/read_graph.Rd
+722234f5312acaa2c9ed8528637a592d *man/reciprocity.Rd
+dcbfb6acf13e522c7fc980c900620764 *man/rep.igraph.Rd
+72be6e89f3c7c80ad288aeec1ae2ae53 *man/rev.igraph.es.Rd
+0d6b7e062a8d3944ddf060cd40fd1047 *man/rev.igraph.vs.Rd
+3cb49ba7cf1a25f19e8828321ce3873e *man/rewire.Rd
+2c7675cdd07144d1fdc73b54c9351069 *man/rglplot.Rd
+3234c78394d779d9afd48500c8335d89 *man/running_mean.Rd
+bf3ee03d3cfa2eb50ee9ad93bbd85bbc *man/sample_.Rd
+8df93ff90f9fb23a3bcdd8badc8cbb97 *man/sample_bipartite.Rd
+d5ce00b378da107ec2fc37763e2d16db *man/sample_correlated_gnp.Rd
+5fa79986e19cc1c0e171906e36d2fac5 *man/sample_correlated_gnp_pair.Rd
+e10647ff481fa0122c8bc5f7f456dada *man/sample_degseq.Rd
+8ddcd941f37392142712c33cdbb62c95 *man/sample_dirichlet.Rd
+20eab3d3e55c5d8c5afbac354f6c01bc *man/sample_dot_product.Rd
+413719af01335ff51ca12b207f6b8c5b *man/sample_fitness.Rd
+1d61ad78fc6dbcf870fa683b146e0c8b *man/sample_fitness_pl.Rd
+af14208df423fe62dead3c5b9a84a071 *man/sample_forestfire.Rd
+ef72b8f52e6f76d2374354380dd12053 *man/sample_gnm.Rd
+8290688f843ae5ba11f5b026cb74ab10 *man/sample_gnp.Rd
+b1cc338cea2adf8d7ea4a2cb58dcf8d0 *man/sample_grg.Rd
+500163b3ab3616d7eb4faf3dee677d74 *man/sample_growing.Rd
+c43122b207874d159a85d0e1fef41ec3 *man/sample_hierarchical_sbm.Rd
+661531ad452e4787aed3bdc16686f659 *man/sample_hrg.Rd
+15e601e6beac6346e68d3072ad49dfe8 *man/sample_islands.Rd
+242512fb3085d4d91011a11ace3915c2 *man/sample_k_regular.Rd
+5369681727cb19fad828466beea6e5f0 *man/sample_last_cit.Rd
+0af2eef3edb9be7db9b80c11dbc43b21 *man/sample_motifs.Rd
+5d786432acf735037457fa27141b8a2c *man/sample_pa.Rd
+51564e8ee5088f07e411cca9e2cae48e *man/sample_pa_age.Rd
+baeaf2b10de3172061559bf73a2b05dd *man/sample_pref.Rd
+edad97a22e1b47c5148d2fee168c4f4c *man/sample_sbm.Rd
+8d44db4c53823b86da59f27c68dba24c *man/sample_seq.Rd
+3dc67ec4dad01bd6525c88d73f9dc939 *man/sample_smallworld.Rd
+6a1972f48f9411b29f9eac24d46c40e5 *man/sample_sphere_surface.Rd
+3987de5c340ff1554edca08698d6929b *man/sample_sphere_volume.Rd
+1037d358d1f0d9a062be8180b741b3cd *man/sample_traits_callaway.Rd
+97aa7108cbf3a3ba1de425a798522688 *man/scan_stat.Rd
+2e4c6ad36ccdc5336e5254ac37dc7263 *man/scg-method.Rd
+f55dfd254afc5dc8ce8c59688a200c56 *man/scg.Rd
+45dda381388fbf2fbf1b3259db07aa72 *man/scg_eps.Rd
+5083d77b2a8ffa35826b7922becd47e1 *man/scg_group.Rd
+2d33cc20fab97eefce61536692049714 *man/scg_semi_proj.Rd
+27b5263d98bc203982383e4ed6359a73 *man/sequential_pal.Rd
+7c6b3bcc19b21d7ac7ae26426481dbbd *man/set_edge_attr.Rd
+4744c6f86206497f77067d6c62963928 *man/set_graph_attr.Rd
+35f4098793af0d09eabc40d35327a511 *man/set_vertex_attr.Rd
+9c8971b3e73f0a45902665bef7db3302 *man/shapes.Rd
+08daa44bd0dd941f7b866444b69c1b2c *man/similarity.Rd
+3fb66c817f34c8803168f693c4a8e867 *man/simplified.Rd
+7dc18d1c3bd0039ad3c5ac3b60b053ba *man/simplify.Rd
+b8d0c9f6c5f811e4aede7c247bd090a9 *man/sir.Rd
+d3bb4a412fb5cb471efb232014366c0a *man/spectrum.Rd
+e001600f733fc73b7aae95b99fc83faa *man/split_join_distance.Rd
+a757f57e07b4a56e4d3d397bce9e6619 *man/srand.Rd
+8193ddfde70d2dcac112dd45a9b5509e *man/st_cuts.Rd
+736e344890c7fad9664c9b89af710534 *man/st_min_cuts.Rd
+cd29e538c28e46d1fa01254fcd0139bd *man/stochastic_matrix.Rd
+3da3835bc4afc1a556179f53253a560c *man/strength.Rd
+fbf6daa1a792100c1abee1d41d213a40 *man/sub-.igraph.Rd
+af266e780f0a81c9da605e7237b8b879 *man/sub-sub-.igraph.Rd
+c30236e7c904a53f5d4a14051e46b329 *man/subcomponent.Rd
+984b4d4816340485669fdad6a168904a *man/subgraph.Rd
+07db79bc335f0e04a2642ca0edaa2b54 *man/subgraph_centrality.Rd
+141cc8cc55b86b6ff0ad53ac13e28a48 *man/subgraph_isomorphic.Rd
+3e0d417316ddb84b40e6d9b556fd4212 *man/subgraph_isomorphisms.Rd
+dd43518f1cb7fa06f74ff08cd73c3f5b *man/tail_of.Rd
+dcc36d6513810a05dc5aee4db1cf6d06 *man/tkigraph.Rd
+182d4ca047c072835f56925be5ae52c7 *man/tkplot.Rd
+dded70bc91fd4b32470d69c30c3c9288 *man/topo_sort.Rd
+40f46e1a4521ddcf3c933fa5a66f0f26 *man/transitivity.Rd
+650d83ad1f2e618ac55c77128357171a *man/triad_census.Rd
+3cb4abce82cc1b8875c0ddfe69cdf739 *man/unfold_tree.Rd
+f86491a5e94e80cce6a0de1b030e923f *man/union.Rd
+ce33c32b7c727661ab75efe75f3cba21 *man/union.igraph.Rd
+9d9e4f603d1669ca59c4c774432e8547 *man/union.igraph.es.Rd
+68863d16564c21e5f01e1e99cf8fce37 *man/union.igraph.vs.Rd
+81b2a8be8068135f8b364dd373ea8c8c *man/unique.igraph.es.Rd
+9904b84cbf70c88997eca93c650f8441 *man/unique.igraph.vs.Rd
+545164e6a85a8803ad908e69b6ede2ab *man/upgrade_graph.Rd
+42e6a14586647edc7ef491eabe9cc242 *man/vertex.Rd
+618a6de0b4fb2cafd10fb8c33a51733c *man/vertex.shape.pie.Rd
+bf900d751bb4be19ed7c1a46215f8c64 *man/vertex_attr-set.Rd
+fd45c207a24c9d13e14469e7b6553ba2 *man/vertex_attr.Rd
+907a592bb3ecfd2e53e2a0f1c18fe143 *man/vertex_attr_names.Rd
+590defb192b835867ff69d46acde5cc3 *man/vertex_connectivity.Rd
+abc23c6b293e4012236aa24d0a4b96ba *man/which_multiple.Rd
+689e238fb27fda01a75527e0189c945a *man/which_mutual.Rd
+6c4cb8a9f02895453080566affa20fc7 *man/with_edge_.Rd
+5c235e98409d868e164bd8ebd7de9688 *man/with_graph_.Rd
+dfa59de85fd19951adcd6f63ae7d3313 *man/with_vertex_.Rd
+966eecb5b28acd8b8d60d4dbc99da5bf *man/without_attr.Rd
+83dc6af5ee10c09054a6a3ec23d84b87 *man/without_loops.Rd
+28c5fefe65a49821092c31a1dcb0e092 *man/without_multiples.Rd
+cde880d64ac2352cd1873a9f3c425de3 *man/write_graph.Rd
+752c6c39d6c94efc9d6ab8059c1b7335 *src/AMD/Include/amd.h
+c1ec3247520fb501520b4fe077d20856 *src/AMD/Include/amd_internal.h
+b2470d1e2bced70dbd2b7e2f85405a50 *src/AMD/Makefile
+7d60c8defc517d361513bac03d04f13b *src/AMD/README.txt
+83d3a6479a3b589c4b53dc7a220f0cf4 *src/AMD/Source/amd.f
+41ec90eacd97a62c7393f9a66f714662 *src/AMD/Source/amd_1.c
+fc12596df9e5a12177d1c6e5dba8fce5 *src/AMD/Source/amd_2.c
+23003d2ff7e400dc8738a838951a80cb *src/AMD/Source/amd_aat.c
+212a9b583543cc25aceb7c7be7d88b04 *src/AMD/Source/amd_control.c
+c0a3524d4f5ddcb63065eeabe8ae57f8 *src/AMD/Source/amd_defaults.c
+896cccbf9ea7f21142964fe1868da79d *src/AMD/Source/amd_dump.c
+536469fbc9cd69d9ea1ee4a65c183a47 *src/AMD/Source/amd_global.c
+9abf67b12455bb1989b0e9edaa0bec03 *src/AMD/Source/amd_info.c
+e0391fcc241630fa3a5b9b2c5ee3f0ea *src/AMD/Source/amd_order.c
+5f8f83de491e328aefbff08a09c3b467 *src/AMD/Source/amd_post_tree.c
+d696467688131d58e3acf9e5a627360e *src/AMD/Source/amd_postorder.c
+5d46a2442b5d099f6ba9fa6b427d7a1f *src/AMD/Source/amd_preprocess.c
+56f64a3203f5752b5a012b806f101d8c *src/AMD/Source/amd_valid.c
+0da45b5971ee18817fde1702fe1cdf02 *src/AMD/Source/amdbar.f
+57b4f2e5de8a0744eeefbdb59053cee7 *src/CHOLMOD.diff
+d2d49c52f19cae17de0efe9bbd0e50b0 *src/CHOLMOD/Check/License.txt
+0689532ab6ed7c3864c9fafbee1aa1b6 *src/CHOLMOD/Check/cholmod_check.c
+eff565a1144bd2dba2d0a9757e50b481 *src/CHOLMOD/Check/cholmod_read.c
+84444c62831c05f57c0a41336c7a1f3b *src/CHOLMOD/Check/cholmod_write.c
+a6f89e2100d9b6cdffcea4f398e37343 *src/CHOLMOD/Check/lesser.txt
+887d3c7dc221e09fa581c96ce66e76f2 *src/CHOLMOD/Cholesky/License.txt
+8a939bb8ed17557aced224bb47854d8f *src/CHOLMOD/Cholesky/cholmod_amd.c
+7213ecb3b13826762028047c2341d9e6 *src/CHOLMOD/Cholesky/cholmod_analyze.c
+767989bd106e5d9b8da93137c9985dbf *src/CHOLMOD/Cholesky/cholmod_colamd.c
+1fc207b3547818bb016492f2d9714d4b *src/CHOLMOD/Cholesky/cholmod_etree.c
+ed20e10d4965835e49980924b568536c *src/CHOLMOD/Cholesky/cholmod_factorize.c
+7f4ddcc6f7a0b9de350c91ede8b6992c *src/CHOLMOD/Cholesky/cholmod_postorder.c
+4873c960895bf2eec956006e2014061b *src/CHOLMOD/Cholesky/cholmod_rcond.c
+be208074ff7a33899ff08a5ab9102fd9 *src/CHOLMOD/Cholesky/cholmod_resymbol.c
+914dc4160a428eae28de6c5f085ff129 *src/CHOLMOD/Cholesky/cholmod_rowcolcounts.c
+23f6f11fd436f347922790580e2de2fc *src/CHOLMOD/Cholesky/cholmod_rowfac.c
+913f2a4136ae76d3874f4ed82488f486 *src/CHOLMOD/Cholesky/cholmod_solve.c
+6cfb3b948b5ff28de6f8f7d4d8fa4859 *src/CHOLMOD/Cholesky/cholmod_spsolve.c
+a6f89e2100d9b6cdffcea4f398e37343 *src/CHOLMOD/Cholesky/lesser.txt
+2d3b7ec83d164d8189d29581badd2ab2 *src/CHOLMOD/Cholesky/t_cholmod_lsolve.c
+caea1d7895120894a93778e44558bf80 *src/CHOLMOD/Cholesky/t_cholmod_ltsolve.c
+df437e6236532f410f7dec95c530f689 *src/CHOLMOD/Cholesky/t_cholmod_rowfac.c
+5bb20e7d6a626be362a29171bd1eea6d *src/CHOLMOD/Cholesky/t_cholmod_solve.c
+0b650d81b9287230f7335cb5d6404b97 *src/CHOLMOD/Core/License.txt
+8e9fcd70bd9c5a7809519e89df32536d *src/CHOLMOD/Core/cholmod_aat.c
+d38fc004c4240ce11eccf6214b9fb76e *src/CHOLMOD/Core/cholmod_add.c
+212b6834b4f705afd74c1826836074ca *src/CHOLMOD/Core/cholmod_band.c
+3363557ed9201c7fdb11e2a0ee50b938 *src/CHOLMOD/Core/cholmod_change_factor.c
+bd97debc58e4e02b8a02f117aa291ca1 *src/CHOLMOD/Core/cholmod_common.c
+60d8d7bb40db79b8e41a41dd879fe01d *src/CHOLMOD/Core/cholmod_complex.c
+741aa40db56db6df1c4157aa8b35f299 *src/CHOLMOD/Core/cholmod_copy.c
+4ab120fc9bf2143578f57e91f9176115 *src/CHOLMOD/Core/cholmod_dense.c
+a0a55400242cbad3c11df002a8f82ba9 *src/CHOLMOD/Core/cholmod_error.c
+491edb629e50ec8b63e78be48e79fee3 *src/CHOLMOD/Core/cholmod_factor.c
+d43e39ea2e8764bee2120ca9720c864e *src/CHOLMOD/Core/cholmod_memory.c
+353c79883b82016484f8791916d40392 *src/CHOLMOD/Core/cholmod_sparse.c
+4d56f96d959dbb044aad2b1e2543a489 *src/CHOLMOD/Core/cholmod_transpose.c
+749075b69c8f254b01f4c1e2ac700b9a *src/CHOLMOD/Core/cholmod_triplet.c
+d3ab4a4b9ce5287a13a696c837e8178b *src/CHOLMOD/Core/cholmod_version.c
+a6f89e2100d9b6cdffcea4f398e37343 *src/CHOLMOD/Core/lesser.txt
+5935895eb635942363de326b69f1f135 *src/CHOLMOD/Core/t_cholmod_change_factor.c
+113394eba44b660e8b1f250794d9e315 *src/CHOLMOD/Core/t_cholmod_dense.c
+5eba949e29cf3716912d54cbcaa3d691 *src/CHOLMOD/Core/t_cholmod_transpose.c
+c28402b3ada915779c2e3f6ea105ade0 *src/CHOLMOD/Core/t_cholmod_triplet.c
+43dea0a98ff00c4d001efdcf9e1107fe *src/CHOLMOD/Include/License.txt
+aebdd50c54b3d11988fa4be5fb71d05f *src/CHOLMOD/Include/README.txt
+403be4e598bd11adb647b463f7eb4192 *src/CHOLMOD/Include/cholmod.h
+890fe34ad312aca4a0976b28969d5767 *src/CHOLMOD/Include/cholmod_blas.h
+8c1e3f82c00d6a67dd5d9d3139bea5a5 *src/CHOLMOD/Include/cholmod_camd.h
+bf7a358cf5641e22d1ae78fc9b350c47 *src/CHOLMOD/Include/cholmod_check.h
+67ecb03414269c5dda2e161a330fe1f0 *src/CHOLMOD/Include/cholmod_cholesky.h
+3adbb76236b883c09b4065c6f80d0e47 *src/CHOLMOD/Include/cholmod_complexity.h
+2bc29a401875fbec85ba108089b90333 *src/CHOLMOD/Include/cholmod_config.h
+e9946fff88271c4aa2125c88e6316fbf *src/CHOLMOD/Include/cholmod_core.h
+22e2cffd0d0420e8e2fe3c428759ce1a *src/CHOLMOD/Include/cholmod_internal.h
+0fbe5016dc058131ec1b9161271c287d *src/CHOLMOD/Include/cholmod_io64.h
+ea5a291dcfe7892727e272bb2ac6d752 *src/CHOLMOD/Include/cholmod_matrixops.h
+e62d8c9cd22547845a55d05b01fd0c50 *src/CHOLMOD/Include/cholmod_modify.h
+c834620d8dec432569c68147d3d3e886 *src/CHOLMOD/Include/cholmod_partition.h
+690f52f536eca0f17bf339abf01d07ef *src/CHOLMOD/Include/cholmod_supernodal.h
+0f53c41fc3e65fc75bd8489e34c552d0 *src/CHOLMOD/Include/cholmod_template.h
+48a212ecc047cccc04671355413943e2 *src/CHOLMOD/Makefile
+e60f67b276c37ca2fc0796a45b61c470 *src/CHOLMOD/MatrixOps/License.txt
+49cd872b6e8996dcd66d297ba60389ae *src/CHOLMOD/MatrixOps/cholmod_drop.c
+061a1e2dfd78e9ae7ba3c5586faa9acb *src/CHOLMOD/MatrixOps/cholmod_horzcat.c
+df0d737af990b2d73cd268407ba3d6cb *src/CHOLMOD/MatrixOps/cholmod_norm.c
+a7e865911dc280f1a508c8a7f1ff7975 *src/CHOLMOD/MatrixOps/cholmod_scale.c
+469e5a07b5afdbc789ed3229198030df *src/CHOLMOD/MatrixOps/cholmod_sdmult.c
+a2fc03dbf62f15c8ed356c20c1355b54 *src/CHOLMOD/MatrixOps/cholmod_ssmult.c
+7ffeb180ba7ebb9dd887ae2fb4c1876b *src/CHOLMOD/MatrixOps/cholmod_submatrix.c
+2136d5f0931b18d308e9aa9fa44296ca *src/CHOLMOD/MatrixOps/cholmod_symmetry.c
+3973c30221dd6c3fccc0ff15507ee260 *src/CHOLMOD/MatrixOps/cholmod_vertcat.c
+eb723b61539feef013de476e68b5c50a *src/CHOLMOD/MatrixOps/gpl.txt
+884c14d213c4e66bae0d0afbec2e89aa *src/CHOLMOD/MatrixOps/t_cholmod_sdmult.c
+e38b4b22e31f8f215bbf4580cf50619c *src/CHOLMOD/Modify/License.txt
+4797dfd399ed782013687044ef323f7e *src/CHOLMOD/Modify/cholmod_rowadd.c
+11b6fba3ee7f4d4e63dc7dedd394dcf4 *src/CHOLMOD/Modify/cholmod_rowdel.c
+7cf6727bf9f9f03cd07e4e93d533b7f8 *src/CHOLMOD/Modify/cholmod_updown.c
+eb723b61539feef013de476e68b5c50a *src/CHOLMOD/Modify/gpl.txt
+728fec932755d9a0aea090b48d0992d4 *src/CHOLMOD/Modify/t_cholmod_updown.c
+a6f9b195edaa19e04836ca1d7ac2f834 *src/CHOLMOD/Modify/t_cholmod_updown_numkr.c
+b0cf7a9044494b5ea9481a1728c710e6 *src/CHOLMOD/Partition/License.txt
+329fc0f714341b9dbe184b839892d97f *src/CHOLMOD/Partition/cholmod_camd.c
+59e37876b64fb63a152cab1d57bec972 *src/CHOLMOD/Partition/cholmod_ccolamd.c
+577a877ebb40c87dadadcd953a8d9bdc *src/CHOLMOD/Partition/cholmod_csymamd.c
+6b7929df43c72c0a776aa4fe94f741e2 *src/CHOLMOD/Partition/cholmod_metis.c
+6d854f59fdaeb40a885b9bb6e93c5263 *src/CHOLMOD/Partition/cholmod_nesdis.c
+a6f89e2100d9b6cdffcea4f398e37343 *src/CHOLMOD/Partition/lesser.txt
+e4f8cd28fc8be8ab14106630610b9c5f *src/CHOLMOD/README.txt
+08629b176847ad848a0327e6fde2210a *src/CHOLMOD/Supernodal/License.txt
+adcb277096f9457b71dd51acfc652b2a *src/CHOLMOD/Supernodal/cholmod_super_numeric.c
+5023292b43184229686f4026c5251a80 *src/CHOLMOD/Supernodal/cholmod_super_solve.c
+4953c632dbe81cf89d68135e4b340840 *src/CHOLMOD/Supernodal/cholmod_super_symbolic.c
+eb723b61539feef013de476e68b5c50a *src/CHOLMOD/Supernodal/gpl.txt
+1ad404233a51f38540a959c36d880bda *src/CHOLMOD/Supernodal/t_cholmod_gpu.c
+9a9583dbc7d17143de8c7245d05b845d *src/CHOLMOD/Supernodal/t_cholmod_super_numeric.c
+c520e30aafdf20b571fd57ac921e8211 *src/CHOLMOD/Supernodal/t_cholmod_super_solve.c
+e14e53d0b36e1d0647348a326e8b3b54 *src/COLAMD/Include/colamd.h
+9c9253b748adfe1c0afbfbac0f01f955 *src/COLAMD/Makefile
+0a80fb0db9cefb02e290ffd2f3431e6c *src/COLAMD/README.txt
+ed584482056a57c97c84f0f2701f76a6 *src/COLAMD/Source/colamd.c
+d9b27cdbf6cd3a08a921754ba6acbfc0 *src/COLAMD/Source/colamd_global.c
 e9746e10e53c52a8e9468e81ac0e9fe2 *src/DensityGrid.cpp
 11b90b027549d524c4e8af3cbbfcc307 *src/DensityGrid.h
 fc67113e1f6fbfdcda59cf39aab3ff00 *src/DensityGrid_3d.cpp
 5cfb53cff37ca7d43a52db4f8e44ba94 *src/DensityGrid_3d.h
-605d507fd74ae304c92e9a08d23443fa *src/Light.cpp
-a06dcdf977661620d9a30542d0708979 *src/Light.h
-40c74a5c37746c3aa29690de80b78c34 *src/Makevars.in
-39e80b3b5eb15c30c370e8e5d172b813 *src/Makevars.win
+196f552edb1ca1c8f9cf8a97a9e6f707 *src/Makevars.in
+3f6c3b45062c7e7e1bcc6f6e3695542c *src/Makevars.win
 47ce39714f6f9d6ec3bd7c91624d87f4 *src/NetDataTypes.cpp
 69166cb2f393e3ab50bebc72b16d3f7e *src/NetDataTypes.h
 19c564585ab9700eb4356ee8eeb32403 *src/NetRoutines.cpp
 6d28d398db2ae73d18c6c0448b55b8ba *src/NetRoutines.h
-b9106690e86aab37621da51d42ba6673 *src/Point.cpp
-a62fbead2d3a236d5303cc9085c8b2eb *src/Point.h
-8106fda17eb6d6f99a80f111d30d3ac5 *src/RIgraphRay.cpp
-a799c64d3087459d00e419f3fe8d6570 *src/Ray.cpp
-2e3885be19867ed6a3562aeadf9e5271 *src/Ray.h
-1feae5499e54a7b2015c14e67dbf25e7 *src/RayTracer.cpp
-79ce54bb866d3c8341d6ca072b034bb3 *src/RayTracer.h
-c5e9fe64aa620a4c2578d84ce4eb3a69 *src/RayVector.cpp
-61172ce5b49dfa8b864abcfb8808d5bc *src/RayVector.h
-bd7cf3fc7d493820b559dc1a65b6736a *src/Shape.cpp
-e8afe23482477c8dc53db328272ccd7e *src/Shape.h
-5c198eab1fe06123c45405eaa1a09200 *src/Sphere.cpp
-a4e697cdced0ed1c4d1caf55e7dba557 *src/Sphere.h
-dc312c8337bad1b31afdf169f3e9e194 *src/Triangle.cpp
-c422300a2a528aa3da4ec98ed2dd1c8f *src/Triangle.h
-b0bcf8e1b1af2cdebe701b34a00f39f8 *src/adjlist.c
-0e443173d6720b1300cf605bbaece04b *src/amd_1.c
-61f51178cc4c8cdc142f77870d973e37 *src/amd_2.c
-08554ac890dcb81c2b1158c9be01a31b *src/amd_aat.c
-da7c5120c89bb6c50a71d9826416b8ca *src/amd_control.c
-49e3189ef6df390a6ee6d32efcf37d2c *src/amd_defaults.c
-7a507df8b9319bcd17a6cad1dbda3fa7 *src/amd_dump.c
-63b58adb1033575a7733723f79b923d0 *src/amd_info.c
-a1c04b302dbe9454bd0555476ca97077 *src/amd_order.c
-5a26434fda9351c3cd2c440f09e3d031 *src/amd_post_tree.c
-b82d8ed7fea392e568f4fd8962cbb928 *src/amd_postorder.c
-2def6a2ca54e5d6ceccf7bdf1cdf5a7d *src/amd_preprocess.c
-44c8934cd1690b307fb15b90a66924f3 *src/amd_valid.c
+fcce9737f5d328cdc516dd48e2075962 *src/SuiteSparse_config/Makefile
+29429afaf74eaac98cb1957ddd4e8a38 *src/SuiteSparse_config/README.txt
+e9b2be5ad0056f588187cf504cf60764 *src/SuiteSparse_config/SuiteSparse_config.c
+5be5db8ccb99f88f234639b97d8227c5 *src/SuiteSparse_config/SuiteSparse_config.h
+917bb33fe32383364ed1174ebf623868 *src/SuiteSparse_config/SuiteSparse_config.mk
+0ea19089dfd660f6a712ec073f2a24dd *src/SuiteSparse_config/SuiteSparse_config_GPU.mk
+293d047331651328bfd9a3899c45e915 *src/SuiteSparse_config/SuiteSparse_config_Mac.mk
+379698a2a6027eab2a06b0b62cbd1b9a *src/adjlist.c
 cd9fc819a7108d5bd6e3df27bc574f8f *src/arpack.c
 84d831cf06a12ccddc98d577cf34638f *src/array.c
 28757abe7ee47a2a3752132e6521dbe7 *src/array.pmt
@@ -428,12 +754,12 @@ f94137db5d049089a48e8542b40679c8 *src/atlas.c
 971302943c0b86513f8d197306d6855d *src/attributes.c
 7f8eedd101f3f975de419df961bc789d *src/basic_query.c
 8cdb18f2170bd6eb311cb7ac9b12944f *src/bfgs.c
-86b692ba9ac8f2d08ccda011c318ae3a *src/bigint.c
+e0fb18ecf621c13a45bfd435b1638fce *src/bigint.c
 976d10cf54420e8a8f2fc9f6e142d8fa *src/bigint.h
 ba0b88f5f1576546416246735befd49e *src/bignum.c
 29893b4374ace98d58ab689ea1db4540 *src/bignum.h
 e8e1e6680b83ac2a2e4fdae9eb27e20c *src/bipartite.c
-bf276dc5fef4209096cc86529ee5eb6f *src/blas.c
+3b088ee6a512aaf29884856942c7e7f8 *src/blas.c
 ce7bc18dbcd8c9b52277ac9e716040f4 *src/bliss.cc
 d1ea0ed591a4f82f6d1d0e04cbfd1cbb *src/bliss_bignum.hh
 bfed152afaeef7400072c3a9f959fdd8 *src/bliss_defs.hh
@@ -453,73 +779,72 @@ e8f493a4957107b381266cf23402ecd1 *src/bliss_timer.cc
 4fbcb31c629208df6e08de6fc5546e8a *src/bliss_timer.hh
 9dea494c0b450eacc3399124a835ca34 *src/bliss_utils.cc
 40ec60a85a52ae23d365b36be0663e80 *src/bliss_utils.hh
-1deafb8a04546f4283e9ffc0167b441d *src/cattributes.c
-a4e35081fa127db8acbef2047c5206ba *src/centrality.c
+895a5bac13f6db624449469b77ba816f *src/cattributes.c
+c91e3714a9addcb41a25331c72dfe09b *src/centrality.c
 5f28b17df959357c02ebeb9b567cd7e7 *src/cliques.c
 c674dafd0655f930666b309cd023d4f6 *src/clustertool.cpp
 6ad201a1dcc21ac1abc526ff8fc5ec37 *src/cocitation.c
 02021ef565fd8ffb32fe28519d7d067f *src/cohesive_blocks.c
-9ecdde0109759e7b14ad73efc5c1404b *src/colamd.c
-ff913a29f540ae3c05cf05ffe4cd56b7 *src/community.c
+2e1f5738906f7fab0e9f994ea65f0d1e *src/community.c
 c878447bf8cd5bd7d6ad60299325589f *src/complex.c
-9e68a37154e84ab518d06ade0f4fe641 *src/components.c
+9828657420ac846bfe520574e68ef2c9 *src/components.c
 d41d8cd98f00b204e9800998ecf8427e *src/config.h
-1f2d99cf6b8e5bbdd6a4b1b04f586eee *src/config.h.in
+da22a174ed5a1435a55a2ea02737d424 *src/config.h.in
 a4080b528c0b3ef3c28feb24195b1151 *src/conversion.c
 6f20b66f4a09e408f75df47f33b5f04d *src/cores.c
 71e3b8f8d5465f43ca1d555d45ea13d7 *src/cs/UFconfig.h
 aca82a2cdbbcee0810a60c19c2304b0f *src/cs/cs.h
-0de41bfeeb074d64f4e66e522c0ff77d *src/cs_add.c
-c57185921cfac5c1881d63c906acd2a0 *src/cs_amd.c
-1d71a8f26f6985adde5b866d3ca886cf *src/cs_chol.c
-34b2dc25f7038adaeb9fb251dbdc4003 *src/cs_cholsol.c
-6a514645c9c04b6434f0467b9294c060 *src/cs_compress.c
-5d1d491b83bddb4de7dfe784d979267a *src/cs_counts.c
-ec39cce522361be6e4a3758ef018387e *src/cs_cumsum.c
-24b004cfcbd8cc8fb359db0f6234208a *src/cs_dfs.c
-c4f02f5755f68aaa170dbc448a6e0d88 *src/cs_dmperm.c
-50f7fc58048430e8be2208013a2ca117 *src/cs_droptol.c
-569c98d9f0daefdcca1557a9887e12a9 *src/cs_dropzeros.c
-d7406542b69bed807fe1a3649917cb5f *src/cs_dupl.c
-1d83b91ed80fa761c737e28460f142bb *src/cs_entry.c
-e84dcca7eb019c54a63244705be9de83 *src/cs_ereach.c
-56513bbedfdf82fd50257880a7d4110c *src/cs_etree.c
-07a5fe24c1504802ea681fbb392fa3ab *src/cs_fkeep.c
-9ccfa44ef05265c7cecf2b8c472444c6 *src/cs_gaxpy.c
-77d68d1fa7f658c27a7958b1ddb58b2d *src/cs_happly.c
-863e2db4f9333a4c57a145b080830aea *src/cs_house.c
-d91eb5a0ee22f874955dd304d872bc6a *src/cs_ipvec.c
-1ae89c82d2e9acefca697be9bb8c46f9 *src/cs_leaf.c
-7bc484d09f7b0ec2e90c3dfe71cb0050 *src/cs_load.c
-2c8e2c41defd62711d50dbd701b5d24e *src/cs_lsolve.c
-8399329c480228cd4aa3333e9ed55fdb *src/cs_ltsolve.c
-5c83d2012c350815acdfadd9621486fd *src/cs_lu.c
-c8d35a8b5bfc5158055530718355f2ae *src/cs_lusol.c
-85fc4de3b7192e3e578f219057d2c0df *src/cs_malloc.c
-1fa16ad625004c0751972d6167d302a7 *src/cs_maxtrans.c
-cd7f8fbe8b9f24d39398e521ee2d09b0 *src/cs_multiply.c
-3a79c830ce5dd9bb949a9685e1edaeea *src/cs_norm.c
-97293626e9f064a409f1714280395e2e *src/cs_permute.c
-c7f844492120b9225c45a32abeeb455c *src/cs_pinv.c
-fce1c3d237985737250c206c1fa9b364 *src/cs_post.c
-c3ccdcb4c0983305fdd38aed6fcaea4a *src/cs_print.c
-88bb28f69b30603dd19009a3375b8ac3 *src/cs_pvec.c
-d51bb2e9d507761a669a4e87d164aa00 *src/cs_qr.c
-97db2405a8b64e9d702aabc7179cdb89 *src/cs_qrsol.c
-03617d6031fc596d85e13b3a3da43fb7 *src/cs_randperm.c
-a8d7f11049e9dd9adb65b37055089f24 *src/cs_reach.c
-df2cd8d777a7ae7124bb3d3af0336c36 *src/cs_scatter.c
-5ea459c942ba6699f9d1c103896e8cec *src/cs_scc.c
-95fe5e92c37c842cf7f6ffd95bf45a26 *src/cs_schol.c
-25433aeb13e81623bea4fce4f4a386b7 *src/cs_spsolve.c
-ed31244ed5ef4ab0c2caa42b1a92dec0 *src/cs_sqr.c
-637e7a1b32636fe1d088b0895d771c3d *src/cs_symperm.c
-74e77d67862dcac028568c0a50b60844 *src/cs_tdfs.c
-7f9683f97ae6f192c2e4ded4ba51ed71 *src/cs_transpose.c
-5ab9c4c7c85630af49f10c1002795c06 *src/cs_updown.c
-4c8096ddf1737b69d8f41bc51ab1c96a *src/cs_usolve.c
-4ae2ad895b3ad8adcc0927dee0b33b3e *src/cs_util.c
-74e3d5634309a7716491939ecd8b993a *src/cs_utsolve.c
+0de41bfeeb074d64f4e66e522c0ff77d *src/cs/cs_add.c
+c57185921cfac5c1881d63c906acd2a0 *src/cs/cs_amd.c
+1d71a8f26f6985adde5b866d3ca886cf *src/cs/cs_chol.c
+34b2dc25f7038adaeb9fb251dbdc4003 *src/cs/cs_cholsol.c
+6a514645c9c04b6434f0467b9294c060 *src/cs/cs_compress.c
+5d1d491b83bddb4de7dfe784d979267a *src/cs/cs_counts.c
+ec39cce522361be6e4a3758ef018387e *src/cs/cs_cumsum.c
+24b004cfcbd8cc8fb359db0f6234208a *src/cs/cs_dfs.c
+c4f02f5755f68aaa170dbc448a6e0d88 *src/cs/cs_dmperm.c
+50f7fc58048430e8be2208013a2ca117 *src/cs/cs_droptol.c
+569c98d9f0daefdcca1557a9887e12a9 *src/cs/cs_dropzeros.c
+d7406542b69bed807fe1a3649917cb5f *src/cs/cs_dupl.c
+1d83b91ed80fa761c737e28460f142bb *src/cs/cs_entry.c
+e84dcca7eb019c54a63244705be9de83 *src/cs/cs_ereach.c
+56513bbedfdf82fd50257880a7d4110c *src/cs/cs_etree.c
+07a5fe24c1504802ea681fbb392fa3ab *src/cs/cs_fkeep.c
+9ccfa44ef05265c7cecf2b8c472444c6 *src/cs/cs_gaxpy.c
+77d68d1fa7f658c27a7958b1ddb58b2d *src/cs/cs_happly.c
+863e2db4f9333a4c57a145b080830aea *src/cs/cs_house.c
+d91eb5a0ee22f874955dd304d872bc6a *src/cs/cs_ipvec.c
+1ae89c82d2e9acefca697be9bb8c46f9 *src/cs/cs_leaf.c
+7bc484d09f7b0ec2e90c3dfe71cb0050 *src/cs/cs_load.c
+2c8e2c41defd62711d50dbd701b5d24e *src/cs/cs_lsolve.c
+8399329c480228cd4aa3333e9ed55fdb *src/cs/cs_ltsolve.c
+5c83d2012c350815acdfadd9621486fd *src/cs/cs_lu.c
+c8d35a8b5bfc5158055530718355f2ae *src/cs/cs_lusol.c
+85fc4de3b7192e3e578f219057d2c0df *src/cs/cs_malloc.c
+1fa16ad625004c0751972d6167d302a7 *src/cs/cs_maxtrans.c
+cd7f8fbe8b9f24d39398e521ee2d09b0 *src/cs/cs_multiply.c
+3a79c830ce5dd9bb949a9685e1edaeea *src/cs/cs_norm.c
+97293626e9f064a409f1714280395e2e *src/cs/cs_permute.c
+c7f844492120b9225c45a32abeeb455c *src/cs/cs_pinv.c
+fce1c3d237985737250c206c1fa9b364 *src/cs/cs_post.c
+c3ccdcb4c0983305fdd38aed6fcaea4a *src/cs/cs_print.c
+88bb28f69b30603dd19009a3375b8ac3 *src/cs/cs_pvec.c
+d51bb2e9d507761a669a4e87d164aa00 *src/cs/cs_qr.c
+97db2405a8b64e9d702aabc7179cdb89 *src/cs/cs_qrsol.c
+ee1b58b02d03aa41d6708fad642a4805 *src/cs/cs_randperm.c
+a8d7f11049e9dd9adb65b37055089f24 *src/cs/cs_reach.c
+df2cd8d777a7ae7124bb3d3af0336c36 *src/cs/cs_scatter.c
+5ea459c942ba6699f9d1c103896e8cec *src/cs/cs_scc.c
+95fe5e92c37c842cf7f6ffd95bf45a26 *src/cs/cs_schol.c
+25433aeb13e81623bea4fce4f4a386b7 *src/cs/cs_spsolve.c
+ed31244ed5ef4ab0c2caa42b1a92dec0 *src/cs/cs_sqr.c
+637e7a1b32636fe1d088b0895d771c3d *src/cs/cs_symperm.c
+74e77d67862dcac028568c0a50b60844 *src/cs/cs_tdfs.c
+7f9683f97ae6f192c2e4ded4ba51ed71 *src/cs/cs_transpose.c
+5ab9c4c7c85630af49f10c1002795c06 *src/cs/cs_updown.c
+4c8096ddf1737b69d8f41bc51ab1c96a *src/cs/cs_usolve.c
+4ae2ad895b3ad8adcc0927dee0b33b3e *src/cs/cs_util.c
+74e3d5634309a7716491939ecd8b993a *src/cs/cs_utsolve.c
 ae2b99c6930b9d78a067b9f304e4d021 *src/debug.h
 9886eed995d6b524e1a0f57b79cad7d7 *src/decomposition.c
 634a82287e116db541c1c954a3cd9bdc *src/dgetv0.f
@@ -534,15 +859,16 @@ cbd4968767585d82b4ea9762ce7a973b *src/dnaupd.f
 7e7766bc466e28155a85211734e36426 *src/dneigh.f
 92be5de027d3bf234c3adb3c1df81216 *src/dneupd.f
 599f6e77589fa5338379452ab77ec143 *src/dngets.f
-d8ad2b202c8a6ba69842dc7258256b8a *src/dqueue.c
-75b2af8f83aa22849da28cc69e823a3e *src/dqueue.pmt
+e364abbd6786aa5772180af6879cdbd3 *src/dotproduct.c
+03a845c6af6e800d15575f831ea2f18e *src/dqueue.c
+e2ddc9e8d520337ca4fafc08d4bab6d1 *src/dqueue.pmt
 efac25ebd52c48ef108adc8afb018f16 *src/drl_Node.h
 f1ca9cf6ad08537f57409d9ce04a6345 *src/drl_Node_3d.h
 ac508e551027fe56c57650557ae848b5 *src/drl_graph.cpp
 0c4a475dc83152ac2a64f07bc13fbc60 *src/drl_graph.h
 9b685020b218853e6c53e036b52b5f5e *src/drl_graph_3d.cpp
 4ee344063b486976c812f82113d3106c *src/drl_graph_3d.h
-eab1ab611cb3aec65f42ad2f0652c0fe *src/drl_layout.cpp
+d09cfb486851114c28eb5b74a4692e08 *src/drl_layout.cpp
 4c1690cd89b50832fb6ba2398d14414b *src/drl_layout.h
 a77f381105b0246c7a0719c0b669365b *src/drl_layout_3d.cpp
 7e4c69a183df51fc7662e2a3f5c6e6be *src/drl_layout_3d.h
@@ -564,308 +890,328 @@ d4ead7e7ae03b16c06bc2eee64bc99fd *src/dstatn.f
 de4792cfaab6cdda8d557902c2310fcc *src/dstqrb.f
 10246dd04cc987d389f1f369f4b1813b *src/dvout.f
 d971c3cba371000e3ee5232179b380c3 *src/eigen.c
-a132926fc62c5122a0e5db6e7decb1f9 *src/error.c
-3d289f9acb689ff87c11d26ec9431392 *src/evolver_cit.c
-9cd0df4f1d1e6929361821451483c0bb *src/f2c.h
-56707b18b6e21642069a8510f6073147 *src/f2c_dummy.c
+0accc0fa9659dc8f9f4c741decc84b1b *src/embedding.c
 f2de7b7be34e28680986231c4994aba7 *src/fast_community.c
 d0bfcf69eb5733db3c1c2de12f407bc2 *src/feedback_arc_set.c
-0563aa4b46d3a709c7032ef7654b08e5 *src/flow.c
+73856a07710b909efe4515ea1cd593b7 *src/flow.c
 f51da6e3cf3d9e27793f855b469a3663 *src/foreign-dl-header.h
-eccee3dbf7aa788c634b77f65e9bacfc *src/foreign-dl-lexer.c
+bb7f51b277f6b57706d4a525a86fa698 *src/foreign-dl-lexer.c
 311ecd79cb537a22b01912b84f2a73dd *src/foreign-dl-lexer.l
-43559ba4e43746f8aaa961ba4c58ed88 *src/foreign-dl-parser.c
-1c67dc103337b4b9c50ce94528f7af63 *src/foreign-dl-parser.h
+7e624363073352de0f5d152c3ef57876 *src/foreign-dl-parser.c
+3682d35229a1a858fc0f39984250007a *src/foreign-dl-parser.h
 efaed2bbc90cd2438328a2c2e9a65ed8 *src/foreign-dl-parser.y
 3db22bd8908d6d05a56a0856702ee72a *src/foreign-gml-header.h
-441522a2a07ce65ca392904dfcd17e59 *src/foreign-gml-lexer.c
+955e898325748a201742187e3c2c30ad *src/foreign-gml-lexer.c
 c84b6be330a9184096434f55d6de9e87 *src/foreign-gml-lexer.l
-ad2111f203beade7ddd1415e3cb58395 *src/foreign-gml-parser.c
-9407d6efc58f9a454260b2f3d3fe5ee9 *src/foreign-gml-parser.h
+827a6fda456b52478a9eeb1ab45fbfc7 *src/foreign-gml-parser.c
+aa32853c573766b8d0a2475b09ebe237 *src/foreign-gml-parser.h
 19ced477a34f97376c619eea0482f1f3 *src/foreign-gml-parser.y
-05415b608e7a60f77f276c51a3fc0f83 *src/foreign-graphml.c
+65afd90a3ab5f7f586304bbb36605eae *src/foreign-graphml.c
 6b3d524a6e9a9e187df1dbfbfd0afdbc *src/foreign-lgl-header.h
-cc6d81d2c845885a4e5642be9413c9d4 *src/foreign-lgl-lexer.c
+4e9d341f47bee27a4d03c689833df092 *src/foreign-lgl-lexer.c
 fb60d3213c781454f82624410aed67d2 *src/foreign-lgl-lexer.l
-436f645336fd806fa7525ce7c6646ea7 *src/foreign-lgl-parser.c
-2957ad10def23240e3a3bcae7de13c30 *src/foreign-lgl-parser.h
+f39f1b655be9b7cf81265cc2595fad7b *src/foreign-lgl-parser.c
+d9199f3dc95c36150e97dfe02a0b80a4 *src/foreign-lgl-parser.h
 c9aded2d0a81a04ae4dfd0f2e7b92554 *src/foreign-lgl-parser.y
 ba4af782887b2b97dc03481ee7f435bb *src/foreign-ncol-header.h
-cad3d020644bde8c9ab99c3ed5b17c78 *src/foreign-ncol-lexer.c
+ef5970c58031fca4191d276fdb8bdd97 *src/foreign-ncol-lexer.c
 bf1195fe1617392e785438d93fe0021d *src/foreign-ncol-lexer.l
-3fd61d712872dd731107690606e61b39 *src/foreign-ncol-parser.c
-cc506a5dc6e6fb4e4018c873b2a17898 *src/foreign-ncol-parser.h
+48cdda25ffc45336c60846748dd944e2 *src/foreign-ncol-parser.c
+5743f75338b8681b46c4395126f8e2b8 *src/foreign-ncol-parser.h
 50d4e7b6fe1a6589a7c2c8e7830072c9 *src/foreign-ncol-parser.y
 6228545b60873edce3007a3b200efdde *src/foreign-pajek-header.h
-bd4d6001c30c716580dd8e7ba19ab335 *src/foreign-pajek-lexer.c
+46aa2a004b51f35fb195068a85959fca *src/foreign-pajek-lexer.c
 1f9514ce1b24aaf239701148518861f1 *src/foreign-pajek-lexer.l
-7b38b7f9219634f19ff46e47ec646ac9 *src/foreign-pajek-parser.c
-cc0e7c882c550da2fb22d170ea077017 *src/foreign-pajek-parser.h
+8ab1c465db2c33736e330d94168463a7 *src/foreign-pajek-parser.c
+afacd28c6079124a9c7169d3d51427d6 *src/foreign-pajek-parser.h
 8af7eae958466874c8c9c28bce72fb91 *src/foreign-pajek-parser.y
-eda3aa570143c8e8eed6f2caad803636 *src/foreign.c
+05c1aac58e7912f0b763b5cf16e39013 *src/foreign.c
 85aa6b11ac217d0125f2a637b2f44780 *src/forestfire.c
 a13696b3db177831c57b0f4420a35bb1 *src/fortran_intrinsics.c
-2e4feecb12ae7427d53b85958f0941ec *src/games.c
+e329c8b5331df44098797f3782160722 *src/games.c
 9c4ac6869dba15f8f3726febbaa66170 *src/gengraph_box_list.cpp
-88bd52487c626b7650fd6d14e248925e *src/gengraph_box_list.h
-1217fd9a8088ac3c861170a4c2a29118 *src/gengraph_definitions.h
+ffac9e0579529981e1c14cbfd6b9c69e *src/gengraph_box_list.h
+0792e2d1a7190e8d41e332e0ca92bab7 *src/gengraph_definitions.h
 669960a45a8d87d695aead1c4ff45263 *src/gengraph_degree_sequence.cpp
 e91725a3e6fc82814f0838607077462c *src/gengraph_degree_sequence.h
-ff6d04d06e0510300725a54ed0fb29cf *src/gengraph_graph_molloy_hash.cpp
+aa2548014952552b00703886669949eb *src/gengraph_graph_molloy_hash.cpp
 8cd957d8c81c41dfc84b9d3ab52d89a7 *src/gengraph_graph_molloy_hash.h
-d26b760cb945c780486c439f08a31d57 *src/gengraph_graph_molloy_optimized.cpp
+7adabaf25556eb549602b1fd5452db30 *src/gengraph_graph_molloy_optimized.cpp
 1e029605529d2b30e0c51ce3f0118e28 *src/gengraph_graph_molloy_optimized.h
 4cd9c442c3d07a86cdd25c4f23532f3a *src/gengraph_hash.h
 ed698c541b7f649c44e0ad236a1c4889 *src/gengraph_header.h
 3cbf1351fcc949438140bd886b550b46 *src/gengraph_mr-connected.cpp
 dfecde6d15a11f7fe08510ee52505a0d *src/gengraph_powerlaw.cpp
 0cde273c55b4df3bbf9d6db3175ed954 *src/gengraph_powerlaw.h
-591fd6841007b0301c2bef9b05bc648d *src/gengraph_qsort.h
+7a57d0b17fc2497fa2fbd8cd4e88bed8 *src/gengraph_qsort.h
 74f893284897e15ef1058d9359bcee1c *src/gengraph_random.cpp
 0ec1db22781e6e2dfff3c076dc08cc0a *src/gengraph_random.h
-031d4f910e7889608d7ba4268d471c05 *src/gengraph_vertex_cover.h
+7fca2f62df37344887866770376dfe96 *src/gengraph_vertex_cover.h
 3bd5bd3098edf9792af4c01e59beac03 *src/glet.c
-e64c7452742bcfc99310ae9901cbd962 *src/glpapi01.c
-b17a4e69773620daa39e87c45dd48ea0 *src/glpapi02.c
-f7a3441497a86d3599a6882facacff18 *src/glpapi03.c
-8af8227d0296639060aefd772bf35678 *src/glpapi04.c
-a30e64d71793ce20aa6e1b07ed8dd411 *src/glpapi05.c
-f1d134c5e35fb0bb3af94aaa2eb0be7d *src/glpapi06.c
-21e7bc0b19232580d3c0f26bf4bbd1e1 *src/glpapi07.c
-1b8320574d7bc693fa5155dd8e627ab8 *src/glpapi08.c
-677c618173bc03d34ffc5daace06f84c *src/glpapi09.c
-e144bb6919e4e9e431b93e154865a530 *src/glpapi10.c
-9e9de1b47d47eaa4a4cebb74517c4e6e *src/glpapi11.c
-973d4c1f6d64fd170b2154e958ce5ed0 *src/glpapi12.c
-9fe8165a0e987461907848a28f15ca66 *src/glpapi13.c
-4582c7b8b705b3e30bda0c3f5b83597c *src/glpapi14.c
-7d03c791001d49225c7eac6051abb039 *src/glpapi15.c
-4cd43f0ca77c68416e5829c1a5b52c80 *src/glpapi16.c
-0d4439bdbcd5163e2ba728798c1dae53 *src/glpapi17.c
-36f651163d8f8aa7336570d40c68a233 *src/glpapi18.c
-983502183d4dd4e7d495a3fe8713408d *src/glpapi19.c
-2772b3118b3d9544de2a85ad1564d537 *src/glpavl.c
-49f330d09b6d03c651f332b5ecd14354 *src/glpbfd.c
-33ab56a232eb49786711d459bf22f3a1 *src/glpbfx.c
-b3a43b8f06092f5499c2c1ccdc0cbf32 *src/glpcpx.c
-3ccb652f19ee4c399e73fbf56af00658 *src/glpdmp.c
-85d574732e0ed25a328e9d0396cc0e38 *src/glpdmx.c
-6bbbc2b3400d31149365e4086060c7fc *src/glpenv01.c
-02dddf3d64ee5afc72a38462cd3721c5 *src/glpenv02.c
-1a9208853fe32f4d522b2f7622b9076a *src/glpenv03.c
-53bbb8f8863659738a8c953300f19048 *src/glpenv04.c
-c12ae087f99c8407fa1617930d1cc0da *src/glpenv05.c
-6faef60ba452fce1d9a780ea65281ba7 *src/glpenv06.c
-1db57509946800d4800cdf0afc30cdf1 *src/glpenv07.c
-49b7624ba8d7723df57cee48011247e9 *src/glpenv08.c
-46b0d56a190c98086865b183206206d5 *src/glpfhv.c
-342b93b287e4bd6e48fbe6a4ec24b07f *src/glpgmp.c
-996cd36081e5ebc2f56971470741b81d *src/glphbm.c
-ce63bb794e16482df6dbce2fbc84a77d *src/glpini01.c
-5644da9ce91aa2f11063edea8efaec4c *src/glpini02.c
-4a47177352b566b75dd2ad1a158f71a1 *src/glpios01.c
-8887161631f60bbf80adb45b6f7ccbe1 *src/glpios02.c
-29e44df78067e20670cca9b7db196fdf *src/glpios03.c
-11fb8f1cd067c99e11124c294c51e91d *src/glpios04.c
-f6fd7f01acbf12d0efa8901c92f5f10e *src/glpios05.c
-10435d381e839929cc8b0f9792236cc3 *src/glpios06.c
-7ee236816936ec5b2f96458f3d130aed *src/glpios07.c
-32091c062df372e38a001d78a3e1e341 *src/glpios08.c
-95d0e04a78319fc9be7fde38d26173a1 *src/glpios09.c
-a6f59b769898cd2e50d7d61066a9d9c7 *src/glpios10.c
-2a7eed373818656834cf6131bbc89c61 *src/glpios11.c
-7fcebd33c0c4282e72e105cfa7aa12a0 *src/glpios12.c
-b4e358a396f1d487cc49ea19c4bd8e2c *src/glpipm.c
+6aa4c0c48b808b45244efd507765e2b8 *src/glpk/COPYING
+d895c230f75573dfd8c188a8647dd96f *src/glpk/README
+e66651809cac5da60c8b80e9e4e79e08 *src/glpk/amd/COPYING
+bfdd79e55fe996c63b0636e065173e3b *src/glpk/amd/README
 f17b9ad6c570189c90e054e5ad22a48c *src/glpk/amd/amd.h
+0e443173d6720b1300cf605bbaece04b *src/glpk/amd/amd_1.c
+61f51178cc4c8cdc142f77870d973e37 *src/glpk/amd/amd_2.c
+08554ac890dcb81c2b1158c9be01a31b *src/glpk/amd/amd_aat.c
+da7c5120c89bb6c50a71d9826416b8ca *src/glpk/amd/amd_control.c
+49e3189ef6df390a6ee6d32efcf37d2c *src/glpk/amd/amd_defaults.c
+7a507df8b9319bcd17a6cad1dbda3fa7 *src/glpk/amd/amd_dump.c
+63b58adb1033575a7733723f79b923d0 *src/glpk/amd/amd_info.c
 db4e7aaf7501f2cdf05e0fccb0082ed3 *src/glpk/amd/amd_internal.h
+a1c04b302dbe9454bd0555476ca97077 *src/glpk/amd/amd_order.c
+5a26434fda9351c3cd2c440f09e3d031 *src/glpk/amd/amd_post_tree.c
+b82d8ed7fea392e568f4fd8962cbb928 *src/glpk/amd/amd_postorder.c
+2def6a2ca54e5d6ceccf7bdf1cdf5a7d *src/glpk/amd/amd_preprocess.c
+44c8934cd1690b307fb15b90a66924f3 *src/glpk/amd/amd_valid.c
+e66651809cac5da60c8b80e9e4e79e08 *src/glpk/colamd/COPYING
+0495db11d882533d3e1d77314aa08501 *src/glpk/colamd/README
+9ecdde0109759e7b14ad73efc5c1404b *src/glpk/colamd/colamd.c
 c29bfe2c47b141be27d1bbf316f256e3 *src/glpk/colamd/colamd.h
 4dd8a600fd42f610ce619ae89cd1e9c4 *src/glpk/glpapi.h
+e64c7452742bcfc99310ae9901cbd962 *src/glpk/glpapi01.c
+b17a4e69773620daa39e87c45dd48ea0 *src/glpk/glpapi02.c
+f7a3441497a86d3599a6882facacff18 *src/glpk/glpapi03.c
+8af8227d0296639060aefd772bf35678 *src/glpk/glpapi04.c
+a30e64d71793ce20aa6e1b07ed8dd411 *src/glpk/glpapi05.c
+f1d134c5e35fb0bb3af94aaa2eb0be7d *src/glpk/glpapi06.c
+21e7bc0b19232580d3c0f26bf4bbd1e1 *src/glpk/glpapi07.c
+1b8320574d7bc693fa5155dd8e627ab8 *src/glpk/glpapi08.c
+677c618173bc03d34ffc5daace06f84c *src/glpk/glpapi09.c
+e144bb6919e4e9e431b93e154865a530 *src/glpk/glpapi10.c
+9e9de1b47d47eaa4a4cebb74517c4e6e *src/glpk/glpapi11.c
+973d4c1f6d64fd170b2154e958ce5ed0 *src/glpk/glpapi12.c
+9fe8165a0e987461907848a28f15ca66 *src/glpk/glpapi13.c
+4582c7b8b705b3e30bda0c3f5b83597c *src/glpk/glpapi14.c
+7d03c791001d49225c7eac6051abb039 *src/glpk/glpapi15.c
+4cd43f0ca77c68416e5829c1a5b52c80 *src/glpk/glpapi16.c
+0d4439bdbcd5163e2ba728798c1dae53 *src/glpk/glpapi17.c
+36f651163d8f8aa7336570d40c68a233 *src/glpk/glpapi18.c
+983502183d4dd4e7d495a3fe8713408d *src/glpk/glpapi19.c
+2772b3118b3d9544de2a85ad1564d537 *src/glpk/glpavl.c
 701d3775db123ccbd0493d8c4ea34a7e *src/glpk/glpavl.h
+49f330d09b6d03c651f332b5ecd14354 *src/glpk/glpbfd.c
 848678ffb247e83064e327cc95fa06b3 *src/glpk/glpbfd.h
+33ab56a232eb49786711d459bf22f3a1 *src/glpk/glpbfx.c
 bad6d53eb95c74d2a8859557279a9979 *src/glpk/glpbfx.h
+b3a43b8f06092f5499c2c1ccdc0cbf32 *src/glpk/glpcpx.c
+3ccb652f19ee4c399e73fbf56af00658 *src/glpk/glpdmp.c
 de2e8b56e85a0b20dbb430d6aa84f7d0 *src/glpk/glpdmp.h
+85d574732e0ed25a328e9d0396cc0e38 *src/glpk/glpdmx.c
 af185798690a781a8975b4a569e51a76 *src/glpk/glpenv.h
+cf0001c122579632ad5475939adcc984 *src/glpk/glpenv01.c
+02dddf3d64ee5afc72a38462cd3721c5 *src/glpk/glpenv02.c
+1a9208853fe32f4d522b2f7622b9076a *src/glpk/glpenv03.c
+53bbb8f8863659738a8c953300f19048 *src/glpk/glpenv04.c
+c12ae087f99c8407fa1617930d1cc0da *src/glpk/glpenv05.c
+6faef60ba452fce1d9a780ea65281ba7 *src/glpk/glpenv06.c
+1db57509946800d4800cdf0afc30cdf1 *src/glpk/glpenv07.c
+49b7624ba8d7723df57cee48011247e9 *src/glpk/glpenv08.c
+46b0d56a190c98086865b183206206d5 *src/glpk/glpfhv.c
 2bd66523544ce97770e12c8603cd653e *src/glpk/glpfhv.h
+342b93b287e4bd6e48fbe6a4ec24b07f *src/glpk/glpgmp.c
 e1cf5f623aeafc6d82a408d564385746 *src/glpk/glpgmp.h
+996cd36081e5ebc2f56971470741b81d *src/glpk/glphbm.c
 b7d65d02425b2437b080a3f69ea9b3e1 *src/glpk/glphbm.h
+ce63bb794e16482df6dbce2fbc84a77d *src/glpk/glpini01.c
+5644da9ce91aa2f11063edea8efaec4c *src/glpk/glpini02.c
 6427eb0c0dc32e1aea7c20d16851de40 *src/glpk/glpios.h
+4a47177352b566b75dd2ad1a158f71a1 *src/glpk/glpios01.c
+8887161631f60bbf80adb45b6f7ccbe1 *src/glpk/glpios02.c
+29e44df78067e20670cca9b7db196fdf *src/glpk/glpios03.c
+11fb8f1cd067c99e11124c294c51e91d *src/glpk/glpios04.c
+f6fd7f01acbf12d0efa8901c92f5f10e *src/glpk/glpios05.c
+10435d381e839929cc8b0f9792236cc3 *src/glpk/glpios06.c
+7ee236816936ec5b2f96458f3d130aed *src/glpk/glpios07.c
+32091c062df372e38a001d78a3e1e341 *src/glpk/glpios08.c
+95d0e04a78319fc9be7fde38d26173a1 *src/glpk/glpios09.c
+a6f59b769898cd2e50d7d61066a9d9c7 *src/glpk/glpios10.c
+2a7eed373818656834cf6131bbc89c61 *src/glpk/glpios11.c
+7fcebd33c0c4282e72e105cfa7aa12a0 *src/glpk/glpios12.c
+b4e358a396f1d487cc49ea19c4bd8e2c *src/glpk/glpipm.c
 2a6aeaca925e3d8b2c3b9c9016121d27 *src/glpk/glpipm.h
 4eb723473ff13ca6d8c1d1f8a7bf46b8 *src/glpk/glpk.h
+7cc34fbb45352c2779c4e0c18633a620 *src/glpk/glpk.inc
 7a286fa7ac1eceaf243eb1ccdc9614cf *src/glpk/glplib.h
+e86efde3285da6e7e5b70609c9d30ca1 *src/glpk/glplib01.c
+a888f4dca9f00ba57960612fd54bf34f *src/glpk/glplib02.c
+f15b3eec93525eabe3dc1c27afa3a5a3 *src/glpk/glplib03.c
+aa0a9b8867ff151414904269733382e2 *src/glpk/glplpf.c
 0acc7485a685ddb71122d22fa7f3dbc1 *src/glpk/glplpf.h
+8fdffa2d9c8b98e026bc9176b2bf46f3 *src/glpk/glplpx01.c
+1a056d0d76910a9ddc344e9d79862ed2 *src/glpk/glplpx02.c
+b6997c531009890187f84017f092a698 *src/glpk/glplpx03.c
+51f02c1522277d2bcc51e762f8363912 *src/glpk/glpluf.c
 112d86ae170930563c37147d0201232a *src/glpk/glpluf.h
+8b3d8e9c4b6b1c8f980bbb349d82da31 *src/glpk/glplux.c
 4f75ac92850d57038c498931027fbb3a *src/glpk/glplux.h
+0a51e9223e38c9a0a96ee8c94e602213 *src/glpk/glpmat.c
 3d68afbfc8e7cc52600442e25500edde *src/glpk/glpmat.h
 b6fe8b8ff7c7c1405839b916fc6ee538 *src/glpk/glpmpl.h
+802bdfca436334911154b539a1e11091 *src/glpk/glpmpl01.c
+9d97da099e0d0084ccb1adfd8a4cf7e6 *src/glpk/glpmpl02.c
+19da1384b5e4ebd43e7c0c6b13b56350 *src/glpk/glpmpl03.c
+29e89bf6e061131e8eb6c3f50d5ce1dc *src/glpk/glpmpl04.c
+8a0c5bbdbeb1c2ef95479504b7ecf927 *src/glpk/glpmpl05.c
+19784444c34513714f178081c69432f3 *src/glpk/glpmpl06.c
+cd3d8668a985b27986386ea14a3a5509 *src/glpk/glpmps.c
 ef7abdd1cb7279367b64496d1ab5ac40 *src/glpk/glpnet.h
+c60ca0036894a63d2653736af1e7afcd *src/glpk/glpnet01.c
+f7b6379c577fa69e870effe585295275 *src/glpk/glpnet02.c
+ce92ee9eaa913676ef52970365010ee3 *src/glpk/glpnet03.c
+c2676be654346c4f6e0d12226abcd919 *src/glpk/glpnet04.c
+5b90741dd7f9c536e020e02feb947e17 *src/glpk/glpnet05.c
+ccc54db6eb60287bdfa50caf5c7fd6aa *src/glpk/glpnet06.c
+2d26b236a83453d99141d917a6d6dcd5 *src/glpk/glpnet07.c
+4d569359378e4ea5155abe63ce6436f5 *src/glpk/glpnet08.c
+ea0d3b98de940c5d62e344c046226a75 *src/glpk/glpnet09.c
 f10605e75b60797e59acf8c897b8a9fb *src/glpk/glpnpp.h
+2060cf4986223f5b8b1d6e8c7a8e6cbc *src/glpk/glpnpp01.c
+9779f9dcf4f7647a42499260ac3ec674 *src/glpk/glpnpp02.c
+e8d65669ef3915938da77c0d1a79dce6 *src/glpk/glpnpp03.c
+cc66449ea1082cc861d0ee8ef7bdcdb8 *src/glpk/glpnpp04.c
+6b01a6f4adf6b37d51d269c8bcfa1199 *src/glpk/glpnpp05.c
+18f30853f890cbbd2ff1469036daff6d *src/glpk/glpqmd.c
 2d027b66a207e6cb244d9c2ff8407cb2 *src/glpk/glpqmd.h
+ba62d9230bd3da1bedfd72fca32cc638 *src/glpk/glprgr.c
 fed50a39c1e72847ccff3a0e6f5356a4 *src/glpk/glprgr.h
 2575fe5808c2e6b86e0f8bbf328e31f0 *src/glpk/glprng.h
+a932ccfb7e961ef982bfa572a75c5b8b *src/glpk/glprng01.c
+a4319cc6438d545af19a46a0e860e205 *src/glpk/glprng02.c
+eb21955a5df4900fe0fedc7545005869 *src/glpk/glpscf.c
 c8ccbd6d72148da380dc7199729a48a2 *src/glpk/glpscf.h
+f0b5b2351e57e092b4755039297adefd *src/glpk/glpscl.c
+44700faf1076640bf15615a837ea7e32 *src/glpk/glpsdf.c
+3dade41dd2de4039094bd0417d47dafe *src/glpk/glpspm.c
 6ee41754eec62d95a8799714907143cd *src/glpk/glpspm.h
 8a4640b9634afc20ca92bc5d9b7e608d *src/glpk/glpspx.h
+b1b3ecfc42873be5665f7e2c371bef41 *src/glpk/glpspx01.c
+acf9363f8de2e02cbfdf4d6b0852d5a0 *src/glpk/glpspx02.c
+7bfa819a7610ad46b8daa7b53c31321f *src/glpk/glpsql.c
 a1763cdc5fb411f8c4b5f62510675b4d *src/glpk/glpsql.h
 a0122421497d5ce9813fcad4eb3f9a1c *src/glpk/glpssx.h
+417a7397688277ced9a0991447ec476d *src/glpk/glpssx01.c
+2cf632f6ddb252f241558ce06b72aa3e *src/glpk/glpssx02.c
 effb42a09a2fad5d5c9577a6c8c375f4 *src/glpk/glpstd.h
+07f66c70186d7f7c18b979baf3087984 *src/glpk/glptsp.c
 35eb2e8022860add92b53b914cb99993 *src/glpk/glptsp.h
 901398d9a9f4b8df25e57ce11950d886 *src/glpk_support.c
-e86efde3285da6e7e5b70609c9d30ca1 *src/glplib01.c
-a888f4dca9f00ba57960612fd54bf34f *src/glplib02.c
-f15b3eec93525eabe3dc1c27afa3a5a3 *src/glplib03.c
-aa0a9b8867ff151414904269733382e2 *src/glplpf.c
-8fdffa2d9c8b98e026bc9176b2bf46f3 *src/glplpx01.c
-1a056d0d76910a9ddc344e9d79862ed2 *src/glplpx02.c
-b6997c531009890187f84017f092a698 *src/glplpx03.c
-51f02c1522277d2bcc51e762f8363912 *src/glpluf.c
-8b3d8e9c4b6b1c8f980bbb349d82da31 *src/glplux.c
-0a51e9223e38c9a0a96ee8c94e602213 *src/glpmat.c
-802bdfca436334911154b539a1e11091 *src/glpmpl01.c
-9d97da099e0d0084ccb1adfd8a4cf7e6 *src/glpmpl02.c
-19da1384b5e4ebd43e7c0c6b13b56350 *src/glpmpl03.c
-29e89bf6e061131e8eb6c3f50d5ce1dc *src/glpmpl04.c
-8a0c5bbdbeb1c2ef95479504b7ecf927 *src/glpmpl05.c
-19784444c34513714f178081c69432f3 *src/glpmpl06.c
-cd3d8668a985b27986386ea14a3a5509 *src/glpmps.c
-c60ca0036894a63d2653736af1e7afcd *src/glpnet01.c
-f7b6379c577fa69e870effe585295275 *src/glpnet02.c
-ce92ee9eaa913676ef52970365010ee3 *src/glpnet03.c
-c2676be654346c4f6e0d12226abcd919 *src/glpnet04.c
-5b90741dd7f9c536e020e02feb947e17 *src/glpnet05.c
-ccc54db6eb60287bdfa50caf5c7fd6aa *src/glpnet06.c
-2d26b236a83453d99141d917a6d6dcd5 *src/glpnet07.c
-4d569359378e4ea5155abe63ce6436f5 *src/glpnet08.c
-ea0d3b98de940c5d62e344c046226a75 *src/glpnet09.c
-2060cf4986223f5b8b1d6e8c7a8e6cbc *src/glpnpp01.c
-9779f9dcf4f7647a42499260ac3ec674 *src/glpnpp02.c
-e8d65669ef3915938da77c0d1a79dce6 *src/glpnpp03.c
-cc66449ea1082cc861d0ee8ef7bdcdb8 *src/glpnpp04.c
-6b01a6f4adf6b37d51d269c8bcfa1199 *src/glpnpp05.c
-18f30853f890cbbd2ff1469036daff6d *src/glpqmd.c
-ba62d9230bd3da1bedfd72fca32cc638 *src/glprgr.c
-a932ccfb7e961ef982bfa572a75c5b8b *src/glprng01.c
-a4319cc6438d545af19a46a0e860e205 *src/glprng02.c
-eb21955a5df4900fe0fedc7545005869 *src/glpscf.c
-f0b5b2351e57e092b4755039297adefd *src/glpscl.c
-44700faf1076640bf15615a837ea7e32 *src/glpsdf.c
-3dade41dd2de4039094bd0417d47dafe *src/glpspm.c
-b1b3ecfc42873be5665f7e2c371bef41 *src/glpspx01.c
-acf9363f8de2e02cbfdf4d6b0852d5a0 *src/glpspx02.c
-7bfa819a7610ad46b8daa7b53c31321f *src/glpsql.c
-417a7397688277ced9a0991447ec476d *src/glpssx01.c
-2cf632f6ddb252f241558ce06b72aa3e *src/glpssx02.c
-07f66c70186d7f7c18b979baf3087984 *src/glptsp.c
 9e49afee60da929ba8be5d9561949edd *src/gml_tree.c
-3325bc090cc6c9f8dfac22689e534a28 *src/gss.c
 9cbe127f9ca1413b025474021b3dbbf8 *src/hacks.c
 502e94a6e46f91ec49aef1978e388a99 *src/heap.c
-507189bbcdaeddda2b3e1bee2640388c *src/heap.pmt
+9e02248d200bf72c7fcff7d5e50019fd *src/heap.pmt
 6e09173c5033b55d9a469c8dd2152847 *src/hrg_dendro.h
 db1d06d3f6afa649b603447a27db2ba3 *src/hrg_graph.h
 2a55b5aa6dd24af3fbed23c777f3356a *src/hrg_graph_simp.h
 45a515d92fd7d19d6b58ce9a99790443 *src/hrg_rbtree.h
 aa24b037d218c2525ba09ead3425f554 *src/hrg_splittree_eq.h
-5d261d8b02b68a913b7ea2fa61750032 *src/igraph.h
-06c01d2a2f3b3bffa3d14ef21f26b646 *src/igraph_adjlist.h
-75c807b296c812f666ab218a80b61d2e *src/igraph_arpack.h
 d049469367b24df3aaa04a335e19ae1f *src/igraph_arpack_internal.h
-623fd0301b11d9b7e7d518410be151bc *src/igraph_array.h
-9001525eae9a131c06ec404e2027450e *src/igraph_array_pmt.h
-0e9277d3c012dfb936cb3dcccf9a6d04 *src/igraph_attributes.h
-f206398b5b1ebd455a888fd4e039df3b *src/igraph_bipartite.h
-d5ad44bb127140ed7d1897b902453eb7 *src/igraph_blas.h
-35de0146121ed0d2e5ce0f3a2de72740 *src/igraph_blas_internal.h
+0ba0b5c96c3f5ee66e361b402f6ba852 *src/igraph_blas_internal.h
 8c23d74aac650a5a31f7aa2c5fd5e4cb *src/igraph_buckets.c
-82e0de14549bd32301dfc35f040141da *src/igraph_centrality.h
-08c3846da4ba18485b169257ab2e6247 *src/igraph_cliques.h
-e45a8025313dd0029619f82777b1abe5 *src/igraph_cocitation.h
-1914da75cb7d341220431e0ace1c15d7 *src/igraph_cohesive_blocks.h
-3b0614e0c2f1b3fd0cc1abd56178ab44 *src/igraph_community.h
-6b70a9038174acc3f988b831296c366a *src/igraph_complex.h
-c0501c548df97a52edccec56c888b743 *src/igraph_components.h
-267b1633bbcbdffea58242ae64fb902f *src/igraph_constants.h
-49689ad5d8365f90ee241f37eddc996f *src/igraph_constructors.h
-16b3e1150995475d75000a4d3f3da6e9 *src/igraph_conversion.h
-5628489dc4a2f581a70e63de6d0de7f8 *src/igraph_datatype.h
-ca6d0973e081cc25330a166205e3b553 *src/igraph_dqueue.h
-1f7fa9c5233d679f978df2fce00db6f6 *src/igraph_dqueue_pmt.h
-6b82a7f6360f79e1814f3d127d96e87c *src/igraph_eigen.h
-d58a291f8865cf4fe45092185076ef19 *src/igraph_epidemics.h
 b19e0c7e19e68ea56da4bc4d4adb9d42 *src/igraph_error.c
-312cd51739e41ddaa050cbc8fc8af42a *src/igraph_error.h
 89d68f6df7bcbf4d4076ac0b0e49c76d *src/igraph_estack.c
 5724366acc9829a7710570238fb8757c *src/igraph_estack.h
 b820670b0847175947527134ac67632e *src/igraph_f2c.h
 cb0744105e9a3bec9c23b323122abf18 *src/igraph_fixed_vectorlist.c
-2887c1f547c4ffd5bceaa6edb2d3c471 *src/igraph_flow.h
 47ee6b99a58e0f65a3c5bc3d393c9778 *src/igraph_flow_internal.h
-87156e6fa6bdf23bd94526021c603f59 *src/igraph_foreign.h
-fdebccf6bed02c480bda1f8e6d3a55e8 *src/igraph_games.h
 ba6345ae75a97b8435b3f1008394d521 *src/igraph_glpk_support.h
 7427a7fd438c1e5c394d9dc3b9296d38 *src/igraph_gml_tree.h
-9aaf4a333500cdd37d1813ce68e598bc *src/igraph_graphlets.h
 6cc5ff7eb59a0e80a55dd276d626058a *src/igraph_grid.c
 70dde0752bdfd37e737b8f919f559296 *src/igraph_hacks_internal.h
 798db32cb0483138312afbcee380996c *src/igraph_hashtable.c
 5fcba758c3db2a7b7e087ddf0ce31b2d *src/igraph_heap.c
-1717da324eb54cd1e1f71c10c8ae53b5 *src/igraph_heap.h
-7db2e0e75dfd1cc2da3126e9f5e62f14 *src/igraph_heap_pmt.h
 8c9642f7427ed582fcfeb23711106b51 *src/igraph_hrg.cc
-e09223330884413f8ad790dbecb6fe70 *src/igraph_hrg.h
 ec23eb8c9f95ac5333a7c4a955888c90 *src/igraph_hrg_types.cc
-3245b2c2ff708563207e8691bb9ce5b5 *src/igraph_interface.h
-96e9fa6414a7f6b9a58cb0aea6d9dc50 *src/igraph_interrupt.h
 491ac34973b02bee0561a49d3c5b75a9 *src/igraph_interrupt_internal.h
-626c2ad06dbf67663fa9e477fb579806 *src/igraph_iterators.h
-803628fbecb75a03af18aa90f2d73a67 *src/igraph_lapack.h
-ba664f4e2b69d9835ffabfc336bd37ee *src/igraph_lapack_internal.h
-5f36fb91cef12b727f3edbe07386bae4 *src/igraph_layout.h
+ea12c293520c96311f5df9e4de3871a0 *src/igraph_lapack_internal.h
 1ea6795e5745f48a13b85a5d565ef2db *src/igraph_marked_queue.c
 84c6ecb9eadc9a6615dada2a134ed3a4 *src/igraph_marked_queue.h
-5f74e30a6cc5e2afcaa04c850b1d62e2 *src/igraph_matching.h
-4dd979dc14d2f0e96da0c03548e98610 *src/igraph_math.h
-2a114796ba515085832c79f565b47b3f *src/igraph_matrix.h
-cae6389b9031f10ad056793bd59378b3 *src/igraph_matrix_pmt.h
-d3bb0da57b31cb5ab0ce4429a7078a27 *src/igraph_memory.h
-030d41f451590d25e199bdb9dd9b7a15 *src/igraph_microscopic_update.h
-8ee4888b80c021ed79c30c5b6b7de3d2 *src/igraph_mixing.h
-f16cc28c3fe2320314760e352ec2fa7f *src/igraph_motifs.h
-5962e2e4968d711454971ec88b02c5d8 *src/igraph_neighborhood.h
-cb2f513f20d1b9e1fc768b4a01ba949a *src/igraph_nongraph.h
-e86604269fd6942eadb6f4c6f37986de *src/igraph_operators.h
-9941a7947be349e5f828864780994958 *src/igraph_paths.h
-024bc0d4b6363037ea93edd33b1adb1b *src/igraph_pmt.h
-c7e18522a9ed70278190d35aad0c2788 *src/igraph_pmt_off.h
-8f739083243bd8c0146a4c4b44bfe258 *src/igraph_progress.h
+783f7fc62be2829c0467d07ac846b90a *src/igraph_math.h
 d3872c797d7d9d20338f3988b3bffa1f *src/igraph_psumtree.c
-7e39b7c3cdc2c7793b47222dec147610 *src/igraph_psumtree.h
-5445a7660a7f5a2aed7c1aca66a040d4 *src/igraph_qsort.h
-0ebf3c6bcac0918c60215f63f75790f9 *src/igraph_random.h
-bc2b831c79515f52022144ea4b479c2d *src/igraph_revolver.h
-320603e1a9f5f6b5d9564f933fc70282 *src/igraph_scg.h
-1c38c4ad71bc32f3701965af38c42035 *src/igraph_separators.h
 ef0a9f0275dd11cd340293b9c350431b *src/igraph_set.c
-573f3f42b20e9fce226470bc3518d317 *src/igraph_sparsemat.h
-817c003ae01fb4cee9c8412545ffacd6 *src/igraph_spmatrix.h
-2b815210b218876ee107f06fba86d04f *src/igraph_stack.c
-feda6bb336f17776c2fd0558de484dd9 *src/igraph_stack.h
-961b488b4455466255c740b779ffd37d *src/igraph_stack_pmt.h
-161ecbcf55c9af968ba800562168695a *src/igraph_statusbar.h
-ae8f253b9c1ebb15d454116b4af0c247 *src/igraph_structural.h
+d45e5264e0d3d4938d079599356bc688 *src/igraph_stack.c
 276b378aa4479d729baf29fdca1dd84b *src/igraph_strvector.c
-325e434438ca624456bfa3e7e675c036 *src/igraph_strvector.h
 f988c64c2045ca1b71eeda347e45905f *src/igraph_threading.h
-d22c3634d4677a6585641cd8c463887d *src/igraph_topology.h
-9066c301497c3f3c34d31cb2a71329f9 *src/igraph_transitivity.h
 78c519533ba34d958b11a20b183c3dfb *src/igraph_trie.c
-7f2373fa6dfb143ea9e3a5cdd4d5ad85 *src/igraph_types.h
 4aa482a23cfc790fe9de29e1f8867038 *src/igraph_types_internal.h
-a2bfa55d95c670368db1ca866efc29a4 *src/igraph_vector.h
-383762630cb8bf896dda3d74e16d5173 *src/igraph_vector_pmt.h
-64f1a9c71d6f9b2c68f09d63540c231e *src/igraph_vector_ptr.h
-58c8dccae0eda3cbda698d40a73c5deb *src/igraph_vector_type.h
-628d7afbfb67b953c74b1d474b430495 *src/igraph_version.h
-050ea429bcfd86ad679748fa9cbaa8b6 *src/igraph_visitor.h
+99c57c3a70ce472c78f5a5ec3fb23bce *src/igraph_version.h
+0d9165112b0f0c8b86842e679b44359b *src/include/igraph.h
+37472f54aeb9a7c18f07db1e9bea2761 *src/include/igraph_adjlist.h
+75c807b296c812f666ab218a80b61d2e *src/include/igraph_arpack.h
+623fd0301b11d9b7e7d518410be151bc *src/include/igraph_array.h
+9001525eae9a131c06ec404e2027450e *src/include/igraph_array_pmt.h
+0e9277d3c012dfb936cb3dcccf9a6d04 *src/include/igraph_attributes.h
+f206398b5b1ebd455a888fd4e039df3b *src/include/igraph_bipartite.h
+5c8be918cb0f086369f60069fb96a31e *src/include/igraph_blas.h
+82e0de14549bd32301dfc35f040141da *src/include/igraph_centrality.h
+08c3846da4ba18485b169257ab2e6247 *src/include/igraph_cliques.h
+e45a8025313dd0029619f82777b1abe5 *src/include/igraph_cocitation.h
+1914da75cb7d341220431e0ace1c15d7 *src/include/igraph_cohesive_blocks.h
+3b0614e0c2f1b3fd0cc1abd56178ab44 *src/include/igraph_community.h
+6b70a9038174acc3f988b831296c366a *src/include/igraph_complex.h
+c0501c548df97a52edccec56c888b743 *src/include/igraph_components.h
+e5242123fcea4d208db42746628e146c *src/include/igraph_constants.h
+49689ad5d8365f90ee241f37eddc996f *src/include/igraph_constructors.h
+16b3e1150995475d75000a4d3f3da6e9 *src/include/igraph_conversion.h
+5628489dc4a2f581a70e63de6d0de7f8 *src/include/igraph_datatype.h
+854fe9d404b9297dfe28cb345e16184c *src/include/igraph_dqueue.h
+1f7fa9c5233d679f978df2fce00db6f6 *src/include/igraph_dqueue_pmt.h
+fe6c31d313aa3c790c33f9e336cc8dad *src/include/igraph_eigen.h
+3eebe0dd5dd4fdc8e33317dcf747f5e2 *src/include/igraph_embedding.h
+d58a291f8865cf4fe45092185076ef19 *src/include/igraph_epidemics.h
+4015ea0ddca5a576656fca68e1ee9d46 *src/include/igraph_error.h
+2887c1f547c4ffd5bceaa6edb2d3c471 *src/include/igraph_flow.h
+87156e6fa6bdf23bd94526021c603f59 *src/include/igraph_foreign.h
+3a43cba5ced27eb95b115bb6a2d24516 *src/include/igraph_games.h
+9aaf4a333500cdd37d1813ce68e598bc *src/include/igraph_graphlets.h
+1717da324eb54cd1e1f71c10c8ae53b5 *src/include/igraph_heap.h
+7db2e0e75dfd1cc2da3126e9f5e62f14 *src/include/igraph_heap_pmt.h
+e09223330884413f8ad790dbecb6fe70 *src/include/igraph_hrg.h
+3245b2c2ff708563207e8691bb9ce5b5 *src/include/igraph_interface.h
+96e9fa6414a7f6b9a58cb0aea6d9dc50 *src/include/igraph_interrupt.h
+626c2ad06dbf67663fa9e477fb579806 *src/include/igraph_iterators.h
+5ee9175be30a58b456d2a9b0abb85e2a *src/include/igraph_lapack.h
+c00447123b9c1a88afef448d7516b4c2 *src/include/igraph_layout.h
+4183af0a346c6f9c9d23174c0712122c *src/include/igraph_lsap.h
+5f74e30a6cc5e2afcaa04c850b1d62e2 *src/include/igraph_matching.h
+9a93437b27e1ea58e601ee4a9b3bd941 *src/include/igraph_matrix.h
+86c0e0f30484ae675d06cb5ac8ffac43 *src/include/igraph_matrix_pmt.h
+d3bb0da57b31cb5ab0ce4429a7078a27 *src/include/igraph_memory.h
+030d41f451590d25e199bdb9dd9b7a15 *src/include/igraph_microscopic_update.h
+8ee4888b80c021ed79c30c5b6b7de3d2 *src/include/igraph_mixing.h
+a3e4fbbeb4dba712d7958dca6b594c5b *src/include/igraph_motifs.h
+c78c1c89ccd2d19cb96d2ca011e55d84 *src/include/igraph_neighborhood.h
+cb2f513f20d1b9e1fc768b4a01ba949a *src/include/igraph_nongraph.h
+e86604269fd6942eadb6f4c6f37986de *src/include/igraph_operators.h
+9fa4a86d827b66db5e090e0e07366b77 *src/include/igraph_paths.h
+e78b1f96059bbfaeafdb0477067edf51 *src/include/igraph_pmt.h
+c7e18522a9ed70278190d35aad0c2788 *src/include/igraph_pmt_off.h
+8f739083243bd8c0146a4c4b44bfe258 *src/include/igraph_progress.h
+7e39b7c3cdc2c7793b47222dec147610 *src/include/igraph_psumtree.h
+5445a7660a7f5a2aed7c1aca66a040d4 *src/include/igraph_qsort.h
+70b876685a343319ffaa3e57a61ee94d *src/include/igraph_random.h
+56f4889324a204a891acded5cf6792d0 *src/include/igraph_scan.h
+320603e1a9f5f6b5d9564f933fc70282 *src/include/igraph_scg.h
+1c38c4ad71bc32f3701965af38c42035 *src/include/igraph_separators.h
+77af613883e73a35e659d57940a0ad08 *src/include/igraph_sparsemat.h
+817c003ae01fb4cee9c8412545ffacd6 *src/include/igraph_spmatrix.h
+3a1098682a2b8318c1d040237e730872 *src/include/igraph_stack.h
+961b488b4455466255c740b779ffd37d *src/include/igraph_stack_pmt.h
+161ecbcf55c9af968ba800562168695a *src/include/igraph_statusbar.h
+ae8f253b9c1ebb15d454116b4af0c247 *src/include/igraph_structural.h
+325e434438ca624456bfa3e7e675c036 *src/include/igraph_strvector.h
+54813dc234e4b95869093015fa9eab9f *src/include/igraph_threading.h.in
+d22c3634d4677a6585641cd8c463887d *src/include/igraph_topology.h
+9066c301497c3f3c34d31cb2a71329f9 *src/include/igraph_transitivity.h
+7f2373fa6dfb143ea9e3a5cdd4d5ad85 *src/include/igraph_types.h
+577c03aaaa1f82a272c35381af3ad910 *src/include/igraph_vector.h
+383762630cb8bf896dda3d74e16d5173 *src/include/igraph_vector_pmt.h
+64f1a9c71d6f9b2c68f09d63540c231e *src/include/igraph_vector_ptr.h
+58c8dccae0eda3cbda698d40a73c5deb *src/include/igraph_vector_type.h
+2342032bb31be02392e38f58c90fde46 *src/include/igraph_version.h.in
+050ea429bcfd86ad679748fa9cbaa8b6 *src/include/igraph_visitor.h
 0ceee7df894ce42f555f5effe0240702 *src/infomap.cc
 d7095b8ca721c2507d81152d722308e8 *src/infomap_FlowGraph.cc
 bbf84d35c2016510d97be2b41be84017 *src/infomap_FlowGraph.h
@@ -876,75 +1222,86 @@ bbf84d35c2016510d97be2b41be84017 *src/infomap_FlowGraph.h
 14be091d75db4df0c8261c571a3c235f *src/interrupt.c
 491b61dbc3c8a265485f6b29eb5b84aa *src/iterators.c
 e9e8f2dac33c5cc7bfe1da70a95cc05f *src/ivout.f
-04b05118dedd5d894b7451a3077a2abf *src/kolmogorov.c
-22cb5d77f20ba43b40ee2882254776f3 *src/lad.c
-f6c80d45596a09a7a18de3edb95fe105 *src/lapack.c
-e0c0fb18b46e111743fa4e74fa550186 *src/layout.c
-a3f7a0497381c0fecd2c2634913c48e3 *src/lbfgs.c
-284719df65b4db536352f3bed6309975 *src/matching.c
+5e6f8a30ab44c555920fb5e190ee48d4 *src/lad.c
+f95ab29a3f1862dc2133f145ef2b8387 *src/lapack.c
+944bc5f5cdc345aebd7988a9b76b7fe6 *src/layout.c
+4f7b469bb975af226464e9566c043569 *src/layout_dh.c
+e9f5de5a325c01c520ac96f81ae8aa19 *src/layout_fr.c
+6bd4b13078318989464833728953da47 *src/layout_gem.c
+9a12cc013eec9145c563599e69c9f6b0 *src/layout_kk.c
+1080de49342aac0ca288d2db820e22bd *src/lazyeval.c
+201a9c70e7ebac764daf2578e9753397 *src/lsap.c
+fbbb25d689af1199a667bb5dbc2c11b3 *src/matching.c
 6235a73cc32cfaad6c3413719e36d16c *src/math.c
-bb7fbeb13293233a4927f790d2eaaa93 *src/matrix.c
-c2c748ceb15110c1cd5ce628a10719c5 *src/matrix.pmt
+57dbb4060ac063511e83d2c23c04c1e0 *src/matrix.c
+4ff709482db7e3630c81937607e072b1 *src/matrix.pmt
 6f99b8e27ee426917236833013db4ce5 *src/maximal_cliques.c
 09c8159e923bc5d13cb081d6f8c4657a *src/maximal_cliques_template.h
 4ae56c99425d054546ce50eee102c70d *src/memory.c
 38fc41da5fa51c0be97f084498a9d8d5 *src/microscopic_update.c
 8a97bea8b83111ca8fb2f2886db91fc1 *src/mixing.c
 2abdabfdf646e8dc092679df31ecd5e4 *src/motifs.c
-579a7e919b6c29f9ee0b736e6f5bc11c *src/operators.c
+8abad248bfc770d94c3496b6426a531e *src/operators.c
 13711e38459b1fc13a31384f665405d7 *src/optimal_modularity.c
-52f301d8733c4362b51ab461fd41b376 *src/options.c
-9fbb2134332fae527cc3200bff1690b8 *src/other.c
-a68a32d67b810ad2271da3d932506179 *src/plfit.c
+7f4dba9bcfbe0db2a808ba15ab2f9329 *src/other.c
+d27219d9ea7116704ecd446de3502e9b *src/paths.c
 a6595cc90c64e0aab7a336856a219e53 *src/plfit/arithmetic_ansi.h
 098651533f8c80ffeef3d3e43bf39783 *src/plfit/arithmetic_sse_double.h
 896685565ace49c58c8587e52c9fdfcb *src/plfit/arithmetic_sse_float.h
+a132926fc62c5122a0e5db6e7decb1f9 *src/plfit/error.c
 9351bcba0c90fce3ad1dc3abdfbad525 *src/plfit/error.h
+3325bc090cc6c9f8dfac22689e534a28 *src/plfit/gss.c
 24b12def90aee37671bc29d1c267997a *src/plfit/gss.h
+04b05118dedd5d894b7451a3077a2abf *src/plfit/kolmogorov.c
 1af9acf6c110147ab7392148cf24c0ce *src/plfit/kolmogorov.h
+a3f7a0497381c0fecd2c2634913c48e3 *src/plfit/lbfgs.c
 f3601e97b1249e5888d73fd10e8126d9 *src/plfit/lbfgs.h
+52f301d8733c4362b51ab461fd41b376 *src/plfit/options.c
 2af6a5ba8d50aaa2493f188475fbab8d *src/plfit/platform.h
+a68a32d67b810ad2271da3d932506179 *src/plfit/plfit.c
 ec39eb232b03766144d5ce70434cd470 *src/plfit/plfit.h
+e7ea89c52ae68ed4acd40cee7848cc98 *src/plfit/plfit.inc
+23aa3f72d6724222f7563bb22fa011df *src/plfit/zeta.c
 2cb90ff85be06e53110d04f2ee7574e3 *src/plfit/zeta.h
 5219cdfa910aac54c77dc3ba3d87105b *src/pottsmodel_2.cpp
 b39bce59a0e9fdfe1b028aca69f040d3 *src/pottsmodel_2.h
 3b4575360f029b448db3946a22672a8d *src/progress.c
-9be80fc38a8b4cce2458b8995b0db38c *src/prpack.cpp
+09ff2ff1c1daad014e1b03bc2ea1f3b1 *src/prpack.cpp
 f239c9f27078f7fc0ade177796514f7a *src/prpack.h
 9cdd08531c091877493dc38d6d9a76a6 *src/prpack/prpack.h
+d270166efd776ce2b037b5e33c9e65c9 *src/prpack/prpack.inc
+0bd04ba0eae9e7e3c81786f64d64f5d7 *src/prpack/prpack_base_graph.cpp
 9204c4b68e204d547368fe45215f1933 *src/prpack/prpack_base_graph.h
 11ef113ef2afa4d58490fcd2b150c070 *src/prpack/prpack_csc.h
 6dd85cebd13f0a8636f2410131e7a096 *src/prpack/prpack_csr.h
 16f1218cac357f6853a1ef4a56a97a1e *src/prpack/prpack_edge_list.h
+13554f0c55678a78ba701e20669282db *src/prpack/prpack_igraph_graph.cpp
 f4725104dcd769f5b8c536e1e7e7a629 *src/prpack/prpack_igraph_graph.h
+4d3341314d147c7713eabf7bf2b28808 *src/prpack/prpack_preprocessed_ge_graph.cpp
 23b18b1935c305ff6f8ea72ace07fcb0 *src/prpack/prpack_preprocessed_ge_graph.h
 f3f1eb733b38a2686c5443728bae2090 *src/prpack/prpack_preprocessed_graph.h
+71f33cc3adc3806482f0154329cc996e *src/prpack/prpack_preprocessed_gs_graph.cpp
 4bce367b866843fa89ec64a448a209cb *src/prpack/prpack_preprocessed_gs_graph.h
+d38e02fad914bac940da4a32ac39afea *src/prpack/prpack_preprocessed_scc_graph.cpp
 b1c479ed32faf5a58f406615ce6f48bd *src/prpack/prpack_preprocessed_scc_graph.h
+86aa47464bc6d84a6ebd0912dc66ea66 *src/prpack/prpack_preprocessed_schur_graph.cpp
 f705b565d4dc23052d5ec58dc2f63d33 *src/prpack/prpack_preprocessed_schur_graph.h
+7dbb50744056002b707ae5232924d448 *src/prpack/prpack_result.cpp
 9a2d350363928141ef4785e6f0e2cfd5 *src/prpack/prpack_result.h
+041cf12b9a1bf4bf64970211f15b1318 *src/prpack/prpack_solver.cpp
 aa69309ad88c68bd3aef2d3b9f78d8ac *src/prpack/prpack_solver.h
+3108bd08055e25c22b24cd7aee26f8c5 *src/prpack/prpack_utils.cpp
 d8e4562102dd19aa2b0ebb8b9ffc761a *src/prpack/prpack_utils.h
-0bd04ba0eae9e7e3c81786f64d64f5d7 *src/prpack_base_graph.cpp
-13554f0c55678a78ba701e20669282db *src/prpack_igraph_graph.cpp
-4d3341314d147c7713eabf7bf2b28808 *src/prpack_preprocessed_ge_graph.cpp
-71f33cc3adc3806482f0154329cc996e *src/prpack_preprocessed_gs_graph.cpp
-d38e02fad914bac940da4a32ac39afea *src/prpack_preprocessed_scc_graph.cpp
-86aa47464bc6d84a6ebd0912dc66ea66 *src/prpack_preprocessed_schur_graph.cpp
-7dbb50744056002b707ae5232924d448 *src/prpack_result.cpp
-1188482777588f7f569217973ad29698 *src/prpack_solver.cpp
-6be9e55d9e9a8962d8a11145d94f89bf *src/prpack_utils.cpp
 051b93697a782d5ee7443e6d14273f95 *src/pstdint.h
 44ba6e8d2fe1c99c7598c6f337c39c9a *src/qsort.c
 f9a82bcf4a3a750ab39528bc8d304053 *src/qsort_r.c
-85bd6a1c98ce55dced77f667051025ea *src/random.c
-c37956ab8d0dbfcaee2d4710140c24c7 *src/revolver_cit.c
-e0671ef91b7374b5823821f20011f968 *src/revolver_grow.c
-cd7cb4802771d928add18fcadd0357d4 *src/revolver_ml_cit.c
-b9c425eb6157b194fb5cca7378c6efcd *src/rinterface.c
-3bc0f1802a0de2718213b62b126cbb5c *src/rinterface.h
-d17a9c6ea82a7e1178559a889c086e96 *src/rinterface_extra.c
-21218e152a5873af8c41295a60784f38 *src/sbm.c
+e786dc518261ef5f38e1baba523457ab *src/random.c
+b0e44ade8f91b8ea8609d6f7d54d2ae5 *src/random_walk.c
+391ab7cd3f42decd92736699cbda417f *src/rinterface.c
+55c344dc2daf18e33b5e11a248013759 *src/rinterface.h
+8ded947de0b87f80bf2ca9191dd2f0b1 *src/rinterface_extra.c
+e14049547150220f7e9adbbe7d498d89 *src/sbm.c
+6e1336d05a0466d5c0cc830116a22eaf *src/scan.c
 aea038197b2d7bf291ffae04eb916e1e *src/scg.c
 0c45c2990b0c5da3975c486a76988a88 *src/scg_approximate_methods.c
 57172adf7c8ab509ba78ca5249e491dc *src/scg_exact_scg.c
@@ -954,31 +1311,68 @@ f02cb493011fc03a7afd0f73429e7444 *src/scg_headers.h
 bd4eee538520a213640c06c511215412 *src/scg_utils.c
 fe76b21dffc13a149499515906044064 *src/second.f
 900f269653a3550d5804bdd246d46e80 *src/separators.c
+af447f07a45af2b4f7edaee5d0a877a7 *src/simpleraytracer/Color.cpp
+be39147aa9a658a401d5d8e304bfbb68 *src/simpleraytracer/Color.h
+605d507fd74ae304c92e9a08d23443fa *src/simpleraytracer/Light.cpp
+a06dcdf977661620d9a30542d0708979 *src/simpleraytracer/Light.h
+b9106690e86aab37621da51d42ba6673 *src/simpleraytracer/Point.cpp
+a62fbead2d3a236d5303cc9085c8b2eb *src/simpleraytracer/Point.h
+8106fda17eb6d6f99a80f111d30d3ac5 *src/simpleraytracer/RIgraphRay.cpp
+a799c64d3087459d00e419f3fe8d6570 *src/simpleraytracer/Ray.cpp
+2e3885be19867ed6a3562aeadf9e5271 *src/simpleraytracer/Ray.h
+1feae5499e54a7b2015c14e67dbf25e7 *src/simpleraytracer/RayTracer.cpp
+79ce54bb866d3c8341d6ca072b034bb3 *src/simpleraytracer/RayTracer.h
+c5e9fe64aa620a4c2578d84ce4eb3a69 *src/simpleraytracer/RayVector.cpp
+61172ce5b49dfa8b864abcfb8808d5bc *src/simpleraytracer/RayVector.h
+bd7cf3fc7d493820b559dc1a65b6736a *src/simpleraytracer/Shape.cpp
+e8afe23482477c8dc53db328272ccd7e *src/simpleraytracer/Shape.h
+5c198eab1fe06123c45405eaa1a09200 *src/simpleraytracer/Sphere.cpp
+a4e697cdced0ed1c4d1caf55e7dba557 *src/simpleraytracer/Sphere.h
+dc312c8337bad1b31afdf169f3e9e194 *src/simpleraytracer/Triangle.cpp
+c422300a2a528aa3da4ec98ed2dd1c8f *src/simpleraytracer/Triangle.h
+fc6fc5c9aa5a5187e6a2b1643f72ed4a *src/simpleraytracer/unit_limiter.cpp
+10c5f89c9426685c966b72e159221f1a *src/simpleraytracer/unit_limiter.h
 2afac75f121c2b327f3a2310c2d2cfb8 *src/sir.c
 eee880ddc507c1a7add8ffa2a86ffc78 *src/spanning_trees.c
-1f36e5b63e7e4c76ea9ceb017bbd3f6b *src/sparsemat.c
+f58958b871663e26442111eb4242f114 *src/sparsemat.c
 6bb03a8313135637cc13b229466c5fb2 *src/spectral_properties.c
 c09d0e9140d619f214444c71395afbe6 *src/spmatrix.c
 eca023c1e47dc08d757a306ce363251c *src/st-cuts.c
-cb9349c6655ec534ec5f9350ce6d368a *src/stack.pmt
+6900ecd75c77fa349fd21b96ac3948cf *src/stack.pmt
 b5163c86a9a4ff980ad7a02f9303d2b7 *src/stat.h
 0a0892716e6bfe89fa6cccb8d9685b2f *src/statusbar.c
-d2bbf1e2d44182f30147731f748b3960 *src/structural_properties.c
+70c0a6a6052cf99b350d710849b1a4ef *src/structural_properties.c
 9bf218baeb55418532e13ff952319dbb *src/structure_generators.c
 8fa4711e4da6193579f9dda3dda2b5d6 *src/sugiyama.c
 b75142ca495ff1275ac3ffd5982d853b *src/topology.c
-b5278d5c248ba78fb24d8470dbc8283f *src/triangles.c
-7f2cb9bfd820624e7628cb8fc904fb4b *src/triangles_template.h
-123e666d740c6b4d2462358a45769698 *src/triangles_template1.h
-063203b293418cb30f8696ce52bff124 *src/type_indexededgelist.c
+50ad754b8d0b5dd84e7083b1e4b434c1 *src/triangles.c
+279f73c47d166d3c9a7a8a46677163aa *src/triangles_template.h
+72543eb9f61505227afa82bcd98a9aab *src/triangles_template1.h
+2475f0aeb10d27edef133c0533a11d63 *src/type_indexededgelist.c
 79ff3df7bfa26151b9893cffeba4d002 *src/types.c
-fc6fc5c9aa5a5187e6a2b1643f72ed4a *src/unit_limiter.cpp
-10c5f89c9426685c966b72e159221f1a *src/unit_limiter.h
-40ebfd83365fd2f13c9a233f0585275a *src/vector.c
+cfb66084ea2bfc7648ab47ed1018e8a4 *src/uuid/COPYING
+c733862ac29e8bbd01a49b5ac7d4a780 *src/uuid/Makevars.in
+81a759562546aeea16d466fece227601 *src/uuid/Makevars.win
+3eb0f4eb28341a52ddd7790ad4c043ae *src/uuid/R.c
+137be172372dd9bfeb50ed7aa2869b3e *src/uuid/clear.c
+d2b39a0b3d72632db235a9c6d36ef344 *src/uuid/compare.c
+76087d772af7d37cab53b1a56cf72ade *src/uuid/config.h.in
+d0026e30bb2f3feb7ac1db9827dd4820 *src/uuid/copy.c
+50e3c817e70104f83a75afb978071f5f *src/uuid/gen_uuid.c
+7374a713629b202c4fb82d650e510acb *src/uuid/isnull.c
+b671656493c2119636a4e981e9aad857 *src/uuid/pack.c
+dcc91eb622c08bf2fca11680c71b92cc *src/uuid/parse.c
+bededb71c0c869f06c3275a79781ed17 *src/uuid/unpack.c
+e51bd355555086e18222fbe3dff9d59f *src/uuid/unparse.c
+35a97c82d22737936a4ba8fb6924bcd4 *src/uuid/uuid.h
+84c21b1a1c769a488f5ff52e91be798a *src/uuid/uuidP.h
+aad9fd83e8f3cc7eb80e2ab0b2c4f84c *src/uuid/uuidd.h
+9e16418d043b96a6061ffb43150c5abd *src/uuid/win32/config.h
+b345cf8deb9563717b23547730686212 *src/vector.c
 97226f108c97b7abda68537cfdcb3c8a *src/vector.pmt
 50416ee45e4b1e7e1c465d3c440963aa *src/vector_ptr.c
 86dd274efc3061285ec0d3930f21fc2f *src/version.c
-911557f42ca1079bdfe405d791f18710 *src/visitors.c
+e593dc778e53754657c788127e1a1ab0 *src/visitors.c
 3e539674df5de90da12ae880863af9c6 *src/walktrap.cpp
 15455e530da0bd2c8f68cef84a7a6870 *src/walktrap_communities.cpp
 d4677977768e0f15fb39a1d42bb4a7e7 *src/walktrap_communities.h
@@ -987,4 +1381,3 @@ d4677977768e0f15fb39a1d42bb4a7e7 *src/walktrap_communities.h
 4708174b9d0a7ad332731d356b1f51fd *src/walktrap_heap.cpp
 50c30f2b5e618bc971622ee539994586 *src/walktrap_heap.h
 5125d305fe99bd9f8a0f550eb758a30f *src/zeroin.c
-23aa3f72d6724222f7563bb22fa011df *src/zeta.c
diff --git a/NAMESPACE b/NAMESPACE
index fbb8920..04daa57 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,449 +1,871 @@
-
-importFrom(stats, as.dendrogram)
-importFrom(stats, as.hclust)
-importFrom(stats, median)
-importFrom(stats, quantile)
-import(methods)
-
-# The igraph interface
-
-export(add.vertices, delete.edges,
-       delete.vertices, ecount, neighbors, incident, get.edges, get.edge.ids)
-
-export("[.igraph", "[[.igraph", "[<-.igraph")
-
-S3method("[", "igraph")
-S3method("[[", "igraph")
-S3method("[<-", "igraph")
-
-export(edge, edges, vertex, vertices, path,
-       "+.igraph", "-.igraph")
-
-S3method("+", "igraph")
-S3method("-", "igraph")
-
-# Attributes
-
-export(get.graph.attribute, set.graph.attribute, graph.attributes,
-       get.vertex.attribute, set.vertex.attribute, vertex.attributes,
-       get.edge.attribute, set.edge.attribute, edge.attributes,
-       list.graph.attributes, list.vertex.attributes,
-       list.edge.attributes, remove.graph.attribute,
-       remove.vertex.attribute, remove.edge.attribute,
-       "graph.attributes<-", "vertex.attributes<-", "edge.attributes<-")
-
-# iterators
-
-export(V, E, "$.igraph.vs", "$.igraph.es",
-       "[.igraph.vs", "[[.igraph.vs", "[.igraph.es", "[[.igraph.es",
-       "[<-.igraph.vs", "[<-.igraph.es", "[[<-.igraph.vs", "[[<-.igraph.es",
-       "$<-.igraph.vs", "$<-.igraph.es", "V<-", "E<-",
-       print.igraph.vs, print.igraph.es, "%--%", "%->%", "%<-%")
-
-S3method("$", igraph)
-S3method("$<-", igraph)
-S3method("$", igraph.vs)
-S3method("[", igraph.vs)
-S3method("[[", igraph.vs)
-S3method("[<-", igraph.vs)
-S3method("[[<-", igraph.vs)
-S3method("$<-", igraph.vs)
-S3method("$", igraph.es)
-S3method("[", igraph.es)
-S3method("[[", igraph.es)
-S3method("[<-", igraph.es)
-S3method("[[<-", igraph.es)
-S3method("$<-", igraph.es)
-S3method(print, igraph.vs)
-S3method(print, igraph.es)
-  
-# basic functions, printing
-
-export(is.igraph, is.named, is.weighted, is.bipartite,
-       are.connected, print.igraph, str.igraph, summary.igraph,
-       is.directed, get.edge)
-
-S3method("str", "igraph")
-
-# structure generators
-
-export(graph, graph.adjacency, graph.star, graph.tree, graph.lattice,
-       graph.ring, graph.full, graph.atlas, graph.data.frame, graph.edgelist,
-       graph.extended.chordal.ring, line.graph, graph.de.bruijn, graph.kautz,
-       graph.formula, graph.famous)
-
-# games
-
-export(erdos.renyi.game, random.graph.game, degree.sequence.game,
-       aging.prefatt.game, aging.barabasi.game, aging.ba.game,
-       growing.random.game, barabasi.game, ba.game,
-       callaway.traits.game, establishment.game, grg.game,
-       preference.game, asymmetric.preference.game, connect.neighborhood,
-       rewire.edges, watts.strogatz.game, lastcit.game, cited.type.game,
-       citing.cited.type.game, bipartite.random.game)
-
-# community structure
-
-export(edge.betweenness.community,
-       spinglass.community, walktrap.community,
-       edge.betweenness.community.merges, fastgreedy.community,
-       community.to.membership)
-
-export(membership, modularity, sizes, algorithm, is.hierarchical, merges,
-       cutat, communities, crossing, plot.communities, compare,
-       compare.communities, showtrace, code.length, asPhylo, dendPlot,
-       create.communities)
-
-S3method("print", communities)
-S3method("modularity", communities)
-S3method("length", communities)
-S3method("as.dendrogram", communities)
-S3method("as.hclust", communities)
-S3method("asPhylo", communities)
-S3method("modularity", igraph)
-S3method("dendPlot", communities)
-S3method("compare", communities)
-S3method("compare", numeric)
-S3method("compare", default)
-
-# conversion
-
-export(get.adjacency, get.edgelist, as.directed, as.undirected,
-       get.adjlist, get.adjedgelist, igraph.from.graphNEL, 
-       igraph.to.graphNEL, get.data.frame)
-
-# fitting, other
-
-export(power.law.fit, running.mean, igraph.sample, srand)
-
-# foreign formats
-
-export(read.graph, write.graph, graph.graphdb)
-
-# layouts
-
-export(layout.auto, layout.random, layout.circle,
-       layout.spring, layout.kamada.kawai, layout.lgl,
-       layout.fruchterman.reingold.grid, layout.sphere, layout.merge,
-       layout.reingold.tilford, layout.norm, piecewise.layout)
-export(igraph.drl.default, igraph.drl.coarsen, igraph.drl.coarsest,
-       igraph.drl.refine, igraph.drl.final)
-
-# structural properties
-
-export(subgraph, degree, degree.distribution, diameter,
-       subcomponent, betweenness, bibcoupling, cocitation,
-       shortest.paths, minimum.spanning.tree,
-       get.shortest.paths, average.path.length, transitivity,
-       get.all.shortest.paths, get.diameter, farthest.nodes,
-       constraint, page.rank, reciprocity, rewire,
-       graph.density, neighborhood.size, neighborhood, graph.neighborhood,
-       graph.coreness, topological.sort, girth, is.loop, is.multiple,
-       count.multiple)
-
-# plotting
-
-export(plot.igraph, tkplot, tkplot.close, tkplot.off, tkplot.fit.to.screen,
-       tkplot.reshape, tkplot.export.postscript, tkplot.getcoords,
-       tkplot.center, tkplot.rotate, tkplot.canvas, tkplot.setcoords,
-       rglplot.igraph, rglplot,
-       autocurve.edges, vertex.shapes, add.vertex.shape,
-       igraph.shape.noclip, igraph.shape.noplot)
-
-S3method(rglplot, igraph)
-
-# components
-
-export(cluster.distribution, is.connected, decompose.graph,
-       no.clusters)
-
-# centrality
-
-export(evcent, bonpow, alpha.centrality, subgraph.centrality)
-export(igraph.arpack.default, igraph.eigen.default)
-
-# dynamics measurement
-
-export(revolver.d, revolver.error.d,
-       revolver.ad, revolver.error.ad,
-       revolver.ade, revolver.error.ade,
-       revolver.e, revolver.error.e,
-       revolver.de, revolver.error.de,
-       revolver.l, revolver.error.l,
-       revolver.dl, revolver.error.dl,
-       revolver.el, revolver.error.el,
-       revolver.r, revolver.error.r,
-       revolver.ar, revolver.error.ar,
-       revolver.di, revolver.error.di,
-       revolver.adi, revolver.error.adi,
-       revolver.il, revolver.error.il,
-       revolver.ir, revolver.error.ir,
-       revolver.air, revolver.error.air)
-
-export (revolver.d.d, revolver.p.p)
-
-export (evolver.d)
-
-# isomorphism, motifs
-
-export(graph.isoclass, graph.isomorphic, graph.motifs,
-       graph.motifs.est, graph.isocreate, graph.motifs.no,
-       graph.isomorphic.vf2, graph.subisomorphic.vf2,
-       graph.count.isomorphisms.vf2, graph.count.subisomorphisms.vf2,
-       graph.get.isomorphisms.vf2, graph.get.subisomorphisms.vf2)
-
-# operators
-
-export(graph.disjoint.union, "%du%", graph.intersection, "%s%",
-       graph.union, "%u%", graph.difference, "%m%",
-       graph.complementer, graph.compose, "%c%")
-
-# parameters, config
-
-export(igraph.par, igraph.options, getIgraphOpt, igraphtest, igraph.version)
-
-# console
-
-export(igraph.console, .igraph.progress, .igraph.status)
-
-# flows, cuts, etc.
-
-export(graph.mincut, vertex.connectivity, edge.connectivity,
-       edge.disjoint.paths, vertex.disjoint.paths, graph.adhesion,
-       graph.cohesion)
-
-# cliques
-
-export(cliques, largest.cliques, maximal.cliques, clique.number,
-       independent.vertex.sets, largest.independent.vertex.sets,
-       maximal.independent.vertex.sets, independence.number)
-
-# cohesive blocking, this is what remains from the old implementation
-
-S3method(layout.svd, igraph)
-export(layout.svd)
-
-# cohesive blocking, new style 
-
-export(blocks, blockGraphs, cohesion, hierarchy, parent,
-       plotHierarchy, exportPajek, maxcohesion)
-
-S3method(print, cohesiveBlocks)
-S3method(summary, cohesiveBlocks)
-S3method(plot, cohesiveBlocks)
-S3method(length, cohesiveBlocks)
-
-# arpack
-
+# Generated by roxygen2 (4.1.1): do not edit by hand
+
+S3method("$",igraph)
+S3method("$",igraph.es)
+S3method("$",igraph.vs)
+S3method("$<-",igraph)
+S3method("$<-",igraph.es)
+S3method("$<-",igraph.vs)
+S3method("*",igraph)
+S3method("+",igraph)
+S3method("-",igraph)
+S3method("[",communities)
+S3method("[",igraph)
+S3method("[",igraph.es)
+S3method("[",igraph.vs)
+S3method("[<-",igraph)
+S3method("[<-",igraph.es)
+S3method("[<-",igraph.vs)
+S3method("[[",communities)
+S3method("[[",igraph)
+S3method("[[",igraph.es)
+S3method("[[",igraph.vs)
+S3method("[[<-",igraph.es)
+S3method("[[<-",igraph.vs)
+S3method(as.dendrogram,communities)
+S3method(as.hclust,communities)
+S3method(as.igraph,igraphHRG)
+S3method(as_ids,igraph.es)
+S3method(as_ids,igraph.vs)
+S3method(as_phylo,communities)
+S3method(c,igraph.es)
+S3method(c,igraph.vs)
+S3method(cohesion,cohesiveBlocks)
+S3method(cohesion,igraph)
+S3method(compare,communities)
+S3method(compare,default)
+S3method(compare,membership)
+S3method(difference,igraph)
+S3method(difference,igraph.es)
+S3method(difference,igraph.vs)
+S3method(groups,communities)
+S3method(groups,default)
+S3method(intersection,igraph)
+S3method(intersection,igraph.es)
+S3method(intersection,igraph.vs)
+S3method(length,cohesiveBlocks)
+S3method(length,communities)
+S3method(median,sir)
+S3method(modularity,communities)
+S3method(modularity,igraph)
+S3method(plot,cohesiveBlocks)
+S3method(plot,communities)
+S3method(plot,igraph)
+S3method(plot,sir)
+S3method(plot_dendrogram,communities)
+S3method(plot_dendrogram,igraphHRG)
+S3method(print,cohesiveBlocks)
+S3method(print,communities)
+S3method(print,igraph)
+S3method(print,igraph.es)
+S3method(print,igraph.vs)
+S3method(print,igraphHRG)
+S3method(print,igraphHRGConsensus)
+S3method(print,igraph_layout_modifier)
+S3method(print,igraph_layout_spec)
+S3method(print,membership)
+S3method(quantile,sir)
+S3method(rep,igraph)
+S3method(rev,igraph.es)
+S3method(rev,igraph.vs)
+S3method(rglplot,igraph)
+S3method(scg,Matrix)
+S3method(scg,igraph)
+S3method(scg,matrix)
+S3method(str,igraph)
+S3method(summary,cohesiveBlocks)
+S3method(summary,igraph)
+S3method(time_bins,sir)
+S3method(union,default)
+S3method(union,igraph)
+S3method(union,igraph.es)
+S3method(union,igraph.vs)
+S3method(unique,igraph.es)
+S3method(unique,igraph.vs)
+export("%--%")
+export("%->%")
+export("%<-%")
+export("%>%")
+export("%c%")
+export("%du%")
+export("%m%")
+export("%s%")
+export("%u%")
+export("E<-")
+export("V<-")
+export("edge.attributes<-")
+export("edge_attr<-")
+export("graph.attributes<-")
+export("graph_attr<-")
+export("vertex.attributes<-")
+export("vertex_attr<-")
+export(.igraph.progress)
+export(.igraph.status)
+export(E)
+export(V)
+export(add.edges)
+export(add.vertex.shape)
+export(add.vertices)
+export(add_edges)
+export(add_layout_)
+export(add_shape)
+export(add_vertices)
+export(adhesion)
+export(adjacent.triangles)
+export(adjacent_vertices)
+export(aging.ba.game)
+export(aging.barabasi.game)
+export(aging.prefatt.game)
+export(algorithm)
+export(all_shortest_paths)
+export(all_simple_paths)
+export(alpha.centrality)
+export(alpha_centrality)
+export(any_multiple)
+export(are.connected)
+export(are_adjacent)
 export(arpack)
-
-# tkigraph, demo
-
-export(tkigraph,igraphdemo)
-
-# HRG
-
-S3method(print, igraphHRG)
-S3method(print, igraphHRGConsensus)
-S3method("as.dendrogram", igraphHRG)
-S3method("as.hclust", igraphHRG)
-S3method("asPhylo", igraphHRG)
-S3method("dendPlot", igraphHRG)
-
-# SCG
-
-export(scg)
-S3method(scg, "igraph")
-S3method(scg, "matrix")
-S3method(scg, "Matrix")
-
-# nexus
-
-export(nexus.get, nexus.list, nexus.info, nexus.search)
-S3method(print, nexusDatasetInfo)
-S3method(print, nexusDatasetInfoList)
-S3method(summary, nexusDatasetInfoList)
-S3method("[", nexusDatasetInfoList)
-
-# Sparse data frame
-
-S3method(as.data.frame, igraphSDF)
-S3method("[", igraphSDF)
-S3method("[<-", igraphSDF)
-
-# convert to igraph
-
+export(arpack_defaults)
+export(articulation.points)
+export(articulation_points)
+export(as.directed)
 export(as.igraph)
-S3method(as.igraph, "igraphHRG")
-
-# Graphlets
-
-export(graphlets, graphlets.project)
-
-# SIR
-
-export(plot.sir, time_bins)
-S3method(plot, sir)
-S3method(median, sir)
-S3method(quantile, sir)
-S3method(time_bins, sir)
-
-######################## REST IS GENERATED BY stimulus
-export(graph.empty)
-export(add.edges)
-export(vcount)
-export(graph.full.citation)
-export(graph.lcf)
-export(graph.adjlist)
-export(graph.full.bipartite)
-export(forest.fire.game)
-export(interconnected.islands.game)
-export(static.fitness.game)
-export(static.power.law.game)
-export(k.regular.game)
-export(sbm.game)
-export(closeness)
-export(closeness.estimate)
-export(betweenness.estimate)
-export(edge.betweenness)
-export(edge.betweenness.estimate)
-export(page.rank.old)
-export(page.rank)
-export(induced.subgraph)
-export(subgraph.edges)
-export(path.length.hist)
-export(simplify)
-export(is.dag)
-export(is.simple)
-export(has.multiple)
-export(evcent)
-export(hub.score)
+export(as.undirected)
+export(asPhylo)
+export(as_adj)
+export(as_adj_edge_list)
+export(as_adj_list)
+export(as_adjacency_matrix)
+export(as_bipartite)
+export(as_data_frame)
+export(as_edgelist)
+export(as_graphnel)
+export(as_ids)
+export(as_incidence_matrix)
+export(as_long_data_frame)
+export(as_membership)
+export(as_phylo)
+export(as_star)
+export(as_tree)
+export(assortativity)
+export(assortativity.degree)
+export(assortativity.nominal)
+export(assortativity_degree)
+export(assortativity_nominal)
+export(asym_pref)
+export(asymmetric.preference.game)
+export(atlas)
 export(authority.score)
-export(arpack.unpack.complex)
-export(unfold.tree)
-export(is.mutual)
-export(maximum.cardinality.search)
-export(is.chordal)
-export(graph.knn)
-export(graph.strength)
-export(centralize.scores)
-export(centralization.degree)
-export(centralization.degree.tmax)
+export(authority_score)
+export(autocurve.edges)
+export(automorphisms)
+export(average.path.length)
+export(ba.game)
+export(barabasi.game)
+export(betweenness)
+export(betweenness.estimate)
+export(bfs)
+export(bibcoupling)
+export(biconnected.components)
+export(biconnected_components)
+export(bipartite)
+export(bipartite.mapping)
+export(bipartite.projection)
+export(bipartite.projection.size)
+export(bipartite.random.game)
+export(bipartite_graph)
+export(bipartite_mapping)
+export(bipartite_projection)
+export(bipartite_projection_size)
+export(blockGraphs)
+export(blocks)
+export(bonpow)
+export(callaway.traits.game)
+export(canonical.permutation)
+export(canonical_permutation)
+export(categorical_pal)
+export(centr_betw)
+export(centr_betw_tmax)
+export(centr_clo)
+export(centr_clo_tmax)
+export(centr_degree)
+export(centr_degree_tmax)
+export(centr_eigen)
+export(centr_eigen_tmax)
 export(centralization.betweenness)
 export(centralization.betweenness.tmax)
 export(centralization.closeness)
 export(centralization.closeness.tmax)
+export(centralization.degree)
+export(centralization.degree.tmax)
 export(centralization.evcent)
 export(centralization.evcent.tmax)
-export(assortativity.nominal)
-export(assortativity)
-export(assortativity.degree)
+export(centralize)
+export(centralize.scores)
+export(chordal_ring)
+export(cit_cit_types)
+export(cit_types)
+export(cited.type.game)
+export(citing.cited.type.game)
+export(clique.number)
+export(clique_num)
+export(cliques)
+export(closeness)
+export(closeness.estimate)
+export(cluster.distribution)
+export(cluster_edge_betweenness)
+export(cluster_fast_greedy)
+export(cluster_infomap)
+export(cluster_label_prop)
+export(cluster_leading_eigen)
+export(cluster_louvain)
+export(cluster_optimal)
+export(cluster_spinglass)
+export(cluster_walktrap)
+export(clusters)
+export(cocitation)
+export(code.length)
+export(code_len)
+export(cohesion)
+export(cohesive.blocks)
+export(cohesive_blocks)
+export(communities)
+export(compare)
+export(complementer)
+export(component_distribution)
+export(component_wise)
+export(components)
+export(compose)
+export(connect)
+export(connect.neighborhood)
+export(consensus_tree)
+export(console)
+export(constraint)
+export(contract)
 export(contract.vertices)
+export(convex.hull)
+export(convex_hull)
+export(coreness)
+export(count.multiple)
+export(count_components)
+export(count_isomorphisms)
+export(count_max_cliques)
+export(count_motifs)
+export(count_multiple)
+export(count_subgraph_isomorphisms)
+export(count_triangles)
+export(create.communities)
+export(crossing)
+export(curve_multiple)
+export(cut_at)
+export(cutat)
+export(de_bruijn_graph)
+export(decompose)
+export(decompose.graph)
+export(degree)
+export(degree.distribution)
+export(degree.sequence.game)
+export(degree_distribution)
+export(degseq)
+export(delete.edges)
+export(delete.vertices)
+export(delete_edge_attr)
+export(delete_edges)
+export(delete_graph_attr)
+export(delete_vertex_attr)
+export(delete_vertices)
+export(dendPlot)
+export(dfs)
+export(diameter)
+export(difference)
+export(dim_select)
+export(directed_graph)
+export(disjoint_union)
+export(distance_table)
+export(distances)
+export(diverging_pal)
+export(diversity)
+export(dominator.tree)
+export(dominator_tree)
+export(dot_product)
+export(drl_defaults)
+export(dyad.census)
+export(dyad_census)
+export(each_edge)
 export(eccentricity)
-export(radius)
-export(graph.diversity)
-export(is.degree.sequence)
-export(is.graphical.degree.sequence)
+export(ecount)
+export(edge)
+export(edge.attributes)
+export(edge.betweenness)
+export(edge.betweenness.community)
+export(edge.betweenness.estimate)
+export(edge.connectivity)
+export(edge.disjoint.paths)
+export(edge_attr)
+export(edge_attr_names)
+export(edge_betweenness)
+export(edge_connectivity)
+export(edge_density)
+export(edge_disjoint_paths)
+export(edges)
+export(ego)
+export(ego_size)
+export(eigen_centrality)
+export(embed_adjacency_matrix)
+export(embed_laplacian_matrix)
+export(empty_graph)
+export(ends)
+export(erdos.renyi.game)
+export(establishment.game)
+export(estimate_betweenness)
+export(estimate_closeness)
+export(estimate_edge_betweenness)
+export(evcent)
+export(exportPajek)
+export(export_pajek)
+export(farthest.nodes)
+export(farthest_vertices)
+export(fastgreedy.community)
+export(fit_hrg)
+export(fit_power_law)
+export(forest.fire.game)
+export(from_adjacency)
+export(from_data_frame)
+export(from_edgelist)
+export(from_incidence_matrix)
+export(from_literal)
+export(full_bipartite_graph)
+export(full_citation_graph)
+export(full_graph)
+export(gclust.app)
+export(gclust.rsvt)
+export(get.adjacency)
+export(get.adjedgelist)
+export(get.adjlist)
+export(get.all.shortest.paths)
+export(get.data.frame)
+export(get.diameter)
+export(get.edge)
+export(get.edge.attribute)
+export(get.edge.ids)
+export(get.edgelist)
+export(get.edges)
+export(get.graph.attribute)
+export(get.incidence)
+export(get.shortest.paths)
+export(get.stochastic)
+export(get.vertex.attribute)
+export(getAICc)
+export(getIgraphOpt)
+export(get_diameter)
+export(girth)
+export(gnm)
+export(gnp)
+export(gorder)
+export(graph)
+export(graph.adhesion)
+export(graph.adjacency)
+export(graph.adjlist)
+export(graph.atlas)
+export(graph.attributes)
+export(graph.automorphisms)
 export(graph.bfs)
-export(graph.dfs)
-export(bipartite.projection.size)
-export(bipartite.projection)
 export(graph.bipartite)
+export(graph.cohesion)
+export(graph.complementer)
+export(graph.compose)
+export(graph.coreness)
+export(graph.count.isomorphisms.vf2)
+export(graph.count.subisomorphisms.vf2)
+export(graph.data.frame)
+export(graph.de.bruijn)
+export(graph.density)
+export(graph.dfs)
+export(graph.difference)
+export(graph.disjoint.union)
+export(graph.diversity)
+export(graph.edgelist)
+export(graph.eigen)
+export(graph.empty)
+export(graph.extended.chordal.ring)
+export(graph.famous)
+export(graph.formula)
+export(graph.full)
+export(graph.full.bipartite)
+export(graph.full.citation)
+export(graph.get.isomorphisms.vf2)
+export(graph.get.subisomorphisms.vf2)
+export(graph.graphdb)
 export(graph.incidence)
-export(get.incidence)
-export(bipartite.mapping)
+export(graph.intersection)
+export(graph.isoclass)
+export(graph.isoclass.subgraph)
+export(graph.isocreate)
+export(graph.isomorphic)
+export(graph.isomorphic.34)
+export(graph.isomorphic.bliss)
+export(graph.isomorphic.vf2)
+export(graph.kautz)
+export(graph.knn)
 export(graph.laplacian)
-export(clusters)
-export(articulation.points)
-export(biconnected.components)
-export(maximal.cliques.count)
-export(layout.star)
-export(layout.grid)
-export(layout.grid.3d)
-export(layout.fruchterman.reingold)
-export(layout.graphopt)
-export(layout.drl)
-export(layout.drl)
-export(layout.sugiyama)
-export(layout.mds)
-export(layout.bipartite)
-export(similarity.jaccard)
-export(similarity.dice)
-export(similarity.invlogweighted)
-export(community.le.to.membership)
-export(mod.matrix)
-export(leading.eigenvector.community)
-export(label.propagation.community)
-export(multilevel.community)
-export(optimal.community)
+export(graph.lattice)
+export(graph.lcf)
+export(graph.maxflow)
+export(graph.mincut)
+export(graph.motifs)
+export(graph.motifs.est)
+export(graph.motifs.no)
+export(graph.neighborhood)
+export(graph.ring)
+export(graph.star)
+export(graph.strength)
+export(graph.subisomorphic.lad)
+export(graph.subisomorphic.vf2)
+export(graph.tree)
+export(graph.union)
+export(graph_)
+export(graph_attr)
+export(graph_attr_names)
+export(graph_from_adj_list)
+export(graph_from_adjacency_matrix)
+export(graph_from_atlas)
+export(graph_from_data_frame)
+export(graph_from_edgelist)
+export(graph_from_graphdb)
+export(graph_from_graphnel)
+export(graph_from_incidence_matrix)
+export(graph_from_isomorphism_class)
+export(graph_from_lcf)
+export(graph_from_literal)
+export(graph_version)
+export(graphlet_basis)
+export(graphlet_proj)
+export(graphlets)
+export(graphlets.candidate.basis)
+export(graphlets.project)
+export(graphs_from_cohesive_blocks)
+export(grg)
+export(grg.game)
+export(groups)
+export(growing)
+export(growing.random.game)
+export(gsize)
+export(has.multiple)
+export(head_of)
+export(hierarchical_sbm)
+export(hierarchy)
+export(hrg)
+export(hrg.consensus)
+export(hrg.create)
+export(hrg.dendrogram)
 export(hrg.fit)
 export(hrg.game)
-export(hrg.dendrogram)
-export(hrg.consensus)
 export(hrg.predict)
-export(hrg.create)
+export(hrg_tree)
+export(hub.score)
+export(hub_score)
+export(identical_graphs)
+export(igraph.arpack.default)
+export(igraph.console)
+export(igraph.drl.coarsen)
+export(igraph.drl.coarsest)
+export(igraph.drl.default)
+export(igraph.drl.final)
+export(igraph.drl.refine)
+export(igraph.eigen.default)
+export(igraph.from.graphNEL)
+export(igraph.options)
+export(igraph.sample)
+export(igraph.shape.noclip)
+export(igraph.shape.noplot)
+export(igraph.to.graphNEL)
+export(igraph.version)
+export(igraph_demo)
+export(igraph_opt)
+export(igraph_options)
+export(igraph_test)
+export(igraph_version)
+export(igraphdemo)
+export(igraphtest)
+export(in_circle)
+export(incident)
+export(incident_edges)
+export(independence.number)
+export(independent.vertex.sets)
+export(induced.subgraph)
+export(induced_subgraph)
 export(infomap.community)
-export(graphlets)
-export(graphlets.candidate.basis)
-export(graphlets.project)
-export(as.undirected)
-export(get.stochastic)
-export(dyad.census)
-export(triad.census)
-export(adjacent.triangles)
-export(graph.maxflow)
-export(dominator.tree)
-export(stCuts)
-export(stMincuts)
-export(is.separator)
+export(interconnected.islands.game)
+export(intersection)
+export(is.bipartite)
+export(is.chordal)
+export(is.connected)
+export(is.dag)
+export(is.degree.sequence)
+export(is.directed)
+export(is.graphical.degree.sequence)
+export(is.hierarchical)
+export(is.igraph)
+export(is.loop)
+export(is.matching)
+export(is.maximal.matching)
 export(is.minimal.separator)
+export(is.multiple)
+export(is.mutual)
+export(is.named)
+export(is.separator)
+export(is.simple)
+export(is.weighted)
+export(is_bipartite)
+export(is_chordal)
+export(is_connected)
+export(is_dag)
+export(is_degseq)
+export(is_directed)
+export(is_graphical)
+export(is_hierarchical)
+export(is_igraph)
+export(is_isomorphic_to)
+export(is_matching)
+export(is_max_matching)
+export(is_min_separator)
+export(is_named)
+export(is_separator)
+export(is_simple)
+export(is_subgraph_isomorphic_to)
+export(is_weighted)
+export(isomorphic)
+export(isomorphism_class)
+export(isomorphisms)
+export(ivs)
+export(ivs_size)
+export(k.regular.game)
+export(kautz_graph)
+export(keeping_degseq)
+export(knn)
+export(label.propagation.community)
+export(laplacian_matrix)
+export(largest.cliques)
+export(largest.independent.vertex.sets)
+export(largest_cliques)
+export(largest_ivs)
+export(last_cit)
+export(lastcit.game)
+export(lattice)
+export(layout.auto)
+export(layout.bipartite)
+export(layout.circle)
+export(layout.davidson.harel)
+export(layout.drl)
+export(layout.fruchterman.reingold)
+export(layout.fruchterman.reingold.grid)
+export(layout.gem)
+export(layout.graphopt)
+export(layout.grid)
+export(layout.grid.3d)
+export(layout.kamada.kawai)
+export(layout.lgl)
+export(layout.mds)
+export(layout.merge)
+export(layout.norm)
+export(layout.random)
+export(layout.reingold.tilford)
+export(layout.sphere)
+export(layout.spring)
+export(layout.star)
+export(layout.sugiyama)
+export(layout.svd)
+export(layout_)
+export(layout_as_bipartite)
+export(layout_as_star)
+export(layout_as_tree)
+export(layout_components)
+export(layout_in_circle)
+export(layout_nicely)
+export(layout_on_grid)
+export(layout_on_sphere)
+export(layout_randomly)
+export(layout_with_dh)
+export(layout_with_drl)
+export(layout_with_fr)
+export(layout_with_gem)
+export(layout_with_graphopt)
+export(layout_with_kk)
+export(layout_with_lgl)
+export(layout_with_mds)
+export(layout_with_sugiyama)
+export(leading.eigenvector.community)
+export(line.graph)
+export(line_graph)
+export(list.edge.attributes)
+export(list.graph.attributes)
+export(list.vertex.attributes)
+export(local_scan)
+export(make_)
+export(make_bipartite_graph)
+export(make_chordal_ring)
+export(make_clusters)
+export(make_de_bruijn_graph)
+export(make_directed_graph)
+export(make_ego_graph)
+export(make_empty_graph)
+export(make_full_bipartite_graph)
+export(make_full_citation_graph)
+export(make_full_graph)
+export(make_graph)
+export(make_kautz_graph)
+export(make_lattice)
+export(make_line_graph)
+export(make_ring)
+export(make_star)
+export(make_tree)
+export(make_undirected_graph)
+export(match_vertices)
+export(max_bipartite_match)
+export(max_cardinality)
+export(max_cliques)
+export(max_cohesion)
+export(max_flow)
+export(maxcohesion)
+export(maximal.cliques)
+export(maximal.cliques.count)
+export(maximal.independent.vertex.sets)
+export(maximal_ivs)
+export(maximum.bipartite.matching)
+export(maximum.cardinality.search)
+export(mean_distance)
+export(membership)
+export(merge_coords)
+export(merges)
+export(min_cut)
+export(min_separators)
+export(min_st_separators)
 export(minimal.st.separators)
 export(minimum.size.separators)
-export(cohesive.blocks)
-export(graph.isoclass)
-export(graph.isomorphic)
-export(graph.isoclass.subgraph)
-export(graph.isocreate)
-export(graph.isomorphic.vf2)
-export(graph.count.isomorphisms.vf2)
-export(graph.get.isomorphisms.vf2)
-export(graph.subisomorphic.vf2)
-export(graph.count.subisomorphisms.vf2)
-export(graph.get.subisomorphisms.vf2)
-export(graph.isomorphic.34)
-export(canonical.permutation)
+export(minimum.spanning.tree)
+export(mod.matrix)
+export(modularity)
+export(modularity_matrix)
+export(motifs)
+export(mst)
+export(multilevel.community)
+export(neighborhood)
+export(neighborhood.size)
+export(neighbors)
+export(nexus.get)
+export(nexus.info)
+export(nexus.list)
+export(nexus.search)
+export(nexus_get)
+export(nexus_info)
+export(nexus_list)
+export(nexus_search)
+export(nicely)
+export(no.clusters)
+export(norm_coords)
+export(normalize)
+export(on_grid)
+export(on_sphere)
+export(optimal.community)
+export(pa)
+export(pa_age)
+export(page.rank)
+export(page.rank.old)
+export(page_rank)
+export(page_rank_old)
+export(parent)
+export(path)
+export(path.length.hist)
+export(permute)
 export(permute.vertices)
-export(graph.isomorphic.bliss)
-export(graph.automorphisms)
-export(graph.subisomorphic.lad)
+export(piecewise.layout)
+export(plot.igraph)
+export(plotHierarchy)
+export(plot_dendrogram)
+export(plot_hierarchy)
+export(power.law.fit)
+export(power_centrality)
+export(predict_edges)
+export(pref)
+export(preference.game)
+export(print.igraph)
+export(r_pal)
+export(radius)
+export(random.graph.game)
+export(random_walk)
+export(randomly)
+export(read.graph)
+export(read_graph)
+export(reciprocity)
+export(remove.edge.attribute)
+export(remove.graph.attribute)
+export(remove.vertex.attribute)
+export(rewire)
+export(rglplot)
+export(ring)
+export(running.mean)
+export(running_mean)
+export(sample_)
+export(sample_asym_pref)
+export(sample_bipartite)
+export(sample_cit_cit_types)
+export(sample_cit_types)
+export(sample_correlated_gnp)
+export(sample_correlated_gnp_pair)
+export(sample_degseq)
+export(sample_dirichlet)
+export(sample_dot_product)
+export(sample_fitness)
+export(sample_fitness_pl)
+export(sample_forestfire)
+export(sample_gnm)
+export(sample_gnp)
+export(sample_grg)
+export(sample_growing)
+export(sample_hierarchical_sbm)
+export(sample_hrg)
+export(sample_islands)
+export(sample_k_regular)
+export(sample_last_cit)
+export(sample_motifs)
+export(sample_pa)
+export(sample_pa_age)
+export(sample_pref)
+export(sample_sbm)
+export(sample_seq)
+export(sample_smallworld)
+export(sample_sphere_surface)
+export(sample_sphere_volume)
+export(sample_traits)
+export(sample_traits_callaway)
+export(sbm)
+export(sbm.game)
+export(scan_stat)
+export(scg)
 export(scgGrouping)
-export(scgSemiProjectors)
 export(scgNormEps)
-export(is.matching)
-export(is.maximal.matching)
-export(maximum.bipartite.matching)
-export(graph.eigen)
+export(scgSemiProjectors)
+export(scg_eps)
+export(scg_group)
+export(scg_semi_proj)
+export(sequential_pal)
+export(set.edge.attribute)
+export(set.graph.attribute)
+export(set.vertex.attribute)
+export(set_edge_attr)
+export(set_graph_attr)
+export(set_vertex_attr)
+export(shape_noclip)
+export(shape_noplot)
+export(shapes)
+export(shortest.paths)
+export(shortest_paths)
+export(show_trace)
+export(showtrace)
+export(similarity)
+export(similarity.dice)
+export(similarity.invlogweighted)
+export(similarity.jaccard)
+export(simplified)
+export(simplify)
 export(sir)
-export(convex.hull)
-export(revolver.ml.d)
-export(revolver.probs.d)
-export(revolver.ml.de)
-export(revolver.probs.de)
-export(revolver.ml.ade)
-export(revolver.probs.ade)
-export(revolver.ml.f)
-export(revolver.ml.df)
-export(revolver.ml.l)
-export(revolver.ml.ad)
-export(revolver.probs.ad)
-export(revolver.ml.D.alpha)
-export(revolver.ml.D.alpha.a)
-export(revolver.ml.DE.alpha.a)
-export(revolver.ml.AD.alpha.a.beta)
-export(revolver.ml.AD.dpareto)
-export(revolver.ml.AD.dpareto.eval)
-export(revolver.ml.ADE.alpha.a.beta)
-export(revolver.ml.ADE.dpareto)
-export(revolver.ml.ADE.dpareto.eval)
-export(revolver.ml.ADE.dpareto.evalf)
-export(revolver.probs.ADE.dpareto)
+export(sizes)
+export(smallworld)
+export(spectrum)
+export(spinglass.community)
+export(split_join_distance)
+export(srand)
+export(stCuts)
+export(stMincuts)
+export(st_cuts)
+export(st_min_cuts)
+export(star)
+export(static.fitness.game)
+export(static.power.law.game)
+export(stochastic_matrix)
+export(strength)
+export(subcomponent)
+export(subgraph)
+export(subgraph.centrality)
+export(subgraph.edges)
+export(subgraph_centrality)
+export(subgraph_isomorphic)
+export(subgraph_isomorphisms)
+export(tail_of)
+export(time_bins)
+export(tk_canvas)
+export(tk_center)
+export(tk_close)
+export(tk_coords)
+export(tk_fit)
+export(tk_off)
+export(tk_postscript)
+export(tk_reshape)
+export(tk_rotate)
+export(tk_set_coords)
+export(tkigraph)
+export(tkplot)
+export(tkplot.canvas)
+export(tkplot.center)
+export(tkplot.close)
+export(tkplot.export.postscript)
+export(tkplot.fit.to.screen)
+export(tkplot.getcoords)
+export(tkplot.off)
+export(tkplot.reshape)
+export(tkplot.rotate)
+export(tkplot.setcoords)
+export(topo_sort)
+export(topological.sort)
+export(traits)
+export(traits_callaway)
+export(transitivity)
+export(tree)
+export(triad.census)
+export(triad_census)
+export(triangles)
+export(undirected_graph)
+export(unfold.tree)
+export(unfold_tree)
+export(union)
+export(upgrade_graph)
+export(vcount)
+export(vertex)
+export(vertex.attributes)
+export(vertex.connectivity)
+export(vertex.disjoint.paths)
+export(vertex.shapes)
+export(vertex_attr)
+export(vertex_attr_names)
+export(vertex_connectivity)
+export(vertex_disjoint_paths)
+export(vertices)
+export(walktrap.community)
+export(watts.strogatz.game)
+export(which_loop)
+export(which_multiple)
+export(which_mutual)
+export(with_dh)
+export(with_drl)
+export(with_edge_)
+export(with_fr)
+export(with_gem)
+export(with_graph_)
+export(with_graphopt)
+export(with_kk)
+export(with_lgl)
+export(with_mds)
+export(with_sugiyama)
+export(with_vertex_)
+export(without_attr)
+export(without_loops)
+export(without_multiples)
+export(write.graph)
+export(write_graph)
+import(methods)
+importFrom(magrittr,"%>%")
+importFrom(stats,as.dendrogram)
+importFrom(stats,as.hclust)
+importFrom(stats,median)
+importFrom(stats,quantile)
+useDynLib(igraph)
diff --git a/NEWS b/NEWS
deleted file mode 100644
index 52b77db..0000000
--- a/NEWS
+++ /dev/null
@@ -1,1036 +0,0 @@
-============
-igraph 0.7.1
-============
-
-April 21, 2014
-
-Release Notes
--------------
-
-Some bug fixes, to make sure that the code included in
-'Statistical Analysis of Network Data with R' works. See
-https://github.com/kolaczyk/sand
-
-Detailed changes:
------------------
-
-- Graph drawing: fix labels of curved edges, issue #181.
-- Graph drawing: allow fixing edge labels at given positions,
-  issue #181.
-- Drop the 'type' vertex attribute after bipartite projection,
-  the projections are not bipartite any more, issue #255.
-- Print logical attributes in header properly (i.e. encoded by `l`,
-  not `x`,  which is for complex attributes. Issue #578.
-- Add a constructor for `communities` objects, see `create.communities()`.
-  Issue #547.
-- Better error handling in the GraphML parser.
-- GraphML reader is a bit more lenient now; makes it possible to read
-  GraphML files saved from yWorks apps.
-- Fixed a bug in `constaint()`, issue #580.
-- Bipartite projection now detects invalid edges instead of giving
-  a cryptic error, issue #543.
-- Fixed the `simplify` argument of `graph.formula()`, which was
-  broken, issue #586.
-- The function `crossing()` adds better names to the result,
-  fixes issue #587.
-- The `sir()` function gives an error if the input graph is
-  not simple, fixes issue #582.
-- Calling igraph functions from igraph callbacks is not allowed now,
-  fixes issue #571.
-
-============
-igraph 0.7.0
-============
-
-February 4, 2014
-
-Release Notes
--------------
-
-There are a bunch of new features in the library itself, and 
-other important changes in the life of the project. Thanks everyone
-for sending code and reporting bugs!
-
-### igraph @ github
-
-igraph's development has moved from Launchpad to github. 
-This has actually happened several month ago, but never 
-announced officially. The place for reporting bugs is 
-at https://github.com/igraph/igraph/issues.
-
-### New homepage
-
-igraph's homepage is now hosted at http://igraph.org, and it is 
-brand new. We wanted to make it easier to use and modern.
-
-### Better nightly downloads
-
-You can download nightly builds from igraph at 
-http://igraph.org/nightly. Source and binary R packages (for windows
-and OSX), are all built.
-
-New features and bug fixes
------------------------------
-
-- Added a demo for hierarchical random graphs, invoke it via
-  `demo(hrg)`.
-- Make attribute prefixes optional when writing a GraphML file.
-- Added function `mod.matrix()`.
-- Support edge weights in leading eigenvector community detection.
-- Added the LAD library for checking (sub)graph isomorphism, version 1.
-- Logical attributes.
-- Added `layout.bipartite()` function, a simple two-column layout
-  for bipartite graphs.
-- Support incidence matrices in bipartite Pajek files.
-- Pajek files in matrix format are now directed by default, unless they
-  are bipartite.
-- Support weighted (and signed) networks in Pajek when file is in
-  matrix format.
-- Fixed a bug in `barabasi.game()`, algorithm psumtree-multiple 
-  just froze.
-- Function `layout.mds()` by default returns a layout matrix now.
-- Added support for Boolean attributes in the GraphML and GML readers
-  and writer.
-- Change MDS layout coordinates, first dim is according to first
-  eigenvalue, etc.
-- `plot.communities()` (`plot.igraph()`, really) draws a border
-  around the marked groups by default.
-- printing graphs now converts the `name` graph attribute to character
-- Convenience functions to query and set all attributes at once:
-  `vertex.attriubutes()`, `graph.attributes()` and `edge.attributes()`.
-- Function `graph.disjoint.union()` handles attributes now.
-- Rewrite `graph.union()` to handle attributes properly.
-- `rewire()`: now supports the generation and destruction of loops.
-- Erdos-Renyi type bipartite random graphs: `bipartite.random.game()`.
-- Support the new options (predecessors and inbound_edges) of
-  `get_shortest_paths()`, reorganized the output of
-  `get.shortest.paths()` completely. 
-- Added `graphlets()` and related functions.
-- Fix modularity values of multilevel community if there are no merges
-  at all.
-- Fixed bug when deleting edges with FALSE in the matrix notation.
-- Fix `bonpow()` and `alpha.centrality()` and make sure that the
-  sparse solver is called.
-- `tkplot()` news: enable setting coordinates from the command line
-  via `tkplot.setcoords()` and access to the canvas via 
-  `tkplot.canvas()`.
-- Fixed a potential crash in `igraph_edge_connectivity()`, because of an
-  un-initialized variable in the C code.
-- Avoiding overflow in `closeness()` and related functions.
-- Check for NAs after converting 'type' to logical in 
-  `bipartite.projection()`.
-- `graphNEL` conversion functions only load the 'graph' package if it was 
-  not loaded before and they load it at the end of the search path, 
-  to minimize conflicts.
-- Fixed a bug when creating graphs from adjacency matrices, we now convert
-  them to double, in case they are integers.
-- Fixed an invalid memory read (and a potential crash) in the infomap
-  community detection.
-- Fixed a memory leak in the functions with attribute combinations.
-- Removed some memory leaks from the SCG functions.
-- Fixed some memory leaks in the ray tracer.
-- Fixed memory leak in `graph.bfs()` and `graph.dfs()`.
-- Fix a bug in triad census that set the first element of the result
-  to NaN.
-- Fixed a crash in `is.chordal()`.
-- Fixed a bug in weighted mudularity calculation, sum of the weights
-  was truncated to an integer.
-- Fixed a bug in weighted multilevel communtiies, the maximum weight
-  was rounded to an integer.
-- Fixed a bug in `centralization.closeness.tmax()`.
-- Reimplement push-relabel maximum flow with gap heuristics.
-- Maximum flow functions now return some statistics about the push
-  relabel algorithm steps.
-- Function `arpack()` now gives error message if unknown options are
-  given.
-- Fixed missing whitespace in Pajek writer when the ID attribute was
-  numeric.
-- Fixed a bug that caused the GML reader to crash when the ID
-  attribute was non-numeric.
-- Fixed issue #500, potential segfault if the two graphs in BLISS
-  differ in the number of vertices or edges.
-- Added `igraphtest()` function.
-- Fix dyad census instability, sometimes incorrect results were
-  reported.
-- Dyad census detects integer overflow now and gives a warning.
-- Function `add.edges()` does not allow now zeros in the vertex set.
-- Added a function to count the number of adjacent triangles:
-  `adjacenct.triangles()`.
-- Added `graph.eigen()` function, eigenproblems on adjacency matrices.
-- Added some workarounds for functions that create a lot of
-  graphs, `decompose.graph()` and `graph.neighborhood()` use it. 
-  Fixes issue #508.
-- Added weights support for `optimal.community()`, closes #511.
-- Faster maximal clique finding.
-- Added a function to count maximum cliques.
-- Set operations: union, intersection, disjoint, union, difference,
-  compose now work based on vertex names (if they are present) and
-  keep attributes, closes #20.
-- Removed functions `graph.intersection.by.name()`,
-  `graph.union.by.name()`, `graph.difference.by.name()`.
-- The `+` operator on graphs now calls `graph.union()` if both 
-  argument graphs are named, and calls `graph.disjoint.union()`
-  otherwise.
-- Added function `igraph.version()`.
-- Generate graphs from a stochastic block model: `sbm.game()`.
-- Do not suggest the stats, XML, jpeg and png packages any more.
-- Fixed a `set.vertex/edge.attribute` bug that changed both
-  graph objects, after copying (#533)
-- Fixed a bug in `barabasi.game` that caused crashes.
-- We use PRPACK to calculate PageRank scores
-  see https://github.com/dgleich/prpack
-- Added`'which` argument to `bipartite.projection` (#307).
-- Add `normalized` argument to closeness functions, fixes issue #3.
-- R: better handling of complex attributes, `[[` on vertex/edge sets,
-  fixes #231.
-- Implement the `start` argument in `hrg.fit` (#225).
-- Set root vertex in Reingold-Tilford layout, solves #473.
-- Fix betweenness normalization for directed graphs.
-- Fixed a bug in `graph.density` that resulted in incorrect values for
-  undirected graphs with loops
-- Fixed a bug when many graphs were created in one C call
-  (e.g. by `graph.decompose`), causing #550.
-- Fixed sparse `graph.adjacency` bugs for graphs with one edge,
-  and graphs with zero edges.
-- Fixed a bug that made Bellman-Ford shortest paths calculations fail.
-- Fixed a `graph.adjacency` bug for undirected, weighted graphs and
-  sparse matrices.
-- `main`, `sub`, `xlab` and `ylab` are proper graphics parameters
-  now (#555).
-- `graph.data.frame` coerces arguments to data frame (#557).
-- Fixed a minimum cut bug for weighted undirected graphs (#564).
-- Functions for simulating epidemics (SIR model) on networks,
-  see the `sir` function.
-- Fixed argument ordering in `graph.mincut` and related functions.
-- Avoid copying attributes in query functions and print (#573),
-  these functions are much faster now for graphs with many
-  vertices/edges and attributes.
-- Speed up writing GML and GraphML files, if some attributes are
-  integer. It was really-really slow.
-- Fix multiple root vertices in `graph.bfs` (#575).
-
-============
-igraph 0.6.6
-============
-
-Released Oct 28, 2013
-
-Some bugs fixed:
-
-- Fixed a potential crash in the infomap.community() function.
-- Various fixed for the operators that work on vertex names (#136).
-- Fixed an example in the arpack() manual page.
-- arpack() now gives error message if unknown options
-  are supplied (#492).
-- Better arpack() error messages.
-- Fixed missing whitespace in Pajek writer when ID attribute
-  was numeric.
-- Fixed dyad census instability, sometimes incorrect 
-  results were reported (#496).
-- Fixed a bug that caused the GML reader to crash when the ID
-  attribute was non-numeric
-- Fixed a potential segfault if the two graphs in BLISS
-  differ in the number of vertices or edges (#500).
-- Added the igraphtest() function to run tests from R (#485).
-- Dyad census detects integer overflow now and gives a warning (#497).
-- R: add.edges() does not allow now zeros in the vertex set (#503).
-- Add C++ namespace to the files that didn't have one. 
-  Fixes some incompatibility with other packages (e.g. rgl) 
-  and mysterious crashes (#523).
-- Fixed a bug that caused a side effect in set.vertex.attributes(),
-  set.edge.attributes() and set.graph.attributes() (#533).
-- Fixed a bug in degree.distribution() and cluster.distribution()
-  (#257).
-
-==============
-igraph 0.6.5-2
-==============
-
-Released May 16, 2013
-
-Worked two CRAN check problems, and a gfortran bug (string bound
-checking does not work if code is called from C and without string
-length arguments at the "right" place).
-
-Otherwise identical to 0.6.5-1.
-
-==============
-igraph 0.6.5-1
-==============
-
-Released February 27, 2013
-
-Fixing an annoying bug, that broke two other packages on CRAN:
-
-- Setting graph attributes failed sometimes, if the attributes were 
-  lists or other complex objects.
-
-============
-igraph 0.6.5
-============
-
-Released February 24, 2013
-
-This is a minor release, to fix some very annoying bugs in 0.6.4:
-
-- igraph should now work well with older R versions.
-- Eliminate gap between vertex and edge when plotting an edge without an arrow.
-  Fixes #1118448.
-- Fixed an out-of-bounds array indexing error in the DrL layout, that
-  potentially caused crashes.
-- Fixed a crash in weighted betweenness calculation.
-- Plotting: fixed a bug that caused misplaced arrows at rectangle 
-  vertex shapes. 
-
-============
-igraph 0.6.4
-============
-
-Released February 2, 2013
-
-The version number is not a mistake, we jump to 0.6.4 from 0.6, 
-for technical reasons. This version was actually never really
-released, but some R packages of this version were uplodaded to 
-CRAN, so we include this version in this NEW file.
-
-==========================
-New features and bug fixes
-==========================
-
-- Added a vertex shape API for defining new vertex shapes, and also 
-  a couple of new vertex shapes.
-- Added the get.data.frame() function, opposite of graph.data.frame().
-- Added bipartite support to the Pajek reader and writer, closes bug
-  #1042298.
-- degree.sequence.game() has a new method now: "simple_no_multiple".
-- Added the is.degree.sequence() and is.graphical.degree.sequence()
-  functions.
-- rewire() has a new method: "loops", that can create loop edges.
-- Walktrap community detection now handles isolates.
-- layout.mds() returns a layout matrix now.
-- layout.mds() uses LAPACK instead of ARPACK.
-- Handle the '~' character in write.graph and read.graph. Bug
-  #1066986.
-- Added k.regular.game().
-- Use vertex names to plot if no labels are specified in the function
-  call or as vetex attributes. Fixes issue #1085431.
-- power.law.fit() can now use a C implementation.
-
-- Fixed a bug in barabasi.game() when out.seq was an empty vector.
-- Fixed a bug that made functions with a progress bar fail if called 
-  from another package.
-- Fixed a bug when creating graphs from a weighted integer adjacency 
-  matrix via graph.adjacency(). Bug #1019624.
-- Fixed overflow issues in centralization calculations.
-- Fixed a minimal.st.separators() bug, some vertex sets were incorrectly
-  reported as separators. Bug #1033045.
-- Fixed a bug that mishandled vertex colors in VF2 isomorphism
-  functions. Bug #1032819.
-- Pajek exporter now always quotes strings, thanks to Elena Tea Russo.
-- Fixed a bug with handling small edge weights in shortest paths 
-  calculation in shortest.paths() (Dijkstra's algorithm.) Thanks to 
-  Martin J Reed.
-- Weighted transitivity uses V(graph) as 'vids' if it is NULL.
-- Fixed a bug when 'pie' vertices were drawn together with other 
-  vertex shapes.
-- Speed up printing graphs.
-- Speed up attribute queries and other basic operations, by avoiding 
-  copying of the graph. Bug #1043616.
-- Fixed a bug in the NCV setting for ARPACK functions. It cannot be
-  bigger than the matrix size.
-- layout.merge()'s DLA mode has better defaults now.
-- Fixed a bug in layout.mds() that resulted vertices on top of each
-  other.
-- Fixed a bug in layout.spring(), it was not working properly.
-- Fixed layout.svd(), which was completely defunct.
-- Fixed a bug in layout.graphopt() that caused warnings and on 
-  some platforms crashes.
-- Fixed community.to.membership(). Bug #1022850.
-- Fixed a graph.incidence() crash if it was called with a non-matrix
-  argument.
-- Fixed a get.shortest.paths bug, when output was set to "both".
-- Motif finding functions return NA for isomorphism classes that are
-  not motifs (i.e. not connected). Fixes bug #1050859. 
-- Fixed get.adjacency() when attr is given, and the attribute has some
-  complex type. Bug #1025799. 
-- Fixed attribute name in graph.adjacency() for dense matrices. Bug
-  #1066952. 
-- Fixed erratic behavior of alpha.centrality().
-- Fixed igraph indexing, when attr is given. Bug #1073705.
-- Fixed a bug when calculating the largest cliques of a directed
-  graph. Bug #1073800.
-- Fixed a bug in the maximal clique search, closes #1074402.
-- Warn for negative weights when calculating PageRank.
-- Fixed dense, unweighted graph.adjacency when diag=FALSE. Closes
-  issue #1077425. 
-- Fixed a bug in eccentricity() and radius(), the results were often
-  simply wrong.
-- Fixed a bug in get.all.shortest.paths() when some edges had zero weight.
-- graph.data.frame() is more careful when vertex names are numbers, to
-  avoid their scientific notation. Fixes issue #1082221. 
-- Better check for NAs in vertex names. Fixes issue #1087215
-- Fixed a potential crash in the DrL layout generator.
-- Fixed a bug in the Reingold-Tilford layout when the graph is
-  directed and mode != ALL.
-
-==========
-igraph 0.6
-==========
-
-Released June 11, 2012
-
-See also the release notes at 
-http://igraph.sf.net/relnotes-0.6.html
-
-=====================
-R: Major new features
-=====================
-
-- Vertices and edges are numbered from 1 instead of 0. 
-  Note that this makes most of the old R igraph code incompatible
-  with igraph 0.6. If you want to use your old code, please use 
-  the igraph0 package. See more at http://igraph.sf.net/relnotes-0.6.html.
-- The '[' and '[[' operators can now be used on igraph graphs, 
-  for '[' the graph behaves as an adjacency matrix, for '[[' is 
-  is treated as an adjacency list. It is also much simpler to
-  manipulate the graph structure, i.e. add/remove edges and vertices, 
-  with some new operators. See more at ?graph.structure.
-- In all functions that take a vector or list of vertices or edges, 
-  vertex/edge names can be given instead of the numeric ids.
-- New package 'igraphdata', contains a number of data sets that can
-  be used directly in igraph.
-- Igraph now supports loading graphs from the Nexus online data
-  repository, see nexus.get(), nexus.info(), nexus.list() and 
-  nexus.search().
-- All the community structure finding algorithm return a 'communities'
-  object now, which has a bunch of useful operations, see 
-  ?communities for details.
-- Vertex and edge attributes are handled much better now. They 
-  are kept whenever possible, and can be combined via a flexible API.
-  See ?attribute.combination.
-- R now prints igraph graphs to the screen in a more structured and 
-  informative way. The output of summary() was also updated
-  accordingly.
-
-=====================
-R: Other new features
-=====================
-
-- It is possible to mark vertex groups on plots, via
-  shading. Communities and cohesive blocks are plotted using this by
-  default.
-- Some igraph demos are now available, see a list via 
-  'demo(package="igraph")'.
-- igraph now tries to select the optimal layout algorithm, when
-  plotting a graph.
-- Added a simple console, using Tcl/Tk. It contains a text area
-  for status messages and also a status bar. See igraph.console().
-- Reimplemented igraph options support, see igraph.options() and 
-  getIgraphOpt().
-- Igraph functions can now print status messages.
-
-===========================
-R: New or updated functions
-===========================
-
-Community detection
--------------------
-- The multi-level modularity optimization community structure detection 
-  algorithm by Blondel et al. was added, see multilevel.community().
-- Distance between two community structures: compare.communities().
-- Community structure via exact modularity optimization,
-  optimal.community().
-- Hierarchical random graphs and community finding, porting the code
-  from Aaron Clauset. See hrg.game(), hrg.fit(), etc.
-- Added the InfoMAP community finding method, thanks to Emmanuel
-  Navarro for the code. See infomap.community().
-
-Shortest paths
---------------
-- Eccentricity (eccentricity()), and radius (radius()) calculations.
-- Shortest path calculations with get.shortest.paths() can now 
-  return the edges along the shortest paths.
-- get.all.shortest.paths() now supports edge weights.
-
-Centrality
-----------
-- Centralization scores for degree, closeness, betweenness and 
-  eigenvector centrality. See centralization.scores().
-- Personalized Page-Rank scores, see page.rank().
-- Subgraph centrality, subgraph.centrality().
-- Authority (authority.score()) and hub (hub.score()) scores support 
-  edge weights now.
-- Support edge weights in betweenness and closeness calculations.
-- bonpow(), Bonacich's power centrality and alpha.centrality(), 
-  Alpha centrality calculations now use sparse matrices by default.
-- Eigenvector centrality calculation, evcent() now works for 
-  directed graphs.
-- Betweenness calculation can now use arbitrarily large integers,
-  this is required for some lattice-like graphs to avoid overflow.
-
-Input/output and file formats
------------------------------
-- Support the DL file format in graph.read(). See 
-  http://www.analytictech.com/networks/dataentry.htm.
-- Support writing the LEDA file format in write.graph().
-
-Plotting and layouts
---------------------
-- Star layout: layout.star().
-- Layout based on multidimensional scaling, layout.mds().
-- New layouts layout.grid() and layout.grid.3d().
-- Sugiyama layout algorithm for layered directed acyclic graphs, 
-  layout.sugiyama().
-
-Graph generators
-----------------
-- New graph generators: static.fitness.game(), static.power.law.game().
-- barabasi.game() was rewritten and it supports three algorithms now,
-  the default algorithm does not generate multiple or loop edges.
-  The graph generation process can now start from a supplied graph.
-- The Watts-Strogatz graph generator, igraph_watts_strogatz() can 
-  now create graphs without loop edges.
-
-Others
-------
-- Added the Spectral Coarse Graining algorithm, see scg(). 
-- The cohesive.blocks() function was rewritten in C, it is much faster
-  now. It has a nicer API, too. See demo("cohesive").
-- Added generic breadth-first and depth-first search implementations
-  with many callbacks, graph.bfs() and graph_dfs().
-- Support vertex and edge coloring in the VF2 (sub)graph isomorphism 
-  functions (graph.isomorphic.vf2(), graph.count.isomorphisms.vf2(), 
-  graph.get.isomorphisms.vf2(), graph.subisomorphic.vf2(), 
-  graph.count.subisomorphisms.vf2(), graph.get.subisomorphisms.vf2()).
-- Assortativity coefficient, assortativity(), assortativity.nominal()
-  and assortativity.degree().
-- Vertex operators that work by vertex names: 
-  graph.intersection.by.name(), graph.union.by.name(), 
-  graph.difference.by.name(). Thanks to Magnus Torfason for 
-  contributing his code!
-- Function to calculate a non-induced subraph: subgraph.edges().
-- More comprehensive maximum flow and minimum cut calculation, 
-  see functions graph.maxflow(), graph.mincut(), stCuts(), stMincuts().
-- Check whether a directed graph is a DAG, is.dag().
-- has.multiple() to decide whether a graph has multiple edges.
-- Added a function to calculate a diversity score for the vertices,
-  graph.diversity().
-- Graph Laplacian calculation (graph.laplacian()) supports edge 
-  weights now.
-- Biconnected component calculation, biconnected.components() 
-  now returns the components themselves.
-- bipartite.projection() calculates multiplicity of edges.
-- Maximum cardinality search: maximum.cardinality.search() and 
-  chordality test: is.chordal()
-- Convex hull computation, convex.hull().
-- Contract vertices, contract.vertices().
-
-============
-igraph 0.5.3
-============
-
-Released November 22, 2009
-
-Bugs corrected in the R interface
----------------------------------
-- Some small changes to make 'R CMD check' clean
-- Fixed a bug in graph.incidence, the 'directed' and 'mode' arguments 
-  were not handled correctly
-- Betweenness and edge betweenness functions work for graphs with
-  many shortest paths now (up to the limit of long long int)
-- When compiling the package, the configure script fails if there is
-  no C compiler available
-- igraph.from.graphNEL creates the right number of loop edges now
-- Fixed a bug in bipartite.projection() that caused occasional crashes 
-  on some systems
-
-============
-igraph 0.5.2
-============
-
-Released April 10, 2009
-
-See also the release notes at
-http://igraph.sf.net/relnotes-0.5.2.html
-
-New in the R interface
-----------------------
-
-- Added progress bar support to beweenness() and
-  betweenness.estimate(), layout.drl()
-- Speeded up betweenness estimation
-- Speeded up are.connected()
-- Johnson's shortest paths algorithm added
-- shortest.paths() has now an 'algorithm' argument to choose from the
-  various implementations manually
-- Always quote symbolic vertex names when printing graphs or edges
-- Average nearest neighbor degree calculation, graph.knn()
-- Weighted degree (also called strength) calculation, graph.strength()
-- Some new functions to support bipartite graphs: graph.bipartite(),
-  is.bipartite(), get.indicence(), graph.incidence(),
-  bipartite.projection(), bipartite.projection.size()
-- Support for plotting curved edges with plot.igraph() and tkplot()
-- Added support for weighted graphs in alpha.centrality()
-- Added the label propagation community detection algorithm by
-  Raghavan et al., label.propagation.community()
-- cohesive.blocks() now has a 'cutsetHeuristic' argument to choose
-  between two cutset algorithms
-- Added a function to "unfold" a tree, unfold.tree()
-- New tkplot() arguments to change the drawing area
-- Added a minimal GUI, invoke it with tkigraph()
-- The DrL layout generator, layout.drl() has a three dimensional mode
-  now.
-
-Bugs corrected in the R interface
----------------------------------
-
-- Fixed a bug in VF2 graph isomorphism functions
-- Fixed a bug when a sparse adjacency matrix was requested in
-  get.adjacency() and the graph was named
-- VL graph generator in degree.sequence.game() checks now that
-  the sum of the degrees is even
-- Many fixes for supporting various compilers, e.g. GCC 4.4 and Sun's
-  C compiler
-- Fixed memory leaks in graph.automorphisms(), Bellman-Ford
-  shortest.paths(), independent.vertex.sets()
-- Fix a bug when a graph was imported from LGL and exported to NCOL
-  format (#289596)
-- cohesive.blocks() creates its temporary file in the session
-  temporary directory
-- write.graph() and read.graph() now give error messages when unknown
-  arguments are given
-- The GraphML reader checks the name of the attributes to avoid adding
-  a duplicate 'id' attribute
-- It is possible to change the 'ncv' ARPACK parameter for
-  leading.eigenvector.community()
-- Fixed a bug in path.length.hist(), 'unconnected' was wrong
-  for unconnected and undirected graphs
-- Better handling of attribute assingment via iterators, this is now
-  also clarified in the manual
-- Better error messages for unknown vertex shapes
-- Make R package unload cleanly if unloadNamespace() is used
-- Fixed a bug in plotting square shaped vertices (#325244)
-- Fixed a bug in graph.adjacency() when the matrix is a sparse matrix
-  of class "dgTMatrix"
-
-============
-igraph 0.5.1
-============
-
-Released July 14, 2008
-
-See also the release notes at 
-http://igraph.sf.net/relnotes-0.5.1.html
-
-New in the R interface
-----------------------
-
-- A new layout generator called DrL.
-- Uniform sampling of random connected undirected graphs with a 
-  given degree sequence.
-- Edge labels are plotted at 1/3 of the edge, this is better if 
-  the graph has mutual edges.
-- Initial and experimental vertex shape support in 'plot'.
-- New function, 'graph.adjlist' creates igraph graphs from
-  adjacency lists.
-- Conversion to/from graphNEL graphs, from the 'graph' R package.
-- Fastgreedy community detection can utilize edge weights now, this 
-  was missing from the R interface.
-- The 'arrow.width' graphical parameter was added.
-- graph.data.frame has a new argument 'vertices'.
-- graph.adjacency and get.adjacency support sparse matrices, 
-  the 'Matrix' package is required to use this functionality.
-- graph.adjacency adds column/row names as 'name' attribute.
-- Weighted shortest paths using Dijkstra's or the Belmann-Ford 
-  algorithm.
-- Shortest path functions return 'Inf' for unreachable vertices.
-- New function 'is.mutual' to find mutual edges in a directed graph.
-- Added inverse log-weighted similarity measure (a.k.a. Adamic/Adar
-  similarity).
-- preference.game and asymmetric.preference.game were 
-  rewritten, they are O(|V|+|E|) now, instead of O(|V|^2).
-- Edge weight support in function 'get.shortest.paths', it uses 
-  Dijkstra's algorithm.
-
-Bugs corrected in the R interface
----------------------------------
-  
-- A bug was corrected in write.pajek.bgraph.
-- Several bugs were corrected in graph.adjacency.
-- Pajek reader bug corrected, used to segfault if '*Vertices' 
-  was missing.
-- Directedness is handled correctly when writing GML files.
-  (But note that 'correct' conflicts the standard here.)
-- Corrected a bug when calculating weighted, directed PageRank on an 
-  undirected graph. (Which does not make sense anyway.)
-- Several bugs were fixed in the Reingold-Tilford layout to avoid 
-  edge crossings.
-- A bug was fixed in the GraphML reader, when the value of a graph
-  attribute was not specified.
-- Fixed a bug in the graph isomorphism routine for small (3-4 vertices)
-  graphs.
-- Corrected the random sampling implementation (igraph_random_sample),
-  now it always generates unique numbers. This affects the 
-  Gnm Erdos-Renyi generator, it always generates simple graphs now.
-- The basic igraph constructor (igraph_empty_attrs, all functions 
-  are expected to call this internally) now checks whether the number
-  of vertices is finite.
-- The LGL, NCOL and Pajek graph readers handle errors properly now.
-- The non-symmetric ARPACK solver returns results in a consistent form
-  now.
-- The fast greedy community detection routine now checks that the graph
-  is simple.
-- The LGL and NCOL parsers were corrected to work with all 
-  kinds of end-of-line encodings.
-- Hub & authority score calculations initialize ARPACK parameters now.
-- Fixed a bug in the Walktrap community detection routine, when applied 
-  to unconnected graphs.
-- Several small memory leaks were removed, and a big one from the Spinglass
-  community structure detection function
-
-=========
-igraph 0.5
-=========
-
-Released February 14, 2008
-
-See also the release notes at http://igraph.sf.net/relnotes-0.5.html
-
-New in the R interface
-----------------------
-
-- The 'rescale', 'asp' and 'frame' graphical parameters were added
-- Create graphs from a formula notation (graph.formula)
-- Handle graph attributes properly
-- Calculate the actual minimum cut for undirected graphs
-- Adjacency lists, get.adjlist and get.adjedgelist added
-- Eigenvector centrality computation is much faster now
-- Proper R warnings, instead of writing the warning to the terminal
-- R checks graphical parameters now, the unknown ones are not just
-  ignored, but an error message is given  
-- plot.igraph has an 'add' argument now to compose plots with multiple
-  graphs
-- plot.igraph supports the 'main' and 'sub' arguments
-- layout.norm is public now, it can normalize a layout
-- It is possible to supply startup positions to layout generators
-- Always free memory when CTRL+C/ESC is pressed, in all operating
-  systems
-- plot.igraph can plot square vertices now, see the 'shape' parameter
-- graph.adjacency rewritten when creating weighted graphs
-- We use match.arg whenever possible. This means that character scalar 
-  options can be abbreviated and they are always case insensitive
-
-- VF2 graph isomorphism routines can check subgraph isomorphism now,
-  and they are able to return matching(s)
-- The BLISS graph isomorphism algorithm is included in igraph now. See
-  canonical.permutation, graph.isomorphic.bliss
-- We use ARPACK for eigenvalue/eigenvector calculation. This means that the
-  following functions were rewritten: page.rank,
-  leading.eigenvector.community.*, evcent. New functions based on
-  ARPACK: hub.score, authority.score, arpack.
-- Edge weights for Fruchterman-Reingold layout (layout.fruchterman.reingold).
-- Line graph calculation (line.graph)
-- Kautz and de Bruijn graph generators (graph.kautz, graph.de.bruijn)
-- Support for writing graphs in DOT format
-- Jaccard and Dice similarity coefficients added (similarity.jaccard,
-  similarity.dice)
-- Counting the multiplicity of edges (count.multiple)
-- The graphopt layout algorithm was added, layout.graphopt
-- Generation of "famous" graphs (graph.famous).
-- Create graphs from LCF notation (graph.cf).
-- Dyad census and triad cencus functions (dyad.census, triad.census)
-- Cheking for simple graphs (is.simple)
-- Create full citation networks (graph.full.citation)
-- Create a histogram of path lengths (path.length.hist)
-- Forest fire model added (forest.fire.game)
-- DIMACS reader can handle different file types now
-- Biconnected components and articulation points (biconnected.components,
-  articulation.points)
-- Kleinberg's hub and authority scores (hub.score, authority.score)
-- as.undirected handles attributes now
-- Geometric random graph generator (grg.game) can return the
-  coordinates of the vertices
-- Function added to convert leading eigenvector community structure result to
-  a membership vector (community.le.to.membership)
-- Weighted fast greedy community detection
-- Weighted page rank calculation
-- Functions for estimating closeness, betweenness, edge betweenness by 
-  introducing a cutoff for path lengths (closeness.estimate,
-  betweenness.estimate, edge.betweenness.estimate)
-- Weighted modularity calculation
-- Function for permuting vertices (permute.vertices)
-- Betweenness and closeness calculations are speeded up
-- read.graph can handle all possible line terminators now (\r, \n, \r\n, \n\r)
-- Error handling was rewritten for walktrap community detection,
-  the calculation can be interrupted now
-- The maxflow/mincut functions allow to supply NULL pointer for edge
-  capacities, implying unit capacities for all edges
-
-Bugs corrected in the R interface
----------------------------------
-
-- Fixed a bug in cohesive.blocks, cohesive blocks were sometimes not
-  calculated correctly
-
-=========
-igraph 0.4.5
-=========
-
-Released January 1, 2008
-
-New:
-- Cohesive block finding in the R interface, thanks to Peter McMahan
-  for contributing his code. See James Moody and Douglas R. White,
-  2003, in Structural Cohesion and Embeddedness: A Hierarchical
-  Conception of Social Groups American Sociological Review 68(1):1-25 
-- Biconnected components and articulation points.
-- R interface: better printing of attributes.
-- R interface: graph attributes can be used via '$'.
-
-Bug fixed:
-- Erdos-Renyi random graph generators rewritten.
-
-=========
-igraph 0.4.4
-=========
-
-Released October 3, 2007
-
-This release should work seemlessly with the new R 2.6.0 version.
-Some other bugs were also fixed:
-- A bug was fixed in the Erdos-Renyi graph generator, which sometimes
-  added an extra vertex.
-
-=========
-igraph 0.4.3
-=========
-
-Released August 13, 2007
-
-The next one in the sequence of bugfix releases. Thanks to many people
-sending bug reports. Here are the changes:
-- Some memory leaks removed when using attributes from R or Python.
-- GraphML parser: entities and character data in multiple chunks are
-  now handled correctly. 
-- A bug corrected in edge betweenness community structure detection,
-  it failed if called many times from the same program/session.
-- Edge betweeness community structure: handle unconnected graphs properly.
-- Fixed bug related to fast greedy community detection in unconnected graphs.
-- Use a different kind of parser (Push) for reading GraphML
-  files. This is almost invisible for users but fixed a
-  nondeterministic bug when reading in GraphML files.
-- R interface: plot now handles properly if called with a vector as
-  the edge.width argument for directed graphs.
-- R interface: bug (typo) corrected for walktrap.community and
-  weighted graphs. 
-
-=========
-igraph 0.4.2
-=========
-
-Released June 7, 2007
-
-This is another bugfix release, as there was a serious bug in the 
-R package of the previous version: it could not read and write graphs
-to files in any format under MS Windows.
-
-Some other bits added: 
-- circular Reingold-Tilford layout generator for trees
-- corrected a bug, Pajek files are written properly under MS Windows now.
-- arrow.size graphical edge parameter added in the R interface.
-
-=========
-igraph 0.4.1
-=========
-
-Released May 23, 2007
-
-This is a minor release, it corrects a number of bugs, mostly in the 
-R package.
-
-=========
-igraph 0.4
-=========
-
-Released May 21, 2007
-
-The major new additions in this release is a bunch of community
-detection algorithms and support for the GML file format. Here 
-is the complete list of changes:
-
-New in the R interface
-----------------------
-
-- as the internal representation changed, graphs stored with 'save' 
-  with an older igraph version cannot be read back with the new
-  version reliably.
-- neighbors returns ordered lists
-- is.loop and is.multiple were added
-
-- topological sorting
-- VF2 isomorphism algorithm
-- support for reading graphs from the Graph Database for isomorphism
-- graph.mincut can calculate the actual minimum cut
-- girth calculation added, thanks to Keith Briggs
-- support for reading and writing GML files
-
-- Walktrap community detection algorithm added, thanks to Matthieu Latapy 
-  and Pascal Pons
-- edge betweenness based community detection algorithm added
-- fast greedy algorithm for community detection by Clauset et al. added
-  thanks to Aaron Clauset for sharing his code  
-- leading eigenvector community detection algorithm by Mark Newman added
-- functions for creating dendrograms from the output of the 
-  community detection algorithms added
-- community.membership supporting function added, creates 
-  a membership vector from a community structure merge tree
-- modularity calculation added
-
-- graphics parameter handling is completely rewritten, uniform handling 
-  of colors and fonts, make sure you read ?igraph.plotting
-- new plotting parameter for edges: arrow.mode
-- a bug corrected when playing a nonlinear barabasi.game
-- better looking plotting in 3d using rglplot: edges are 3d too
-- rglplot layout is allowed to be two dimensional now
-- rglplot suspends updates while drawing, this makes it faster
-- loop edges are correctly plotted by all three plotting functions
-
-- better printing of attributes when printing graphs
-- summary of a graph prints attribute names
-- is.igraph rewritten to make it possible to inherit from the 'igraph' class
-- somewhat better looking progress meter for functions which support it
-
-Others
-------
-
-- many functions benefit from the new internal representation and are 
-  faster now: transitivity, reciprocity, graph operator functions like 
-  intersection and union, etc.
-
-Bugs corrected
---------------
-
-- corrected a bug when reading Pajek files: directed graphs were read
-  as undirected 
-
-=========
-igraph 0.3.2
-=========
-
-Released Dec 19, 2006
-
-This is a new major release, it contains many new things:
-
-Changes in the R interface
---------------------------
-
-- bonpow function ported from SNA to calculate Bonacich power centrality
-- get.adjacency supports attributes now, this means that it sets the
-  colnames  and rownames attributes and can return attribute values in
-  the matrix instead of 0/1
-- grg.game, geometric random graphs
-- graph.density, graph density calculation
-- edge and vertex attributes can be added easily now when added new
-  edges with add.edges or new vertices with add.vertices
-- graph.data.frame creates graph from data frames, this can be used to 
-  create graphs with edge attributes easily
-- plot.igraph and tkplot can plot self-loop edges now
-- graph.edgelist to create a graph from an edge list, can also handle 
-  edge lists with symbolic names
-- get.edgelist has now a 'names' argument and can return symbolic
-  vertex names instead of vertex ids, by default id uses the 'name'
-  vertex attribute is returned 
-- printing graphs on screen also prints symbolic symbolic names
-  (the 'name' attribute if present)
-- maximum flow and minimum cut functions: graph.maxflow, graph.mincut
-- vertex and edge connectivity: edge.connectivity, vertex.connectivity
-- edge and vertex disjoint paths: edge.disjoint.paths, 
-  vertex.disjoint.paths
-- White's cohesion and adhesion measure: graph.adhesion, graph.cohesion
-- dimacs file format added
-- as.directed handles attributes now
-- constraint corrected, it handles weighted graphs as well now
-- weighted attribute to graph.adjacency
-- spinglass-based community structure detection, the Joerg Reichardt --
-  Stefan Bornholdt algorithm added: spinglass.community
-- graph.extended.chordal.ring, extended chordal ring generation
-- no.clusters calculates the number of clusters without calculating
-  the clusters themselves
-- minimum spanning tree functions updated to keep attributes
-- transitivity can calculate local transitivity as well
-- neighborhood related functions added: neighborhood,
-  neighborhood.size, graph.neighborhood
-- new graph generators based on vertex types: preference.game and
-  asymmetric.preference.game
-
-Bugs corrected
---------------
-
-- attribute handling bug when deleting edges corrected
-- GraphML escaping and NaN handling corrected
-- bug corrected to make it possible compile the R package without the 
-  libxml2 library
-- a bug in Erdos-Renyi graph generation corrected: it had problems 
-  with generating large directed graphs
-- bug in constraint calculation corrected, it works well now
-- fixed memory leaks in the GraphML reader
-- error handling bug corrected in the GraphML reader
-- bug corrected in R version of graph.laplacian when normalized
-  Laplacian is requested
-- memory leak corrected in get.all.shortest.paths in the R package
-
-=========
-igraph 0.2.1
-=========
-
-Released Aug 23, 2006
-
-This is a bug-fix release. Bugs fixed:
-- reciprocity corrected to avoid segfaults
-- some docs updates
-- various R package updates to make it conform to the CRAN rules
-
-=========
-igraph 0.2
-=========
-
-Released Aug 18, 2006
-
-Release time at last! There are many new things in igraph 0.2, the
-most important ones:
-- reading writing Pajek and GraphML formats with attributes
-  (not all Pajek and GraphML files are supported, see documentation
-  for details)
-- the RANDEDU fast motif search algorithm is implemented
-- many new graph generators, both games and regular graphs
-- many new structural properties: transitivity, reciprocity, etc.
-- graph operators: union, intersection, difference, structural holes, etc.
-- conversion between directed and undirected graphs
-- new layout algorithms for trees and large graphs, 3D layouts
-and many more.
-
-New things specifically in the R package:
-- support for CTRL+C
-- new functions: Graph Laplacian, Burt's constraint, etc.
-- vertex/edge sequences totally rewritten, smart indexing (see manual)
-- new R manual and tutorial: `Network Analysis with igraph', still 
-  under development but useful
-- very basic 3D plotting using OpenGL
-
-Although this release was somewhat tested on Linux, MS Windows, Mac
-OSX, Solaris 8 and FreeBSD, no heavy testing was done, so it might
-contain bugs, and we kindly ask you to send bug reports to make igraph
-better.
-
-=========
-igraph 0.1
-=========
-
-Released Jan 30, 2006
-
-After about a year of development this is the first "official" release 
-of the igraph library. This release should be considered as beta 
-software, but it should be useful in general. Please send your 
-questions and comments.
-
-
diff --git a/R/adjacency.R b/R/adjacency.R
new file mode 100644
index 0000000..d4a110e
--- /dev/null
+++ b/R/adjacency.R
@@ -0,0 +1,400 @@
+
+## ----------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2005-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------
+
+graph.adjacency.dense <- function(adjmatrix, mode=c("directed", "undirected", "max",
+                                               "min", "upper", "lower", "plus"),
+                                  weighted=NULL, diag=TRUE) {
+
+  mode <- igraph.match.arg(mode)
+  mode <- switch(mode,
+                 "directed"=0,
+                 "undirected"=1,
+                 "max"=1,
+                 "upper"=2,
+                 "lower"=3,
+                 "min"=4,
+                 "plus"=5)
+
+  mode(adjmatrix) <- "double"
+
+  if (!is.null(weighted)) {
+    if (is.logical(weighted) && weighted) {
+      weighted <- "weight"
+    }
+    if (!is.character(weighted)) {
+      stop("invalid value supplied for `weighted' argument, please see docs.")
+    }
+
+    if (nrow(adjmatrix) != ncol(adjmatrix)) {
+      stop("not a square matrix")
+    }
+
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    res <- .Call("R_igraph_weighted_adjacency", adjmatrix,
+                 as.numeric(mode), weighted, diag,
+                 PACKAGE="igraph")
+  } else {
+
+    adjmatrix <- as.matrix(adjmatrix)
+    attrs <- attributes(adjmatrix)
+    adjmatrix <- as.numeric(adjmatrix)
+    attributes(adjmatrix) <- attrs
+
+    if (!diag) { diag(adjmatrix) <- 0 }
+
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    res <- .Call("R_igraph_graph_adjacency", adjmatrix, as.numeric(mode),
+                 PACKAGE="igraph")
+  }
+
+  res
+}
+
+graph.adjacency.sparse <- function(adjmatrix, mode=c("directed", "undirected", "max",
+                                                "min", "upper", "lower", "plus"),
+                                   weighted=NULL, diag=TRUE) {
+
+  mode <- igraph.match.arg(mode)
+
+  if (!is.null(weighted)) {
+    if (is.logical(weighted) && weighted) {
+      weighted <- "weight"
+    }
+    if (!is.character(weighted)) {
+      stop("invalid value supplied for `weighted' argument, please see docs.")
+    }
+  }
+
+  mysummary <- Matrix::summary
+
+  if (nrow(adjmatrix) != ncol(adjmatrix)) {
+    stop("not a square matrix")
+  }
+
+  vc <- nrow(adjmatrix)
+
+  ## to remove non-redundancies that can persist in a dgtMatrix
+  if(inherits(adjmatrix, "dgTMatrix")) {
+    adjmatrix = as(adjmatrix, "CsparseMatrix")
+  }
+
+  if (is.null(weighted) && mode=="undirected") { mode <- "max" }
+
+  if (mode == "directed") {
+    ## DIRECTED
+    el <- mysummary(adjmatrix)
+    if (!diag) { el <- el[ el[,1] != el[,2], ] }
+  } else if (mode == "undirected") {
+    ## UNDIRECTED, must be symmetric if weighted
+    if (!is.null(weighted) && !Matrix::isSymmetric(adjmatrix)) {
+      stop("Please supply a symmetric matrix if you want to create a weighted graph with mode=UNDIRECTED.")
+    }
+    if (diag) {
+      adjmatrix <- Matrix::tril(adjmatrix)
+    } else {
+      adjmatrix <- Matrix::tril(adjmatrix, -1)
+    }
+    el <- mysummary(adjmatrix)
+  } else if (mode=="max") {
+    ## MAXIMUM
+    el <- mysummary(adjmatrix)
+    rm(adjmatrix)
+    if (!diag) { el <- el[ el[,1] != el[,2], ] }
+    el <- el[ el[,3] != 0, ]
+    w <- el[,3]
+    el <- el[,1:2]
+    el <- cbind( pmin(el[,1],el[,2]), pmax(el[,1], el[,2]) )
+    o <- order(el[,1], el[,2])
+    el <- el[o,,drop=FALSE]
+    w <- w[o]
+    if (nrow(el) > 1) {
+      dd <- el[2:nrow(el),1] == el[1:(nrow(el)-1),1] &
+        el[2:nrow(el),2] == el[1:(nrow(el)-1),2]
+      dd <- which(dd)
+      if (length(dd)>0) {
+        mw <- pmax(w[dd], w[dd+1])
+        w[dd] <- mw
+        w[dd+1] <- mw
+        el <- el[-dd,,drop=FALSE]
+        w <- w[-dd]
+      }
+    }
+    el <- cbind(el, w)
+  } else if (mode=="upper") {
+    ## UPPER
+    if (diag) {
+      adjmatrix <- Matrix::triu(adjmatrix)
+    } else {
+      adjmatrix <- Matrix::triu(adjmatrix, 1)
+    }
+    el <- mysummary(adjmatrix)
+    rm(adjmatrix)
+    if (!diag) { el <- el[ el[,1] != el[,2], ] }
+  } else if (mode=="lower") {
+    ## LOWER
+    if (diag) {
+      adjmatrix <- Matrix::tril(adjmatrix)
+    } else {
+      adjmatrix <- Matrix::tril(adjmatrix, -1)
+    }
+    el <- mysummary(adjmatrix)
+    rm(adjmatrix)
+    if (!diag) { el <- el[ el[,1] != el[,2], ] }
+  } else if (mode=="min") {
+    ## MINIMUM
+    adjmatrix <- sign(adjmatrix) * sign(Matrix::t(adjmatrix)) * adjmatrix
+    el <- mysummary(adjmatrix)
+    if (!diag) { el <- el[ el[,1] != el[,2], ] }
+    el <- el[ el[,3] != 0, ]
+    w <- el[,3]
+    el <- el[,1:2]
+    el <- cbind( pmin(el[,1],el[,2]), pmax(el[,1], el[,2]) )
+    o <- order(el[,1], el[,2])
+    el <- el[o,]
+    w <- w[o]
+    if (nrow(el) > 1) {
+      dd <- el[2:nrow(el),1] == el[1:(nrow(el)-1),1] &
+        el[2:nrow(el),2] == el[1:(nrow(el)-1),2]
+      dd <- which(dd)
+      if (length(dd)>0) {
+        mw <- pmin(w[dd], w[dd+1])
+        w[dd] <- mw
+        w[dd+1] <- mw
+        el <- el[-dd,]
+        w <- w[-dd]
+      }
+    }
+    el <- cbind(el, w)
+  } else if (mode=="plus") {
+    ## PLUS
+    adjmatrix <- adjmatrix + Matrix::t(adjmatrix)
+    if (diag) {
+      adjmatrix <- Matrix::tril(adjmatrix)
+    } else {
+      adjmatrix <- Matrix::tril(adjmatrix, -1)
+    }
+    el <- mysummary(adjmatrix)
+    if (diag) {
+      loop <- el[,1] == el[,2]
+      el[loop,3] <- el[loop,3] / 2
+    }
+    el <- el[ el[,3] != 0, ]
+    rm(adjmatrix)
+  }
+
+  if (!is.null(weighted)) {
+    res <- make_empty_graph(n=vc, directed=(mode=="directed"))
+    weight <- list(el[,3])
+    names(weight) <- weighted
+    res <- add_edges(res, edges=t(as.matrix(el[,1:2])), attr=weight)
+  } else {
+    edges <- unlist(apply(el, 1, function(x) rep(unname(x[1:2]), x[3])))
+    res <- graph(n=vc, edges, directed=(mode=="directed"))
+  }
+  res
+}
+
+
+
+#' Create graphs from adjacency matrices
+#'
+#' \code{graph_from_adjacency_matrix} is a flexible function for creating \code{igraph}
+#' graphs from adjacency matrices.
+#'
+#' The order of the vertices are preserved, i.e. the vertex corresponding to
+#' the first row will be vertex 0 in the graph, etc.
+#'
+#' \code{graph_from_adjacency_matrix} operates in two main modes, depending on the
+#' \code{weighted} argument.
+#'
+#' If this argument is \code{NULL} then an unweighted graph is created and an
+#' element of the adjacency matrix gives the number of edges to create between
+#' the two corresponding vertices.  The details depend on the value of the
+#' \code{mode} argument: \describe{ \item{"directed"}{The graph will be
+#' directed and a matrix element gives the number of edges between two
+#' vertices.} \item{"undirected"}{This is exactly the same as \code{max},
+#' for convenience. Note that it is \emph{not} checked whether the matrix is
+#' symmetric.} \item{"max"}{An undirected graph will be created and
+#' \code{max(A(i,j), A(j,i))} gives the number of edges.}
+#' \item{"upper"}{An undirected graph will be created, only the upper
+#' right triangle (including the diagonal) is used for the number of edges.}
+#' \item{"lower"}{An undirected graph will be created, only the lower
+#' left triangle (including the diagonal) is used for creating the edges.}
+#' \item{"min"}{undirected graph will be created with \code{min(A(i,j),
+#' A(j,i))} edges between vertex \code{i} and \code{j}.} \item{"plus"}{
+#' undirected graph will be created with \code{A(i,j)+A(j,i)} edges between
+#' vertex \code{i} and \code{j}.} }
+#'
+#' If the \code{weighted} argument is not \code{NULL} then the elements of the
+#' matrix give the weights of the edges (if they are not zero).  The details
+#' depend on the value of the \code{mode} argument: \describe{
+#' \item{"directed"}{The graph will be directed and a matrix element
+#' gives the edge weights.} \item{"undirected"}{First we check that the
+#' matrix is symmetric. It is an error if not. Then only the upper triangle is
+#' used to create a weighted undirected graph.} \item{"max"}{An
+#' undirected graph will be created and \code{max(A(i,j), A(j,i))} gives the
+#' edge weights.} \item{"upper"}{An undirected graph will be created,
+#' only the upper right triangle (including the diagonal) is used (for the edge
+#' weights).} \item{"lower"}{An undirected graph will be created, only
+#' the lower left triangle (including the diagonal) is used for creating the
+#' edges.} \item{"min"}{An undirected graph will be created,
+#' \code{min(A(i,j), A(j,i))} gives the edge weights.} \item{"plus"}{An
+#' undirected graph will be created, \code{A(i,j)+A(j,i)} gives the edge
+#' weights.} }
+#'
+#' @aliases graph.adjacency
+#' @param adjmatrix A square adjacency matrix. From igraph version 0.5.1 this
+#' can be a sparse matrix created with the \code{Matrix} package.
+#' @param mode Character scalar, specifies how igraph should interpret the
+#' supplied matrix. See also the \code{weighted} argument, the interpretation
+#' depends on that too. Possible values are: \code{directed},
+#' \code{undirected}, \code{upper}, \code{lower}, \code{max}, \code{min},
+#' \code{plus}. See details below.
+#' @param weighted This argument specifies whether to create a weighted graph
+#' from an adjacency matrix. If it is \code{NULL} then an unweighted graph is
+#' created and the elements of the adjacency matrix gives the number of edges
+#' between the vertices. If it is a character constant then for every non-zero
+#' matrix entry an edge is created and the value of the entry is added as an
+#' edge attribute named by the \code{weighted} argument. If it is \code{TRUE}
+#' then a weighted graph is created and the name of the edge attribute will be
+#' \code{weight}. See also details below.
+#' @param diag Logical scalar, whether to include the diagonal of the matrix in
+#' the calculation. If this is \code{FALSE} then the diagonal is zerod out
+#' first.
+#' @param add.colnames Character scalar, whether to add the column names as
+#' vertex attributes. If it is \sQuote{\code{NULL}} (the default) then, if
+#' present, column names are added as vertex attribute \sQuote{name}. If
+#' \sQuote{\code{NA}} then they will not be added.  If a character constant,
+#' then it gives the name of the vertex attribute to add.
+#' @param add.rownames Character scalar, whether to add the row names as vertex
+#' attributes. Possible values the same as the previous argument. By default
+#' row names are not added. If \sQuote{\code{add.rownames}} and
+#' \sQuote{\code{add.colnames}} specify the same vertex attribute, then the
+#' former is ignored.
+#' @return An igraph graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \link{graph} and \code{\link{graph_from_literal}} for other ways to
+#' create graphs.
+#' @keywords graphs
+#' @examples
+#'
+#' adjm <- matrix(sample(0:1, 100, replace=TRUE, prob=c(0.9,0.1)), nc=10)
+#' g1 <- graph_from_adjacency_matrix( adjm )
+#' adjm <- matrix(sample(0:5, 100, replace=TRUE,
+#'                       prob=c(0.9,0.02,0.02,0.02,0.02,0.02)), nc=10)
+#' g2 <- graph_from_adjacency_matrix(adjm, weighted=TRUE)
+#' E(g2)$weight
+#'
+#' ## various modes for weighted graphs, with some tests
+#' nzs <- function(x) sort(x [x!=0])
+#' adjm <- matrix(runif(100), 10)
+#' adjm[ adjm<0.5 ] <- 0
+#' g3 <- graph_from_adjacency_matrix((adjm + t(adjm))/2, weighted=TRUE,
+#'                       mode="undirected")
+#'
+#' g4 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="max")
+#' all(nzs(pmax(adjm, t(adjm))[upper.tri(adjm)]) == sort(E(g4)$weight))
+#'
+#' g5 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="min")
+#' all(nzs(pmin(adjm, t(adjm))[upper.tri(adjm)]) == sort(E(g5)$weight))
+#'
+#' g6 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="upper")
+#' all(nzs(adjm[upper.tri(adjm)]) == sort(E(g6)$weight))
+#'
+#' g7 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="lower")
+#' all(nzs(adjm[lower.tri(adjm)]) == sort(E(g7)$weight))
+#'
+#' g8 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="plus")
+#' d2 <- function(x) { diag(x) <- diag(x)/2; x }
+#' all(nzs((d2(adjm+t(adjm)))[lower.tri(adjm)]) == sort(E(g8)$weight))
+#'
+#' g9 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="plus", diag=FALSE)
+#' d0 <- function(x) { diag(x) <- 0 }
+#' all(nzs((d0(adjm+t(adjm)))[lower.tri(adjm)]) == sort(E(g9)$weight))
+#'
+#' ## row/column names
+#' rownames(adjm) <- sample(letters, nrow(adjm))
+#' colnames(adjm) <- seq(ncol(adjm))
+#' g10 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, add.rownames="code")
+#' summary(g10)
+#'
+graph_from_adjacency_matrix <- function(adjmatrix, mode=c("directed", "undirected", "max",
+                                         "min", "upper", "lower", "plus"),
+                            weighted=NULL, diag=TRUE,
+                            add.colnames=NULL, add.rownames=NA) {
+
+  if (inherits(adjmatrix, "Matrix")) {
+    res <- graph.adjacency.sparse(adjmatrix, mode=mode, weighted=weighted, diag=diag)
+  } else {
+    res <- graph.adjacency.dense(adjmatrix, mode=mode, weighted=weighted, diag=diag)
+  }
+
+  ## Add columns and row names as attributes
+  if (is.null(add.colnames)) {
+    if (!is.null(colnames(adjmatrix))) {
+      add.colnames <- "name"
+    } else {
+      add.colnames <- NA
+    }
+  } else if (!is.na(add.colnames)) {
+    if (is.null(colnames(adjmatrix))) {
+      warning("No column names to add")
+      add.colnames <- NA
+    }
+  }
+
+  if (is.null(add.rownames)) {
+    if (!is.null(rownames(adjmatrix))) {
+      add.rownames <- "name"
+    } else {
+      add.colnames <- NA
+    }
+  } else if (!is.na(add.rownames)) {
+    if (is.null(rownames(adjmatrix))) {
+      warning("No row names to add")
+      add.rownames <- NA
+    }
+  }
+
+  if (!is.na(add.rownames) && !is.na(add.colnames) &&
+      add.rownames == add.colnames ) {
+    warning("Same attribute for columns and rows, row names are ignored")
+    add.rownames <- NA
+  }
+
+  if (!is.na(add.colnames)) {
+    res <- set_vertex_attr(res, add.colnames, value=colnames(adjmatrix))
+  }
+  if (!is.na(add.rownames)) {
+    res <- set_vertex_attr(res, add.rownames, value=rownames(adjmatrix))
+  }
+
+  res
+}
+
+#' @rdname graph_from_adjacency_matrix
+#' @param ... Passed to \code{graph_from_adjacency_matrix}.
+#' @export
+
+from_adjacency <- function(...) constructor_spec(graph_from_adjacency_matrix, ...)
diff --git a/R/assortativity.R b/R/assortativity.R
new file mode 100644
index 0000000..bd17a30
--- /dev/null
+++ b/R/assortativity.R
@@ -0,0 +1,113 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+
+#' Assortativity coefficient
+#' 
+#' The assortativity coefficient is positive is similar vertices (based on some
+#' external property) tend to connect to each, and negative otherwise.
+#' 
+#' The assortativity coefficient measures the level of homophyly of the graph,
+#' based on some vertex labeling or values assigned to vertices. If the
+#' coefficient is high, that means that connected vertices tend to have the
+#' same labels or similar assigned values.
+#' 
+#' M.E.J. Newman defined two kinds of assortativity coefficients, the first one
+#' is for categorical labels of vertices. \code{assortativity_nominal}
+#' calculates this measure. It is defines as
+#' 
+#' \deqn{r=\frac{\sum_i e_{ii}-\sum_i a_i b_i}{1-\sum_i a_i b_i}}{
+#' r=(sum(e(i,i), i) - sum(a(i)b(i), i)) / (1 - sum(a(i)b(i), i))}
+#' 
+#' where \eqn{e_{ij}}{e(i,j)} is the fraction of edges connecting vertices of
+#' type \eqn{i} and \eqn{j}, \eqn{a_i=\sum_j e_{ij}}{a(i)=sum(e(i,j), j)} and
+#' \eqn{b_j=\sum_i e_{ij}}{b(j)=sum(e(i,j), i)}.
+#' 
+#' The second assortativity variant is based on values assigned to the
+#' vertices. \code{assortativity} calculates this measure. It is defined as
+#' 
+#' \deqn{r=\frac1{\sigma_q^2}\sum_{jk} jk(e_{jk}-q_j q_k)}{
+#' sum(jk(e(j,k)-q(j)q(k)), j, k) / sigma(q)^2}
+#' 
+#' for undirected graphs (\eqn{q_i=\sum_j e_{ij}}{q(i)=sum(e(i,j), j)}) and as
+#' 
+#' \deqn{r=\frac1{\sigma_o\sigma_i}\sum_{jk}jk(e_{jk}-q_j^o q_k^i)}{
+#' sum(jk(e(j,k)-qout(j)qin(k)), j, k) / sigma(qin) / sigma(qout) }
+#' 
+#' for directed ones. Here \eqn{q_i^o=\sum_j e_{ij}}{qout(i)=sum(e(i,j), j)},
+#' \eqn{q_i^i=\sum_j e_{ji}}{qin(i)=sum(e(j,i), j)}, moreover,
+#' \eqn{\sigma_q}{sigma(q)}, \eqn{sigma_o}{sigma(qout)} and
+#' \eqn{sigma_i}{sigma(qin)} are the standard deviations of \eqn{q},
+#' \eqn{q^o}{qout} and \eqn{q^i}{qin}, respectively.
+#' 
+#' The reason of the difference is that in directed networks the relationship
+#' is not symmetric, so it is possible to assign different values to the
+#' outgoing and the incoming end of the edges.
+#' 
+#' \code{assortativity_degree} uses vertex degree (minus one) as vertex values
+#' and calls \code{assortativity}.
+#' 
+#' @aliases assortativity assortativity.degree assortativity_degree
+#' assortativity.nominal assortativity_nominal
+#' @param graph The input graph, it can be directed or undirected.
+#' @param types Vector giving the vertex types. They as assumed to be integer
+#' numbers, starting with one. Non-integer values are converted to integers
+#' with \code{\link{as.integer}}.
+#' @param types1 The vertex values, these can be arbitrary numeric values.
+#' @param types2 A second value vector to be using for the incoming edges when
+#' calculating assortativity for a directed graph.  Supply \code{NULL} here if
+#' you want to use the same values for outgoing and incoming edges. This
+#' argument is ignored (with a warning) if it is not \code{NULL} and undirected
+#' assortativity coefficient is being calculated.
+#' @param directed Logical scalar, whether to consider edge directions for
+#' directed graphs. This argument is ignored for undirected graphs. Supply
+#' \code{TRUE} here to do the natural thing, i.e. use directed version of the
+#' measure for directed graphs and the undirected version for undirected
+#' graphs.
+#' @return A single real number.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references M. E. J. Newman: Mixing patterns in networks, \emph{Phys. Rev.
+#' E} 67, 026126 (2003) \url{http://arxiv.org/abs/cond-mat/0209450}
+#' 
+#' M. E. J. Newman: Assortative mixing in networks, \emph{Phys. Rev. Lett.} 89,
+#' 208701 (2002) \url{http://arxiv.org/abs/cond-mat/0205405/}
+#' @keywords graphs
+#' @examples
+#' 
+#' # random network, close to zero
+#' assortativity_degree(sample_gnp(10000, 3/10000))
+#' 
+#' # BA model, tends to be dissortative
+#' assortativity_degree(sample_pa(10000, m=4))
+#' @include auto.R
+
+assortativity <- assortativity
+
+#' @rdname assortativity
+
+assortativity_nominal <- assortativity_nominal
+
+#' @rdname assortativity
+
+assortativity_degree <- assortativity_degree
diff --git a/R/attributes.R b/R/attributes.R
index 1c26142..96bdc2f 100644
--- a/R/attributes.R
+++ b/R/attributes.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -34,33 +33,108 @@
 ## e(graph)$weight[1:10]           # get edge attribute
 ##
 
-get.graph.attribute <- function(graph, name) {
-  if (!is.igraph(graph)) {
+
+#' Graph attributes of a graph
+#'
+#' @param graph Input graph.
+#' @param name The name of attribute to query. If missing, then all
+#'   attributes are returned in a list.
+#' @return A list of graph attributes, or a single graph attribute.
+#'
+#' @aliases get.graph.attribute graph.attributes
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' graph_attr(g)
+#' graph_attr(g, "name")
+
+graph_attr <- function(graph, name) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  .Call("R_igraph_mybracket2", graph, 9L, 2L,
-        PACKAGE="igraph")[[as.character(name)]]
+  if (missing(name)) {
+    graph.attributes(graph)
+  } else {
+    base::.Call("R_igraph_mybracket2", graph, 9L, 2L,
+                PACKAGE="igraph")[[as.character(name)]]
+  }
+}
+
+
+#' Set all or some graph attributes
+#'
+#' @param graph The graph.
+#' @param name The name of the attribute to set. If missing, then
+#'   \code{value} should be a named list, and all list members
+#'   are set as attributes.
+#' @param value The value of the attribute to set
+#' @return The graph, with the attribute(s) added.
+#'
+#' @aliases graph.attributes<-
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_graph(~ A - B:C:D)
+#' graph_attr(g, "name") <- "4-star"
+#' g
+#'
+#' graph_attr(g) <- list(layout = layout_with_fr(g),
+#'                        name = "4-star layed out")
+#' plot(g)
+
+`graph_attr<-` <- function(graph, name, value) {
+  if (missing(name)) {
+    `graph.attributes<-`(graph, value)
+  } else {
+    set_graph_attr(graph, name, value)
+  }
 }
 
-set.graph.attribute <- function(graph, name, value) {
-  if (!is.igraph(graph)) {
+#' Set a graph attribute
+#'
+#' An existing attribute with the same name is overwritten.
+#' 
+#' @param graph The graph.
+#' @param name The name of the attribute to set.
+#' @param value New value of the attribute.
+#' @return The graph with the new graph attribute added or set.
+#'
+#' @family graph attributes
+#' @aliases set.graph.attribute
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_graph_attr("layout", layout_with_fr)
+#' g
+#' plot(g)
+
+set_graph_attr <- function(graph, name, value) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
-  .Call("R_igraph_mybracket3_set", graph, 9L, 2L, name, value,
-        PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket3_set", graph, 9L, 2L, name, value,
+              PACKAGE="igraph")
 }
 
+#' @export
+
 graph.attributes <- function(graph) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  .Call("R_igraph_mybracket2_copy", graph, 9L, 2L,
-        PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_copy", graph, 9L, 2L,
+              PACKAGE="igraph")
 } 
 
+#' @export
+
 "graph.attributes<-" <- function(graph, value) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   if (!is.list(value) || (length(value) > 0 && is.null(names(value))) ||
@@ -68,30 +142,122 @@ graph.attributes <- function(graph) {
     stop("Value must be a named list with unique names")
   }
             
-  .Call("R_igraph_mybracket2_set", graph, 9L, 2L, value,
-        PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 2L, value,
+              PACKAGE="igraph")
 }
 
-get.vertex.attribute <- function(graph, name, index=V(graph)) {
-  if (!is.igraph(graph)) {
+
+#' Query vertex attributes of a graph
+#'
+#' @param graph The graph.
+#' @param name Name of the attribute to query. If missing, then
+#'   all vertex attributes are returned in a list.
+#' @param index A vertex sequence, to query the attribute only
+#'   for these vertices.
+#' @return The value of the vertex attribute, or the list of
+#'   all vertex attributes, if \code{name} is missing.
+#'
+#' @aliases get.vertex.attribute vertex.attributes
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_vertex_attr("color", value = "red") %>%
+#'   set_vertex_attr("label", value = letters[1:10])
+#' vertex_attr(g, "label")
+#' vertex_attr(g)
+#' plot(g)
+
+vertex_attr <- function(graph, name, index=V(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  index <- as.igraph.vs(graph, index)  
-  myattr <- .Call("R_igraph_mybracket2", graph, 9L, 3L,
-                  PACKAGE="igraph")[[as.character(name)]]
-  myattr[index]
+  if (missing(name)) {
+    if (missing(index)) {
+      vertex.attributes(graph)
+    } else {
+      vertex.attributes(graph, index = index)
+    }
+  } else {
+    myattr <- base::.Call("R_igraph_mybracket2", graph, 9L, 3L,
+                          PACKAGE="igraph")[[as.character(name)]]
+    if (! missing(index)) {
+      index <- as.igraph.vs(graph, index)
+      myattr <- myattr[index]
+    }
+    myattr
+  }
 }
 
-set.vertex.attribute <- function(graph, name, index=V(graph), value) {
-  if (!is.igraph(graph)) {
+#' Set one or more vertex attributes
+#'
+#' @param graph The graph.
+#' @param name The name of the vertex attribute to set. If missing,
+#'   then \code{value} must be a named list, and its entries are
+#'   set as vertex attributes.
+#' @param index An optional vertex sequence to set the attributes
+#'   of a subset of vertices.
+#' @param value The new value of the attribute(s) for all
+#'   (or \code{index}) vertices. 
+#' @return The graph, with the vertex attribute(s) added or set.
+#'
+#' @aliases vertex.attributes<-
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' vertex_attr(g) <- list(name = LETTERS[1:10],
+#'                         color = rep("yellow", gorder(g)))
+#' vertex_attr(g, "label") <- V(g)$name
+#' g
+#' plot(g)
+
+`vertex_attr<-` <- function(graph, name, index = V(graph), value) {
+  if (missing(name)) {
+    `vertex.attributes<-`(graph, index = index, value = value)
+  } else {
+    set_vertex_attr(graph, name = name, index = index, value = value)
+  }
+}
+
+#' Set vertex attributes
+#' 
+#' @param graph The graph.
+#' @param name  The name of the attribute to set.
+#' @param index An optional vertex sequence to set the attributes
+#'   of a subset of vertices.
+#' @param value The new value of the attribute for all (or \code{index})
+#'   vertices.
+#' @return The graph, with the vertex attribute added or set.
+#'
+#' @aliases set.vertex.attribute
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_vertex_attr("label", value = LETTERS[1:10])
+#' g
+#' plot(g)
+
+set_vertex_attr <- function(graph, name, index = V(graph), value) {
+  i_set_vertex_attr(graph = graph, name = name, index = index,
+                    value = value)
+}
+
+i_set_vertex_attr <- function(graph, name, index=V(graph), value,
+                              check = TRUE) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   single <- "single" %in% names(attributes(index)) && attr(index, "single")
-  if (!missing(index)) { index <- as.igraph.vs(graph, index) }
+  if (!missing(index) && check) { index <- as.igraph.vs(graph, index) }
   name <- as.character(name)
   vc <- vcount(graph)
 
-  vattrs <- .Call("R_igraph_mybracket2", graph, 9L, 3L, PACKAGE="igraph")
+  vattrs <- base::.Call("R_igraph_mybracket2", graph, 9L, 3L, PACKAGE="igraph")
   if (single) {
     vattrs[[name]][[index]] <- value
   } else {
@@ -99,53 +265,172 @@ set.vertex.attribute <- function(graph, name, index=V(graph), value) {
   }
   length(vattrs[[name]]) <- vc
   
-  .Call("R_igraph_mybracket2_set", graph, 9L, 3L, vattrs, PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 3L, vattrs, PACKAGE="igraph")
 }
 
-vertex.attributes <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+vertex.attributes <- function(graph, index = V(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  .Call("R_igraph_mybracket2_copy", graph, 9L, 3L, PACKAGE="igraph")  
+
+  if (!missing(index)) {
+    index <- as.igraph.vs(graph, index)
+  }
+
+  res <- base::.Call("R_igraph_mybracket2_copy", graph, 9L, 3L, PACKAGE="igraph")
+
+  if (!missing(index) &&
+      (length(index) != vcount(graph) || any(index != V(graph)))) {
+    for (i in seq_along(value)) {
+      value[[i]] <- value[[i]][index]
+    }
+  }
+  res
 }
 
-"vertex.attributes<-" <- function(graph, value) {
-  if (!is.igraph(graph)) {
+#' @export
+
+"vertex.attributes<-" <- function(graph, index = V(graph), value) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   if (!is.list(value) || (length(value) > 0 && is.null(names(value))) ||
       any(names(value) == "") || any(duplicated(names(value)))) {
     stop("Value must be a named list with unique names")
   }
-  if ( any(sapply(value, length) != vcount(graph)) ) {
+  if ( any(sapply(value, length) != length(index)) ) {
     stop("Invalid attribute value length, must match number of vertices")
   }
-  
-  .Call("R_igraph_mybracket2_set", graph, 9L, 3L, value,
-        PACKAGE="igraph")
+
+  if (!missing(index)) {
+    index <- as.igraph.vs(graph, index)
+    if (any(duplicated(index)) || any(is.na(index))) {
+      stop("Invalid vertices in index")
+    }
+  }
+
+  if (!missing(index) &&
+      (length(index) != vcount(graph) || any(index != V(graph)))) {
+    vs <- V(graph)
+    for (i in seq_along(value)) {
+      tmp <- value[[i]]
+      length(tmp) <- 0
+      length(tmp) <- length(vs)
+      tmp[index] <- value[[i]]
+      value[[i]] <- tmp
+    }
+  }
+
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 3L, value,
+              PACKAGE="igraph")
 }
 
-get.edge.attribute <- function(graph, name, index=E(graph)) {
-  if (!is.igraph(graph)) {
+
+#' Query edge attributes of a graph
+#' 
+#' @param graph The graph
+#' @param name The name of the attribute to query. If missing, then
+#'   all edge attributes are returned in a list.
+#' @param index An optional edge sequence, to query edge attributes
+#'   for a subset of edges.
+#' @return The value of the edge attribute, or the list of all
+#'   edge attributes if \code{name} is missing.
+#'
+#' @aliases get.edge.attribute edge.attributes
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_edge_attr("weight", value = 1:10) %>%
+#'   set_edge_attr("color", value = "red")
+#' g
+#' plot(g, edge.width = E(g)$weight)
+
+edge_attr <- function(graph, name, index=E(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  name <- as.character(name)
-  index <- as.igraph.es(graph, index)
-  myattr <- .Call("R_igraph_mybracket2", graph, 9L, 4L,
-                  PACKAGE="igraph")[[name]]
-  myattr[index]
+  if (missing(name)) {
+    edge.attributes(graph, name)
+  } else {
+    name <- as.character(name)
+    index <- as.igraph.es(graph, index)
+    myattr <- base::.Call("R_igraph_mybracket2", graph, 9L, 4L,
+                    PACKAGE="igraph")[[name]]
+    myattr[index]
+  }
+}
+
+#' Set one or more edge attributes
+#' 
+#' @param graph The graph.
+#' @param name The name of the edge attribute to set. If missing,
+#'   then \code{value} must be a named list, and its entries are
+#'   set as edge attributes.
+#' @param index An optional edge sequence to set the attributes
+#'   of a subset of edges.
+#' @param value The new value of the attribute(s) for all
+#'   (or \code{index}) edges.
+#' @return The graph, with the edge attribute(s) added or set.
+#'
+#' @aliases edge.attributes<-
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' edge_attr(g) <- list(name = LETTERS[1:10],
+#'                       color = rep("green", gsize(g)))
+#' edge_attr(g, "label") <- E(g)$name
+#' g
+#' plot(g)
+
+`edge_attr<-` <- function(graph, name, index = E(graph), value) {
+  if (missing(name)) {
+    `edge.attributes<-`(graph, index = index, value = value)
+  } else {
+    set_edge_attr(graph, name = name, index = index, value = value)
+  }
 }
 
-set.edge.attribute <- function(graph, name, index=E(graph), value) {
-  if (!is.igraph(graph)) {
+#' Set edge attributes
+#' 
+#' @param graph The graph
+#' @param name  The name of the attribute to set.
+#' @param index An optional edge sequence to set the attributes of
+#'   a subset of edges.
+#' @param value The new value of the attribute for all (or \code{index})
+#'   edges.
+#' @return The graph, with the edge attribute added or set.
+#'
+#' @aliases set.edge.attribute
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_edge_attr("label", value = LETTERS[1:10])
+#' g
+#' plot(g)
+
+set_edge_attr <- function(graph, name, index = E(graph), value) {
+  i_set_edge_attr(graph = graph, name = name, index = index, value = value)
+}
+
+i_set_edge_attr <- function(graph, name, index=E(graph), value,
+                              check = TRUE) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   single <- "single" %in% names(attributes(index)) && attr(index, "single")
   name <- as.character(name)
-  index <- as.igraph.es(graph, index)
+  if (!missing(index) && check) index <- as.igraph.es(graph, index)
   ec <- ecount(graph)
 
-  eattrs <- .Call("R_igraph_mybracket2", graph, 9L, 4L, PACKAGE="igraph")
+  eattrs <- base::.Call("R_igraph_mybracket2", graph, 9L, 4L, PACKAGE="igraph")
   if (single) {
     eattrs[[name]][[index]] <- value
   } else {
@@ -153,18 +438,35 @@ set.edge.attribute <- function(graph, name, index=E(graph), value) {
   }
   length(eattrs[[name]]) <- ec
 
-  .Call("R_igraph_mybracket2_set", graph, 9L, 4L, eattrs, PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 4L, eattrs, PACKAGE="igraph")
 }
 
-edge.attributes <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+edge.attributes <- function(graph, index = E(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  .Call("R_igraph_mybracket2_copy", graph, 9L, 4L, PACKAGE="igraph")  
+
+  if (!missing(index)) {
+    index <- as.igraph.es(graph, index)
+  }
+
+  res <- base::.Call("R_igraph_mybracket2_copy", graph, 9L, 4L, PACKAGE="igraph")
+
+  if (!missing(index) &&
+      (length(index) != ecount(graph) || any(index != E(graph)))) {
+    for (i in seq_along(value)) {
+      value[[i]] <- value[[i]][index]
+    }
+  }
+  res
 }
 
-"edge.attributes<-" <- function(graph, value) {
-  if (!is.igraph(graph)) {
+#' @export
+
+"edge.attributes<-" <- function(graph, index = E(graph), value) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -172,108 +474,288 @@ edge.attributes <- function(graph) {
       any(names(value) == "") || any(duplicated(names(value)))) {
     stop("Value must be a named list with unique names")
   }
-  if ( any(sapply(value, length) != ecount(graph)) ) {
+  if ( any(sapply(value, length) != length(index)) ) {
     stop("Invalid attribute value length, must match number of edges")
   }
+
+  if (!missing(index)) {
+    index <- as.igraph.es(graph, index)
+    if (any(duplicated(index)) || any(is.na(index))) {
+      stop("Invalid edges in index")
+    }
+  }
+
+  if (!missing(index) &&
+      (length(index) != ecount(graph) || any(index != E(graph)))) {
+    es <- E(graph)
+    for (i in seq_along(value)) {
+      tmp <- value[[i]]
+      length(tmp) <- 0
+      length(tmp) <- length(es)
+      tmp[index] <- value[[i]]
+      value[[i]] <- tmp
+    }
+  }
   
-  .Call("R_igraph_mybracket2_set", graph, 9L, 4L, value,
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 4L, value,
         PACKAGE="igraph")
 }
 
-list.graph.attributes <- function(graph) {
-  if (!is.igraph(graph)) {
+#' List names of graph attributes
+#' 
+#' @param graph The graph.
+#' @return Character vector, the names of the graph attributes.
+#'
+#' @aliases list.graph.attributes attributes
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' graph_attr_names(g)
+
+graph_attr_names <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  res <- .Call("R_igraph_mybracket2_names", graph, 9L, 2L, PACKAGE="igraph")
+  res <- base::.Call("R_igraph_mybracket2_names", graph, 9L, 2L, PACKAGE="igraph")
   if (is.null(res)) { res <- character() }
   res
 }
 
-list.vertex.attributes <- function(graph) {
-  if (!is.igraph(graph)) {
+#' List names of vertex attributes
+#'
+#' @param graph The graph.
+#' @return Character vector, the names of the vertex attributes.
+#'
+#' @aliases list.vertex.attributes
+#' @family graph attributes
+#'
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10]) %>%
+#'   set_vertex_attr("color", value = rep("green", 10))
+#' vertex_attr_names(g)
+#' plot(g)
+
+vertex_attr_names <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  res <- .Call("R_igraph_mybracket2_names", graph, 9L, 3L, PACKAGE="igraph")
+  res <- base::.Call("R_igraph_mybracket2_names", graph, 9L, 3L, PACKAGE="igraph")
                      
   if (is.null(res)) { res <- character() }
   res
 }
 
-list.edge.attributes <- function(graph) {
-  if (!is.igraph(graph)) {
+#' List names of edge attributes
+#'
+#' @param graph The graph.
+#' @return Character vector, the names of the edge attributes.
+#'
+#' @aliases list.edge.attributes
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_edge_attr("label", value = letters[1:10])
+#' edge_attr_names(g)
+#' plot(g)
+
+edge_attr_names <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  res <- .Call("R_igraph_mybracket2_names", graph, 9L, 4L, PACKAGE="igraph")
+  res <- base::.Call("R_igraph_mybracket2_names", graph, 9L, 4L, PACKAGE="igraph")
   if (is.null(res)) { res <- character() }
   res
 }
 
-remove.graph.attribute <- function(graph, name) {
-  if (!is.igraph(graph)) {
+#' Delete a graph attribute
+#'
+#' @param graph The graph.
+#' @param name Name of the attribute to delete.
+#' @return The graph, with the specified attribute removed.
+#'
+#' @aliases remove.graph.attribute
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' graph_attr_names(g)
+#' g2 <- delete_graph_attr(g, "name")
+#' graph_attr_names(g2)
+
+delete_graph_attr <- function(graph, name) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   name <- as.character(name)
-  if (!name %in% list.graph.attributes(graph)) {
+  if (!name %in% graph_attr_names(graph)) {
     stop("No such graph attribute: ", name)
   }
 
-  gattr <- .Call("R_igraph_mybracket2", graph, 9L, 2L, PACKAGE="igraph")
+  gattr <- base::.Call("R_igraph_mybracket2", graph, 9L, 2L, PACKAGE="igraph")
   gattr[[name]] <- NULL
   
-  .Call("R_igraph_mybracket2_set", graph, 9L, 2L, gattr, PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 2L, gattr, PACKAGE="igraph")
 }
 
-remove.vertex.attribute <- function(graph, name) {
-  if (!is.igraph(graph)) {
+#' Delete a vertex attribute
+#'
+#' @param graph The graph
+#' @param name The name of the vertex attribute to delete.
+#' @return The graph, with the specified vertex attribute removed.
+#'
+#' @aliases remove.vertex.attribute
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10])
+#' vertex_attr_names(g)
+#' g2 <- delete_vertex_attr(g, "name")
+#' vertex_attr_names(g2)
+
+delete_vertex_attr <- function(graph, name) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   name <- as.character(name)
-  if (!name %in% list.vertex.attributes(graph)) {
+  if (!name %in% vertex_attr_names(graph)) {
     stop("No such vertex attribute: ", name)
   }
 
-  vattr <- .Call("R_igraph_mybracket2", graph, 9L, 3L, PACKAGE="igraph")
+  vattr <- base::.Call("R_igraph_mybracket2", graph, 9L, 3L, PACKAGE="igraph")
   vattr[[name]] <- NULL
   
-  .Call("R_igraph_mybracket2_set", graph, 9L, 3L, vattr, PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 3L, vattr, PACKAGE="igraph")
 }
 
-remove.edge.attribute <- function(graph, name) {
-  if (!is.igraph(graph)) {
+#' Delete an edge attribute
+#'
+#' @param graph The graph
+#' @param name The name of the edge attribute to delete.
+#' @return The graph, with the specified edge attribute removed.
+#'
+#' @aliases remove.edge.attribute
+#' @family graph attributes
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_edge_attr("name", value = LETTERS[1:10])
+#' edge_attr_names(g)
+#' g2 <- delete_edge_attr(g, "name")
+#' edge_attr_names(g2)
+
+delete_edge_attr <- function(graph, name) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   name <- as.character(name)
-  if (!name %in% list.edge.attributes(graph)) {
+  if (!name %in% edge_attr_names(graph)) {
     stop("No such edge attribute: ", name)
   }
 
-  eattr <- .Call("R_igraph_mybracket2", graph, 9L, 4L, PACKAGE="igraph")
+  eattr <- base::.Call("R_igraph_mybracket2", graph, 9L, 4L, PACKAGE="igraph")
   eattr[[name]] <- NULL
   
-  .Call("R_igraph_mybracket2_set", graph, 9L, 4L, eattr, PACKAGE="igraph")
+  base::.Call("R_igraph_mybracket2_set", graph, 9L, 4L, eattr, PACKAGE="igraph")
 }
 
 #############
 
-is.named <- function(graph) {
-  if (!is.igraph(graph)) {
+
+
+#' Named graphs
+#' 
+#' An igraph graph is named, if there is a symbolic name associated with its
+#' vertices.
+#' 
+#' In igraph vertices can always be identified and specified via their numeric
+#' vertex ids. This is, however, not always convenient, and in many cases there
+#' exist symbolic ids that correspond to the vertices. To allow this more
+#' flexible identification of vertices, one can assign a vertex attribute
+#' called \sQuote{name} to an igraph graph. After doing this, the symbolic
+#' vertex names can be used in all igraph functions, instead of the numeric
+#' ids.
+#' 
+#' Note that the uniqueness of vertex names are currently not enforced in
+#' igraph, you have to check that for yourself, when assigning the vertex
+#' names.
+#'
+#' @aliases is.named
+#' @param graph The input graph.
+#' @return A logical scalar.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' is_named(g)
+#' V(g)$name <- letters[1:10]
+#' is_named(g)
+#' neighbors(g, "a")
+#' 
+is_named <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  "name" %in% list.vertex.attributes(graph)
+  "name" %in% vertex_attr_names(graph)
 }
 
-is.weighted <- function(graph) {
-  if (!is.igraph(graph)) {
+
+
+#' Weighted graphs
+#' 
+#' In weighted graphs, a real number is assigned to each (directed or
+#' undirected) edge.
+#' 
+#' In igraph edge weights are represented via an edge attribute, called
+#' \sQuote{weight}. The \code{is_weighted} function only checks that such an
+#' attribute exists. (It does not even checks that it is a numeric edge
+#' attribute.)
+#' 
+#' Edge weights are used for different purposes by the different functions.
+#' E.g. shortest path functions use it as the cost of the path; community
+#' finding methods use it as the strength of the relationship between two
+#' vertices, etc. Check the manual pages of the functions working with weighted
+#' graphs for details.
+#'
+#' @aliases is.weighted
+#' @param graph The input graph.
+#' @return A logical scalar.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' shortest_paths(g, 8, 2)
+#' E(g)$weight <- seq_len(ecount(g))
+#' shortest_paths(g, 8, 2)
+#' 
+is_weighted <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  "weight" %in% list.edge.attributes(graph)
+  "weight" %in% edge_attr_names(graph)
 }
 
-is.bipartite <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @rdname make_bipartite_graph
+#' @export
+
+is_bipartite <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  "type" %in% list.vertex.attributes(graph)
+  "type" %in% vertex_attr_names(graph)
 }
 
 #############
@@ -310,3 +792,137 @@ igraph.i.attribute.combination <- function(comb) {
 
   comb
 }
+
+#' How igraph functions handle attributes when the graph changes
+#' 
+#' Many times, when the structure of a graph is modified, vertices/edges map of
+#' the original graph map to vertices/edges in the newly created (modified)
+#' graph. For example \code{\link{simplify}} maps multiple edges to single
+#' edges. igraph provides a flexible mechanism to specify what to do with the
+#' vertex/edge attributes in these cases.
+#' 
+#' The functions that support the combination of attributes have one or two
+#' extra arguments called \code{vertex.attr.comb} and/or \code{edge.attr.comb}
+#' that specify how to perform the mapping of the attributes. E.g.
+#' \code{\link{contract}} contracts many vertices into a single one, the
+#' attributes of the vertices can be combined and stores as the vertex
+#' attributes of the new graph.
+#' 
+#' The specification of the combination of (vertex or edge) attributes can be
+#' given as \enumerate{
+#'   \item a character scalar,
+#'   \item a function object or
+#'   \item a list of character scalars and/or function objects.
+#' }
+#' 
+#' If it is a character scalar, then it refers to one of the predefined
+#' combinations, see their list below.
+#' 
+#' If it is a function, then the given function is expected to perform the
+#' combination. It will be called once for each new vertex/edge in the graph,
+#' with a single argument: the attribute values of the vertices that map to
+#' that single vertex.
+#' 
+#' The third option, a list can be used to specify different combination
+#' methods for different attributes. A named entry of the list corresponds to
+#' the attribute with the same name. An unnamed entry (i.e. if the name is the
+#' empty string) of the list specifies the default combination method. I.e.
+#' \preformatted{list(weight="sum", "ignore")} specifies that the weight of the
+#' new edge should be sum of the weights of the corresponding edges in the old
+#' graph; and that the rest of the attributes should be ignored (=dropped).
+#'
+#' @name igraph-attribute-combination
+#' @aliases attribute.combination
+#' @section Predefined combination functions: The following combination
+#' behaviors are predefined: \describe{ \item{"ignore"}{The attribute is
+#' ignored and dropped.} \item{"sum"}{The sum of the attributes is
+#' calculated. This does not work for character attributes and works for
+#' complex attributes only if they have a \code{sum} generic defined. (E.g. it
+#' works for sparse matrices from the \code{Matrix} package, because they have
+#' a \code{sum} method.)} \item{"prod"}{The product of the attributes is
+#' calculated. This does not work for character attributes and works for
+#' complex attributes only if they have a \code{prod} function defined.}
+#' \item{"min"}{The minimum of the attributes is calculated and returned.
+#' For character and complex attributes the standard R \code{min} function is
+#' used.} \item{"max"}{The maximum of the attributes is calculated and
+#' returned. For character and complex attributes the standard R \code{max}
+#' function is used.} \item{"random"}{Chooses one of the supplied
+#' attribute values, uniformly randomly. For character and complex attributes
+#' this is implemented by calling \code{sample}.} \item{"first"}{Always
+#' chooses the first attribute value. It is implemented by calling the
+#' \code{head} function.} \item{"last"}{Always chooses the last attribute
+#' value. It is implemented by calling the \code{tail} function.}
+#' \item{"mean"}{The mean of the attributes is calculated and returned.
+#' For character and complex attributes this simply calls the \code{mean}
+#' function.} \item{"median"}{The median of the attributes is selected.
+#' Calls the R \code{median} function for all attribute types.}
+#' \item{"concat"}{Concatenate the attributes, using the \code{c}
+#' function. This results almost always a complex attribute.} }
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{graph_attr}}, \code{\link{vertex_attr}},
+#'   \code{\link{edge_attr}} on how to use graph/vertex/edge attributes in
+#'   general. \code{\link{igraph_options}} on igraph parameters.  
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- graph( c(1,2, 1,2, 1,2, 2,3, 3,4) )
+#' E(g)$weight <- 1:5
+#' 
+#' ## print attribute values with the graph
+#' igraph_options(print.graph.attributes=TRUE)
+#' igraph_options(print.vertex.attributes=TRUE)
+#' igraph_options(print.edge.attributes=TRUE)
+#' 
+#' ## new attribute is the sum of the old ones
+#' simplify(g, edge.attr.comb="sum")
+#' 
+#' ## collect attributes into a string
+#' simplify(g, edge.attr.comb=toString)
+#' 
+#' ## concatenate them into a vector, this creates a complex
+#' ## attribute
+#' simplify(g, edge.attr.comb="concat")
+#' 
+#' E(g)$name <- letters[seq_len(ecount(g))]
+#' 
+#' ## both attributes are collected into strings
+#' simplify(g, edge.attr.comb=toString)
+#' 
+#' ## harmonic average of weights, names are dropped
+#' simplify(g, edge.attr.comb=list(weight=function(x) length(x)/sum(1/x),
+#'                                 name="ignore"))
+
+NULL
+
+#' Getting and setting graph attributes, shortcut
+#'
+#' The \code{$} operator is a shortcut to get and and set
+#' graph attributes. It is shorter and just as readable as
+#' \code{\link{graph_attr}} and \code{\link{set_graph_attr}}.
+#'
+#' @param x An igraph graph
+#' @param name Name of the attribute to get/set.
+#'
+#' @method $ igraph
+#' @name igraph-dollar
+#' @export
+#' @family graph attributes
+#' @examples
+#' g <- make_ring(10)
+#' g$name
+#' g$name <- "10-ring"
+#' g$name
+
+`$.igraph` <- function(x, name) {
+  graph_attr(x, name)
+}
+
+#' @param value New value of the graph attribute.
+#'
+#' @method $<- igraph
+#' @name igraph-dollar
+#' @export
+
+`$<-.igraph` <- function(x, name, value) {
+  set_graph_attr(x, name, value)
+}
diff --git a/R/auto.R b/R/auto.R
index d838994..162e5e6 100644
--- a/R/auto.R
+++ b/R/auto.R
@@ -1,19 +1,7 @@
-graph.empty <- function(n=0, directed=TRUE) {
+#' @export
+gorder <- function(graph) {
   # Argument checks
-  n <- as.integer(n)
-  directed <- as.logical(directed)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_empty", n, directed,
-        PACKAGE="igraph")
-
-  res
-}
-
-vcount <- function(graph) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -24,21 +12,8 @@ vcount <- function(graph) {
   res
 }
 
-graph.full.citation <- function(n, directed=TRUE) {
-  # Argument checks
-  n <- as.integer(n)
-  directed <- as.logical(directed)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_full_citation", n, directed,
-        PACKAGE="igraph")
-
-  res <- set.graph.attribute(res, 'name', 'Full citation graph')
-  res
-}
-
-graph.lcf <- function(n, shifts, repeats=1) {
+#' @export
+graph_from_lcf <- function(n, shifts, repeats=1) {
   # Argument checks
   n <- as.integer(n)
   shifts <- as.numeric(shifts)
@@ -53,7 +28,8 @@ graph.lcf <- function(n, shifts, repeats=1) {
   res
 }
 
-graph.adjlist <- function(adjlist, mode=c("out", "in", "all", "total"), duplicate=TRUE) {
+#' @export
+graph_from_adj_list <- function(adjlist, mode=c("out", "in", "all", "total"), duplicate=TRUE) {
   # Argument checks
   adjlist <- lapply(adjlist, function(x) as.integer(x)-1L)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
@@ -67,7 +43,8 @@ graph.adjlist <- function(adjlist, mode=c("out", "in", "all", "total"), duplicat
   res
 }
 
-forest.fire.game <- function(nodes, fw.prob, bw.factor=1, ambs=1, directed=TRUE) {
+#' @export
+sample_forestfire <- function(nodes, fw.prob, bw.factor=1, ambs=1, directed=TRUE) {
   # Argument checks
   nodes <- as.integer(nodes)
   fw.prob <- as.numeric(fw.prob)
@@ -87,7 +64,8 @@ forest.fire.game <- function(nodes, fw.prob, bw.factor=1, ambs=1, directed=TRUE)
   res
 }
 
-interconnected.islands.game <- function(islands.n, islands.size, islands.pin, n.inter) {
+#' @export
+sample_islands <- function(islands.n, islands.size, islands.pin, n.inter) {
   # Argument checks
   islands.n <- as.integer(islands.n)
   islands.size <- as.integer(islands.size)
@@ -107,7 +85,8 @@ interconnected.islands.game <- function(islands.n, islands.size, islands.pin, n.
   res
 }
 
-static.fitness.game <- function(no.of.edges, fitness.out, fitness.in=NULL, loops=FALSE, multiple=FALSE) {
+#' @export
+sample_fitness <- function(no.of.edges, fitness.out, fitness.in=NULL, loops=FALSE, multiple=FALSE) {
   # Argument checks
   no.of.edges <- as.integer(no.of.edges)
   fitness.out <- as.numeric(fitness.out)
@@ -126,7 +105,8 @@ static.fitness.game <- function(no.of.edges, fitness.out, fitness.in=NULL, loops
   res
 }
 
-static.power.law.game <- function(no.of.nodes, no.of.edges, exponent.out, exponent.in=-1, loops=FALSE, multiple=FALSE, finite.size.correction=TRUE) {
+#' @export
+sample_fitness_pl <- function(no.of.nodes, no.of.edges, exponent.out, exponent.in=-1, loops=FALSE, multiple=FALSE, finite.size.correction=TRUE) {
   # Argument checks
   no.of.nodes <- as.integer(no.of.nodes)
   no.of.edges <- as.integer(no.of.edges)
@@ -150,7 +130,8 @@ static.power.law.game <- function(no.of.nodes, no.of.edges, exponent.out, expone
   res
 }
 
-k.regular.game <- function(no.of.nodes, k, directed=FALSE, multiple=FALSE) {
+#' @export
+sample_k_regular <- function(no.of.nodes, k, directed=FALSE, multiple=FALSE) {
   # Argument checks
   no.of.nodes <- as.integer(no.of.nodes)
   k <- as.integer(k)
@@ -167,7 +148,8 @@ k.regular.game <- function(no.of.nodes, k, directed=FALSE, multiple=FALSE) {
   res
 }
 
-sbm.game <- function(n, pref.matrix, block.sizes, directed=FALSE, loops=FALSE) {
+#' @export
+sample_sbm <- function(n, pref.matrix, block.sizes, directed=FALSE, loops=FALSE) {
   # Argument checks
   n <- as.integer(n)
   pref.matrix <- as.matrix(structure(as.double(pref.matrix), dim=dim(pref.matrix)))
@@ -185,61 +167,144 @@ sbm.game <- function(n, pref.matrix, block.sizes, directed=FALSE, loops=FALSE) {
   res
 }
 
-closeness.estimate <- function(graph, vids=V(graph), mode=c("out", "in", "all", "total"), cutoff, weights=NULL, normalized=FALSE) {
+hsbm.1.game <- function(n, m, rho, C, p) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  vids <- as.igraph.vs(graph, vids)
-  mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
-  cutoff <- as.numeric(cutoff)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
-  weights <- E(graph)$weight 
-  } 
-  if (!is.null(weights) && any(!is.na(weights))) { 
-  weights <- as.numeric(weights) 
-  } else { 
-  weights <- NULL 
-  }
-  normalized <- as.logical(normalized)
+  n <- as.integer(n)
+  m <- as.integer(m)
+  rho <- as.numeric(rho)
+  C <- as.matrix(structure(as.double(C), dim=dim(C)))
+  p <- as.numeric(p)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_closeness_estimate", graph, vids-1, mode, cutoff, weights, normalized,
+  res <- .Call("R_igraph_hsbm_game", n, m, rho, C, p,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res) <- get.vertex.attribute(graph, "name", vids) 
-  }
+
+  res <- set.graph.attribute(res, 'name', 'Hierarchical stochastic block model')
+  res <- set.graph.attribute(res, 'm', m)
+  res <- set.graph.attribute(res, 'rho', rho)
+  res <- set.graph.attribute(res, 'C', C)
+  res <- set.graph.attribute(res, 'p', p)
   res
 }
 
-betweenness.estimate <- function(graph, vids=V(graph), directed=TRUE, cutoff, weights=NULL, nobigint=TRUE) {
+hsbm.list.game <- function(n, mlist, rholist, Clist, p) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  vids <- as.igraph.vs(graph, vids)
+  n <- as.integer(n)
+  mlist <- as.integer(mlist)
+  if (!all(sapply(Clist, is.matrix))) { stop("%I is not a list of matrices") }
+  p <- as.numeric(p)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_hsbm_list_game", n, mlist, rholist, Clist, p,
+        PACKAGE="igraph")
+
+  res <- set.graph.attribute(res, 'name', 'Hierarchical stochastic block model')
+  res <- set.graph.attribute(res, 'p', p)
+  res
+}
+
+#' @export
+sample_correlated_gnp <- function(old.graph, corr, p=old.graph$p, permutation=NULL) {
+  # Argument checks
+  if (!is_igraph(old.graph)) { stop("Not a graph object") }
+  corr <- as.numeric(corr)
+  p <- as.numeric(p)
+  if (!is.null(permutation)) permutation <- as.numeric(permutation)-1
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_correlated_game", old.graph, corr, p, permutation,
+        PACKAGE="igraph")
+
+  res <- set.graph.attribute(res, 'name', 'Correlated random graph')
+  res <- set.graph.attribute(res, 'corr', corr)
+  res <- set.graph.attribute(res, 'p', p)
+  res
+}
+
+#' @export
+sample_correlated_gnp_pair <- function(n, corr, p, directed=FALSE, permutation=NULL) {
+  # Argument checks
+  n <- as.integer(n)
+  corr <- as.numeric(corr)
+  p <- as.numeric(p)
   directed <- as.logical(directed)
-  cutoff <- as.numeric(cutoff)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
-  weights <- E(graph)$weight 
-  } 
-  if (!is.null(weights) && any(!is.na(weights))) { 
-  weights <- as.numeric(weights) 
-  } else { 
-  weights <- NULL 
-  }
-  nobigint <- as.logical(nobigint)
+  if (!is.null(permutation)) permutation <- as.numeric(permutation)-1
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_betweenness_estimate", graph, vids-1, directed, cutoff, weights, nobigint,
+  res <- .Call("R_igraph_correlated_pair_game", n, corr, p, directed, permutation,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res) <- get.vertex.attribute(graph, "name", vids) 
-  }
+
+  res
+}
+
+#' @export
+sample_dot_product <- function(vecs, directed=FALSE) {
+  # Argument checks
+  vecs <- as.matrix(structure(as.double(vecs), dim=dim(vecs)))
+  directed <- as.logical(directed)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_dot_product_game", vecs, directed,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @export
+sample_sphere_surface <- function(dim, n=1, radius=1, positive=TRUE) {
+  # Argument checks
+  dim <- as.integer(dim)
+  n <- as.integer(n)
+  radius <- as.numeric(radius)
+  positive <- as.logical(positive)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_sample_sphere_surface", dim, n, radius, positive,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @export
+sample_sphere_volume <- function(dim, n=1, radius=1, positive=TRUE) {
+  # Argument checks
+  dim <- as.integer(dim)
+  n <- as.integer(n)
+  radius <- as.numeric(radius)
+  positive <- as.logical(positive)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_sample_sphere_volume", dim, n, radius, positive,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @export
+sample_dirichlet <- function(n, alpha) {
+  # Argument checks
+  n <- as.integer(n)
+  alpha <- as.numeric(alpha)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_sample_dirichlet", n, alpha,
+        PACKAGE="igraph")
+
   res
 }
 
-page.rank.old <- function(graph, vids=V(graph), directed=TRUE, niter=1000, eps=0.001, damping=0.85, old=FALSE) {
+#' @export
+page_rank_old <- function(graph, vids=V(graph), directed=TRUE, niter=1000, eps=0.001, damping=0.85, old=FALSE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   directed <- as.logical(directed)
   niter <- as.integer(niter)
@@ -251,22 +316,23 @@ page.rank.old <- function(graph, vids=V(graph), directed=TRUE, niter=1000, eps=0
   # Function call
   res <- .Call("R_igraph_pagerank_old", graph, vids-1, directed, niter, eps, damping, old,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res) <- get.vertex.attribute(graph, "name", vids) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res) <- vertex_attr(graph, "name", vids) 
   }
   res
 }
 
-page.rank <- function(graph, algo=c("prpack", "arpack", "power"), vids=V(graph), directed=TRUE, damping=0.85, personalized=NULL, weights=NULL, options=NULL) {
+#' @export
+page_rank <- function(graph, algo=c("prpack", "arpack", "power"), vids=V(graph), directed=TRUE, damping=0.85, personalized=NULL, weights=NULL, options=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   algo <- switch(igraph.match.arg(algo), "power"=0L, "arpack"=1L, 
   "prpack"=2L)
   vids <- as.igraph.vs(graph, vids)
   directed <- as.logical(directed)
   damping <- as.numeric(damping)
   if (!is.null(personalized)) personalized <- as.numeric(personalized)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -278,7 +344,7 @@ page.rank <- function(graph, algo=c("prpack", "arpack", "power"), vids=V(graph),
   if (algo == 0L) {                         
   options <- list(niter=1000, eps=0.001)      
   } else if (algo == 1L) {                  
-  options <- igraph.arpack.default            
+  options <- arpack_defaults                  
   } else {                                  
   options <- NULL                             
   }                                         
@@ -288,43 +354,16 @@ page.rank <- function(graph, algo=c("prpack", "arpack", "power"), vids=V(graph),
   # Function call
   res <- .Call("R_igraph_personalized_pagerank", graph, algo, vids-1, directed, damping, personalized, weights, options,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res$vector) <- get.vertex.attribute(graph, "name", vids) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res$vector) <- vertex_attr(graph, "name", vids) 
   }
   res
 }
 
-induced.subgraph <- function(graph, vids, impl=c("auto", "copy_and_delete", "create_from_scratch")) {
+#' @export
+distance_table <- function(graph, directed=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  vids <- as.igraph.vs(graph, vids)
-  impl <- switch(igraph.match.arg(impl), "auto"=0, "copy_and_delete"=1, "create_from_scratch"=2)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_induced_subgraph", graph, vids-1, impl,
-        PACKAGE="igraph")
-
-  res
-}
-
-subgraph.edges <- function(graph, eids, delete.vertices=TRUE) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  eids <- as.igraph.es(graph, eids)
-  delete.vertices <- as.logical(delete.vertices)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_subgraph_edges", graph, eids-1, delete.vertices,
-        PACKAGE="igraph")
-
-  res
-}
-
-path.length.hist <- function(graph, directed=TRUE) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   directed <- as.logical(directed)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -335,9 +374,10 @@ path.length.hist <- function(graph, directed=TRUE) {
   res
 }
 
-simplify <- function(graph, remove.multiple=TRUE, remove.loops=TRUE, edge.attr.comb=getIgraphOpt("edge.attr.comb")) {
+#' @export
+simplify <- function(graph, remove.multiple=TRUE, remove.loops=TRUE, edge.attr.comb=igraph_opt("edge.attr.comb")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   remove.multiple <- as.logical(remove.multiple)
   remove.loops <- as.logical(remove.loops)
   edge.attr.comb <- igraph.i.attribute.combination(edge.attr.comb)
@@ -350,9 +390,10 @@ simplify <- function(graph, remove.multiple=TRUE, remove.loops=TRUE, edge.attr.c
   res
 }
 
-is.dag <- function(graph) {
+#' @export
+is_dag <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -362,9 +403,10 @@ is.dag <- function(graph) {
   res
 }
 
-is.simple <- function(graph) {
+#' @export
+is_simple <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -374,9 +416,10 @@ is.simple <- function(graph) {
   res
 }
 
-has.multiple <- function(graph) {
+#' @export
+any_multiple <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -386,12 +429,13 @@ has.multiple <- function(graph) {
   res
 }
 
-evcent <- function(graph, directed=FALSE, scale=TRUE, weights=NULL, options=igraph.arpack.default) {
+#' @export
+eigen_centrality <- function(graph, directed=FALSE, scale=TRUE, weights=NULL, options=arpack_defaults) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   directed <- as.logical(directed)
   scale <- as.logical(scale)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -399,23 +443,24 @@ evcent <- function(graph, directed=FALSE, scale=TRUE, weights=NULL, options=igra
   } else { 
   weights <- NULL 
   }
-  options.tmp <- igraph.arpack.default; options.tmp[ names(options) ] <- options ; options <- options.tmp
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_eigenvector_centrality", graph, directed, scale, weights, options,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res$vector) <- get.vertex.attribute(graph, "name", ) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res$vector) <- vertex_attr(graph, "name", ) 
   }
   res
 }
 
-hub.score <- function(graph, scale=TRUE, weights=NULL, options=igraph.arpack.default) {
+#' @export
+hub_score <- function(graph, scale=TRUE, weights=NULL, options=arpack_defaults) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   scale <- as.logical(scale)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -423,23 +468,24 @@ hub.score <- function(graph, scale=TRUE, weights=NULL, options=igraph.arpack.def
   } else { 
   weights <- NULL 
   }
-  options.tmp <- igraph.arpack.default; options.tmp[ names(options) ] <- options ; options <- options.tmp
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_hub_score", graph, scale, weights, options,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res$vector) <- get.vertex.attribute(graph, "name", ) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res$vector) <- vertex_attr(graph, "name", ) 
   }
   res
 }
 
-authority.score <- function(graph, scale=TRUE, weights=NULL, options=igraph.arpack.default) {
+#' @export
+authority_score <- function(graph, scale=TRUE, weights=NULL, options=arpack_defaults) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   scale <- as.logical(scale)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -447,35 +493,22 @@ authority.score <- function(graph, scale=TRUE, weights=NULL, options=igraph.arpa
   } else { 
   weights <- NULL 
   }
-  options.tmp <- igraph.arpack.default; options.tmp[ names(options) ] <- options ; options <- options.tmp
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_authority_score", graph, scale, weights, options,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res$vector) <- get.vertex.attribute(graph, "name", ) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res$vector) <- vertex_attr(graph, "name", ) 
   }
   res
 }
 
-arpack.unpack.complex <- function(vectors, values, nev) {
-  # Argument checks
-  vectors <- as.matrix(structure(as.double(vectors), dim=dim(vectors)))
-  values <- as.matrix(structure(as.double(values), dim=dim(values)))
-  nev <- as.integer(nev)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_arpack_unpack_complex", vectors, values, nev,
-        PACKAGE="igraph")
-
-  res
-}
-
-is.mutual <- function(graph, es=E(graph)) {
+#' @export
+which_mutual <- function(graph, es=E(graph)) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   es <- as.igraph.es(graph, es)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -486,23 +519,27 @@ is.mutual <- function(graph, es=E(graph)) {
   res
 }
 
-maximum.cardinality.search <- function(graph) {
+#' @export
+max_cardinality <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_maximum_cardinality_search", graph,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  res$alpha <- create_vs(graph, res$alpha) 
+  }
   res
 }
 
-graph.knn <- function(graph, vids=V(graph), weights=NULL) {
+#' @export
+knn <- function(graph, vids=V(graph), weights=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -515,19 +552,20 @@ graph.knn <- function(graph, vids=V(graph), weights=NULL) {
   # Function call
   res <- .Call("R_igraph_avg_nearest_neighbor_degree", graph, vids-1, weights,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res$knn) <- get.vertex.attribute(graph, "name", vids) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res$knn) <- vertex_attr(graph, "name", vids) 
   }
   res
 }
 
-graph.strength <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total"), loops=TRUE, weights=NULL) {
+#' @export
+strength <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total"), loops=TRUE, weights=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   loops <- as.logical(loops)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -540,13 +578,14 @@ graph.strength <- function(graph, vids=V(graph), mode=c("all", "out", "in", "tot
   # Function call
   res <- .Call("R_igraph_strength", graph, vids-1, mode, loops, weights,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res) <- get.vertex.attribute(graph, "name", vids) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res) <- vertex_attr(graph, "name", vids) 
   }
   res
 }
 
-centralize.scores <- function(scores, theoretical.max=0, normalized=TRUE) {
+#' @export
+centralize <- function(scores, theoretical.max=0, normalized=TRUE) {
   # Argument checks
   scores <- as.numeric(scores)
   theoretical.max <- as.numeric(theoretical.max)
@@ -561,9 +600,10 @@ centralize.scores <- function(scores, theoretical.max=0, normalized=TRUE) {
   res
 }
 
-centralization.degree <- function(graph, mode=c("all", "out", "in", "total"), loops=TRUE, normalized=TRUE) {
+#' @export
+centr_degree <- function(graph, mode=c("all", "out", "in", "total"), loops=TRUE, normalized=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   loops <- as.logical(loops)
   normalized <- as.logical(normalized)
@@ -576,9 +616,10 @@ centralization.degree <- function(graph, mode=c("all", "out", "in", "total"), lo
   res
 }
 
-centralization.degree.tmax <- function(graph=NULL, nodes=0, mode=c("all", "out", "in", "total"), loops=FALSE) {
+#' @export
+centr_degree_tmax <- function(graph=NULL, nodes=0, mode=c("all", "out", "in", "total"), loops=FALSE) {
   # Argument checks
-  if (!is.null(graph) && !is.igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(graph) && !is_igraph(graph)) { stop("Not a graph object") }
   nodes <- as.integer(nodes)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   loops <- as.logical(loops)
@@ -591,9 +632,10 @@ centralization.degree.tmax <- function(graph=NULL, nodes=0, mode=c("all", "out",
   res
 }
 
-centralization.betweenness <- function(graph, directed=TRUE, nobigint=TRUE, normalized=TRUE) {
+#' @export
+centr_betw <- function(graph, directed=TRUE, nobigint=TRUE, normalized=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   directed <- as.logical(directed)
   nobigint <- as.logical(nobigint)
   normalized <- as.logical(normalized)
@@ -606,9 +648,10 @@ centralization.betweenness <- function(graph, directed=TRUE, nobigint=TRUE, norm
   res
 }
 
-centralization.betweenness.tmax <- function(graph=NULL, nodes=0, directed=TRUE) {
+#' @export
+centr_betw_tmax <- function(graph=NULL, nodes=0, directed=TRUE) {
   # Argument checks
-  if (!is.null(graph) && !is.igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(graph) && !is_igraph(graph)) { stop("Not a graph object") }
   nodes <- as.integer(nodes)
   directed <- as.logical(directed)
 
@@ -620,9 +663,10 @@ centralization.betweenness.tmax <- function(graph=NULL, nodes=0, directed=TRUE)
   res
 }
 
-centralization.closeness <- function(graph, mode=c("out", "in", "all", "total"), normalized=TRUE) {
+#' @export
+centr_clo <- function(graph, mode=c("out", "in", "all", "total"), normalized=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   normalized <- as.logical(normalized)
 
@@ -634,9 +678,10 @@ centralization.closeness <- function(graph, mode=c("out", "in", "all", "total"),
   res
 }
 
-centralization.closeness.tmax <- function(graph=NULL, nodes=0, mode=c("out", "in", "all", "total")) {
+#' @export
+centr_clo_tmax <- function(graph=NULL, nodes=0, mode=c("out", "in", "all", "total")) {
   # Argument checks
-  if (!is.null(graph) && !is.igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(graph) && !is_igraph(graph)) { stop("Not a graph object") }
   nodes <- as.integer(nodes)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
 
@@ -648,12 +693,13 @@ centralization.closeness.tmax <- function(graph=NULL, nodes=0, mode=c("out", "in
   res
 }
 
-centralization.evcent <- function(graph, directed=FALSE, scale=TRUE, options=igraph.arpack.default, normalized=TRUE) {
+#' @export
+centr_eigen <- function(graph, directed=FALSE, scale=TRUE, options=arpack_defaults, normalized=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   directed <- as.logical(directed)
   scale <- as.logical(scale)
-  options.tmp <- igraph.arpack.default; options.tmp[ names(options) ] <- options ; options <- options.tmp
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
   normalized <- as.logical(normalized)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -664,9 +710,10 @@ centralization.evcent <- function(graph, directed=FALSE, scale=TRUE, options=igr
   res
 }
 
-centralization.evcent.tmax <- function(graph=NULL, nodes=0, directed=FALSE, scale=TRUE) {
+#' @export
+centr_eigen_tmax <- function(graph=NULL, nodes=0, directed=FALSE, scale=TRUE) {
   # Argument checks
-  if (!is.null(graph) && !is.igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(graph) && !is_igraph(graph)) { stop("Not a graph object") }
   nodes <- as.integer(nodes)
   directed <- as.logical(directed)
   scale <- as.logical(scale)
@@ -679,9 +726,10 @@ centralization.evcent.tmax <- function(graph=NULL, nodes=0, directed=FALSE, scal
   res
 }
 
-assortativity.nominal <- function(graph, types, directed=TRUE) {
+#' @export
+assortativity_nominal <- function(graph, types, directed=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   types <- as.numeric(types)-1
   directed <- as.logical(directed)
 
@@ -693,9 +741,10 @@ assortativity.nominal <- function(graph, types, directed=TRUE) {
   res
 }
 
+#' @export
 assortativity <- function(graph, types1, types2=NULL, directed=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   types1 <- as.numeric(types1)
   if (!is.null(types2)) types2 <- as.numeric(types2)
   directed <- as.logical(directed)
@@ -708,9 +757,10 @@ assortativity <- function(graph, types1, types2=NULL, directed=TRUE) {
   res
 }
 
-assortativity.degree <- function(graph, directed=TRUE) {
+#' @export
+assortativity_degree <- function(graph, directed=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   directed <- as.logical(directed)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -721,9 +771,10 @@ assortativity.degree <- function(graph, directed=TRUE) {
   res
 }
 
-contract.vertices <- function(graph, mapping, vertex.attr.comb=getIgraphOpt("vertex.attr.comb")) {
+#' @export
+contract <- function(graph, mapping, vertex.attr.comb=igraph_opt("vertex.attr.comb")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   mapping <- as.numeric(mapping)-1
   vertex.attr.comb <- igraph.i.attribute.combination(vertex.attr.comb)
 
@@ -735,9 +786,10 @@ contract.vertices <- function(graph, mapping, vertex.attr.comb=getIgraphOpt("ver
   res
 }
 
+#' @export
 eccentricity <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
 
@@ -745,15 +797,16 @@ eccentricity <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total
   # Function call
   res <- .Call("R_igraph_eccentricity", graph, vids-1, mode,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res) <- get.vertex.attribute(graph, "name", vids) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res) <- vertex_attr(graph, "name", vids) 
   }
   res
 }
 
+#' @export
 radius <- function(graph, mode=c("all", "out", "in", "total")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -764,10 +817,11 @@ radius <- function(graph, mode=c("all", "out", "in", "total")) {
   res
 }
 
-graph.diversity <- function(graph, weights=NULL, vids=V(graph)) {
+#' @export
+diversity <- function(graph, weights=NULL, vids=V(graph)) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -781,13 +835,14 @@ graph.diversity <- function(graph, weights=NULL, vids=V(graph)) {
   # Function call
   res <- .Call("R_igraph_diversity", graph, weights, vids-1,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-  names(res) <- get.vertex.attribute(graph, "name", vids) 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res) <- vertex_attr(graph, "name", vids) 
   }
   res
 }
 
-is.degree.sequence <- function(out.deg, in.deg=NULL) {
+#' @export
+is_degseq <- function(out.deg, in.deg=NULL) {
   # Argument checks
   out.deg <- as.numeric(out.deg)
   if (!is.null(in.deg)) in.deg <- as.numeric(in.deg)
@@ -800,7 +855,8 @@ is.degree.sequence <- function(out.deg, in.deg=NULL) {
   res
 }
 
-is.graphical.degree.sequence <- function(out.deg, in.deg=NULL) {
+#' @export
+is_graphical <- function(out.deg, in.deg=NULL) {
   # Argument checks
   out.deg <- as.numeric(out.deg)
   if (!is.null(in.deg)) in.deg <- as.numeric(in.deg)
@@ -813,10 +869,11 @@ is.graphical.degree.sequence <- function(out.deg, in.deg=NULL) {
   res
 }
 
-bipartite.projection.size <- function(graph, types=NULL) {
+#' @export
+bipartite_projection_size <- function(graph, types=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) { 
   types <- V(graph)$type 
   } 
   if (!is.null(types)) { 
@@ -839,9 +896,10 @@ bipartite.projection.size <- function(graph, types=NULL) {
   res
 }
 
-bipartite.mapping <- function(graph) {
+#' @export
+bipartite_mapping <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -851,103 +909,55 @@ bipartite.mapping <- function(graph) {
   res
 }
 
-articulation.points <- function(graph) {
+#' @export
+articulation_points <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_articulation_points", graph,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  res <- create_vs(graph, res) 
+  }
   res
 }
 
-biconnected.components <- function(graph) {
+#' @export
+biconnected_components <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_biconnected_components", graph,
         PACKAGE="igraph")
-
-  res
-}
-
-layout.star <- function(graph, center=V(graph)[1], order=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  center <- as.igraph.vs(graph, center)
-  if (!is.null(order)) order <- as.numeric(order)-1
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_layout_star", graph, center-1, order,
-        PACKAGE="igraph")
-
-  res
-}
-
-layout.grid <- function(graph, width=0) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  width <- as.integer(width)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_layout_grid", graph, width,
-        PACKAGE="igraph")
-
-  res
-}
-
-layout.grid.3d <- function(graph, width=0, height=0) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  width <- as.integer(width)
-  height <- as.integer(height)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_layout_grid_3d", graph, width, height,
-        PACKAGE="igraph")
-
-  res
-}
-
-layout.bipartite <- function(graph, types=NULL, hgap=1, vgap=1, maxiter=100) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
-  types <- V(graph)$type 
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$tree_edges)) { 
+  res$tree_edges[[i_]] <- create_es(graph, res$tree_edges[[i_]]) 
   } 
-  if (!is.null(types)) { 
-  if (!is.logical(types)) { 
-  warning("vertex types converted to logical") 
+  }
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$component_edges)) { 
+  res$component_edges[[i_]] <- create_es(graph, res$component_edges[[i_]]) 
   } 
-  types <- as.logical(types) 
-  if (any(is.na(types))) { 
-  stop("`NA' is not allowed in vertex types") 
+  }
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$components)) { 
+  res$components[[i_]] <- create_vs(graph, res$components[[i_]]) 
   } 
-  } else { 
-  stop("Not a bipartite graph, supply `types' argument") 
   }
-  hgap <- as.numeric(hgap)
-  vgap <- as.numeric(vgap)
-  maxiter <- as.integer(maxiter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_layout_bipartite", graph, types, hgap, vgap, maxiter,
-        PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  res$articulation_points <- create_vs(graph, res$articulation_points) 
+  }
   res
 }
 
+#' @export
 similarity.jaccard <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total"), loops=FALSE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   loops <- as.logical(loops)
@@ -960,9 +970,10 @@ similarity.jaccard <- function(graph, vids=V(graph), mode=c("all", "out", "in",
   res
 }
 
+#' @export
 similarity.dice <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total"), loops=FALSE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   loops <- as.logical(loops)
@@ -975,9 +986,10 @@ similarity.dice <- function(graph, vids=V(graph), mode=c("all", "out", "in", "to
   res
 }
 
+#' @export
 similarity.invlogweighted <- function(graph, vids=V(graph), mode=c("all", "out", "in", "total")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
 
@@ -989,54 +1001,8 @@ similarity.invlogweighted <- function(graph, vids=V(graph), mode=c("all", "out",
   res
 }
 
-community.le.to.membership <- function(merges, steps, membership) {
-  # Argument checks
-  merges <- as.matrix(structure(as.double(merges), dim=dim(merges)))
-  steps <- as.integer(steps)
-  membership <- as.numeric(membership)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_le_community_to_membership", merges, steps, membership,
-        PACKAGE="igraph")
-
-  res
-}
-
-mod.matrix <- function(graph, membership, weights=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  membership <- as.numeric(membership)-1
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
-  weights <- E(graph)$weight 
-  } 
-  if (!is.null(weights) && any(!is.na(weights))) { 
-  weights <- as.numeric(weights) 
-  } else { 
-  weights <- NULL 
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_modularity_matrix", graph, membership, weights,
-        PACKAGE="igraph")
-
-  res
-}
-
-reindex.membership <- function(membership) {
-  # Argument checks
-  membership <- as.numeric(membership)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_reindex_membership", membership,
-        PACKAGE="igraph")
-
-  res
-}
-
-hrg.game <- function(hrg) {
+#' @export
+sample_hrg <- function(hrg) {
   # Argument checks
   if (is.null(hrg)) { 
   hrg <- list(left=c(), right=c(), prob=c(), edges=c(), 
@@ -1054,7 +1020,8 @@ hrg.game <- function(hrg) {
   res
 }
 
-hrg.dendrogram <- function(hrg) {
+#' @export
+hrg_tree <- function(hrg) {
   # Argument checks
   if (is.null(hrg)) { 
   hrg <- list(left=c(), right=c(), prob=c(), edges=c(), 
@@ -1071,9 +1038,10 @@ hrg.dendrogram <- function(hrg) {
   res
 }
 
-hrg.consensus <- function(graph, hrg=NULL, start=FALSE, num.samples=10000) {
+#' @export
+consensus_tree <- function(graph, hrg=NULL, start=FALSE, num.samples=10000) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   if (is.null(hrg)) { 
   hrg <- list(left=c(), right=c(), prob=c(), edges=c(), 
   vertices=c()) 
@@ -1091,9 +1059,10 @@ hrg.consensus <- function(graph, hrg=NULL, start=FALSE, num.samples=10000) {
   res
 }
 
-hrg.create <- function(graph, prob) {
+#' @export
+hrg <- function(graph, prob) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   prob <- as.numeric(prob)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -1105,10 +1074,11 @@ hrg.create <- function(graph, prob) {
   res
 }
 
+#' @export
 graphlets <- function(graph, weights=NULL, niter=1000) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -1122,67 +1092,76 @@ graphlets <- function(graph, weights=NULL, niter=1000) {
   # Function call
   res <- .Call("R_igraph_graphlets", graph, weights, niter,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$cliques)) { 
+  res$cliques[[i_]] <- create_vs(graph, res$cliques[[i_]]) 
+  } 
+  }
   res
 }
 
-as.undirected <- function(graph, mode=c("collapse", "each", "mutual"), edge.attr.comb=getIgraphOpt("edge.attr.comb")) {
+#' @export
+dyad_census <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  mode <- switch(igraph.match.arg(mode), "collapse"=1, "each"=0, "mutual"=2)
-  edge.attr.comb <- igraph.i.attribute.combination(edge.attr.comb)
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_to_undirected", graph, mode, edge.attr.comb,
+  res <- .Call("R_igraph_dyad_census", graph,
         PACKAGE="igraph")
 
   res
 }
 
-dyad.census <- function(graph) {
+#' @export
+triad_census <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_dyad_census", graph,
+  res <- .Call("R_igraph_triad_census", graph,
         PACKAGE="igraph")
 
   res
 }
 
-triad.census <- function(graph) {
+#' @export
+count_triangles <- function(graph, vids=V(graph)) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  vids <- as.igraph.vs(graph, vids)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_triad_census", graph,
+  res <- .Call("R_igraph_adjacent_triangles", graph, vids-1,
         PACKAGE="igraph")
 
   res
 }
 
-adjacent.triangles <- function(graph, vids=V(graph)) {
+#' @export
+triangles <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  vids <- as.igraph.vs(graph, vids)
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_adjacent_triangles", graph, vids-1,
+  res <- .Call("R_igraph_list_triangles", graph,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  res <- create_vs(graph, res) 
+  }
   res
 }
 
-graph.maxflow <- function(graph, source, target, capacity=NULL) {
+#' @export
+max_flow <- function(graph, source, target, capacity=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   source <- as.igraph.vs(graph, source)
   target <- as.igraph.vs(graph, target)
-  if (is.null(capacity) && "capacity" %in% list.edge.attributes(graph)) { 
+  if (is.null(capacity) && "capacity" %in% edge_attr_names(graph)) { 
   capacity <- E(graph)$capacity 
   } 
   if (!is.null(capacity) && any(!is.na(capacity))) { 
@@ -1195,13 +1174,19 @@ graph.maxflow <- function(graph, source, target, capacity=NULL) {
   # Function call
   res <- .Call("R_igraph_maxflow", graph, source-1, target-1, capacity,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  res$partition1 <- create_vs(graph, res$partition1) 
+  }
+  if (igraph_opt("return.vs.es")) { 
+  res$partition2 <- create_vs(graph, res$partition2) 
+  }
   res
 }
 
-dominator.tree <- function(graph, root, mode=c("out", "in")) {
+#' @export
+dominator_tree <- function(graph, root, mode=c("out", "in")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   root <- as.igraph.vs(graph, root)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2)
 
@@ -1209,13 +1194,19 @@ dominator.tree <- function(graph, root, mode=c("out", "in")) {
   # Function call
   res <- .Call("R_igraph_dominator_tree", graph, root-1, mode,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  res$dom <- create_vs(graph, res$dom) 
+  }
+  if (igraph_opt("return.vs.es")) { 
+  res$leftout <- create_vs(graph, res$leftout) 
+  }
   res
 }
 
-stCuts <- function(graph, source, target) {
+#' @export
+st_cuts <- function(graph, source, target) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   source <- as.igraph.vs(graph, source)
   target <- as.igraph.vs(graph, target)
 
@@ -1223,16 +1214,26 @@ stCuts <- function(graph, source, target) {
   # Function call
   res <- .Call("R_igraph_all_st_cuts", graph, source-1, target-1,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$cuts)) { 
+  res$cuts[[i_]] <- create_es(graph, res$cuts[[i_]]) 
+  } 
+  }
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$partition1s)) { 
+  res$partition1s[[i_]] <- create_vs(graph, res$partition1s[[i_]]) 
+  } 
+  }
   res
 }
 
-stMincuts <- function(graph, source, target, capacity=NULL) {
+#' @export
+st_min_cuts <- function(graph, source, target, capacity=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   source <- as.igraph.vs(graph, source)
   target <- as.igraph.vs(graph, target)
-  if (is.null(capacity) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(capacity) && "weight" %in% edge_attr_names(graph)) { 
   capacity <- E(graph)$weight 
   } 
   if (!is.null(capacity) && any(!is.na(capacity))) { 
@@ -1245,13 +1246,23 @@ stMincuts <- function(graph, source, target, capacity=NULL) {
   # Function call
   res <- .Call("R_igraph_all_st_mincuts", graph, source-1, target-1, capacity,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$cuts)) { 
+  res$cuts[[i_]] <- create_es(graph, res$cuts[[i_]]) 
+  } 
+  }
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res$partition1s)) { 
+  res$partition1s[[i_]] <- create_vs(graph, res$partition1s[[i_]]) 
+  } 
+  }
   res
 }
 
-is.separator <- function(graph, candidate) {
+#' @export
+is_separator <- function(graph, candidate) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   candidate <- as.igraph.vs(graph, candidate)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -1262,9 +1273,10 @@ is.separator <- function(graph, candidate) {
   res
 }
 
-is.minimal.separator <- function(graph, candidate) {
+#' @export
+is_min_separator <- function(graph, candidate) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   candidate <- as.igraph.vs(graph, candidate)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -1275,33 +1287,44 @@ is.minimal.separator <- function(graph, candidate) {
   res
 }
 
-minimal.st.separators <- function(graph) {
+#' @export
+min_st_separators <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_all_minimal_st_separators", graph,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res)) { 
+  res[[i_]] <- create_vs(graph, res[[i_]]) 
+  } 
+  }
   res
 }
 
-minimum.size.separators <- function(graph) {
+#' @export
+min_separators <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_minimum_size_separators", graph,
         PACKAGE="igraph")
-
+  if (igraph_opt("return.vs.es")) { 
+  for (i_ in seq_along(res)) { 
+  res[[i_]] <- create_vs(graph, res[[i_]]) 
+  } 
+  }
   res
 }
 
+#' @export
 graph.isoclass <- function(graph) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -1311,10 +1334,11 @@ graph.isoclass <- function(graph) {
   res
 }
 
+#' @export
 graph.isomorphic <- function(graph1, graph2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -1324,7 +1348,8 @@ graph.isomorphic <- function(graph1, graph2) {
   res
 }
 
-graph.isocreate <- function(size, number, directed=TRUE) {
+#' @export
+graph_from_isomorphism_class <- function(size, number, directed=TRUE) {
   # Argument checks
   size <- as.integer(size)
   number <- as.integer(number)
@@ -1338,12 +1363,13 @@ graph.isocreate <- function(size, number, directed=TRUE) {
   res
 }
 
+#' @export
 graph.isomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, edge.color1, edge.color2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
   if (missing(vertex.color1)) { 
-  if ("color" %in% list.vertex.attributes(graph1)) { 
+  if ("color" %in% vertex_attr_names(graph1)) { 
   vertex.color1 <- V(graph1)$color 
   } else { 
   vertex.color1 <- NULL 
@@ -1353,7 +1379,7 @@ graph.isomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, e
   vertex.color1 <- as.integer(vertex.color1)-1L 
   }
   if (missing(vertex.color2)) { 
-  if ("color" %in% list.vertex.attributes(graph2)) { 
+  if ("color" %in% vertex_attr_names(graph2)) { 
   vertex.color2 <- V(graph2)$color 
   } else { 
   vertex.color2 <- NULL 
@@ -1363,7 +1389,7 @@ graph.isomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, e
   vertex.color2 <- as.integer(vertex.color2)-1L 
   }
   if (missing(edge.color1)) { 
-  if ("color" %in% list.edge.attributes(graph1)) { 
+  if ("color" %in% edge_attr_names(graph1)) { 
   edge.color1 <- E(graph1)$color 
   } else { 
   edge.color1 <- NULL 
@@ -1373,7 +1399,7 @@ graph.isomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, e
   edge.color1 <- as.integer(edge.color1)-1L 
   }
   if (missing(edge.color2)) { 
-  if ("color" %in% list.edge.attributes(graph2)) { 
+  if ("color" %in% edge_attr_names(graph2)) { 
   edge.color2 <- E(graph2)$color 
   } else { 
   edge.color2 <- NULL 
@@ -1391,12 +1417,13 @@ graph.isomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, e
   res
 }
 
+#' @export
 graph.count.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, edge.color1, edge.color2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
   if (missing(vertex.color1)) { 
-  if ("color" %in% list.vertex.attributes(graph1)) { 
+  if ("color" %in% vertex_attr_names(graph1)) { 
   vertex.color1 <- V(graph1)$color 
   } else { 
   vertex.color1 <- NULL 
@@ -1406,7 +1433,7 @@ graph.count.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1, vertex.c
   vertex.color1 <- as.integer(vertex.color1)-1L 
   }
   if (missing(vertex.color2)) { 
-  if ("color" %in% list.vertex.attributes(graph2)) { 
+  if ("color" %in% vertex_attr_names(graph2)) { 
   vertex.color2 <- V(graph2)$color 
   } else { 
   vertex.color2 <- NULL 
@@ -1416,7 +1443,7 @@ graph.count.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1, vertex.c
   vertex.color2 <- as.integer(vertex.color2)-1L 
   }
   if (missing(edge.color1)) { 
-  if ("color" %in% list.edge.attributes(graph1)) { 
+  if ("color" %in% edge_attr_names(graph1)) { 
   edge.color1 <- E(graph1)$color 
   } else { 
   edge.color1 <- NULL 
@@ -1426,7 +1453,7 @@ graph.count.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1, vertex.c
   edge.color1 <- as.integer(edge.color1)-1L 
   }
   if (missing(edge.color2)) { 
-  if ("color" %in% list.edge.attributes(graph2)) { 
+  if ("color" %in% edge_attr_names(graph2)) { 
   edge.color2 <- E(graph2)$color 
   } else { 
   edge.color2 <- NULL 
@@ -1444,12 +1471,13 @@ graph.count.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1, vertex.c
   res
 }
 
+#' @export
 graph.subisomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, edge.color1, edge.color2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
   if (missing(vertex.color1)) { 
-  if ("color" %in% list.vertex.attributes(graph1)) { 
+  if ("color" %in% vertex_attr_names(graph1)) { 
   vertex.color1 <- V(graph1)$color 
   } else { 
   vertex.color1 <- NULL 
@@ -1459,7 +1487,7 @@ graph.subisomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2
   vertex.color1 <- as.integer(vertex.color1)-1L 
   }
   if (missing(vertex.color2)) { 
-  if ("color" %in% list.vertex.attributes(graph2)) { 
+  if ("color" %in% vertex_attr_names(graph2)) { 
   vertex.color2 <- V(graph2)$color 
   } else { 
   vertex.color2 <- NULL 
@@ -1469,7 +1497,7 @@ graph.subisomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2
   vertex.color2 <- as.integer(vertex.color2)-1L 
   }
   if (missing(edge.color1)) { 
-  if ("color" %in% list.edge.attributes(graph1)) { 
+  if ("color" %in% edge_attr_names(graph1)) { 
   edge.color1 <- E(graph1)$color 
   } else { 
   edge.color1 <- NULL 
@@ -1479,7 +1507,7 @@ graph.subisomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2
   edge.color1 <- as.integer(edge.color1)-1L 
   }
   if (missing(edge.color2)) { 
-  if ("color" %in% list.edge.attributes(graph2)) { 
+  if ("color" %in% edge_attr_names(graph2)) { 
   edge.color2 <- E(graph2)$color 
   } else { 
   edge.color2 <- NULL 
@@ -1497,12 +1525,13 @@ graph.subisomorphic.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2
   res
 }
 
+#' @export
 graph.count.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1, vertex.color2, edge.color1, edge.color2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
   if (missing(vertex.color1)) { 
-  if ("color" %in% list.vertex.attributes(graph1)) { 
+  if ("color" %in% vertex_attr_names(graph1)) { 
   vertex.color1 <- V(graph1)$color 
   } else { 
   vertex.color1 <- NULL 
@@ -1512,7 +1541,7 @@ graph.count.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1, verte
   vertex.color1 <- as.integer(vertex.color1)-1L 
   }
   if (missing(vertex.color2)) { 
-  if ("color" %in% list.vertex.attributes(graph2)) { 
+  if ("color" %in% vertex_attr_names(graph2)) { 
   vertex.color2 <- V(graph2)$color 
   } else { 
   vertex.color2 <- NULL 
@@ -1522,7 +1551,7 @@ graph.count.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1, verte
   vertex.color2 <- as.integer(vertex.color2)-1L 
   }
   if (missing(edge.color1)) { 
-  if ("color" %in% list.edge.attributes(graph1)) { 
+  if ("color" %in% edge_attr_names(graph1)) { 
   edge.color1 <- E(graph1)$color 
   } else { 
   edge.color1 <- NULL 
@@ -1532,7 +1561,7 @@ graph.count.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1, verte
   edge.color1 <- as.integer(edge.color1)-1L 
   }
   if (missing(edge.color2)) { 
-  if ("color" %in% list.edge.attributes(graph2)) { 
+  if ("color" %in% edge_attr_names(graph2)) { 
   edge.color2 <- E(graph2)$color 
   } else { 
   edge.color2 <- NULL 
@@ -1550,10 +1579,11 @@ graph.count.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1, verte
   res
 }
 
+#' @export
 graph.isomorphic.34 <- function(graph1, graph2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -1563,9 +1593,10 @@ graph.isomorphic.34 <- function(graph1, graph2) {
   res
 }
 
-canonical.permutation <- function(graph, sh="fm") {
+#' @export
+canonical_permutation <- function(graph, sh="fm") {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   sh <- switch(igraph.match.arg(sh), "f"=0, "fl"=1, "fs"=2, "fm"=3, "flm"=4, "fsm"=5)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -1576,9 +1607,10 @@ canonical.permutation <- function(graph, sh="fm") {
   res
 }
 
-permute.vertices <- function(graph, permutation) {
+#' @export
+permute <- function(graph, permutation) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   permutation <- as.numeric(permutation)-1
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -1589,10 +1621,11 @@ permute.vertices <- function(graph, permutation) {
   res
 }
 
+#' @export
 graph.isomorphic.bliss <- function(graph1, graph2, sh1="fm", sh2="fm") {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
   sh1 <- switch(igraph.match.arg(sh1), "f"=0, "fl"=1, "fs"=2, "fm"=3, "flm"=4, "fsm"=5)
   sh2 <- switch(igraph.match.arg(sh2), "f"=0, "fl"=1, "fs"=2, "fm"=3, "flm"=4, "fsm"=5)
 
@@ -1604,9 +1637,10 @@ graph.isomorphic.bliss <- function(graph1, graph2, sh1="fm", sh2="fm") {
   res
 }
 
-graph.automorphisms <- function(graph, sh="fm") {
+#' @export
+automorphisms <- function(graph, sh="fm") {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   sh <- switch(igraph.match.arg(sh), "f"=0, "fl"=1, "fs"=2, "fm"=3, "flm"=4, "fsm"=5)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -1617,7 +1651,8 @@ graph.automorphisms <- function(graph, sh="fm") {
   res
 }
 
-scgNormEps <- function(V, groups, mtype=c("symmetric", "laplacian", "stochastic"), p=NULL, norm=c("row", "col")) {
+#' @export
+scg_eps <- function(V, groups, mtype=c("symmetric", "laplacian", "stochastic"), p=NULL, norm=c("row", "col")) {
   # Argument checks
   V <- as.matrix(structure(as.double(V), dim=dim(V)))
   groups <- as.numeric(groups)-1
@@ -1634,439 +1669,119 @@ scgNormEps <- function(V, groups, mtype=c("symmetric", "laplacian", "stochastic"
   res
 }
 
-graph.eigen <- function(graph, algorithm=c("arpack", "auto", "lapack", "comp_auto", "comp_lapack", "comp_arpack"), which=list(), options=igraph.arpack.default) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  algorithm <- switch(igraph.match.arg(algorithm), "auto"=0, "lapack"=1, 
-  "arpack"=2, "comp_auto"=3, "comp_lapack"=4, 
-  "comp_arpack"=5)
-  which.tmp <- igraph.eigen.default; 
-  which.tmp[ names(which) ] <- which ; which <- which.tmp
-  options.tmp <- igraph.arpack.default; options.tmp[ names(options) ] <- options ; options <- options.tmp
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_eigen_adjacency", graph, algorithm, which, options,
-        PACKAGE="igraph")
-
-  res
-}
-
-power.law.fit.new <- function(data, xmin=-1, force.continuous=FALSE) {
-  # Argument checks
-  data <- as.numeric(data)
-  xmin <- as.numeric(xmin)
-  force.continuous <- as.logical(force.continuous)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_power_law_fit", data, xmin, force.continuous,
-        PACKAGE="igraph")
-
-  res
-}
-
-sir <- function(graph, beta, gamma, no.sim=100) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  beta <- as.numeric(beta)
-  gamma <- as.numeric(gamma)
-  no.sim <- as.integer(no.sim)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_sir", graph, beta, gamma, no.sim,
-        PACKAGE="igraph")
-
-  class(res) <- "sir"
-  res
-}
-
-convex.hull <- function(data) {
-  # Argument checks
-  data <- as.matrix(structure(as.double(data), dim=dim(data)))
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_convex_hull", data,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.d <- function(graph, niter, delta=1e-10, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  delta <- as.numeric(delta)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_d", graph, niter, delta, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.probs.d <- function(graph, kernel, ntk=FALSE) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  kernel <- as.numeric(kernel)
-  ntk <- as.logical(ntk)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_probs_d", graph, kernel, ntk,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.de <- function(graph, niter, cats, delta=1e-10, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  cats <- as.numeric(cats)
-  delta <- as.numeric(delta)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_de", graph, niter, cats, delta, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.probs.de <- function(graph, kernel, cats) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  kernel <- as.matrix(structure(as.double(kernel), dim=dim(kernel)))
-  cats <- as.numeric(cats)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_probs_de", graph, kernel, cats,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.ade <- function(graph, niter, cats, agebins=300, delta=1e-10, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  cats <- as.numeric(cats)
-  agebins <- as.integer(agebins)
-  delta <- as.numeric(delta)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_ade", graph, niter, cats, agebins, delta, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.probs.ade <- function(graph, kernel, cats) {
+#' @export
+embed_adjacency_matrix <- function(graph, no, weights=NULL, which=c("lm", "la", "sa"), scaled=TRUE, cvec=graph.strength(graph, weights=weights)/(vcount(graph)-1), options=igraph.arpack.default) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  kernel <- structure(as.double(kernel), dim=dim(kernel))
-  cats <- as.numeric(cats)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_probs_ade", graph, kernel, cats,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.f <- function(graph, niter, delta=1e-10) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  delta <- as.numeric(delta)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_f", graph, niter, delta,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.df <- function(graph, niter, delta=1e-10) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  delta <- as.numeric(delta)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_df", graph, niter, delta,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.l <- function(graph, niter, agebins=300, delta=1e-10) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  agebins <- as.integer(agebins)
-  delta <- as.numeric(delta)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_l", graph, niter, agebins, delta,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.ad <- function(graph, niter, agebins=300, delta=1e-10, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  niter <- as.integer(niter)
-  agebins <- as.integer(agebins)
-  delta <- as.numeric(delta)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_ad", graph, niter, agebins, delta, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.probs.ad <- function(graph, kernel, ntk=FALSE) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  kernel <- as.matrix(structure(as.double(kernel), dim=dim(kernel)))
-  ntk <- as.logical(ntk)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_probs_ad", graph, kernel, ntk,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.D.alpha <- function(graph, alpha, abstol=1e-8, reltol=1e-8, maxit=1000, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  alpha <- as.numeric(alpha)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_D_alpha", graph, alpha, abstol, reltol, maxit, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.D.alpha.a <- function(graph, alpha, a, abstol=1e-8, reltol=1e-8, maxit=1000, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_D_alpha_a", graph, alpha, a, abstol, reltol, maxit, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.DE.alpha.a <- function(graph, cats, alpha, a, coeffs, abstol=1e-8, reltol=1e-8, maxit=1000, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  cats <- as.numeric(cats)
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  coeffs <- as.numeric(coeffs)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_DE_alpha_a", graph, cats, alpha, a, coeffs, abstol, reltol, maxit, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.AD.alpha.a.beta <- function(graph, alpha, a, beta, abstol=1e-8, reltol=1e-8, maxit=1000, agebins=300, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  beta <- as.numeric(beta)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  no <- as.integer(no)
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
+  weights <- E(graph)$weight 
+  } 
+  if (!is.null(weights) && any(!is.na(weights))) { 
+  weights <- as.numeric(weights) 
+  } else { 
+  weights <- NULL 
+  }
+  which <- switch(igraph.match.arg(which), "lm"=0L, "la"=2L, "sa"=3L)
+  scaled <- as.logical(scaled)
+  cvec <- as.numeric(cvec)
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_revolver_ml_AD_alpha_a_beta", graph, alpha, a, beta, abstol, reltol, maxit, agebins, filter,
+  res <- .Call("R_igraph_adjacency_spectral_embedding", graph, no, weights, which, scaled, cvec, options,
         PACKAGE="igraph")
 
   res
 }
 
-revolver.ml.AD.dpareto <- function(graph, alpha, a, paralpha, parbeta, parscale, abstol=1e-8, reltol=1e-8, maxit=1000, agebins=300, filter=NULL) {
+#' @export
+embed_laplacian_matrix <- function(graph, no, weights=NULL, which=c("lm", "la", "sa"), degmode=c("out", "in", "all", "total"), type=c("default", "D-A", "DAD", "I-DAD", "OAP"), scaled=TRUE, options=igraph.arpack.default) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  paralpha <- as.numeric(paralpha)
-  parbeta <- as.numeric(parbeta)
-  parscale <- as.numeric(parscale)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  no <- as.integer(no)
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
+  weights <- E(graph)$weight 
+  } 
+  if (!is.null(weights) && any(!is.na(weights))) { 
+  weights <- as.numeric(weights) 
+  } else { 
+  weights <- NULL 
+  }
+  which <- switch(igraph.match.arg(which), "lm"=0L, "la"=2L, "sa"=3L)
+  degmode <- switch(igraph.match.arg(degmode), "out"=1, "in"=2, "all"=3, "total"=3)
+  type <- switch(igraph.match.arg(type), 
+  "default"=if (is.directed(graph)) 3L else 0L, 
+  "da"=0L, "d-a"=0L, "idad"=1L, "i-dad"=1L, "dad"=2L, 
+  "oap"=3L)
+  scaled <- as.logical(scaled)
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_revolver_ml_AD_dpareto", graph, alpha, a, paralpha, parbeta, parscale, abstol, reltol, maxit, agebins, filter,
+  res <- .Call("R_igraph_laplacian_spectral_embedding", graph, no, weights, which, degmode, type, scaled, options,
         PACKAGE="igraph")
 
   res
 }
 
-revolver.ml.AD.dpareto.eval <- function(graph, alpha, a, paralpha, parbeta, parscale, agebins=300, filter=NULL) {
+#' @export
+spectrum <- function(graph, algorithm=c("arpack", "auto", "lapack", "comp_auto", "comp_lapack", "comp_arpack"), which=list(), options=arpack_defaults) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  paralpha <- as.numeric(paralpha)
-  parbeta <- as.numeric(parbeta)
-  parscale <- as.numeric(parscale)
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  algorithm <- switch(igraph.match.arg(algorithm), "auto"=0, "lapack"=1, 
+  "arpack"=2, "comp_auto"=3, "comp_lapack"=4, 
+  "comp_arpack"=5)
+  which.tmp <- eigen_defaults; 
+  which.tmp[ names(which) ] <- which ; which <- which.tmp
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_revolver_ml_AD_dpareto_eval", graph, alpha, a, paralpha, parbeta, parscale, agebins, filter,
+  res <- .Call("R_igraph_eigen_adjacency", graph, algorithm, which, options,
         PACKAGE="igraph")
 
   res
 }
 
-revolver.ml.ADE.alpha.a.beta <- function(graph, cats, alpha, a, beta, coeffs, abstol=1e-8, reltol=1e-8, maxit=1000, agebins=300, filter=NULL) {
+#' @export
+sir <- function(graph, beta, gamma, no.sim=100) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  cats <- as.numeric(cats)
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   beta <- as.numeric(beta)
-  coeffs <- as.numeric(coeffs)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_ADE_alpha_a_beta", graph, cats, alpha, a, beta, coeffs, abstol, reltol, maxit, agebins, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.ADE.dpareto <- function(graph, cats, alpha, a, paralpha, parbeta, parscale, coeffs, abstol=1e-8, reltol=1e-8, maxit=1000, agebins=300, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  cats <- as.numeric(cats)
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  paralpha <- as.numeric(paralpha)
-  parbeta <- as.numeric(parbeta)
-  parscale <- as.numeric(parscale)
-  coeffs <- as.numeric(coeffs)
-  abstol <- as.numeric(abstol)
-  reltol <- as.numeric(reltol)
-  maxit <- as.integer(maxit)
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_revolver_ml_ADE_dpareto", graph, cats, alpha, a, paralpha, parbeta, parscale, coeffs, abstol, reltol, maxit, agebins, filter,
-        PACKAGE="igraph")
-
-  res
-}
-
-revolver.ml.ADE.dpareto.eval <- function(graph, cats, alpha, a, paralpha, parbeta, parscale, coeffs, agebins=300, filter=NULL) {
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  cats <- as.numeric(cats)
-  alpha <- as.numeric(alpha)
-  a <- as.numeric(a)
-  paralpha <- as.numeric(paralpha)
-  parbeta <- as.numeric(parbeta)
-  parscale <- as.numeric(parscale)
-  coeffs <- as.numeric(coeffs)
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
+  gamma <- as.numeric(gamma)
+  no.sim <- as.integer(no.sim)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_revolver_ml_ADE_dpareto_eval", graph, cats, alpha, a, paralpha, parbeta, parscale, coeffs, agebins, filter,
+  res <- .Call("R_igraph_sir", graph, beta, gamma, no.sim,
         PACKAGE="igraph")
 
+  class(res) <- "sir"
   res
 }
 
-revolver.ml.ADE.dpareto.evalf <- function(graph, cats, par, agebins, filter=NULL) {
+#' @export
+convex_hull <- function(data) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  cats <- as.numeric(cats)
-  par <- as.matrix(structure(as.double(par), dim=dim(par)))
-  agebins <- as.integer(agebins)
-  if (!is.null(filter)) filter <- as.numeric(filter)
+  data <- as.matrix(structure(as.double(data), dim=dim(data)))
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_revolver_ml_ADE_dpareto_evalf", graph, cats, par, agebins, filter,
+  res <- .Call("R_igraph_convex_hull", data,
         PACKAGE="igraph")
 
   res
 }
 
-revolver.probs.ADE.dpareto <- function(graph, par, cats, gcats, agebins) {
+#' @export
+dim_select <- function(sv) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  par <- as.matrix(structure(as.double(par), dim=dim(par)))
-  cats <- as.numeric(cats)
-  gcats <- as.numeric(gcats)
-  agebins <- as.integer(agebins)
+  sv <- as.numeric(sv)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
-  res <- .Call("R_igraph_revolver_probs_ADE_dpareto", graph, par, cats, gcats, agebins,
+  res <- .Call("R_igraph_dim_select", sv,
         PACKAGE="igraph")
 
   res
diff --git a/R/basic.R b/R/basic.R
index 3a5b042..6501eac 100644
--- a/R/basic.R
+++ b/R/basic.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,23 +19,35 @@
 #
 ###################################################################
 
-is.igraph <- function(graph){
-  "igraph" %in% class(graph)
-}
 
-is.directed <- function(graph) {
 
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_is_directed", graph,
-        PACKAGE="igraph")
+#' Is this object an igraph graph?
+#' 
+#' @aliases is.igraph
+#' @param graph An R object.
+#' @return A logical constant, \code{TRUE} if argument \code{graph} is a graph
+#' object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' is_igraph(g)
+#' is_igraph(numeric(10))
+
+is_igraph <- function(graph){
+  "igraph" %in% class(graph)
 }
 
+#' @export
+
 get.edge <- function(graph, id) {
 
-  if (!is.igraph(graph)) {
+  .Deprecated("ends", msg = paste("'get.edge' is deperecated, please use",
+                        "'ends' instead."))
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -54,3 +65,38 @@ get.edge <- function(graph, id) {
 }
 
 
+#' Head of the edge(s) in a graph
+#'
+#' For undirected graphs, head and tail is not defined.  In this case
+#' \code{head_of} returns vertices incident to the supplied edges, and
+#' \code{tail_of} returns the other end(s) of the edge(s).
+#' 
+#' @param graph The input graph.
+#' @param es The edges to query.
+#' @return A vertex sequence with the head(s) of the edge(s).
+#'
+#' @family structural queries
+#' 
+#' @export
+
+head_of <- function(graph, es) {
+  create_vs(graph,  ends(graph, es, names = FALSE)[,1])
+}
+
+#' Tails of the edge(s) in a graph
+#'
+#' For undirected graphs, head and tail is not defined.  In this case
+#' \code{tail_of} returns vertices incident to the supplied edges, and
+#' \code{head_of} returns the other end(s) of the edge(s).
+#'
+#' @param graph The input graph.
+#' @param es The edges to query.
+#' @return A vertex sequence with the tail(s) of the edge(s).
+#'
+#' @family structural queries
+#' 
+#' @export
+
+tail_of <- function(graph, es) {
+  create_vs(graph, ends(graph, es, names = FALSE)[,2])
+}
diff --git a/R/bipartite.R b/R/bipartite.R
index 894ab0d..b7aed83 100644
--- a/R/bipartite.R
+++ b/R/bipartite.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,13 +19,81 @@
 #
 ###################################################################
 
-bipartite.projection <- function(graph, types=NULL,
+
+
+#' Project a bipartite graph
+#' 
+#' A bipartite graph is projected into two one-mode networks
+#' 
+#' Bipartite graphs have a \code{type} vertex attribute in igraph, this is
+#' boolean and \code{FALSE} for the vertices of the first kind and \code{TRUE}
+#' for vertices of the second kind.
+#' 
+#' \code{bipartite_projection_size} calculates the number of vertices and edges
+#' in the two projections of the bipartite graphs, without calculating the
+#' projections themselves. This is useful to check how much memory the
+#' projections would need if you have a large bipartite graph.
+#' 
+#' \code{bipartite_projection} calculates the actual projections.  You can use
+#' the \code{probe1} argument to specify the order of the projections in the
+#' result. By default vertex type \code{FALSE} is the first and \code{TRUE} is
+#' the second.
+#' 
+#' \code{bipartite_projection} keeps vertex attributes.
+#' 
+#' @aliases bipartite.projection bipartite.projection.size bipartite_projection_size bipartite_projection
+#' @param graph The input graph. It can be directed, but edge directions are
+#' ignored during the computation.
+#' @param types An optional vertex type vector to use instead of the
+#' \sQuote{\code{type}} vertex attribute. You must supply this argument if the
+#' graph has no \sQuote{\code{type}} vertex attribute.
+#' @param multiplicity If \code{TRUE}, then igraph keeps the multiplicity of
+#' the edges as an edge attribute. E.g. if there is an A-C-B and also an A-D-B
+#' triple in the bipartite graph (but no more X, such that A-X-B is also in the
+#' graph), then the multiplicity of the A-B edge in the projection will be 2.
+#' @param probe1 This argument can be used to specify the order of the
+#' projections in the resulting list. If given, then it is considered as a
+#' vertex id (or a symbolic vertex name); the projection containing this vertex
+#' will be the first one in the result list.  This argument is ignored if only
+#' one projection is requested in argument \code{which}.
+#' @param which A character scalar to specify which projection(s) to calculate.
+#' The default is to calculate both.
+#' @param remove.type Logical scalar, whether to remove the \code{type} vertex
+#' attribute from the projections. This makes sense because these graphs are
+#' not bipartite any more. However if you want to combine them with each other
+#' (or other bipartite graphs), then it is worth keeping this attribute. By
+#' default it will be removed.
+#' @return A list of two undirected graphs. See details above.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Projection of a full bipartite graph is a full graph
+#' g <- make_full_bipartite_graph(10,5)
+#' proj <- bipartite_projection(g)
+#' graph.isomorphic(proj[[1]], make_full_graph(10))
+#' graph.isomorphic(proj[[2]], make_full_graph(5))
+#' 
+#' ## The projection keeps the vertex attributes
+#' M <- matrix(0, nr=5, nc=3)
+#' rownames(M) <- c("Alice", "Bob", "Cecil", "Dan", "Ethel")
+#' colnames(M) <- c("Party", "Skiing", "Badminton")
+#' M[] <- sample(0:1, length(M), replace=TRUE)
+#' M
+#' g2 <- graph_from_incidence_matrix(M)
+#' g2$name <- "Event network"
+#' proj2 <- bipartite_projection(g2)
+#' print(proj2[[1]], g=TRUE, e=TRUE)
+#' print(proj2[[2]], g=TRUE, e=TRUE)
+#' 
+bipartite_projection <- function(graph, types=NULL,
                                  multiplicity=TRUE, probe1=NULL,
 				 which=c("both", "true", "false"),
                                  remove.type=TRUE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) { 
   types <- V(graph)$type 
   } 
   if (!is.null(types)) {
@@ -56,11 +123,11 @@ bipartite.projection <- function(graph, types=NULL,
   res <- .Call("R_igraph_bipartite_projection", graph, types,
                as.integer(probe1), which, PACKAGE="igraph")
   if (remove.type) {
-    if (is.igraph(res[[1]])) {
-      res[[1]] <- remove.vertex.attribute(res[[1]], "type")
+    if (is_igraph(res[[1]])) {
+      res[[1]] <- delete_vertex_attr(res[[1]], "type")
     }
-    if (is.igraph(res[[2]])) {
-      res[[2]] <- remove.vertex.attribute(res[[2]], "type")
+    if (is_igraph(res[[2]])) {
+      res[[2]] <- delete_vertex_attr(res[[2]], "type")
     }
   }
   if (which == 0L) {
@@ -77,3 +144,50 @@ bipartite.projection <- function(graph, types=NULL,
     res[[2]]
   }
 }
+
+
+#' Decide whether a graph is bipartite
+#' 
+#' This function decides whether the vertices of a network can be mapped to two
+#' vertex types in a way that no vertices of the same type are connected.
+#' 
+#' A bipartite graph in igraph has a \sQuote{\code{type}} vertex attribute
+#' giving the two vertex types.
+#' 
+#' This function simply checks whether a graph \emph{could} be bipartite. It
+#' tries to find a mapping that gives a possible division of the vertices into
+#' two classes, such that no two vertices of the same class are connected by an
+#' edge.
+#' 
+#' The existence of such a mapping is equivalent of having no circuits of odd
+#' length in the graph. A graph with loop edges cannot bipartite.
+#' 
+#' Note that the mapping is not necessarily unique, e.g. if the graph has at
+#' least two components, then the vertices in the separate components can be
+#' mapped independently.
+#' 
+#' @aliases bipartite.mapping bipartite_mapping
+#' @param graph The input graph.
+#' @return A named list with two elements: \item{res}{A logical scalar,
+#' \code{TRUE} if the can be bipartite, \code{FALSE} otherwise.} \item{type}{A
+#' possibly vertex type mapping, a logical vector. If no such mapping exists,
+#' then an empty vector.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A ring has just one loop, so it is fine
+#' g <- make_ring(10)
+#' bipartite_mapping(g)
+#' 
+#' ## A star is fine, too
+#' g2 <- make_star(10)
+#' bipartite_mapping(g2)
+#' 
+#' ## A graph containing a triangle is not fine
+#' g3 <- make_ring(10)
+#' g3 <- add_edges(g3, c(1,3))
+#' bipartite_mapping(g3)
+#' @export
+
+bipartite_mapping <- bipartite_mapping
diff --git a/R/centrality.R b/R/centrality.R
index 04044aa..4ec07bf 100644
--- a/R/centrality.R
+++ b/R/centrality.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,11 +19,198 @@
 #
 ###################################################################
 
-igraph.arpack.default <- list(bmat="I", n=0, which="XX", nev=1, tol=0.0,
-                              ncv=3, ldv=0, ishift=1, maxiter=3000, nb=1,
+#' @rdname arpack
+#' @export
+
+arpack_defaults <- list(bmat="I", n=0, which="XX", nev=1, tol=0.0,
+                              ncv=3, ldv=0, ishift=1, maxiter=1000, nb=1,
                               mode=1, start=0, sigma=0.0, sigmai=0.0)
 
-arpack <- function(func, extra=NULL, sym=FALSE, options=igraph.arpack.default,
+#' ARPACK eigenvector calculation
+#' 
+#' Interface to the ARPACK library for calculating eigenvectors of sparse
+#' matrices
+#' 
+#' ARPACK is a library for solving large scale eigenvalue problems.  The
+#' package is designed to compute a few eigenvalues and corresponding
+#' eigenvectors of a general \eqn{n} by \eqn{n} matrix \eqn{A}. It is most
+#' appropriate for large sparse or structured matrices \eqn{A} where structured
+#' means that a matrix-vector product \code{w <- Av} requires order \eqn{n}
+#' rather than the usual order \eqn{n^2} floating point operations. Please see
+#' \url{http://www.caam.rice.edu/software/ARPACK/} for details.
+#' 
+#' This function is an interface to ARPACK. igraph does not contain all ARPACK
+#' routines, only the ones dealing with symmetric and non-symmetric eigenvalue
+#' problems using double precision real numbers.
+#' 
+#' The eigenvalue calculation in ARPACK (in the simplest case) involves the
+#' calculation of the \eqn{Av} product where \eqn{A} is the matrix we work with
+#' and \eqn{v} is an arbitrary vector. The function supplied in the \code{fun}
+#' argument is expected to perform this product. If the product can be done
+#' efficiently, e.g. if the matrix is sparse, then \code{arpack} is usually
+#' able to calculate the eigenvalues very quickly.
+#' 
+#' The \code{options} argument specifies what kind of calculation to perform.
+#' It is a list with the following members, they correspond directly to ARPACK
+#' parameters. On input it has the following fields: \describe{
+#' \item{bmat}{Character constant, possible values: \sQuote{\code{I}}, stadard
+#' eigenvalue problem, \eqn{Ax=\lambda x}{A*x=lambda*x}; and \sQuote{\code{G}},
+#' generalized eigenvalue problem, \eqn{Ax=\lambda B x}{A*x=lambda B*x}.
+#' Currently only \sQuote{\code{I}} is supported.} \item{n}{Numeric scalar. The
+#' dimension of the eigenproblem. You only need to set this if you call
+#' \code{\link{arpack}} directly. (I.e. not needed for
+#' \code{\link{eigen_centrality}}, \code{\link{page_rank}}, etc.)}
+#' \item{which}{Specify which eigenvalues/vectors to compute, character
+#' constant with exactly two characters.
+#' 
+#' Possible values for symmetric input matrices: \describe{
+#' \item{"LA"}{Compute \code{nev} largest (algebraic) eigenvalues.}
+#' \item{"SA"}{Compute \code{nev} smallest (algebraic)
+#' eigenvalues.} \item{"LM"}{Compute \code{nev} largest (in
+#' magnitude) eigenvalues.} \item{"SM"}{Compute \code{nev} smallest
+#' (in magnitude) eigenvalues.} \item{"BE"}{Compute \code{nev}
+#' eigenvalues, half from each end of the spectrum. When \code{nev} is odd,
+#' compute one more from the high end than from the low end.} }
+#' 
+#' Possible values for non-symmetric input matrices: \describe{
+#' \item{"LM"}{Compute \code{nev} eigenvalues of largest
+#' magnitude.} \item{"SM"}{Compute \code{nev} eigenvalues of
+#' smallest magnitude.} \item{"LR"}{Compute \code{nev} eigenvalues
+#' of largest real part.} \item{"SR"}{Compute \code{nev}
+#' eigenvalues of smallest real part.} \item{"LI"}{Compute
+#' \code{nev} eigenvalues of largest imaginary part.}
+#' \item{"SI"}{Compute \code{nev} eigenvalues of smallest imaginary
+#' part.} }
+#' 
+#' This parameter is sometimes overwritten by the various functions, e.g.
+#' \code{\link{page_rank}} always sets \sQuote{\code{LM}}.  }
+#' \item{nev}{Numeric scalar. The number of eigenvalues to be computed.}
+#' \item{tol}{Numeric scalar. Stopping criterion: the relative accuracy of the
+#' Ritz value is considered acceptable if its error is less than \code{tol}
+#' times its estimated value. If this is set to zero then machine precision is
+#' used.} \item{ncv}{Number of Lanczos vectors to be generated.}
+#' \item{ldv}{Numberic scalar. It should be set to zero in the current
+#' implementation.} \item{ishift}{Either zero or one. If zero then the shifts
+#' are provided by the user via reverse communication. If one then exact shifts
+#' with respect to the reduced tridiagonal matrix \eqn{T}.  Please always set
+#' this to one.} \item{maxiter}{Maximum number of Arnoldi update iterations
+#' allowed. } \item{nb}{Blocksize to be used in the recurrence. Please always
+#' leave this on the default value, one.} \item{mode}{The type of the
+#' eigenproblem to be solved.  Possible values if the input matrix is
+#' symmetric: \describe{ \item{1}{\eqn{Ax=\lambda x}{A*x=lambda*x}, \eqn{A} is
+#' symmetric.} \item{2}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{A} is
+#' symmetric, \eqn{M} is symmetric positive definite.} \item{3}{\eqn{Kx=\lambda
+#' Mx}{K*x=lambda*M*x}, \eqn{K} is symmetric, \eqn{M} is symmetric positive
+#' semi-definite.} \item{4}{\eqn{Kx=\lambda KGx}{K*x=lambda*KG*x}, \eqn{K} is
+#' symmetric positive semi-definite, \eqn{KG} is symmetric indefinite.}
+#' \item{5}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{A} is symmetric, \eqn{M}
+#' is symmetric positive semi-definite. (Cayley transformed mode.)} } Please
+#' note that only \code{mode==1} was tested and other values might not work
+#' properly.
+#' 
+#' Possible values if the input matrix is not symmetric: \describe{
+#' \item{1}{\eqn{Ax=\lambda x}{A*x=lambda*x}.} \item{2}{\eqn{Ax=\lambda
+#' Mx}{A*x=lambda*M*x}, \eqn{M} is symmetric positive definite.}
+#' \item{3}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is symmetric
+#' semi-definite.} \item{4}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is
+#' symmetric semi-definite.} } Please note that only \code{mode==1} was tested
+#' and other values might not work properly.  } \item{start}{Not used
+#' currently. Later it be used to set a starting vector.} \item{sigma}{Not used
+#' currently.} \item{sigmai}{Not use currently.}
+#' 
+#' On output the following additional fields are added: \describe{
+#' \item{info}{Error flag of ARPACK. Possible values: \describe{
+#' \item{0}{Normal exit.} \item{1}{Maximum number of iterations taken.}
+#' \item{3}{No shifts could be applied during a cycle of the Implicitly
+#' restarted Arnoldi iteration. One possibility is to increase the size of
+#' \code{ncv} relative to \code{nev}.} }
+#' 
+#' ARPACK can return more error conditions than these, but they are converted
+#' to regular igraph errors.  } \item{iter}{Number of Arnoldi iterations
+#' taken.} \item{nconv}{Number of \dQuote{converged} Ritz values. This
+#' represents the number of Ritz values that satisfy the convergence critetion.
+#' } \item{numop}{Total number of matrix-vector multiplications.}
+#' \item{numopb}{Not used currently.} \item{numreo}{Total number of steps of
+#' re-orthogonalization.} } } Please see the ARPACK documentation for
+#' additional details.
+#' 
+#' @aliases arpack arpack-options igraph.arpack.default arpack.unpack.complex
+#' arpack_defaults
+#' @param func The function to perform the matrix-vector multiplication. ARPACK
+#' requires to perform these by the user. The function gets the vector \eqn{x}
+#' as the first argument, and it should return \eqn{Ax}, where \eqn{A} is the
+#' \dQuote{input matrix}. (The input matrix is never given explicitly.) The
+#' second argument is \code{extra}.
+#' @param extra Extra argument to supply to \code{func}.
+#' @param sym Logical scalar, whether the input matrix is symmetric. Always
+#' supply \code{TRUE} here if it is, since it can speed up the computation.
+#' @param options Options to ARPACK, a named list to overwrite some of the
+#' default option values. See details below.
+#' @param env The environment in which \code{func} will be evaluated.
+#' @param complex Whether to convert the eigenvectors returned by ARPACK into R
+#' complex vectors. By default this is not done for symmetric problems (these
+#' only have real eigenvectors/values), but only non-symmetric ones. If you
+#' have a non-symmetric problem, but you're sure that the results will be real,
+#' then supply \code{FALSE} here.
+#' @return A named list with the following members: \item{values}{Numeric
+#' vector, the desired eigenvalues.} \item{vectors}{Numeric matrix, the desired
+#' eigenvectors as columns. If \code{complex=TRUE} (the default for
+#' non-symmetric problems), then the matrix is complex.} \item{options}{A named
+#' list with the supplied \code{options} and some information about the
+#' performed calculation, including an ARPACK exit code. See the details above.
+#' }
+#' @author Rich Lehoucq, Kristi Maschhoff, Danny Sorensen, Chao Yang for
+#' ARPACK, Gabor Csardi \email{csardi.gabor@@gmail.com} for the R interface.
+#' @seealso \code{\link{eigen_centrality}}, \code{\link{page_rank}},
+#' \code{\link{hub_score}}, \code{\link{cluster_leading_eigen}} are some of the
+#' functions in igraph which use ARPACK. The ARPACK homepage is at
+#' \url{http://www.caam.rice.edu/software/ARPACK/}.
+#' @references D.C. Sorensen, Implicit Application of Polynomial Filters in a
+#' k-Step Arnoldi Method. \emph{SIAM J. Matr. Anal. Apps.}, 13 (1992), pp
+#' 357-385.
+#' 
+#' R.B. Lehoucq, Analysis and Implementation of an Implicitly Restarted Arnoldi
+#' Iteration. \emph{Rice University Technical Report} TR95-13, Department of
+#' Computational and Applied Mathematics.
+#' 
+#' B.N. Parlett & Y. Saad, Complex Shift and Invert Strategies for Real
+#' Matrices. \emph{Linear Algebra and its Applications}, vol 88/89, pp 575-595,
+#' (1987).
+#' @keywords graphs
+#' @examples
+#' 
+#' # Identity matrix
+#' f <- function(x, extra=NULL) x
+#' arpack(f, options=list(n=10, nev=2, ncv=4), sym=TRUE)
+#' 
+#' # Graph laplacian of a star graph (undirected), n>=2
+#' # Note that this is a linear operation
+#' f <- function(x, extra=NULL) {
+#'   y <- x
+#'   y[1] <- (length(x)-1)*x[1] - sum(x[-1])
+#'   for (i in 2:length(x)) {
+#'     y[i] <- x[i] - x[1]
+#'   }
+#'   y
+#' }
+#' 
+#' arpack(f, options=list(n=10, nev=1, ncv=3), sym=TRUE)
+#' 
+#' # double check
+#' eigen(laplacian_matrix(make_star(10, mode="undirected")))
+#' 
+#' ## First three eigenvalues of the adjacency matrix of a graph
+#' ## We need the 'Matrix' package for this
+#' if (require(Matrix)) {
+#'   g <- sample_gnp(1000, 5/1000)
+#'   M <- as_adj(g, sparse=TRUE)
+#'   f2 <- function(x, extra=NULL) { cat("."); as.vector(M %*% x) }
+#'   baev <- arpack(f2, sym=TRUE, options=list(n=vcount(g), nev=3, ncv=8,
+#'                                   which="LM", maxiter=200))
+#' }
+#' @export
+
+arpack <- function(func, extra=NULL, sym=FALSE, options=arpack_defaults,
                    env=parent.frame(), complex=!sym) {
 
   if (!is.list(options) ||
@@ -34,13 +220,13 @@ arpack <- function(func, extra=NULL, sym=FALSE, options=igraph.arpack.default,
   if (any(names(options) == "")) {
     stop("all options must be named")
   }
-  if (any(! names(options) %in% names(igraph.arpack.default))) {
+  if (any(! names(options) %in% names(arpack_defaults))) {
     stop("unkown ARPACK option(s): ",
-         paste(setdiff(names(options), names(igraph.arpack.default)),
+         paste(setdiff(names(options), names(arpack_defaults)),
                        collapse=", "))
   }
   
-  options.tmp <- igraph.arpack.default
+  options.tmp <- arpack_defaults
   options.tmp[ names(options) ] <- options
   options <- options.tmp
 
@@ -78,17 +264,490 @@ arpack <- function(func, extra=NULL, sym=FALSE, options=igraph.arpack.default,
   res
 }
 
-subgraph.centrality <- function(graph, diag=FALSE) {
-  A <- get.adjacency(graph)
+arpack.unpack.complex <- function(vectors, values, nev) {
+  # Argument checks
+  vectors <- as.matrix(structure(as.double(vectors), dim=dim(vectors)))
+  values <- as.matrix(structure(as.double(values), dim=dim(values)))
+  nev <- as.integer(nev)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_arpack_unpack_complex", vectors, values, nev,
+        PACKAGE="igraph")
+
+  res
+}
+
+
+
+#' Find subgraph centrality scores of network positions
+#' 
+#' Subgraph centrality of a vertex measures the number of subgraphs a vertex
+#' participates in, weighting them according to their size.
+#' 
+#' The subgraph centrality of a vertex is defined as the number of closed loops
+#' originating at the vertex, where longer loops are exponentially
+#' downweighted.
+#' 
+#' Currently the calculation is performed by explicitly calculating all
+#' eigenvalues and eigenvectors of the adjacency matrix of the graph. This
+#' effectively means that the measure can only be calculated for small graphs.
+#'
+#' @aliases subgraph.centrality
+#' @param graph The input graph, it should be undirected, but the
+#' implementation does not check this currently.
+#' @param diag Boolean scalar, whether to include the diagonal of the adjacency
+#' matrix in the analysis. Giving \code{FALSE} here effectively eliminates the
+#' loops edges from the graph before the calculation.
+#' @return A numeric vector, the subgraph centrality scores of the vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com} based on the Matlab
+#' code by Ernesto Estrada
+#' @seealso \code{\link{eigen_centrality}}, \code{\link{page_rank}}
+#' @references Ernesto Estrada, Juan A. Rodriguez-Velazquez: Subgraph
+#' centrality in Complex Networks. \emph{Physical Review E} 71, 056103 (2005).
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_pa(100, m=4, dir=FALSE)
+#' sc <- subgraph_centrality(g)
+#' cor(degree(g), sc)
+#' 
+subgraph_centrality <- function(graph, diag=FALSE) {
+  A <- as_adj(graph)
   if (!diag) { diag(A) <- 0 }
   eig <- eigen(A)
   res <- as.vector(eig$vectors^2 %*% exp(eig$values))
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) { 
-    names(res) <- get.vertex.attribute(graph, "name") 
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+    names(res) <- vertex_attr(graph, "name") 
   }
   res
 }
 
-igraph.eigen.default <- list(pos="LM", howmany=1L, il=-1L, iu=-1L,
+
+#' Eigenvalues and eigenvectors of the adjacency matrix of a graph
+#' 
+#' Calculate selected eigenvalues and eigenvectors of a (supposedly sparse)
+#' graph.
+#' 
+#' The \code{which} argument is a list and it specifies which eigenvalues and
+#' corresponding eigenvectors to calculate: There are eight options:
+#' \enumerate{ \item Eigenvalues with the largest magnitude. Set \code{pos} to
+#' \code{LM}, and \code{howmany} to the number of eigenvalues you want.  \item
+#' Eigenvalues with the smallest magnitude. Set \code{pos} to \code{SM} and
+#' \code{howmany} to the number of eigenvalues you want.  \item Largest
+#' eigenvalues. Set \code{pos} to \code{LA} and \code{howmany} to the number of
+#' eigenvalues you want.  \item Smallest eigenvalues. Set \code{pos} to
+#' \code{SA} and \code{howmany} to the number of eigenvalues you want.  \item
+#' Eigenvalues from both ends of the spectrum. Set \code{pos} to \code{BE} and
+#' \code{howmany} to the number of eigenvalues you want. If \code{howmany} is
+#' odd, then one more eigenvalue is returned from the larger end.  \item
+#' Selected eigenvalues. This is not (yet) implemented currently.  \item
+#' Eigenvalues in an interval. This is not (yet) implemented.  \item All
+#' eigenvalues. This is not implemented yet. The standard \code{eigen} function
+#' does a better job at this, anyway.  }
+#' 
+#' Note that ARPACK might be unstable for graphs with multiple components, e.g.
+#' graphs with isolate vertices.
+#' 
+#' @aliases graph.eigen spectrum igraph.eigen.default
+#' @param graph The input graph, can be directed or undirected.
+#' @param algorithm The algorithm to use. Currently only \code{arpack} is
+#' implemented, which uses the ARPACK solver. See also \code{\link{arpack}}.
+#' @param which A list to specify which eigenvalues and eigenvectors to
+#' calculate. By default the leading (i.e. largest magnitude) eigenvalue and
+#' the corresponding eigenvector is calculated.
+#' @param options Options for the ARPACK solver. See
+#' \code{\link{arpack_defaults}}.
+#' @return Depends on the algorithm used.
+#' 
+#' For \code{arpack} a list with three entries is returned: \item{options}{See
+#' the return value for \code{arpack} for a complete description.}
+#' \item{values}{Numeric vector, the eigenvalues.} \item{vectors}{Numeric
+#' matrix, with the eigenvectors as columns.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{as_adj}} to create a (sparse) adjacency matrix.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Small example graph, leading eigenvector by default
+#' kite <- make_graph("Krackhardt_kite")
+#' spectrum(kite)[c("values", "vectors")]
+#' 
+#' ## Double check
+#' eigen(as_adj(kite, sparse=FALSE))$vectors[,1]
+#' 
+#' ## Should be the same as 'eigen_centrality' (but rescaled)
+#' cor(eigen_centrality(kite)$vector, spectrum(kite)$vectors)
+#' 
+#' ## Smallest eigenvalues
+#' spectrum(kite, which=list(pos="SM", howmany=2))$values
+#' 
+#' @export
+#' @include auto.R
+
+spectrum <- spectrum
+
+eigen_defaults <- list(pos="LM", howmany=1L, il=-1L, iu=-1L,
                              vl=-Inf, vu=Inf, vestimate=0L,
                              balance="none")
+
+#' Find Eigenvector Centrality Scores of Network Positions
+#' 
+#' \code{eigen_centrality} takes a graph (\code{graph}) and returns the
+#' eigenvector centralities of positions \code{v} within it
+#' 
+#' Eigenvector centrality scores correspond to the values of the first
+#' eigenvector of the graph adjacency matrix; these scores may, in turn, be
+#' interpreted as arising from a reciprocal process in which the centrality of
+#' each actor is proportional to the sum of the centralities of those actors to
+#' whom he or she is connected.  In general, vertices with high eigenvector
+#' centralities are those which are connected to many other vertices which are,
+#' in turn, connected to many others (and so on).  (The perceptive may realize
+#' that this implies that the largest values will be obtained by individuals in
+#' large cliques (or high-density substructures).  This is also intelligible
+#' from an algebraic point of view, with the first eigenvector being closely
+#' related to the best rank-1 approximation of the adjacency matrix (a
+#' relationship which is easy to see in the special case of a diagonalizable
+#' symmetric real matrix via the \eqn{SLS^-1}{$S \Lambda S^{-1}$}
+#' decomposition).)
+#' 
+#' From igraph version 0.5 this function uses ARPACK for the underlying
+#' computation, see \code{\link{arpack}} for more about ARPACK in igraph.
+#' 
+#' @aliases evcent eigen_centrality
+#' @param graph Graph to be analyzed.
+#' @param directed Logical scalar, whether to consider direction of the edges
+#' in directed graphs. It is ignored for undirected graphs.
+#' @param scale Logical scalar, whether to scale the result to have a maximum
+#' score of one. If no scaling is used then the result vector has unit length
+#' in the Euclidean norm.
+#' @param weights A numerical vector or \code{NULL}. This argument can be used
+#' to give edge weights for calculating the weighted eigenvector centrality of
+#' vertices. If this is \code{NULL} and the graph has a \code{weight} edge
+#' attribute then that is used. If \code{weights} is a numerical vector then it
+#' used, even if the graph has a \code{weights} edge attribute. If this is
+#' \code{NA}, then no edge weights are used (even if the graph has a
+#' \code{weight} edge attribute. Note that if there are negative edge weights
+#' and the direction of the edges is considered, then the eigenvector might be
+#' complex. In this case only the real part is reported.
+#' @param options A named list, to override some ARPACK options. See
+#' \code{\link{arpack}} for details.
+#' @return A named list with components: \item{vector}{A vector containing the
+#' centrality scores.} \item{value}{The eigenvalue corresponding to the
+#' calculated eigenvector, i.e. the centrality scores.} \item{options}{A named
+#' list, information about the underlying ARPACK computation. See
+#' \code{\link{arpack}} for the details.  }
+#' @section WARNING : \code{eigen_centrality} will not symmetrize your data
+#' before extracting eigenvectors; don't send this routine asymmetric matrices
+#' unless you really mean to do so.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com} and Carter T. Butts
+#' (\url{http://www.faculty.uci.edu/profile.cfm?faculty_id=5057}) for the
+#' manual page.
+#' @references Bonacich, P.  (1987).  Power and Centrality: A Family of
+#' Measures. \emph{American Journal of Sociology}, 92, 1170-1182.
+#' @keywords graphs
+#' @examples
+#' 
+#' #Generate some test data
+#' g <- make_ring(10, directed=FALSE)
+#' #Compute eigenvector centrality scores
+#' eigen_centrality(g)
+#' @export
+
+eigen_centrality <- eigen_centrality
+
+
+#' Strength or weighted vertex degree
+#' 
+#' Summing up the edge weights of the adjacent edges for each vertex.
+#' 
+#' 
+#' @aliases graph.strength strength
+#' @param graph The input graph.
+#' @param vids The vertices for which the strength will be calculated.
+#' @param mode Character string, \dQuote{out} for out-degree, \dQuote{in} for
+#' in-degree or \dQuote{all} for the sum of the two. For undirected graphs this
+#' argument is ignored.
+#' @param loops Logical; whether the loop edges are also counted.
+#' @param weights Weight vector. If the graph has a \code{weight} edge
+#' attribute, then this is used by default. If the graph does not have a
+#' \code{weight} edge attribute and this argument is \code{NULL}, then a
+#' warning is given and \code{\link{degree}} is called.
+#' @return A numeric vector giving the strength of the vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{degree}} for the unweighted version.
+#' @references Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras,
+#' Alessandro Vespignani: The architecture of complex weighted networks, Proc.
+#' Natl. Acad. Sci. USA 101, 3747 (2004)
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_star(10)
+#' E(g)$weight <- seq(ecount(g))
+#' strength(g)
+#' strength(g, mode="out")
+#' strength(g, mode="in")
+#' 
+#' # No weights, a warning is given
+#' g <- make_ring(10)
+#' strength(g)
+#' @export
+
+strength <- strength
+
+
+#' Graph diversity
+#' 
+#' Calculates a measure of diversity for all vertices.
+#' 
+#' The diversity of a vertex is defined as the (scaled) Shannon entropy of the
+#' weights of its incident edges:
+#' \deqn{D(i)=\frac{H(i)}{\log k_i}}{D(i)=H(i)/log(k[i])}
+#' and
+#' \deqn{H(i)=-\sum_{j=1}^{k_i} p_{ij}\log p_{ij},}{H(i) =
+#'   -sum(p[i,j] log(p[i,j]), j=1..k[i]),} where
+#' \deqn{p_{ij}=\frac{w_{ij}}{\sum_{l=1}^{k_i}}V_{il},}{p[i,j] = w[i,j] /
+#' sum(w[i,l], l=1..k[i]),} and \eqn{k_i}{k[i]} is the (total) degree of vertex
+#' \eqn{i}, \eqn{w_{ij}}{w[i,j]} is the weight of the edge(s) between vertices
+#' \eqn{i} and \eqn{j}.
+#' 
+#' For vertices with degree less than two the function returns \code{NaN}.
+#' 
+#' @aliases graph.diversity diversity
+#' @param graph The input graph. Edge directions are ignored.
+#' @param weights \code{NULL}, or the vector of edge weights to use for the
+#' computation. If \code{NULL}, then the \sQuote{weight} attibute is used. Note
+#' that this measure is not defined for unweighted graphs.
+#' @param vids The vertex ids for which to calculate the measure.
+#' @return A numeric vector, its length is the number of vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Nathan Eagle, Michael Macy and Rob Claxton: Network Diversity
+#' and Economic Development, \emph{Science} \bold{328}, 1029--1031, 2010.
+#' @keywords graphs
+#' @examples
+#' 
+#' g1 <- sample_gnp(20, 2/20)
+#' g2 <- sample_gnp(20, 2/20)
+#' g3 <- sample_gnp(20, 5/20)
+#' E(g1)$weight <- 1
+#' E(g2)$weight <- runif(ecount(g2))
+#' E(g3)$weight <- runif(ecount(g3))
+#' diversity(g1)
+#' diversity(g2)
+#' diversity(g3)
+#' @export
+
+diversity <- diversity
+
+
+#' Kleinberg's hub centrality scores.
+#' 
+#' The hub scores of the vertices are defined as the principal eigenvector
+#' of \eqn{A A^T}{A*t(A)}, where \eqn{A} is the adjacency matrix of the
+#' graph.
+#' 
+#' For undirected matrices the adjacency matrix is symmetric and the hub
+#' scores are the same as authority scores, see
+#' \code{\link{authority_score}}.
+#' 
+#' @aliases hub.score
+#' @param graph The input graph.
+#' @param scale Logical scalar, whether to scale the result to have a maximum
+#' score of one. If no scaling is used then the result vector has unit length
+#' in the Euclidean norm.
+#' @param weights Optional positive weight vector for calculating weighted
+#' scores. If the graph has a \code{weight} edge attribute, then this is used
+#' by default.
+#' @param options A named list, to override some ARPACK options. See
+#' \code{\link{arpack}} for details.
+#' @return A named list with members:
+#'   \item{vector}{The authority/hub scores of the vertices.}
+#'   \item{value}{The corresponding eigenvalue of the calculated
+#'     principal eigenvector.}
+#'   \item{options}{Some information about the ARPACK computation, it has
+#'     the same members as the \code{options} member returned 
+#'     by \code{\link{arpack}}, see that for documentation.}
+#' @seealso \code{\link{authority_score}},
+#' \code{\link{eigen_centrality}} for eigenvector centrality,
+#' \code{\link{page_rank}} for the Page Rank scores. \code{\link{arpack}} for
+#' the underlining machinery of the computation.
+#' @references J. Kleinberg. Authoritative sources in a hyperlinked
+#' environment. \emph{Proc. 9th ACM-SIAM Symposium on Discrete Algorithms},
+#' 1998. Extended version in \emph{Journal of the ACM} 46(1999). Also appears
+#' as IBM Research Report RJ 10076, May 1997.
+#' @examples
+#' ## An in-star
+#' g <- make_star(10)
+#' hub_score(g)$vector
+#' 
+#' ## A ring
+#' g2 <- make_ring(10)
+#' hub_score(g2)$vector
+
+hub_score <- hub_score
+
+
+#' Kleinberg's authority centrality scores.
+#' 
+#' The authority scores of the vertices are defined as the principal
+#' eigenvector of \eqn{A^T A}{t(A)*A}, where \eqn{A} is the adjacency
+#' matrix of the graph.
+#' 
+#' For undirected matrices the adjacency matrix is symmetric and the
+#' authority scores are the same as hub scores, see
+#' \code{\link{hub_score}}.
+#' 
+#' @aliases authority.score
+#' @param graph The input graph.
+#' @param scale Logical scalar, whether to scale the result to have a maximum
+#' score of one. If no scaling is used then the result vector has unit length
+#' in the Euclidean norm.
+#' @param weights Optional positive weight vector for calculating weighted
+#' scores. If the graph has a \code{weight} edge attribute, then this is used
+#' by default.
+#' @param options A named list, to override some ARPACK options. See
+#' \code{\link{arpack}} for details.
+#' @return A named list with members:
+#'   \item{vector}{The authority/hub scores of the vertices.}
+#'   \item{value}{The corresponding eigenvalue of the calculated
+#'     principal eigenvector.}
+#'   \item{options}{Some information about the ARPACK computation, it has
+#'     the same members as the \code{options} member returned 
+#'     by \code{\link{arpack}}, see that for documentation.}
+#' @seealso \code{\link{hub_score}}, \code{\link{eigen_centrality}} for
+#' eigenvector centrality, \code{\link{page_rank}} for the Page Rank
+#' scores. \code{\link{arpack}} for the underlining machinery of the
+#' computation.
+#' @references J. Kleinberg. Authoritative sources in a hyperlinked
+#' environment. \emph{Proc. 9th ACM-SIAM Symposium on Discrete Algorithms},
+#' 1998. Extended version in \emph{Journal of the ACM} 46(1999). Also appears
+#' as IBM Research Report RJ 10076, May 1997.
+#' @examples
+#' ## An in-star
+#' g <- make_star(10)
+#' hub_score(g)$vector
+#' authority_score(g)$vector
+#' 
+#' ## A ring
+#' g2 <- make_ring(10)
+#' hub_score(g2)$vector
+#' authority_score(g2)$vector
+
+authority_score <- authority_score
+
+
+#' The Page Rank algorithm
+#' 
+#' Calculates the Google PageRank for the specified vertices.
+#' 
+#' For the explanation of the PageRank algorithm, see the following webpage:
+#' \url{http://infolab.stanford.edu/~backrub/google.html}, or the following
+#' reference:
+#' 
+#' Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual Web
+#' Search Engine. Proceedings of the 7th World-Wide Web Conference, Brisbane,
+#' Australia, April 1998.
+#' 
+#' igraph 0.5 (and later) contains two PageRank calculation implementations.
+#' The \code{page_rank} function uses ARPACK to perform the calculation, see
+#' also \code{\link{arpack}}.
+#' 
+#' The \code{page_rank_old} function performs a simple power method, this is
+#' the implementation that was available under the name \code{page_rank} in pre
+#' 0.5 igraph versions. Note that \code{page_rank_old} has an argument called
+#' \code{old}. If this argument is \code{FALSE} (the default), then the proper
+#' PageRank algorithm is used, i.e. \eqn{(1-d)/n} is added to the weighted
+#' PageRank of vertices to calculate the next iteration. If this argument is
+#' \code{TRUE} then \eqn{(1-d)} is added, just like in the PageRank paper;
+#' \eqn{d} is the damping factor, and \eqn{n} is the total number of vertices.
+#' A further difference is that the old implementation does not renormalize the
+#' page rank vector after each iteration.  Note that the \code{old=FALSE}
+#' method is not stable, is does not necessarily converge to a fixed point. It
+#' should be avoided for new code, it is only included for compatibility with
+#' old igraph versions.
+#' 
+#' Please note that the PageRank of a given vertex depends on the PageRank of
+#' all other vertices, so even if you want to calculate the PageRank for only
+#' some of the vertices, all of them must be calculated. Requesting the
+#' PageRank for only some of the vertices does not result in any performance
+#' increase at all.
+#' 
+#' Since the calculation is an iterative process, the algorithm is stopped
+#' after a given count of iterations or if the PageRank value differences
+#' between iterations are less than a predefined value.
+#' 
+#' @aliases page.rank page_rank page.rank.old page_rank_old
+#' @param graph The graph object.
+#' @param algo Character scalar, which implementation to use to carry out the
+#' calculation. The default is \code{"prpack"}, which uses the PRPACK library
+#' (https://github.com/dgleich/prpack). This is a new implementation in igraph
+#' version 0.7, and the suggested one, as it is the most stable and the fastest
+#' for all but small graphs.  \code{"arpack"} uses the ARPACK library, the
+#' default implementation from igraph version 0.5 until version 0.7.
+#' \code{power} uses a simple implementation of the power method, this was the
+#' default in igraph before version 0.5 and is the same as calling
+#' \code{page_rank_old}.
+#' @param vids The vertices of interest.
+#' @param directed Logical, if true directed paths will be considered for
+#' directed graphs. It is ignored for undirected graphs.
+#' @param damping The damping factor (\sQuote{d} in the original paper).
+#' @param personalized Optional vector giving a probability distribution to
+#' calculate personalized PageRank. For personalized PageRank, the probability
+#' of jumping to a node when abandoning the random walk is not uniform, but it
+#' is given by this vector. The vector should contains an entry for each vertex
+#' and it will be rescaled to sum up to one.
+#' @param weights A numerical vector or \code{NULL}. This argument can be used
+#' to give edge weights for calculating the weighted PageRank of vertices. If
+#' this is \code{NULL} and the graph has a \code{weight} edge attribute then
+#' that is used. If \code{weights} is a numerical vector then it used, even if
+#' the graph has a \code{weights} edge attribute. If this is \code{NA}, then no
+#' edge weights are used (even if the graph has a \code{weight} edge attribute.
+#' @param options Either a named list, to override some ARPACK options. See
+#' \code{\link{arpack}} for details; or a named list to override the default
+#' options for the power method (if \code{algo="power"}).  The default options
+#' for the power method are \code{niter=1000} and \code{eps=0.001}. This
+#' argument is ignored if the PRPACK implementation is used.
+#' @param niter The maximum number of iterations to perform.
+#' @param eps The algorithm will consider the calculation as complete if the
+#' difference of PageRank values between iterations change less than this value
+#' for every node.
+#' @param old A logical scalar, whether the old style (pre igraph 0.5)
+#' normalization to use. See details below.
+#' @return For \code{page_rank} a named list with entries: \item{vector}{A
+#' numeric vector with the PageRank scores.} \item{value}{The eigenvalue
+#' corresponding to the eigenvector with the page rank scores. It should be
+#' always exactly one.} \item{options}{Some information about the underlying
+#' ARPACK calculation. See \code{\link{arpack}} for details. This entry is
+#' \code{NULL} if not the ARPACK implementation was used.}
+#' 
+#' For \code{page_rank_old} a numeric vector of Page Rank scores.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @seealso Other centrality scores: \code{\link{closeness}},
+#' \code{\link{betweenness}}, \code{\link{degree}}
+#' @references Sergey Brin and Larry Page: The Anatomy of a Large-Scale
+#' Hypertextual Web Search Engine. Proceedings of the 7th World-Wide Web
+#' Conference, Brisbane, Australia, April 1998.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(20, 5/20, directed=TRUE)
+#' page_rank(g)$vector
+#' 
+#' g2 <- make_star(10)
+#' page_rank(g2)$vector
+#' 
+#' # Personalized PageRank
+#' g3 <- make_ring(10)
+#' page_rank(g3)$vector
+#' reset <- seq(vcount(g3))
+#' page_rank(g3, personalized=reset)$vector
+#' @export
+
+page_rank <- page_rank
+
+#' @export
+#' @rdname page_rank
+
+page_rank_old <- page_rank_old
diff --git a/R/centralization.R b/R/centralization.R
new file mode 100644
index 0000000..57e4965
--- /dev/null
+++ b/R/centralization.R
@@ -0,0 +1,345 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' @include auto.R
+NULL
+
+#' Centralization of a graph
+#' 
+#' Centralization is a method for creating a graph level centralization
+#' measure from the centrality scores of the vertices.
+#' 
+#' Centralization is a general method for calculating a graph-level
+#' centrality score based on node-level centrality measure. The formula for
+#' this is
+#' \deqn{C(G)=\sum_v (\max_w c_w - c_v),}{ C(G)=sum( max(c(w), w) - c(v),v),}
+#' where \eqn{c_v}{c(v)} is the centrality of vertex \eqn{v}.
+#' 
+#' The graph-level centrality score can be normalized by dividing by the
+#' maximum theoretical score for a graph with the same number of vertices,
+#' using the same parameters, e.g. directedness, whether we consider loop
+#' edges, etc.
+#' 
+#' For degree, closeness and betweenness the most centralized structure is
+#' some version of the star graph, in-star, out-star or undirected star.
+#' 
+#' For eigenvector centrality the most centralized structure is the graph
+#' with a single edge (and potentially many isolates).
+#' 
+#' \code{centralize} implements general centralization formula to calculate
+#' a graph-level score from vertex-level scores.
+#' 
+#' @param scores The vertex level centrality scores.
+#' @param theoretical.max Real scalar. The graph level centrality score of
+#'   the most centralized graph with the same number of vertices as the graph
+#'   under study. This is only used if the \code{normalized} argument is set
+#'   to \code{TRUE}.
+#' @param normalized Logical scalar. Whether to normalize the graph level
+#'   centrality score by dividing by the supplied theoretical maximum.
+#' @return A real scalar, the centralization of the graph from which
+#'   \code{scores} were derived.
+#'
+#' @aliases centralization centralize.scores
+#' @family centralization related
+#' 
+#' @export
+#' @references Freeman, L.C.  (1979).  Centrality in Social Networks I:
+#' Conceptual Clarification. \emph{Social Networks} 1, 215--239.
+#' 
+#' Wasserman, S., and Faust, K.  (1994).  \emph{Social Network Analysis:
+#' Methods and Applications.} Cambridge University Press.
+#'
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m=4)
+#' centr_degree(g)$centralization
+#' centr_clo(g, mode="all")$centralization
+#' centr_eigen(g, directed=FALSE)$centralization
+#' 
+#' # The most centralized graph according to eigenvector centrality
+#' g0 <- graph( c(2,1), n=10, dir=FALSE )
+#' g1 <- make_star(10, mode="undirected")
+#' centr_eigen(g0)$centralization
+#' centr_eigen(g1)$centralization
+
+centralize <- centralize
+
+#' Centralize a graph according to the degrees of vertices
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph.
+#' @param mode This is the same as the \code{mode} argument of
+#'   \code{degree}.
+#' @param loops Logical scalar, whether to consider loops edges when
+#'   calculating the degree.
+#' @param normalized Logical scalar. Whether to normalize the graph level
+#'   centrality score by dividing by the theoretical maximum.
+#' @return A named list with the following components:
+#'   \item{res}{The node-level centrality scores.}
+#'   \item{centralization}{The graph level centrality index.}
+#'   \item{theoretical_max}{The maximum theoretical graph level
+#'     centralization score for a graph with the given number of vertices,
+#'     using the same parameters. If the \code{normalized} argument was
+#'     \code{TRUE}, then the result was divided by this number.}
+#'
+#' @aliases centralization.degree
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_degree(g)$centralization
+#' centr_clo(g, mode = "all")$centralization
+#' centr_betw(g, directed = FALSE)$centralization
+#' centr_eigen(g, directed = FALSE)$centralization
+
+centr_degree <- centr_degree
+
+#' Theoretical maximum for degree centralization
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph. It can also be \code{NULL}, if
+#'   \code{nodes}, \code{mode} and \code{loops} are all given.
+#' @param nodes The number of vertices. This is ignored if the graph is given.
+#' @param mode This is the same as the \code{mode} argument of
+#'   \code{degree}.
+#' @param loops Logical scalar, whether to consider loops edges when
+#'   calculating the degree.
+#' @return Real scalar, the theoratical maximum (unnormalized) graph degree
+#'   centrality score for graphs with given order and other parameters.
+#'
+#' @aliases centralization.degree.tmax
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_degree(g, normalized = FALSE)$centralization %>%
+#'  `/`(centr_degree_tmax(g))
+#' centr_degree(g, normalized = TRUE)$centralization
+
+centr_degree_tmax <- centr_degree_tmax
+
+
+#' Centralize a graph according to the betweenness of vertices
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph.
+#' @param directed logical scalar, whether to use directed shortest paths for
+#'   calculating betweenness.
+#' @param nobigint Logical scalar, whether to use big integers for the
+#' betweenness calculation. This argument is passed to the
+#' \code{\link{betweenness}} function.
+#' @param normalized Logical scalar. Whether to normalize the graph level
+#'   centrality score by dividing by the theoretical maximum.
+#' @return A named list with the following components:
+#'   \item{res}{The node-level centrality scores.}
+#'   \item{centralization}{The graph level centrality index.}
+#'   \item{theoretical_max}{The maximum theoretical graph level
+#'     centralization score for a graph with the given number of vertices,
+#'     using the same parameters. If the \code{normalized} argument was
+#'     \code{TRUE}, then the result was divided by this number.}
+#'
+#' @aliases centralization.betweenness
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_degree(g)$centralization
+#' centr_clo(g, mode = "all")$centralization
+#' centr_betw(g, directed = FALSE)$centralization
+#' centr_eigen(g, directed = FALSE)$centralization
+
+centr_betw <- centr_betw
+
+#' Theoretical maximum for betweenness centralization
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph. It can also be \code{NULL}, if
+#'   \code{nodes} is given.
+#' @param nodes The number of vertices. This is ignored if the graph is
+#'   given.
+#' @param directed logical scalar, whether to use directed shortest paths
+#'   for calculating betweenness.
+#' @return Real scalar, the theoratical maximum (unnormalized) graph
+#'   betweenness centrality score for graphs with given order and other
+#'   parameters.
+#'
+#' @aliases centralization.betweenness.tmax
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_betw(g, normalized = FALSE)$centralization %>%
+#'  `/`(centr_betw_tmax(g))
+#' centr_betw(g, normalized = TRUE)$centralization
+
+centr_betw_tmax <- centr_betw_tmax
+
+#' Centralize a graph according to the closeness of vertices
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph.
+#' @param mode This is the same as the \code{mode} argument of 
+#'   \code{closeness}.
+#' @param normalized Logical scalar. Whether to normalize the graph level
+#'   centrality score by dividing by the theoretical maximum.
+#' @return A named list with the following components:
+#'   \item{res}{The node-level centrality scores.}
+#'   \item{centralization}{The graph level centrality index.}
+#'   \item{theoretical_max}{The maximum theoretical graph level
+#'     centralization score for a graph with the given number of vertices,
+#'     using the same parameters. If the \code{normalized} argument was
+#'     \code{TRUE}, then the result was divided by this number.}
+#'
+#' @aliases centralization.closeness
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_degree(g)$centralization
+#' centr_clo(g, mode = "all")$centralization
+#' centr_betw(g, directed = FALSE)$centralization
+#' centr_eigen(g, directed = FALSE)$centralization
+
+centr_clo <- centr_clo
+
+#' Theoretical maximum for closeness centralization
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph. It can also be \code{NULL}, if
+#'   \code{nodes} is given.
+#' @param nodes The number of vertices. This is ignored if the graph is
+#'   given.
+#' @param mode This is the same as the \code{mode} argument of 
+#'   \code{closeness}.
+#' @return Real scalar, the theoratical maximum (unnormalized) graph
+#'   closeness centrality score for graphs with given order and other
+#'   parameters.
+#'
+#' @aliases centralization.closeness.tmax
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_clo(g, normalized = FALSE)$centralization %>%
+#'  `/`(centr_clo_tmax(g))
+#' centr_clo(g, normalized = TRUE)$centralization
+
+centr_clo_tmax <- centr_clo_tmax
+
+#' Centralize a graph according to the eigenvector centrality of vertices
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph.
+#' @param directed logical scalar, whether to use directed shortest paths for
+#'   calculating eigenvector centrality.
+#' @param scale Whether to rescale the eigenvector centrality scores, such that
+#'   the maximum score is one.
+#' @param options This is passed to \code{\link{eigen_centrality}}, the options
+#'   for the ARPACK eigensolver.
+#' @param normalized Logical scalar. Whether to normalize the graph level
+#'   centrality score by dividing by the theoretical maximum.
+#' @return A named list with the following components:
+#'   \item{vector}{The node-level centrality scores.}
+#'   \item{value}{The corresponding eigenvalue.}
+#'   \item{options}{ARPACK options, see the return value of
+#'     \code{\link{eigen_centrality}} for details.} 
+#'   \item{centralization}{The graph level centrality index.}
+#'   \item{theoretical_max}{The same as above, the theoretical maximum
+#'     centralization score for a graph with the same number of vertices.}
+#'
+#' @aliases centralization.evcent
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_degree(g)$centralization
+#' centr_clo(g, mode = "all")$centralization
+#' centr_betw(g, directed = FALSE)$centralization
+#' centr_eigen(g, directed = FALSE)$centralization
+#'
+#' # The most centralized graph according to eigenvector centrality
+#' g0 <- make_graph(c(2,1), n = 10, dir = FALSE)
+#' g1 <- make_star(10, mode = "undirected")
+#' centr_eigen(g0)$centralization
+#' centr_eigen(g1)$centralization
+
+centr_eigen <- centr_eigen
+
+#' Theoretical maximum for betweenness centralization
+#'
+#' See \code{\link{centralize}} for a summary of graph centralization.
+#' 
+#' @param graph The input graph. It can also be \code{NULL}, if
+#'   \code{nodes} is given.
+#' @param nodes The number of vertices. This is ignored if the graph is
+#'   given.
+#' @param directed logical scalar, whether to use directed shortest paths
+#'   for calculating betweenness.
+#' @param scale Whether to rescale the eigenvector centrality scores,
+#'   such that the maximum score is one.
+#' @return Real scalar, the theoratical maximum (unnormalized) graph
+#'   betweenness centrality score for graphs with given order and other
+#'   parameters.
+#'
+#' @aliases centralization.evcent.tmax
+#' @family centralization related
+#' 
+#' @export
+#' 
+#' @examples
+#' # A BA graph is quite centralized
+#' g <- sample_pa(1000, m = 4)
+#' centr_eigen(g, normalized = FALSE)$centralization %>%
+#'  `/`(centr_eigen_tmax(g))
+#' centr_eigen(g, normalized = TRUE)$centralization
+
+centr_eigen_tmax <- centr_eigen_tmax
diff --git a/R/cliques.R b/R/cliques.R
index 8a7edaa..770f340 100644
--- a/R/cliques.R
+++ b/R/cliques.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,8 +19,73 @@
 #
 ###################################################################
 
+
+
+#' The functions find cliques, ie. complete subgraphs in a graph
+#' 
+#' These functions find all, the largest or all the maximal cliques in an
+#' undirected graph. The size of the largest clique can also be calculated.
+#' 
+#' \code{cliques} find all complete subgraphs in the input graph, obeying the
+#' size limitations given in the \code{min} and \code{max} arguments.
+#' 
+#' \code{largest_cliques} finds all largest cliques in the input graph. A
+#' clique is largest if there is no other clique including more vertices.
+#' 
+#' \code{max_cliques} finds all maximal cliques in the input graph.  A
+#' clique in maximal if it cannot be extended to a larger clique. The largest
+#' cliques are always maximal, but a maximal clique is not neccessarily the
+#' largest.
+#' 
+#' \code{count_max_cliques} counts the maximal cliques.
+#' 
+#' \code{clique_num} calculates the size of the largest clique(s).
+#' 
+#' The current implementation of these functions searches for maximal
+#' independent vertex sets (see \code{\link{ivs}}) in the
+#' complementer graph.
+#' 
+#' @aliases cliques largest_cliques maximal.cliques maximal.cliques.count
+#' clique.number clique_num largest.cliques count_max_cliques max_cliques
+#' @param graph The input graph, directed graphs will be considered as
+#' undirected ones, multiple edges and loops are ignored.
+#' @param min Numeric constant, lower limit on the size of the cliques to find.
+#' \code{NULL} means no limit, ie. it is the same as 0.
+#' @param max Numeric constant, upper limit on the size of the cliques to find.
+#' \code{NULL} means no limit.
+#' @return \code{cliques}, \code{largest_cliques} and \code{clique_num}
+#' return a list containing numeric vectors of vertex ids. Each list element is
+#' a clique.
+#' 
+#' \code{max_cliques} returns \code{NULL}, invisibly, if its \code{file}
+#' argument is not \code{NULL}. The output is written to the specified file in
+#' this case.
+#' 
+#' \code{clique_num} and \code{count_max_cliques} return an integer
+#' scalar.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{ivs}}
+#' @references For maximal cliques the following algorithm is implemented:
+#' David Eppstein, Maarten Loffler, Darren Strash: Listing All Maximal Cliques
+#' in Sparse Graphs in Near-optimal Time.  \url{http://arxiv.org/abs/1006.5440}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # this usually contains cliques of size six
+#' g <- sample_gnp(100, 0.3)
+#' clique_num(g)
+#' cliques(g, min=6)
+#' largest_cliques(g)
+#' 
+#' # To have a bit less maximal cliques, about 100-200 usually
+#' g <- sample_gnp(100, 0.03)
+#' max_cliques(g)
+#' 
+#' 
 cliques <- function(graph, min=NULL, max=NULL) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -35,23 +99,50 @@ cliques <- function(graph, min=NULL, max=NULL) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_cliques", graph, as.numeric(min), as.numeric(max),
                PACKAGE="igraph")
-  lapply(res, function(x) x+1)
+  res <- lapply(res, function(x) x+1)
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, create_vs, graph = graph)
+  }
+
+  res
 }
 
-largest.cliques <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+largest_cliques <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_largest_cliques", graph,
                PACKAGE="igraph")
-  lapply(res, function(x) x+1)  
+  res <- lapply(res, function(x) x+1)
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, create_vs, graph = graph)
+  }
+
+  res
 }
 
-maximal.cliques <- function(graph, min=NULL, max=NULL,
+#' @rdname cliques
+#' @param subset If not \code{NULL}, then it must be a vector of vertex ids,
+#' numeric or symbolic if the graph is named. The algorithm is run from these
+#' vertices only, so only a subset of all maximal cliques is returned. See the
+#' Eppstein paper for details. This argument makes it possible to easily
+#' parallelize the finding of maximal cliques.
+#' @param file If not \code{NULL}, then it must be a file name, i.e. a
+#' character scalar. The output of the algorithm is written to this file. (If
+#' it exists, then it will be overwritten.) Each clique will be a separate line
+#' in the file, given with the numeric ids of its vertices, separated by
+#' whitespace.
+#' @export
+
+max_cliques <- function(graph, min=NULL, max=NULL,
                             subset=NULL, file=NULL) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
@@ -85,14 +176,22 @@ maximal.cliques <- function(graph, min=NULL, max=NULL,
     res <- .Call("R_igraph_maximal_cliques", graph, subset,
                  as.numeric(min), as.numeric(max),
                  PACKAGE="igraph")
-    lapply(res, function(x) x+1)
+    res <- lapply(res, function(x) x+1)
+
+    if (igraph_opt("return.vs.es")) {
+      res <- lapply(res, create_vs, graph = graph)
+    }
+
+    res
   }
 }
 
-maximal.cliques.count <- function(graph, min=NULL, max=NULL,
+#' @export
+
+count_max_cliques <- function(graph, min=NULL, max=NULL,
                                   subset=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   if (is.null(min)) { min <- 0 }
   if (is.null(max)) { max <- 0 }
@@ -111,8 +210,10 @@ maximal.cliques.count <- function(graph, min=NULL, max=NULL,
   res
 }
 
-clique.number <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+clique_num <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
   
@@ -121,8 +222,77 @@ clique.number <- function(graph) {
         PACKAGE="igraph")
 }
 
-independent.vertex.sets <- function(graph, min=NULL, max=NULL) {
-  if (!is.igraph(graph)) {
+
+
+#' Independent vertex sets
+#' 
+#' A vertex set is called independent if there no edges between any two
+#' vertices in it. These functions find independent vertex sets in undirected
+#' graphs
+#' 
+#' \code{ivs} finds all independent vertex sets in the
+#' network, obeying the size limitations given in the \code{min} and \code{max}
+#' arguments.
+#' 
+#' \code{largest_ivs} finds the largest independent vertex
+#' sets in the graph. An independent vertex set is largest if there is no
+#' independent vertex set with more vertices.
+#' 
+#' \code{maximal_ivs} finds the maximal independent vertex
+#' sets in the graph. An independent vertex set is maximal if it cannot be
+#' extended to a larger independent vertex set. The largest independent vertex
+#' sets are maximal, but the opposite is not always true.
+#' 
+#' \code{independece.number} calculate the size of the largest independent
+#' vertex set(s).
+#' 
+#' These functions use the algorithm described by Tsukiyama et al., see
+#' reference below.
+#' 
+#' @aliases independent.vertex.sets largest.independent.vertex.sets
+#' maximal.independent.vertex.sets independence.number ivs_size ivs
+#' largest_ivs maximal_ivs
+#' @param graph The input graph, directed graphs are considered as undirected,
+#' loop edges and multiple edges are ignored.
+#' @param min Numeric constant, limit for the minimum size of the independent
+#' vertex sets to find. \code{NULL} means no limit.
+#' @param max Numeric constant, limit for the maximum size of the independent
+#' vertex sets to find. \code{NULL} means no limit.
+#' @return \code{ivs},
+#' \code{largest_ivs} and
+#' \code{maximal_ivs} return a list containing numeric
+#' vertex ids, each list element is an independent vertex set.
+#' 
+#' \code{ivs_size} returns an integer constant.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} ported it from the Very Nauty
+#' Graph Library by Keith Briggs (\url{http://keithbriggs.info/}) and Gabor
+#' Csardi \email{csardi.gabor@@gmail.com} wrote the R interface and this manual
+#' page.
+#' @seealso \code{\link{cliques}}
+#' @references S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new
+#' algorithm for generating all the maximal independent sets. \emph{SIAM J
+#' Computing}, 6:505--517, 1977.
+#' @export
+#' @keywords graphs
+#' @examples
+#'
+#' # Do not run, takes a couple of seconds
+#' \dontrun{
+#' 
+#' # A quite dense graph
+#' set.seed(42)
+#' g <- sample_gnp(100, 0.9)
+#' ivs_size(g)
+#' ivs(g, min=ivs_size(g))
+#' largest_ivs(g)
+#' # Empty graph
+#' induced_subgraph(g, largest_ivs(g)[[1]])
+#' 
+#' length(maximal_ivs(g))
+#' }
+
+ivs <- function(graph, min=NULL, max=NULL) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
@@ -138,33 +308,57 @@ independent.vertex.sets <- function(graph, min=NULL, max=NULL) {
   res <- .Call("R_igraph_independent_vertex_sets", graph, as.numeric(min),
                as.numeric(max),
                PACKAGE="igraph")
-  lapply(res, function(x) x+1)
+  res <- lapply(res, function(x) x+1)
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, create_vs, graph = graph)
+  }
+
+  res
 }
 
-largest.independent.vertex.sets <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+largest_ivs <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_largest_independent_vertex_sets", graph,
                PACKAGE="igraph")
-  lapply(res, function(x) x+1)
+  res <- lapply(res, function(x) x+1)
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, create_vs, graph = graph)
+  }
+
+  res
 }
 
-maximal.independent.vertex.sets <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+maximal_ivs <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_maximal_independent_vertex_sets", graph,
                PACKAGE="igraph")
-  lapply(res, function(x) x+1)
+  res <- lapply(res, function(x) x+1)
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, create_vs, graph = graph)
+  }
+
+  res
 }
 
-independence.number <- function(graph) {
-  if (!is.igraph(graph)) {
+#' @export
+
+ivs_size <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
diff --git a/R/cocitation.R b/R/cocitation.R
index 32d9b10..2a55cdc 100644
--- a/R/cocitation.R
+++ b/R/cocitation.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,33 +19,71 @@
 #
 ###################################################################
 
+
+
+#' Cocitation coupling
+#' 
+#' Two vertices are cocited if there is another vertex citing both of them.
+#' \code{cocitation} siply counts how many types two vertices are cocited. The
+#' bibliographic coupling of two vertices is the number of other vertices they
+#' both cite, \code{bibcoupling} calculates this.
+#' 
+#' \code{cocitation} calculates the cocitation counts for the vertices in the
+#' \code{v} argument and all vertices in the graph.
+#' 
+#' \code{bibcoupling} calculates the bibliographic coupling for vertices in
+#' \code{v} and all vertices in the graph.
+#' 
+#' Calculating the cocitation or bibliographic coupling for only one vertex
+#' costs the same amount of computation as for all vertices. This might change
+#' in the future.
+#' 
+#' @aliases cocitation bibcoupling
+#' @param graph The graph object to analyze
+#' @param v Vertex sequence or numeric vector, the vertex ids for which the
+#' cocitation or bibliographic coupling values we want to calculate. The
+#' default is all vertices.
+#' @return A numeric matrix with \code{length(v)} lines and
+#' \code{vcount(graph)} columns. Element \code{(i,j)} contains the cocitation
+#' or bibliographic coupling for vertices \code{v[i]} and \code{j}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' cocitation(g)
+#' bibcoupling(g)
+#' 
 cocitation <- function(graph, v=V(graph)) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   v <- as.igraph.vs(graph, v)
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_cocitation", graph, v-1,
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-    rownames(res) <- get.vertex.attribute(graph, "name", v)
-    colnames(res) <- get.vertex.attribute(graph, "name")
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    rownames(res) <- vertex_attr(graph, "name", v)
+    colnames(res) <- vertex_attr(graph, "name")
   }
   res
 }
 
+#' @export
+
 bibcoupling <- function(graph, v=V(graph)) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   v <- as.igraph.vs(graph, v)
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_bibcoupling", graph, v-1,
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-    rownames(res) <- get.vertex.attribute(graph, "name", v)
-    colnames(res) <- get.vertex.attribute(graph, "name")
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    rownames(res) <- vertex_attr(graph, "name", v)
+    colnames(res) <- vertex_attr(graph, "name")
   }
   res
 }
diff --git a/R/cohesive.blocks.R b/R/cohesive.blocks.R
index e33211d..ded7482 100644
--- a/R/cohesive.blocks.R
+++ b/R/cohesive.blocks.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,47 +19,297 @@
 #
 ###################################################################
 
-cohesive.blocks <- function(graph, labels=TRUE) {
+
+
+#' Calculate Cohesive Blocks
+#' 
+#' Calculates cohesive blocks for objects of class \code{igraph}.
+#' 
+#' Cohesive blocking is a method of determining hierarchical subsets of graph
+#' vertices based on their structural cohesion (or vertex connectivity). For a
+#' given graph \eqn{G}, a subset of its vertices \eqn{S\subset V(G)}{S} is said
+#' to be maximally \eqn{k}-cohesive if there is no superset of \eqn{S} with
+#' vertex connectivity greater than or equal to \eqn{k}. Cohesive blocking is a
+#' process through which, given a \eqn{k}-cohesive set of vertices, maximally
+#' \eqn{l}-cohesive subsets are recursively identified with \eqn{l>k}. Thus a
+#' hiearchy of vertex subsets is found, whith the entire graph \eqn{G} at its
+#' root.
+#' 
+#' The function \code{cohesive_blocks} implements cohesive blocking.  It
+#' returns a \code{cohesiveBlocks} object. \code{cohesiveBlocks} should be
+#' handled as an opaque class, i.e. its internal structure should not be
+#' accessed directly, but through the functions listed here.
+#' 
+#' The function \code{length} can be used on \code{cohesiveBlocks} objects and
+#' it gives the number of blocks.
+#' 
+#' The function \code{blocks} returns the actual blocks stored in the
+#' \code{cohesiveBlocks} object. They are returned in a list of numeric
+#' vectors, each containing vertex ids.
+#' 
+#' The function \code{graphs_from_cohesive_blocks} is similar, but returns the blocks as
+#' (induced) subgraphs of the input graph. The various (graph, vertex and edge)
+#' attributes are kept in the subgraph.
+#' 
+#' The function \code{cohesion} returns a numeric vector, the cohesion of the
+#' different blocks. The order of the blocks is the same as for the
+#' \code{blocks} and \code{graphs_from_cohesive_blocks} functions.
+#' 
+#' The block hierarchy can be queried using the \code{hierarchy} function. It
+#' returns an igraph graph, its vertex ids are ordered according the order of
+#' the blocks in the \code{blocks} and \code{graphs_from_cohesive_blocks}, \code{cohesion},
+#' etc. functions.
+#' 
+#' \code{parent} gives the parent vertex of each block, in the block hierarchy,
+#' for the root vertex it gives 0.
+#' 
+#' \code{plot_hierarchy} plots the hierarchy tree of the cohesive blocks on the
+#' active graphics device, by calling \code{igraph.plot}.
+#' 
+#' The \code{export_pajek} function can be used to export the graph and its
+#' cohesive blocks in Pajek format. It can either export a single Pajek project
+#' file with all the information, or a set of files, depending on its
+#' \code{project.file} argument. If \code{project.file} is \code{TRUE}, then
+#' the following information is written to the file (or connection) given in
+#' the \code{file} argument: (1) the input graph, together with its attributes,
+#' see \code{\link{write_graph}} for details; (2) the hierarchy graph; and (3)
+#' one binary partition for each cohesive block. If \code{project.file} is
+#' \code{FALSE}, then the \code{file} argument must be a character scalar and
+#' it is used as the base name for the generated files. If \code{file} is
+#' \sQuote{basename}, then the following files are created: (1)
+#' \sQuote{basename.net} for the original graph; (2)
+#' \sQuote{basename_hierarchy.net} for the hierarchy graph; (3)
+#' \sQuote{basename_block_x.net} for each cohesive block, where \sQuote{x} is
+#' the number of the block, starting with one.
+#' 
+#' \code{max_cohesion} returns the maximal cohesion of each vertex, i.e. the
+#' cohesion of the most cohesive block of the vertex.
+#' 
+#' The generic function \code{summary} works on \code{cohesiveBlocks} objects
+#' and it prints a one line summary to the terminal.
+#' 
+#' The generic function \code{print} is also defined on \code{cohesiveBlocks}
+#' objects and it is invoked automatically if the name of the
+#' \code{cohesiveBlocks} object is typed in. It produces an output like this:
+#' \preformatted{ Cohesive block structure:
+#' B-1 c 1, n 23
+#' '- B-2 c 2, n 14 oooooooo.. .o......oo ooo
+#' '- B-4 c 5, n  7 ooooooo... .......... ...
+#' '- B-3 c 2, n 10 ......o.oo o.oooooo.. ...
+#' '- B-5 c 3, n  4 ......o.oo o......... ...  }
+#' The left part shows the block structure, in this case for five
+#' blocks. The first block always corresponds to the whole graph, even if its
+#' cohesion is zero. Then cohesion of the block and the number of vertices in
+#' the block are shown. The last part is only printed if the display is wide
+#' enough and shows the vertices in the blocks, ordered by vertex ids.
+#' \sQuote{o} means that the vertex is included, a dot means that it is not,
+#' and the vertices are shown in groups of ten.
+#' 
+#' The generic function \code{plot} plots the graph, showing one or more
+#' cohesive blocks in it.
+#' 
+#' @aliases cohesive.blocks cohesiveBlocks blocks graphs_from_cohesive_blocks blockGraphs
+#' hierarchy parent plotHierarchy export_pajek maxcohesion plot.cohesiveBlocks
+#' summary.cohesiveBlocks length.cohesiveBlocks print.cohesiveBlocks
+#' plot_hierarchy max_cohesion exportPajek
+#' @param graph For \code{cohesive_blocks} a graph object of class
+#' \code{igraph}. It must be undirected and simple. (See
+#' \code{\link{is_simple}}.)
+#' 
+#' For \code{graphs_from_cohesive_blocks} and \code{export_pajek} the same graph must be
+#' supplied whose cohesive block structure is given in the \code{blocks}
+#' argument.
+#' @param labels Logical scalar, whether to add the vertex labels to the result
+#' object. These labels can be then used when reporting and plotting the
+#' cohesive blocks.
+#' @param blocks,x,object A \code{cohesiveBlocks} object, created with the
+#' \code{cohesive_blocks} function.
+#' @param file Defines the file (or connection) the Pajek file is written to.
+#' 
+#' If the \code{project.file} argument is \code{TRUE}, then it can be a
+#' filename (with extension), a file object, or in general any king of
+#' connection object. The file/connection will be opened if it wasn't already.
+#' 
+#' If the \code{project.file} argument is \code{FALSE}, then several files are
+#' created and \code{file} must be a character scalar containing the base name
+#' of the files, without extension. (But it can contain the path to the files.)
+#' 
+#' See also details below.
+#' @param project.file Logical scalar, whether to create a single Pajek project
+#' file containing all the data, or to create separated files for each item.
+#' See details below.
+#' @param y The graph whose cohesive blocks are supplied in the \code{x}
+#' argument.
+#' @param colbar Color bar for the vertex colors. Its length should be at least
+#' \eqn{m+1}, where \eqn{m} is the maximum cohesion in the graph.
+#' Alternatively, the vertex colors can also be directly specified via the
+#' \code{col} argument.
+#' @param col A vector of vertex colors, in any of the usual formats. (Symbolic
+#' color names (e.g. \sQuote{red}, \sQuote{blue}, etc.) , RGB colors (e.g.
+#' \sQuote{#FF9900FF}), integer numbers referring to the current palette. By
+#' default the given \code{colbar} is used and vertices with the same maximal
+#' cohesion will have the same color.
+#' @param mark.groups A list of vertex sets to mark on the plot by circling
+#' them. By default all cohesive blocks are marked, except the one
+#' corresponding to the all vertices.
+#' @param layout The layout of a plot, it is simply passed on to
+#' \code{plot.igraph}, see the possible formats there. By default the
+#' Reingold-Tilford layout generator is used.
+#' @param \dots Additional arguments. \code{plot_hierarchy} and \code{plot} pass
+#' them to \code{plot.igraph}.  \code{print} and \code{summary} ignore them.
+#' @return \code{cohesive_blocks} returns a \code{cohesiveBlocks} object.
+#' 
+#' \code{blocks} returns a list of numeric vectors, containing vertex ids.
+#' 
+#' \code{graphs_from_cohesive_blocks} returns a list of igraph graphs, corresponding to the
+#' cohesive blocks.
+#' 
+#' \code{cohesion} returns a numeric vector, the cohesion of each block.
+#' 
+#' \code{hierarchy} returns an igraph graph, the representation of the cohesive
+#' block hierarchy.
+#' 
+#' \code{parent} returns a numeric vector giving the parent block of each
+#' cohesive block, in the block hierarchy. The block at the root of the
+#' hierarchy has no parent and \code{0} is returned for it.
+#' 
+#' \code{plot_hierarchy}, \code{plot} and \code{export_pajek} return \code{NULL},
+#' invisibly.
+#' 
+#' \code{max_cohesion} returns a numeric vector with one entry for each vertex,
+#' giving the cohesion of its most cohesive block.
+#' 
+#' \code{print} and \code{summary} return the \code{cohesiveBlocks} object
+#' itself, invisibly.
+#' 
+#' \code{length} returns a numeric scalar, the number of blocks.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com} for the current
+#' implementation, Peter McMahan (\url{http://home.uchicago.edu/~mcmahan/})
+#' wrote the first version in R.
+#' @seealso \code{\link{cohesion}}
+#' @references J. Moody and D. R. White. Structural cohesion and embeddedness:
+#' A hierarchical concept of social groups. \emph{American Sociological
+#' Review}, 68(1):103--127, Feb 2003.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## The graph from the Moody-White paper
+#' mw <- graph_from_literal(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
+#'                 5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
+#'                 10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
+#'                 17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
+#'                 21-22:23, 22-23)
+#' 
+#' mwBlocks <- cohesive_blocks(mw)
+#' 
+#' # Inspect block membership and cohesion
+#' mwBlocks
+#' blocks(mwBlocks)
+#' cohesion(mwBlocks)
+#' 
+#' # Save results in a Pajek file
+#' \dontrun{
+#' export_pajek(mwBlocks, mw, file="/tmp/mwBlocks.paj")
+#' }
+#' 
+#' # Plot the results
+#' plot(mwBlocks, mw)
+#' 
+#' ## The science camp network
+#' camp <- graph_from_literal(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
+#'                   Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
+#'                   Holly   - Carol:Pat:Pam:Jennie:Bill,
+#'                   Bill    - Pauline:Michael:Lee:Holly,
+#'                   Pauline - Bill:Jennie:Ann,
+#'                   Jennie  - Holly:Michael:Lee:Ann:Pauline,
+#'                   Michael - Bill:Jennie:Ann:Lee:John,
+#'                   Ann     - Michael:Jennie:Pauline,
+#'                   Lee     - Michael:Bill:Jennie,
+#'                   Gery    - Pat:Steve:Russ:John,
+#'                   Russ    - Steve:Bert:Gery:John,
+#'                   John    - Gery:Russ:Michael)
+#' campBlocks <- cohesive_blocks(camp)
+#' campBlocks
+#' 
+#' plot(campBlocks, camp, vertex.label=V(camp)$name, margin=-0.2,
+#'      vertex.shape="rectangle", vertex.size=24, vertex.size2=8,
+#'      mark.border=1, colbar=c(NA, NA,"cyan","orange") )
+#' 
+cohesive_blocks <- function(graph, labels=TRUE) {
 
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_cohesive_blocks", graph,
         PACKAGE="igraph")
   class(res) <- "cohesiveBlocks"
-  if (labels && "name" %in% list.vertex.attributes(graph)) {
+  if (labels && "name" %in% vertex_attr_names(graph)) {
     res$labels <- V(graph)$name
   }
+  if (igraph_opt("return.vs.es")) {
+    res$blocks <- lapply(res$blocks, create_vs, graph = graph)
+  }
+
   res$vcount <- vcount(graph)
   res
 }
 
+#' @rdname cohesive_blocks
+#' @method length cohesiveBlocks
+#' @export
+ 
 length.cohesiveBlocks <- function(x) {
   length(x$blocks)
 }
 
+#' @rdname cohesive_blocks
+#' @export
+
 blocks <- function(blocks) {
   blocks$blocks
 }
 
-blockGraphs <- function(blocks, graph) {
-  lapply(blocks(blocks), induced.subgraph, graph=graph)
+#' @rdname cohesive_blocks
+#' @export
+
+graphs_from_cohesive_blocks <- function(blocks, graph) {
+  lapply(blocks(blocks), induced_subgraph, graph=graph)
 }
 
-cohesion <- function(blocks) {
-  blocks$cohesion
+#' @export
+
+cohesion <- function(x, ...)
+  UseMethod("cohesion")
+
+#' @rdname cohesive_blocks
+#' @method cohesion cohesiveBlocks
+#' @export
+
+cohesion.cohesiveBlocks <- function(x, ...) {
+  x$cohesion
 }
 
+#' @rdname cohesive_blocks
+#' @export
+
 hierarchy <- function(blocks) {
   blocks$blockTree
 }
 
+#' @rdname cohesive_blocks
+#' @export
+
 parent <- function(blocks) {
   blocks$parent
 }
 
+#' @rdname cohesive_blocks
+#' @method print cohesiveBlocks
+#' @export
+
 print.cohesiveBlocks <- function(x, ...) {
   cat("Cohesive block structure:\n")
   myb <- blocks(x)
@@ -69,7 +318,7 @@ print.cohesiveBlocks <- function(x, ...) {
   si <- sapply(myb, length)
 
   cs <- 3 + 2 + nchar(length(x)) +
-    max(shortest.paths(hierarchy(x), mode="out", v=1)) * 3
+    max(distances(hierarchy(x), mode="out", v=1)) * 3
   
   .plot <- function(b, ind="") {
     if (b!=1) {
@@ -103,23 +352,34 @@ print.cohesiveBlocks <- function(x, ...) {
   invisible(x)
 }
 
+#' @rdname cohesive_blocks
+#' @method summary cohesiveBlocks
+#' @export
+
 summary.cohesiveBlocks <- function(object, ...) {
   cat("Structurally cohesive block structure, with",
       length(blocks(object)), "blocks.\n")
   invisible(object)
 }
 
+#' @rdname cohesive_blocks
+#' @method plot cohesiveBlocks
+#' @export
+ 
 plot.cohesiveBlocks <- function(x, y,
                                 colbar=rainbow(max(cohesion(x))+1),
-                                col=colbar[maxcohesion(x)+1],
+                                col=colbar[max_cohesion(x)+1],
                                 mark.groups=blocks(x)[-1],
                                 ...) {
   plot(y, mark.groups=mark.groups,
        vertex.color=col, ...)
 }
 
-plotHierarchy <- function(blocks,
-                          layout=layout.reingold.tilford(hierarchy(blocks),
+#' @rdname cohesive_blocks
+#' @export
+
+plot_hierarchy <- function(blocks,
+                          layout=layout_as_tree(hierarchy(blocks),
                             root=1), ...) {
   plot(hierarchy(blocks), layout=layout, ...)
 }
@@ -138,11 +398,11 @@ exportPajek.cohesiveblocks.pf <- function(blocks, graph, file) {
 
   ## The original graph
   cat(file=file, sep="", "*Network cohesive_blocks_input.net\r\n")
-  write.graph(graph, file=file, format="pajek")
+  write_graph(graph, file=file, format="pajek")
 
   ## The hierarchy graph
   cat(file=file, sep="", "\r\n*Network hierarchy.net\r\n")
-  write.graph(hierarchy(blocks), file=file, format="pajek")
+  write_graph(hierarchy(blocks), file=file, format="pajek")
 
   ## The blocks
   myb <- blocks(blocks)
@@ -163,10 +423,10 @@ exportPajek.cohesiveblocks.pf <- function(blocks, graph, file) {
 exportPajek.cohesiveblocks.nopf <- function(blocks, graph, file) {
 
   ## The original graph
-  write.graph(graph, file=paste(sep="", file, ".net"), format="pajek")
+  write_graph(graph, file=paste(sep="", file, ".net"), format="pajek")
 
   ## The hierarchy graph
-  write.graph(hierarchy(blocks), file=paste(sep="", file, "_hierarchy.net"),
+  write_graph(hierarchy(blocks), file=paste(sep="", file, "_hierarchy.net"),
               format="pajek")
 
   ## The blocks
@@ -181,7 +441,10 @@ exportPajek.cohesiveblocks.nopf <- function(blocks, graph, file) {
   invisible(NULL)
 }
 
-exportPajek <- function(blocks, graph, file,
+#' @rdname cohesive_blocks
+#' @export
+
+export_pajek <- function(blocks, graph, file,
                         project.file=TRUE) {
   
   if (!project.file && !is.character(file)) {
@@ -196,7 +459,10 @@ exportPajek <- function(blocks, graph, file,
   }
 }
 
-maxcohesion <- function(blocks) {
+#' @rdname cohesive_blocks
+#' @export
+
+max_cohesion <- function(blocks) {
   res <- numeric(blocks$vcount)
   myb <- blocks(blocks)
   coh <- cohesion(blocks)
diff --git a/R/community.R b/R/community.R
index 5159192..3992198 100644
--- a/R/community.R
+++ b/R/community.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -24,6 +23,202 @@
 # Community structure
 ###################################################################
 
+
+
+#' Functions to deal with the result of network community detection
+#'
+#' igraph community detection functions return their results as an object from
+#' the \code{communities} class. This manual page describes the operations of
+#' this class.
+#' 
+#' Community structure detection algorithms try to find dense subgraphs in
+#' directed or undirected graphs, by optimizing some criteria, and usually
+#' using heuristics.
+#' 
+#' igraph implements a number of community detection methods (see them below),
+#' all of which return an object of the class \code{communities}. Because the
+#' community structure detection algorithms are different, \code{communities}
+#' objects do not always have the same structure. Nevertheless, they have some
+#' common operations, these are documented here.
+#' 
+#' The \code{print} generic function is defined for \code{communities}, it
+#' prints a short summary.
+#' 
+#' The \code{length} generic function call be called on \code{communities} and
+#' returns the number of communities.
+#' 
+#' The \code{sizes} function returns the community sizes, in the order of their
+#' ids.
+#' 
+#' \code{membership} gives the division of the vertices, into communities. It
+#' returns a numeric vector, one value for each vertex, the id of its
+#' community. Community ids start from one. Note that some algorithms calculate
+#' the complete (or incomplete) hierarchical structure of the communities, and
+#' not just a single partitioning. For these algorithms typically the
+#' membership for the highest modularity value is returned, but see also the
+#' manual pages of the individual algorithms.
+#' 
+#' \code{communities} is also the name of a function, that returns a list of
+#' communities, each identified by their vertices. The vertices will have
+#' symbolic names if the \code{add.vertex.names} igraph option is set, and the
+#' graph itself was named. Otherwise numeric vertex ids are used.
+#' 
+#' \code{modularity} gives the modularity score of the partitioning. (See
+#' \code{\link{modularity.igraph}} for details. For algorithms that do not
+#' result a single partitioning, the highest modularity value is returned.
+#' 
+#' \code{algorithm} gives the name of the algorithm that was used to calculate
+#' the community structure.
+#' 
+#' \code{crossing} returns a logical vector, with one value for each edge,
+#' ordered according to the edge ids. The value is \code{TRUE} iff the edge
+#' connects two different communities, according to the (best) membership
+#' vector, as returned by \code{membership()}.
+#' 
+#' \code{is_hierarchical} checks whether a hierarchical algorithm was used to
+#' find the community structure. Some functions only make sense for
+#' hierarchical methods (e.g. \code{merges}, \code{cut_at} and
+#' \code{as.dendrogram}).
+#' 
+#' \code{merges} returns the merge matrix for hierarchical methods. An error
+#' message is given, if a non-hierarchical method was used to find the
+#' community structure. You can check this by calling \code{is_hierarchical} on
+#' the \code{communities} object.
+#' 
+#' \code{cut_at} cuts the merge tree of a hierarchical community finding method,
+#' at the desired place and returns a membership vector. The desired place can
+#' be expressed as the desired number of communities or as the number of merge
+#' steps to make. The function gives an error message, if called with a
+#' non-hierarchical method.
+#' 
+#' \code{as.dendrogram} converts a hierarchical community structure to a
+#' \code{dendrogram} object. It only works for hierarchical methods, and gives
+#' an error message to others. See \code{\link[stats]{dendrogram}} for details.
+#' 
+#' \code{as.hclust} is similar to \code{as.dendrogram}, but converts a
+#' hierarchical community structure to a \code{hclust} object.
+#' 
+#' \code{as_phylo} converts a hierarchical community structure to a \code{phylo}
+#' object, you will need the \code{ape} package for this.
+#' 
+#' \code{show_trace} works (currently) only for communities found by the leading
+#' eigenvector method (\code{\link{cluster_leading_eigen}}), and
+#' returns a character vector that gives the steps performed by the algorithm
+#' while finding the communities.
+#' 
+#' \code{code_len} is defined for the InfoMAP method
+#' (\code{\link{cluster_infomap}} and returns the code length of the
+#' partition.
+#' 
+#' It is possibly to call the \code{plot} function on \code{communities}
+#' objects. This will plot the graph (and uses \code{\link{plot.igraph}}
+#' internally), with the communities shown. By default it colores the vertices
+#' according to their communities, and also marks the vertex groups
+#' corresponding to the communities. It passes additional arguments to
+#' \code{\link{plot.igraph}}, please see that and also
+#' \code{\link{igraph.plotting}} on how to change the plot.
+#' 
+#' @rdname communities
+#' @aliases communities membership algorithm crossing cutat merges sizes cut_at
+#' is.hierarchical print.communities plot.communities length.communities
+#' as.dendrogram.communities as.hclust.communities code_len
+#' asPhylo asPhylo.communities showtrace code.length
+#' as_phylo as_phylo.communities show_trace is_hierarchical
+#' @param communities,x,object A \code{communities} object, the result of an
+#' igraph community detection function.
+#' @param graph An igraph graph object, corresponding to \code{communities}.
+#' @param y An igraph graph object, corresponding to the communities in
+#' \code{x}.
+#' @param no Integer scalar, the desired number of communities. If too low or
+#' two high, then an error message is given. Exactly one of \code{no} and
+#' \code{steps} must be supplied.
+#' @param steps The number of merge operations to perform to produce the
+#' communities. Exactly one of \code{no} and \code{steps} must be supplied.
+#' @param col A vector of colors, in any format that is accepted by the regular
+#' R plotting methods. This vector gives the colors of the vertices explicitly.
+#' @param mark.groups A list of numeric vectors. The communities can be
+#' highlighted using colored polygons. The groups for which the polygons are
+#' drawn are given here. The default is to use the groups given by the
+#' communities. Supply \code{NULL} here if you do not want to highlight any
+#' groups.
+#' @param edge.color The colors of the edges. By default the edges within
+#' communities are colored green and other edges are red.
+#' @param hang Numeric scalar indicating how the height of leaves should be
+#' computed from the heights of their parents; see \code{\link{plot.hclust}}.
+#' @param use.modularity Logical scalar, whether to use the modularity values
+#' to define the height of the branches.
+#' @param \dots Additional arguments. \code{plot.communities} passes these to
+#' \code{\link{plot.igraph}}. The other functions silently ignore
+#' them.
+#' @param membership Numeric vector, one value for each vertex, the membership
+#' vector of the community structure. Might also be \code{NULL} if the
+#' community structure is given in another way, e.g. by a merge matrix.
+#' @param algorithm If not \code{NULL} (meaning an unknown algorithm), then a
+#' character scalar, the name of the algorithm that produced the community
+#' structure.
+#' @param merges If not \code{NULL}, then the merge matrix of the hierarchical
+#' community structure. See \code{merges} below for more information on its
+#' format.
+#' @param modularity Numeric scalar or vector, the modularity value of the
+#' community structure. It can also be \code{NULL}, if the modularity of the
+#' (best) split is not available.
+#' @return \code{print} returns the \code{communities} object itself,
+#' invisibly.
+#' 
+#' \code{length} returns an integer scalar.
+#' 
+#' \code{sizes} returns a numeric vector.
+#' 
+#' \code{membership} returns a numeric vector, one number for each vertex in
+#' the graph that was the input of the community detection.
+#' 
+#' \code{modularity} returns a numeric scalar.
+#' 
+#' \code{algorithm} returns a character scalar.
+#' 
+#' \code{crossing} returns a logical vector.
+#' 
+#' \code{is_hierarchical} returns a logical scalar.
+#' 
+#' \code{merges} returns a two-column numeric matrix.
+#' 
+#' \code{cut_at} returns a numeric vector, the membership vector of the
+#' vertices.
+#' 
+#' \code{as.dendrogram} returns a \code{\link[stats]{dendrogram}} object.
+#' 
+#' \code{show_trace} returns a character vector.
+#' 
+#' \code{code_len} returns a numeric scalar for communities found with the
+#' InfoMAP method and \code{NULL} for other methods.
+#' 
+#' \code{plot} for \code{communities} objects returns \code{NULL}, invisibly.
+#' 
+#' #' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso See \code{\link{plot_dendrogram}} for plotting community structure
+#' dendrograms.
+#' 
+#' See \code{\link{compare}} for comparing two community structures
+#' on the same graph.
+#' 
+#' The different methods for finding communities, they all return a
+#' \code{communities} object: \code{\link{cluster_edge_betweenness}},
+#' \code{\link{cluster_fast_greedy}},
+#' \code{\link{cluster_label_prop}},
+#' \code{\link{cluster_leading_eigen}},
+#' \code{\link{cluster_louvain}}, \code{\link{cluster_optimal}},
+#' \code{\link{cluster_spinglass}}, \code{\link{cluster_walktrap}}.
+#' @keywords graphs
+#' @export
+#' @examples
+#' 
+#' karate <- make_graph("Zachary")
+#' wc <- cluster_walktrap(karate)
+#' modularity(wc)
+#' membership(wc)
+#' plot(wc, karate)
+#' 
+
 membership <- function(communities) {
   if (!is.null(communities$membership)) {
     res <- communities$membership
@@ -34,92 +229,204 @@ membership <- function(communities) {
   } else {
     stop("Cannot calculate community membership")
   }
-  if (!is.null(communities$names)) {
+  if (igraph_opt("add.vertex.names") && !is.null(communities$names)) {
     names(res) <- communities$names
   }
+  class(res) <- "membership"
   res
 }
 
+#' @method print membership
+#' @export
+
+print.membership <- function(x, ...) print(unclass(x), ...)
+
+#' Declare a numeric vector as a membership vector
+#'
+#' This is useful if you want to use functions defined on
+#' membership vectors, but your membership vector does not
+#' come from an igraph clustering method.
+#'
+#' @param x The input vector.
+#' @return The input vector, with the \code{membership} class added.
+#' @export
+#' @examples
+#' ## Compare to the correct clustering
+#' g <- (make_full_graph(10) + make_full_graph(10)) %>%
+#'   rewire(each_edge(p = 0.2))
+#' correct <- rep(1:2, each = 10) %>% as_membership
+#' fc <- cluster_fast_greedy(g)
+#' compare(correct, fc)
+#' compare(correct, membership(fc))
+
+as_membership <- function(x) add_class(x, "membership")
+
+
+#' @include printr.R
+
+head_print <- printr$head_print
+
+#' @rdname communities
+#' @method print communities
+#' @export
+
 print.communities <- function(x, ...) {
-  cat("Graph community structure calculated with the",
-      algorithm(x), "algorithm\n")
-  if (algorithm(x)=="spinglass") {
-    cat("Number of communities:", max(membership(x)), "\n")
-    cat("Modularity:", modularity(x), "\n")
-    cat("Membership vector:\n")
-    print(membership(x))
-  } else if (algorithm(x) %in% c("walktrap", "edge betweenness",
-                                "fast greedy")) {
-    cat("Number of communities (best split):", max(membership(x)), "\n")
-    cat("Modularity (best split):", modularity(x), "\n")
-    cat("Membership vector:\n")
-    print(membership(x))
-  } else if (algorithm(x) %in% c("leading eigenvector")) {
-    cat("Number of communities (best split):", max(membership(x)), "\n")
-    cat("Modularity (best split):", modularity(x), "\n")
-    cat("Membership vector:\n")
-    print(membership(x))
-  } else if (algorithm(x) == "label propagation") {
-    cat("Number of communities:", max(membership(x)), "\n")
-    cat("Modularity:", modularity(x), "\n")
-    cat("Membership vector:\n")
-    print(membership(x))
-  } else if (algorithm(x) == "multi level") {
-    cat("Number of communities (best split):", max(membership(x)), "\n")
-    cat("Modularity (best split):", modularity(x), "\n")
-    cat("Membership vector:\n")
-    print(membership(x))
-  } else if (algorithm(x) == "optimal") {
-    cat("Number of communities:", max(membership(x)), "\n")
-    cat("Modularity:", modularity(x), "\n")
-    cat("Membership vector:\n")
-    print(membership(x))
-  } else if (algorithm(x) == "infomap") {
-    cat("Number of communities:", max(membership(x)), "\n")
-    if (!is.null(x$modularity)) {
-      cat("Modularity:", modularity(x), "\n")
-    }
-    cat("Membership vector:\n")
-    print(membership(x))
+
+  noc <- if (!is.null(x$membership)) max(membership(x)) else NA
+  mod <- if (!is.null(x$modularity)) {
+    modularity(x) %>% format(digits = 2)
   } else {
-    cat("Number of communities:", max(membership(x)), "\n")
-    if (!is.null(x$modularity)) {
-      cat("Modularity:", modularity(x), "\n")
+    NA_real_
+  }
+  alg <- x$algorithm %||% "unknown"
+
+  cat("IGRAPH clustering ", alg, ", groups: ", noc, ", mod: ", mod, "\n", sep="")
+
+  if (!is.null(x$membership)) {
+    grp <- groups(x)
+    cat("+ groups:\n")
+    hp <- function(o) {
+      head_print(o, max_lines = igraph_opt("auto.print.lines"),
+                 omitted_footer = "+ ... omitted several groups/vertices\n",)
     }
-    cat("Membership vector:\n")
-    print(membership(x))
+    indent_print(grp, .printer = hp, .indent = "  ")
+
+  } else {
+    cat(" + groups not available\n")
   }
+
   invisible(x)
 }
 
-create.communities <- function(membership, algorithm=NULL, merges=NULL,
-                               modularity=NULL, ...) {
-
-  stopifnot(is.numeric(membership))
+#' Creates a communities object.
+#'
+#' This is useful to integrate the results of community finding algorithms
+#' that are not included in igraph.
+#'
+#' @param graph The graph of the community structure.
+#' @param membership The membership vector of the community structure, a
+#'   numeric vector denoting the id of the community for each vertex. It
+#'   might be \code{NULL} for hierarchical community structures.
+#' @param algorithm Character string, the algorithm that generated
+#'   the community structure, it can be arbitrary.
+#' @param merges A merge matrix, for hierarchical community structures (or
+#'   \code{NULL} otherwise.
+#' @param modularity Modularity value of the community structure. If this
+#'   is \code{TRUE} and the membership vector is available, then it the
+#'   modularity values is calculated automatically.
+#' @return A \code{communities} object.
+#'
+#' @aliases create.communities
+#'
+#' @export
+
+make_clusters <- function(graph, membership = NULL, algorithm = NULL,
+                          merges = NULL, modularity = TRUE) {
+
+  stopifnot(is.null(membership) || is.numeric(membership))
   stopifnot(is.null(algorithm) ||
             (is.character(algorithm) && length(algorithm)==1))
   stopifnot(is.null(merges) ||
-            (is.matrix(merges) && is.numeric(merges) && ncol(merges)==2))
+              (is.matrix(merges) && is.numeric(merges) && ncol(merges)==2))
   stopifnot(is.null(modularity) ||
+            (is.logical(modularity) && length(modularity) == 1) ||
             (is.numeric(modularity) &&
              length(modularity) %in% c(1, length(membership))))
 
+  if (is.logical(modularity)) {
+    if (modularity && !is.null(membership)) {
+      modularity <- modularity(graph, membership)
+    } else {
+      modularity <- NULL
+    }
+  }
+
   res <- list(membership=membership,
               algorithm=if (is.null(algorithm)) "unknown" else algorithm,
-              modularity=modularity, ...)
+              modularity=modularity)
   if (!is.null(merges)) {
     res$merges <- merges
   }
+  if (!is.null(membership)) {
+    res$vcount <- length(membership)
+  } else if (!is.null(merges)) {
+    res$vcount <- nrow(merges) + 1
+  }
   class(res) <- "communities"
   res
 }
 
+#' @export
+
 modularity <- function(x, ...)
   UseMethod("modularity")
 
+#' Modularity of a community structure of a graph
+#' 
+#' This function calculates how modular is a given division of a graph into
+#' subgraphs.
+#' 
+#' \code{modularity} calculates the modularity of a graph with respect to the
+#' given \code{membership} vector.
+#' 
+#' The modularity of a graph with respect to some division (or vertex types)
+#' measures how good the division is, or how separated are the different vertex
+#' types from each other. It defined as \deqn{Q=\frac{1}{2m} \sum_{i,j}
+#' (A_{ij}-\frac{k_ik_j}{2m})\delta(c_i,c_j),}{Q=1/(2m) * sum( (Aij-ki*kj/(2m)
+#' ) delta(ci,cj),i,j),} here \eqn{m} is the number of edges, \eqn{A_{ij}}{Aij}
+#' is the element of the \eqn{A} adjacency matrix in row \eqn{i} and column
+#' \eqn{j}, \eqn{k_i}{ki} is the degree of \eqn{i}, \eqn{k_j}{kj} is the degree
+#' of \eqn{j}, \eqn{c_i}{ci} is the type (or component) of \eqn{i},
+#' \eqn{c_j}{cj} that of \eqn{j}, the sum goes over all \eqn{i} and \eqn{j}
+#' pairs of vertices, and \eqn{\delta(x,y)}{delta(x,y)} is 1 if \eqn{x=y} and 0
+#' otherwise.
+#' 
+#' If edge weights are given, then these are considered as the element of the
+#' \eqn{A} adjacency matrix, and \eqn{k_i}{ki} is the sum of weights of
+#' adjacent edges for vertex \eqn{i}.
+#' 
+#' \code{modularity_matrix} calculates the modularity matrix. This is a dense matrix,
+#' and it is defined as the difference of the adjacency matrix and the
+#' configuration model null model matrix. In other words element
+#' \eqn{M_{ij}}{M[i,j]} is given as \eqn{A_{ij}-d_i
+#' d_j/(2m)}{A[i,j]-d[i]d[j]/(2m)}, where \eqn{A_{ij}}{A[i,j]} is the (possibly
+#' weighted) adjacency matrix, \eqn{d_i}{d[i]} is the degree of vertex \eqn{i},
+#' and \eqn{m} is the number of edges (or the total weights in the graph, if it
+#' is weighed).
+#'
+#' @aliases modularity
+#' @param x,graph The input graph.
+#' @param membership Numeric vector, for each vertex it gives its community.
+#' The communities are numbered from one.
+#' @param weights If not \code{NULL} then a numeric vector giving edge weights.
+#' @param \dots Additional arguments, none currently.
+#' @return For \code{modularity} a numeric scalar, the modularity score of the
+#' given configuration.
+#' 
+#' For \code{modularity_matrix} a numeic square matrix, its order is the number of
+#' vertices in the graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{cluster_walktrap}},
+#' \code{\link{cluster_edge_betweenness}},
+#' \code{\link{cluster_fast_greedy}}, \code{\link{cluster_spinglass}} for
+#' various community detection methods.
+#' @references Clauset, A.; Newman, M. E. J. & Moore, C. Finding community
+#' structure in very large networks, \emph{Phyisical Review E} 2004, 70, 066111
+#' @method modularity igraph
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+#' g <- add_edges(g, c(1,6, 1,11, 6, 11))
+#' wtc <- cluster_walktrap(g)
+#' modularity(wtc)
+#' modularity(g, membership(wtc))
+#' 
+
 modularity.igraph <- function(x, membership, weights=NULL, ...) {
   # Argument checks
-  if (!is.igraph(x)) { stop("Not a graph object") }
+  if (!is_igraph(x)) { stop("Not a graph object") }
   membership <- as.numeric(membership)
   if (!is.null(weights)) weights <- as.numeric(weights)
 
@@ -130,6 +437,10 @@ modularity.igraph <- function(x, membership, weights=NULL, ...) {
   res
 }
 
+#' @rdname communities
+#' @method modularity communities
+#' @export
+
 modularity.communities <- function(x, ...) {
   if (!is.null(x$modularity)) {
     max(x$modularity)
@@ -138,26 +449,58 @@ modularity.communities <- function(x, ...) {
   }
 }
 
+#' @rdname modularity.igraph
+#' @aliases mod.matrix
+#' @export
+
+modularity_matrix <- function(graph, membership, weights=NULL) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  membership <- as.numeric(membership)-1
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
+  weights <- E(graph)$weight 
+  } 
+  if (!is.null(weights) && any(!is.na(weights))) { 
+  weights <- as.numeric(weights) 
+  } else { 
+  weights <- NULL 
+  }
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_modularity_matrix", graph, membership, weights,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @rdname communities
+#' @method length communities
+#' @export
+
 length.communities <- function(x) {
   m <- membership(x)
   max(m)
 }
 
+#' @rdname communities
+#' @export
+
 sizes <- function(communities) {
   m <- membership(communities)
   table(`Community sizes`=m)
 }
 
-communities <- function(communities) {
-  m <- membership(communities)
-  tapply(seq_along(m), m, simplify=FALSE,
-         function(x) x)
-}
+#' @rdname communities
+#' @export
 
 algorithm <- function(communities) {
   communities$algorithm
 }
 
+#' @rdname communities
+#' @export
+
 merges <- function(communities) {
   if (!is.null(communities$merges)) {
     communities$merges
@@ -166,9 +509,12 @@ merges <- function(communities) {
   }
 }
 
+#' @rdname communities
+#' @export
+
 crossing <- function(communities, graph) {
   m <- membership(communities)
-  el <- get.edgelist(graph, names=FALSE)
+  el <- as_edgelist(graph, names=FALSE)
   m1 <- m[el[,1]]
   m2 <- m[el[,2]]
   res <- m1 != m2
@@ -178,22 +524,18 @@ crossing <- function(communities, graph) {
   res
 }
 
-code.length <- function(communities) {
+#' @rdname communities
+#' @export
+
+code_len <- function(communities) {
   communities$codelength
 }
 
-is.hierarchical <- function(communities, full=FALSE) {
-  alg <- algorithm(communities)
-  if (alg %in% c("walktrap", "edge betweenness","fast greedy") ||
-      (alg == "leading eigenvector" && !full)) {
-    TRUE
-  } else if (alg %in% c("spinglass", "label propagation", "multi level",
-                        "optimal") ||
-             (alg == "leading eigenvector" && full)) {
-    FALSE
-  } else {
-    stop("Unknown community detection algorithm")
-  }
+#' @rdname communities
+#' @export
+
+is_hierarchical <- function(communities) {
+  ! is.null(communities$merges)
 }
 
 complete.dend <- function(comm, use.modularity) {
@@ -215,10 +557,15 @@ complete.dend <- function(comm, use.modularity) {
 
 # The following functions were adapted from the stats R package
 
+#' @rdname communities
+#' @importFrom stats as.dendrogram
+#' @method as.dendrogram communities
+#' @export
+ 
 as.dendrogram.communities <- function(object, hang=-1, use.modularity=FALSE,
                                       ...) {
-  if (!is.hierarchical(object, full=TRUE)) {
-    stop("Not a fully hierarchical community structure")
+  if (!is_hierarchical(object)) {
+    stop("Not a hierarchical community structure")
   }
 
   .memberDend <- function(x) {
@@ -300,22 +647,32 @@ as.dendrogram.communities <- function(object, hang=-1, use.modularity=FALSE,
   z
 }
 
+#' @rdname communities
+#' @importFrom stats as.hclust
+#' @method as.hclust communities
+#' @export
+ 
 as.hclust.communities <- function(x, hang=-1, use.modularity=FALSE,
                                   ...) {
   as.hclust(as.dendrogram(x, hang=hang, use.modularity=use.modularity))
 }
 
-asPhylo <- function(x, ...)
-  UseMethod("asPhylo")
+#' @rdname communities
+#' @export
+
+as_phylo <- function(x, ...)
+  UseMethod("as_phylo")
 
-asPhylo.communities <- function(x, use.modularity=FALSE, ...) {
+#' @rdname communities
+#' @method as_phylo communities
+#' @export
 
-  if (!is.hierarchical(x, full=TRUE)) {
-    stop("Not a fully hierarchical community structure")
+as_phylo.communities <- function(x, use.modularity=FALSE, ...) {
+
+  if (!is_hierarchical(x)) {
+    stop("Not a hierarchical community structure")
   }
 
-  require(ape, quietly = TRUE)
-  
   ## If multiple components, then we merge them in arbitrary order
   merges <- complete.dend(x, use.modularity)
 
@@ -362,13 +719,16 @@ asPhylo.communities <- function(x, use.modularity=FALSE, ...) {
   reorder(obj)
 }
 
-cutat <- function(communities, no, steps) {
+#' @rdname communities
+#' @export
+
+cut_at <- function(communities, no, steps) {
 
   if (!inherits(communities, "communities")) {
     stop("Not a community structure")
   }
-  if (!is.hierarchical(communities, full=TRUE)) {
-    stop("Not a fully hierarchical communitity structure")
+  if (!is_hierarchical(communities)) {
+    stop("Not a hierarchical communitity structure")
   }
 
   if ((!missing(no) && !missing(steps)) ||
@@ -395,7 +755,10 @@ cutat <- function(communities, no, steps) {
   }
 }
 
-showtrace <- function(communities) {
+#' @rdname communities
+#' @export
+
+show_trace <- function(communities) {
 
   if (!inherits(communities, "communities")) {
     stop("Not a community structure")
@@ -443,18 +806,135 @@ community.to.membership2 <- function(merges, vcount, steps) {
 
 #####################################################################
 
-spinglass.community <- function(graph, weights=NULL, vertex=NULL, spins=25,
+
+
+#' Finding communities in graphs based on statistical meachanics
+#' 
+#' This function tries to find communities in graphs via a spin-glass model and
+#' simulated annealing.
+#' 
+#' This function tries to find communities in a graph. A community is a set of
+#' nodes with many edges inside the community and few edges between outside it
+#' (i.e. between the community itself and the rest of the graph.)
+#' 
+#' This idea is reversed for edges having a negative weight, ie. few negative
+#' edges inside a community and many negative edges between communities. Note
+#' that only the \sQuote{neg} implementation supports negative edge weights.
+#' 
+#' The \code{spinglass.cummunity} function can solve two problems related to
+#' community detection. If the \code{vertex} argument is not given (or it is
+#' \code{NULL}), then the regular community detection problem is solved
+#' (approximately), i.e. partitioning the vertices into communities, by
+#' optimizing the an energy function.
+#' 
+#' If the \code{vertex} argument is given and it is not \code{NULL}, then it
+#' must be a vertex id, and the same energy function is used to find the
+#' community of the the given vertex. See also the examples below.
+#'
+#' @aliases spinglass.community
+#' @param graph The input graph, can be directed but the direction of the edges
+#' is neglected.
+#' @param weights The weights of the edges. Either a numeric vector or
+#' \code{NULL}. If it is null and the input graph has a \sQuote{weight} edge
+#' attribute then that will be used. If \code{NULL} and no such attribute is
+#' present then the edges will have equal weights. Set this to \code{NA} if the
+#' graph was a \sQuote{weight} edge attribute, but you don't want to use it for
+#' community detection.
+#' @param vertex This parameter can be used to calculate the community of a
+#' given vertex without calculating all communities. Note that if this argument
+#' is present then some other arguments are ignored.
+#' @param spins Integer constant, the number of spins to use. This is the upper
+#' limit for the number of communities. It is not a problem to supply a
+#' (reasonably) big number here, in which case some spin states will be
+#' unpopulated.
+#' @param parupdate Logical constant, whether to update the spins of the
+#' vertices in parallel (synchronously) or not. This argument is ignored if the
+#' second form of the function is used (ie. the \sQuote{\code{vertex}} argument
+#' is present). It is also not implemented in the \dQuote{neg} implementation.
+#' @param start.temp Real constant, the start temperature.  This argument is
+#' ignored if the second form of the function is used (ie. the
+#' \sQuote{\code{vertex}} argument is present).
+#' @param stop.temp Real constant, the stop temperature. The simulation
+#' terminates if the temperature lowers below this level.  This argument is
+#' ignored if the second form of the function is used (ie. the
+#' \sQuote{\code{vertex}} argument is present).
+#' @param cool.fact Cooling factor for the simulated annealing.  This argument
+#' is ignored if the second form of the function is used (ie. the
+#' \sQuote{\code{vertex}} argument is present).
+#' @param update.rule Character constant giving the \sQuote{null-model} of the
+#' simulation. Possible values: \dQuote{simple} and \dQuote{config}.
+#' \dQuote{simple} uses a random graph with the same number of edges as the
+#' baseline probability and \dQuote{config} uses a random graph with the same
+#' vertex degrees as the input graph.
+#' @param gamma Real constant, the gamma argument of the algorithm. This
+#' specifies the balance between the importance of present and non-present
+#' edges in a community. Roughly, a comunity is a set of vertices having many
+#' edges inside the community and few edges outside the community. The default
+#' 1.0 value makes existing and non-existing links equally important. Smaller
+#' values make the existing links, greater values the missing links more
+#' important.
+#' @param implementation Character scalar. Currently igraph contains two
+#' implementations for the Spin-glass community finding algorithm. The faster
+#' original implementation is the default. The other implementation, that takes
+#' into account negative weights, can be chosen by supplying \sQuote{neg} here.
+#' @param gamma.minus Real constant, the gamma.minus parameter of the
+#' algorithm. This specifies the balance between the importance of present and
+#' non-present negative weighted edges in a community. Smaller values of
+#' gamma.minus, leads to communities with lesser negative intra-connectivity.
+#' If this argument is set to zero, the algorithm reduces to a graph coloring
+#' algorithm, using the number of spins as the number of colors. This argument
+#' is ignored if the \sQuote{orig} implementation is chosen.
+#' @return If the \code{vertex} argument is not given, ie. the first form is
+#' used then a \code{\link{cluster_spinglass}} returns a
+#' \code{\link{communities}} object.
+#' 
+#' If the \code{vertex} argument is present, ie. the second form is used then a
+#' named list is returned with the following components:
+#' \item{community}{Numeric vector giving the ids of the vertices in the same
+#' community as \code{vertex}.} \item{cohesion}{The cohesion score of the
+#' result, see references.} \item{adhesion}{The adhesion score of the result,
+#' see references.} \item{inner.links}{The number of edges within the community
+#' of \code{vertex}.} \item{outer.links}{The number of edges between the
+#' community of \code{vertex} and the rest of the graph. }
+#' @author Jorg Reichardt
+#' (\url{http://theorie.physik.uni-wuerzburg.de/~reichardt/}) for the original
+#' code and Gabor Csardi \email{csardi.gabor@@gmail.com} for the igraph glue
+#' code.
+#' 
+#' Changes to the original function for including the possibility of negative
+#' ties were implemented by Vincent Traag (\url{http://www.traag.net/}).
+#' @seealso \code{\link{communities}}, \code{\link{components}}
+#' @references J. Reichardt and S. Bornholdt: Statistical Mechanics of
+#' Community Detection, \emph{Phys. Rev. E}, 74, 016110 (2006),
+#' \url{http://arxiv.org/abs/cond-mat/0603718}
+#' 
+#' M. E. J. Newman and M. Girvan: Finding and evaluating community structure in
+#' networks, \emph{Phys. Rev. E} 69, 026113 (2004)
+#' 
+#' V.A. Traag and Jeroen Bruggeman: Community detection in networks with
+#' positive and negative links, \url{http://arxiv.org/abs/0811.2329} (2008).
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#'   g <- sample_gnp(10, 5/10) %du% sample_gnp(9, 5/9)
+#'   g <- add_edges(g, c(1, 12))
+#'   g <- induced_subgraph(g, subcomponent(g, 1))
+#'   cluster_spinglass(g, spins=2)
+#'   cluster_spinglass(g, vertex=1)
+#' 
+cluster_spinglass <- function(graph, weights=NULL, vertex=NULL, spins=25,
                                 parupdate=FALSE, start.temp=1,
                                 stop.temp=0.01, cool.fact=0.99,
                                 update.rule=c("config", "random", "simple"),
                                 gamma=1.0, implementation=c("orig", "neg"),
                                 gamma.minus=1.0) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -480,8 +960,8 @@ spinglass.community <- function(graph, weights=NULL, vertex=NULL, spins=25,
     res$algorithm  <- "spinglass"
     res$vcount     <- vcount(graph)
     res$membership <- res$membership + 1
-    if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-      res$names <- get.vertex.attribute(graph, "name")
+    if (igraph_opt("add.vertex.names") && is_named(graph)) {
+      res$names <- vertex_attr(graph, "name")
     }
     class(res) <- "communities"
   } else {
@@ -494,10 +974,56 @@ spinglass.community <- function(graph, weights=NULL, vertex=NULL, spins=25,
   res
 }
 
-walktrap.community <- function(graph, weights=E(graph)$weight, steps=4,
+
+
+#' Community strucure via short random walks
+#' 
+#' This function tries to find densely connected subgraphs, also called
+#' communities in a graph via random walks. The idea is that short random walks
+#' tend to stay in the same community.
+#' 
+#' 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
+#'
+#' @aliases walktrap.community
+#' @param graph The input graph, edge directions are ignored in directed
+#' graphs.
+#' @param weights The edge weights.
+#' @param steps The length of the random walks to perform.
+#' @param merges Logical scalar, whether to include the merge matrix in the
+#' result.
+#' @param modularity Logical scalar, whether to include the vector of the
+#' modularity scores in the result. If the \code{membership} argument is true,
+#' then it will be always calculated.
+#' @param membership Logical scalar, whether to calculate the membership vector
+#' for the split corresponding to the highest modularity value.
+#' @return \code{cluster_walktrap} returns a \code{\link{communities}}
+#' object, please see the \code{\link{communities}} manual page for details.
+#' @author Pascal Pons (\url{http://psl.pons.free.fr/}) and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com} for the R and igraph interface
+#' @seealso See \code{\link{communities}} on getting the actual membership
+#' vector, merge matrix, modularity score, etc.
+#' 
+#' \code{\link{modularity}} and \code{\link{cluster_fast_greedy}},
+#' \code{\link{cluster_spinglass}},
+#' \code{\link{cluster_leading_eigen}},
+#' \code{\link{cluster_edge_betweenness}} for other community detection
+#' methods.
+#' @references Pascal Pons, Matthieu Latapy: Computing communities in large
+#' networks using random walks, http://arxiv.org/abs/physics/0512106
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+#' g <- add_edges(g, c(1,6, 1,11, 6, 11))
+#' cluster_walktrap(g)
+#' 
+cluster_walktrap <- function(graph, weights=E(graph)$weight, steps=4,
                                merges=TRUE, modularity=TRUE,
                                membership=TRUE) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object!")
   }
 
@@ -513,7 +1039,7 @@ walktrap.community <- function(graph, weights=E(graph)$weight, steps=4,
   res <- .Call("R_igraph_walktrap_community", graph, weights, as.numeric(steps),
         as.logical(merges), as.logical(modularity), as.logical(membership),
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
 
@@ -525,13 +1051,91 @@ walktrap.community <- function(graph, weights=E(graph)$weight, steps=4,
   res
 }
 
-edge.betweenness.community <- function(graph, weights=E(graph)$weight,
+
+
+#' Community structure detection based on edge betweenness
+#' 
+#' Many networks consist of modules which are densely connected themselves but
+#' sparsely connected to other modules.
+#' 
+#' The edge betweenness score of an edge measures the number of shortest paths
+#' through it, see \code{\link{edge_betweenness}} for details. The idea of the
+#' edge betweenness based community structure detection is that it is likely
+#' that edges connecting separate modules have high edge betweenness as all the
+#' shortest paths from one module to another must traverse through them. So if
+#' we gradually remove the edge with the highest edge betweenness score we will
+#' get a hierarchical map, a rooted tree, called a dendrogram of the graph. The
+#' leafs of the tree are the individual vertices and the root of the tree
+#' represents the whole graph.
+#' 
+#' \code{cluster_edge_betweenness} performs this algorithm by calculating the
+#' edge betweenness of the graph, removing the edge with the highest edge
+#' betweenness score, then recalculating edge betweenness of the edges and
+#' again removing the one with the highest score, etc.
+#' 
+#' \code{edge.betweeness.community} returns various information collected
+#' throught the run of the algorithm. See the return value down here.
+#' 
+#' @aliases edge.betweenness.community cluster_edge_betweenness
+#' @param graph The graph to analyze.
+#' @param weights The edge weights. Supply \code{NULL} to omit edge weights. By
+#' default the \sQuote{\code{weight}} edge attribute is used, if it is present.
+#' @param directed Logical constant, whether to calculate directed edge
+#' betweenness for directed graphs. It is ignored for undirected graphs.
+#' @param edge.betweenness Logical constant, whether to return the edge
+#' betweenness of the edges at the time of their removal.
+#' @param merges Logical constant, whether to return the merge matrix
+#' representing the hierarchical community structure of the network.  This
+#' argument is called \code{merges}, even if the community structure algorithm
+#' itself is divisive and not agglomerative: it builds the tree from top to
+#' bottom. There is one line for each merge (i.e. split) in matrix, the first
+#' line is the first merge (last split). The communities are identified by
+#' integer number starting from one. Community ids smaller than or equal to
+#' \eqn{N}, the number of vertices in the graph, belong to singleton
+#' communities, ie. individual vertices. Before the first merge we have \eqn{N}
+#' communities numbered from one to \eqn{N}. The first merge, the first line of
+#' the matrix creates community \eqn{N+1}, the second merge creates community
+#' \eqn{N+2}, etc.
+#' @param bridges Logical constant, whether to return a list the edge removals
+#' which actually splitted a component of the graph.
+#' @param modularity Logical constant, whether to calculate the maximum
+#' modularity score, considering all possibly community structures along the
+#' edge-betweenness based edge removals.
+#' @param membership Logical constant, whether to calculate the membership
+#' vector corresponding to the highest possible modularity score.
+#' @return \code{cluster_edge_betweenness} returns a
+#' \code{\link{communities}} object, please see the \code{\link{communities}}
+#' manual page for details.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{edge_betweenness}} for the definition and calculation
+#' of the edge betweenness, \code{\link{cluster_walktrap}},
+#' \code{\link{cluster_fast_greedy}},
+#' \code{\link{cluster_leading_eigen}} for other community detection
+#' methods.
+#' 
+#' See \code{\link{communities}} for extracting the results of the community
+#' detection.
+#' @references M Newman and M Girvan: Finding and evaluating community
+#' structure in networks, \emph{Physical Review E} 69, 026113 (2004)
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- barabasi.game(100,m=2)
+#' eb <- cluster_edge_betweenness(g)
+#' 
+#' g <- make_full_graph(10) %du% make_full_graph(10)
+#' g <- add_edges(g, c(1,11))
+#' eb <- cluster_edge_betweenness(g)
+#' eb
+#' 
+cluster_edge_betweenness <- function(graph, weights=E(graph)$weight,
                                        directed=TRUE,
                                        edge.betweenness=TRUE,
                                        merges=TRUE, bridges=TRUE,
                                        modularity=TRUE,
                                        membership=TRUE) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object!")
   }
 
@@ -546,7 +1150,7 @@ edge.betweenness.community <- function(graph, weights=E(graph)$weight,
                as.logical(merges), as.logical(bridges),
                as.logical(modularity), as.logical(membership),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$vcount <- vcount(graph)
@@ -559,21 +1163,54 @@ edge.betweenness.community <- function(graph, weights=E(graph)$weight,
   res
 }
 
-edge.betweenness.community.merges <- function(graph, edges) {
-  
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_community_eb_get_merges", graph, as.numeric(edges),
-        PACKAGE="igraph")
-}
-
-fastgreedy.community <- function(graph, merges=TRUE, modularity=TRUE,
+#' Community structure via greedy optimization of modularity
+#' 
+#' This function tries to find dense subgraph, also called communities in
+#' graphs via directly optimizing a modularity score.
+#' 
+#' This function implements the fast greedy modularity optimization algorithm
+#' for finding community structure, see A Clauset, MEJ Newman, C Moore: Finding
+#' community structure in very large networks,
+#' http://www.arxiv.org/abs/cond-mat/0408187 for the details.
+#'
+#' @aliases fastgreedy.community
+#' @param graph The input graph
+#' @param merges Logical scalar, whether to return the merge matrix.
+#' @param modularity Logical scalar, whether to return a vector containing the
+#' modularity after each merge.
+#' @param membership Logical scalar, whether to calculate the membership vector
+#' corresponding to the maximum modularity score, considering all possible
+#' community structures along the merges.
+#' @param weights If not \code{NULL}, then a numeric vector of edge weights.
+#' The length must match the number of edges in the graph.  By default the
+#' \sQuote{\code{weight}} edge attribute is used as weights. If it is not
+#' present, then all edges are considered to have the same weight.
+#' @return \code{cluster_fast_greedy} returns a \code{\link{communities}}
+#' object, please see the \code{\link{communities}} manual page for details.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com} for the R interface.
+#' @seealso \code{\link{communities}} for extracting the results.
+#' 
+#' See also \code{\link{cluster_walktrap}},
+#' \code{\link{cluster_spinglass}},
+#' \code{\link{cluster_leading_eigen}} and
+#' \code{\link{cluster_edge_betweenness}} for other methods.
+#' @references A Clauset, MEJ Newman, C Moore: Finding community structure in
+#' very large networks, http://www.arxiv.org/abs/cond-mat/0408187
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+#' g <- add_edges(g, c(1,6, 1,11, 6, 11))
+#' fc <- cluster_fast_greedy(g)
+#' membership(fc)
+#' sizes(fc)
+#' 
+cluster_fast_greedy <- function(graph, merges=TRUE, modularity=TRUE,
                                  membership=TRUE,
                                  weights=E(graph)$weight) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -585,7 +1222,7 @@ fastgreedy.community <- function(graph, merges=TRUE, modularity=TRUE,
   res <- .Call("R_igraph_community_fastgreedy", graph, as.logical(merges),
                as.logical(modularity), as.logical(membership), weights,
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$algorithm <- "fast greedy"
@@ -596,21 +1233,6 @@ fastgreedy.community <- function(graph, merges=TRUE, modularity=TRUE,
   res
 }
 
-community.to.membership <- function(graph, merges, steps, membership=TRUE,
-                                    csize=TRUE) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-
-  merges <- as.matrix(merges)
-  merges <- structure(as.numeric(merges), dim=dim(merges))
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_community_to_membership", graph, merges-1,
-        as.numeric(steps), as.logical(membership), as.logical(csize),
-        PACKAGE="igraph")
-}
-
 igraph.i.levc.arp <- function(externalP, externalE) {
   f <- function(v) {
     v <- as.numeric(v)
@@ -620,16 +1242,105 @@ igraph.i.levc.arp <- function(externalP, externalE) {
   f
 }
 
-leading.eigenvector.community <- function(graph, steps=-1, weights=NULL,
+
+
+#' Community structure detecting based on the leading eigenvector of the
+#' community matrix
+#' 
+#' This function tries to find densely connected subgraphs in a graph by
+#' calculating the leading non-negative eigenvector of the modularity matrix of
+#' the graph.
+#' 
+#' The function documented in these section implements the \sQuote{leading
+#' eigenvector} method developed by Mark Newman, see the reference below.
+#' 
+#' The heart of the method is the definition of the modularity matrix,
+#' \code{B}, which is \code{B=A-P}, \code{A} being the adjacency matrix of the
+#' (undirected) network, and \code{P} contains the probability that certain
+#' edges are present according to the \sQuote{configuration model}. In other
+#' words, a \code{P[i,j]} element of \code{P} is the probability that there is
+#' an edge between vertices \code{i} and \code{j} in a random network in which
+#' the degrees of all vertices are the same as in the input graph.
+#' 
+#' The leading eigenvector method works by calculating the eigenvector of the
+#' modularity matrix for the largest positive eigenvalue and then separating
+#' vertices into two community based on the sign of the corresponding element
+#' in the eigenvector. If all elements in the eigenvector are of the same sign
+#' that means that the network has no underlying comuunity structure.  Check
+#' Newman's paper to understand why this is a good method for detecting
+#' community structure.
+#' 
+#' @aliases leading.eigenvector.community
+#' @param graph The input graph. Should be undirected as the method needs a
+#' symmetric matrix.
+#' @param steps The number of steps to take, this is actually the number of
+#' tries to make a step. It is not a particularly useful parameter.
+#' #' @param weights An optional weight vector. The \sQuote{weight} edge attribute
+#' is used if present. Supply \sQuote{\code{NA}} here if you want to ignore the
+#' \sQuote{weight} edge attribute.
+#' @param start \code{NULL}, or a numeric membership vector, giving the start
+#' configuration of the algorithm.
+#' @param options A named list to override some ARPACK options.
+#' @param callback If not \code{NULL}, then it must be callback function. This
+#' is called after each iteration, after calculating the leading eigenvector of
+#' the modularity matrix. See details below.
+#' @param extra Additional argument to supply to the callback function.
+#' @param env The environment in which the callback function is evaluated.
+#' @return \code{cluster_leading_eigen} returns a named list with the
+#' following members: \item{membership}{The membership vector at the end of the
+#' algorithm, when no more splits are possible.} \item{merges}{The merges
+#' matrix starting from the state described by the \code{membership} member.
+#' This is a two-column matrix and each line describes a merge of two
+#' communities, the first line is the first merge and it creates community
+#' \sQuote{\code{N}}, \code{N} is the number of initial communities in the
+#' graph, the second line creates community \code{N+1}, etc.  }
+#' \item{options}{Information about the underlying ARPACK computation, see
+#' \code{\link{arpack}} for details.  }
+#' @section Callback functions: The \code{callback} argument can be used to
+#' supply a function that is called after each eigenvector calculation. The
+#' following arguments are supplied to this function: \describe{
+#'   \item{membership}{The actual membership vector, with zero-based indexing.}
+#'   \item{community}{The community that the algorithm just tried to split,
+#'     community numbering starts with zero here.}
+#'   \item{value}{The eigenvalue belonging to the leading eigenvector the
+#'     algorithm just found.}
+#'   \item{vector}{The leading eigenvector the algorithm just found.}
+#'   \item{multiplier}{An R function that can be used to multiple the actual
+#'     modularity matrix with an arbitrary vector. Supply the vector as an
+#'     argument to perform this multiplication. This function can be used
+#'     with ARPACK.}
+#'   \item{extra}{The \code{extra} argument that was passed to
+#'     \code{cluster_leading_eigen}. }
+#'   The callback function should return a scalar number. If this number
+#'   is non-zero, then the clustering is terminated.
+#' }
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{modularity}}, \code{\link{cluster_walktrap}},
+#' \code{\link{cluster_edge_betweenness}},
+#' \code{\link{cluster_fast_greedy}}, \code{\link[stats]{as.dendrogram}}
+#' @references MEJ Newman: Finding community structure using the eigenvectors
+#' of matrices, Physical Review E 74 036104, 2006.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+#' g <- add_edges(g, c(1,6, 1,11, 6, 11))
+#' lec <- cluster_leading_eigen(g)
+#' lec
+#' 
+#' cluster_leading_eigen(g, start=membership(lec))
+#' 
+cluster_leading_eigen <- function(graph, steps=-1, weights=NULL,
                                           start=NULL,
-                                          options=igraph.arpack.default,
+                                          options=arpack_defaults,
                                           callback=NULL, extra=NULL,
                                           env=parent.frame()){
 
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   steps <- as.integer(steps)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
     weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -638,7 +1349,7 @@ leading.eigenvector.community <- function(graph, steps=-1, weights=NULL,
     weights <- NULL 
   }
   if (!is.null(start)) { start <- as.numeric(start)-1 }
-  options.tmp <- igraph.arpack.default; options.tmp[ names(options) ] <- options ; options <- options.tmp
+  options.tmp <- arpack_defaults; options.tmp[ names(options) ] <- options ; options <- options.tmp
   
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
@@ -646,7 +1357,7 @@ leading.eigenvector.community <- function(graph, steps=-1, weights=NULL,
                weights, options, start, callback, extra, env,
                environment(igraph.i.levc.arp),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$algorithm <- "leading eigenvector"
@@ -658,11 +1369,63 @@ leading.eigenvector.community <- function(graph, steps=-1, weights=NULL,
   res
 }
 
-label.propagation.community <- function(graph, weights=NULL, initial=NULL,
+#' Finding communities based on propagating labels
+#' 
+#' This is a fast, nearly linear time algorithm for detecting community
+#' structure in networks. In works by labeling the vertices with unique labels
+#' and then updating the labels by majority voting in the neighborhood of the
+#' vertex.
+#' 
+#' This function implements the community detection method described in:
+#' Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time algorithm to
+#' detect community structures in large-scale networks. Phys Rev E 76, 036106.
+#' (2007). This version extends the original method by the ability to take edge
+#' weights into consideration and also by allowing some labels to be fixed.
+#' 
+#' From the abstract of the paper: \dQuote{In our algorithm every node is
+#' initialized with a unique label and at every step each node adopts the label
+#' that most of its neighbors currently have. In this iterative process densely
+#' connected groups of nodes form a consensus on a unique label to form
+#' communities.}
+#'
+#' @aliases label.propagation.community
+#' @param graph The input graph, should be undirected to make sense.
+#' @param weights An optional weight vector. It should contain a positive
+#' weight for all the edges. The \sQuote{weight} edge attribute is used if
+#' present. Supply \sQuote{\code{NA}} here if you want to ignore the
+#' \sQuote{weight} edge attribute.
+#' @param initial The initial state. If \code{NULL}, every vertex will have a
+#' different label at the beginning. Otherwise it must be a vector with an
+#' entry for each vertex. Non-negative values denote different labels, negative
+#' entries denote vertices without labels.
+#' @param fixed Logical vector denoting which labels are fixed. Of course this
+#' makes sense only if you provided an initial state, otherwise this element
+#' will be ignored. Also note that vertices without labels cannot be fixed.
+#' @return \code{cluster_label_prop} returns a
+#' \code{\link{communities}} object, please see the \code{\link{communities}}
+#' manual page for details.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} for the C implementation,
+#' Gabor Csardi \email{csardi.gabor@@gmail.com} for this manual page.
+#' @seealso \code{\link{communities}} for extracting the actual results.
+#' 
+#' \code{\link{cluster_fast_greedy}}, \code{\link{cluster_walktrap}} and
+#' \code{\link{cluster_spinglass}} for other community detection methods.
+#' @references Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time
+#' algorithm to detect community structures in large-scale networks. \emph{Phys
+#' Rev E} 76, 036106. (2007)
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#'   g <- sample_gnp(10, 5/10) %du% sample_gnp(9, 5/9)
+#'   g <- add_edges(g, c(1, 12))
+#'   cluster_label_prop(g)
+#' 
+cluster_label_prop <- function(graph, weights=NULL, initial=NULL,
                                         fixed=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -677,7 +1440,7 @@ label.propagation.community <- function(graph, weights=NULL, initial=NULL,
   # Function call
   res <- .Call("R_igraph_community_label_propagation", graph, weights, initial, fixed,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$vcount <- vcount(graph)
@@ -687,10 +1450,64 @@ label.propagation.community <- function(graph, weights=NULL, initial=NULL,
   res
 }
 
-multilevel.community <- function(graph, weights=NULL) {
+
+
+#' Finding community structure by multi-level optimization of modularity
+#' 
+#' This function implements the multi-level modularity optimization algorithm
+#' for finding community structure, see references below. It is based on the
+#' modularity measure and a hierarchial approach.
+#' 
+#' This function implements the multi-level modularity optimization algorithm
+#' for finding community structure, see VD Blondel, J-L Guillaume, R Lambiotte
+#' and E Lefebvre: Fast unfolding of community hierarchies in large networks,
+#' \url{http://arxiv.org/abs/arXiv:0803.0476} for the details.
+#' 
+#' It is based on the modularity measure and a hierarchial approach.
+#' Initially, each vertex is assigned to a community on its own. In every step,
+#' vertices are re-assigned to communities in a local, greedy way: each vertex
+#' is moved to the community with which it achieves the highest contribution to
+#' modularity. When no vertices can be reassigned, each community is considered
+#' a vertex on its own, and the process starts again with the merged
+#' communities. The process stops when there is only a single vertex left or
+#' when the modularity cannot be increased any more in a step.
+#' 
+#' This function was contributed by Tom Gregorovic.
+#'
+#' @aliases multilevel.community
+#' @param graph The input graph.
+#' @param weights Optional positive weight vector.  If the graph has a
+#' \code{weight} edge attribute, then this is used by default. Supply \code{NA}
+#' here if the graph has a \code{weight} edge attribute, but you want to ignore
+#' it.
+#' @return \code{cluster_louvain} returns a \code{\link{communities}}
+#' object, please see the \code{\link{communities}} manual page for details.
+#' @author Tom Gregorovic, Tamas Nepusz \email{ntamas@@gmail.com}
+#' @seealso See \code{\link{communities}} for extracting the membership,
+#' modularity scores, etc. from the results.
+#' 
+#' Other community detection algorithms: \code{\link{cluster_walktrap}},
+#' \code{\link{cluster_spinglass}},
+#' \code{\link{cluster_leading_eigen}},
+#' \code{\link{cluster_edge_betweenness}},
+#' \code{\link{cluster_fast_greedy}},
+#' \code{\link{cluster_label_prop}}
+#' @references Vincent D. Blondel, Jean-Loup Guillaume, Renaud Lambiotte,
+#' Etienne Lefebvre: Fast unfolding of communities in large networks. J. Stat.
+#' Mech. (2008) P10008
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # This is so simple that we will have only one level
+#' g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+#' g <- add_edges(g, c(1,6, 1,11, 6, 11))
+#' cluster_louvain(g)
+#' 
+cluster_louvain <- function(graph, weights=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -703,7 +1520,7 @@ multilevel.community <- function(graph, weights=NULL) {
   # Function call
   res <- .Call("R_igraph_community_multilevel", graph, weights,
         PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$vcount <- vcount(graph)
@@ -714,10 +1531,69 @@ multilevel.community <- function(graph, weights=NULL) {
   res
 }
 
-optimal.community <- function(graph, weights=NULL) {
+
+
+#' Optimal community structure
+#' 
+#' This function calculates the optimal community structure of a graph, by
+#' maximizing the modularity measure over all possible partitions.
+#' 
+#' This function calculates the optimal community structure for a graph, in
+#' terms of maximal modularity score.
+#' 
+#' The calculation is done by transforming the modularity maximization into an
+#' integer programming problem, and then calling the GLPK library to solve
+#' that. Please the reference below for details.
+#' 
+#' Note that modularity optimization is an NP-complete problem, and all known
+#' algorithms for it have exponential time complexity. This means that you
+#' probably don't want to run this function on larger graphs. Graphs with up to
+#' fifty vertices should be fine, graphs with a couple of hundred vertices
+#' might be possible.
+#'
+#' @aliases optimal.community
+#' @param graph The input graph. Edge directions are ignored for directed
+#' graphs.
+#' @param weights Optional positive weight vector for optimizing weighted
+#' modularity. If the graph has a \code{weight} edge attribute, then this is
+#' used by default. Supply \code{NA} to ignore the weights of a weighted graph.
+#' @return \code{cluster_optimal} returns a \code{\link{communities}} object,
+#' please see the \code{\link{communities}} manual page for details.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{communities}} for the documentation of the result,
+#' \code{\link{modularity}}. See also \code{\link{cluster_fast_greedy}} for a
+#' fast greedy optimizer.
+#' @references Ulrik Brandes, Daniel Delling, Marco Gaertler, Robert Gorke,
+#' Martin Hoefer, Zoran Nikoloski, Dorothea Wagner: On Modularity Clustering,
+#' \emph{IEEE Transactions on Knowledge and Data Engineering} 20(2):172-188,
+#' 2008.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Zachary's karate club
+#' g <- make_graph("Zachary")
+#' 
+#' ## We put everything into a big 'try' block, in case 
+#' ## igraph was compiled without GLPK support
+#' 
+#' try({
+#'   ## The calculation only takes a couple of seconds
+#'   oc <- cluster_optimal(g)
+#' 
+#'   ## Double check the result
+#'   print(modularity(oc))
+#'   print(modularity(g, membership(oc)))
+#' 
+#'   ## Compare to the greedy optimizer
+#'   fc <- cluster_fast_greedy(g)
+#'   print(modularity(fc))
+#' }, silent=TRUE)
+#' 
+cluster_optimal <- function(graph, weights=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -730,7 +1606,7 @@ optimal.community <- function(graph, weights=NULL) {
   # Function call
   res <- .Call("R_igraph_community_optimal_modularity", graph, weights,
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$vcount <- vcount(graph)
@@ -740,12 +1616,62 @@ optimal.community <- function(graph, weights=NULL) {
   res
 }
 
-infomap.community <- function(graph, e.weights=NULL, v.weights=NULL,
+
+
+#' Infomap community finding
+#' 
+#' Find community structure that minimizes the expected description length of a
+#' random walker trajectory
+#' 
+#' Please see the details of this method in the references given below.
+#'
+#' @aliases infomap.community
+#' @param graph The input graph.
+#' @param e.weights If not \code{NULL}, then a numeric vector of edge weights.
+#' The length must match the number of edges in the graph.  By default the
+#' \sQuote{\code{weight}} edge attribute is used as weights. If it is not
+#' present, then all edges are considered to have the same weight.
+#' @param v.weights If not \code{NULL}, then a numeric vector of vertex
+#' weights. The length must match the number of vertices in the graph.  By
+#' default the \sQuote{\code{weight}} vertex attribute is used as weights. If
+#' it is not present, then all vertices are considered to have the same weight.
+#' @param nb.trials The number of attempts to partition the network (can be any
+#' integer value equal or larger than 1).
+#' @param modularity Logical scalar, whether to calculate the modularity score
+#' of the detected community structure.
+#' @return \code{cluster_infomap} returns a \code{\link{communities}} object,
+#' please see the \code{\link{communities}} manual page for details.
+#' @author Martin Rosvall (\url{http://www.tp.umu.se/~rosvall/}) wrote the
+#' original C++ code. This was ported to be more igraph-like by Emmanuel
+#' Navarro (\url{http://enavarro.me/}).  The R interface and
+#' some cosmetics was done by Gabor Csardi \email{csardi.gabor@@gmail.com}.
+#' @seealso Other community finding methods and \code{\link{communities}}.
+#' @references The original paper: M. Rosvall and C. T. Bergstrom, Maps of
+#' information flow reveal community structure in complex networks, \emph{PNAS}
+#' 105, 1118 (2008) \url{http://dx.doi.org/10.1073/pnas.0706851105},
+#' \url{http://arxiv.org/abs/0707.0609}
+#' 
+#' A more detailed paper: M. Rosvall, D. Axelsson, and C. T. Bergstrom, The map
+#' equation, \emph{Eur. Phys. J. Special Topics} 178, 13 (2009).
+#' \url{http://dx.doi.org/10.1140/epjst/e2010-01179-1},
+#' \url{http://arxiv.org/abs/0906.1405}.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Zachary's karate club
+#' g <- make_graph("Zachary")
+#' 
+#' imc <- cluster_infomap(g)
+#' membership(imc)
+#' communities(imc)
+#' 
+cluster_infomap <- function(graph, e.weights=NULL, v.weights=NULL,
                               nb.trials=10, modularity=TRUE) {
   
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(e.weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(e.weights) && "weight" %in% edge_attr_names(graph)) { 
     e.weights <- E(graph)$weight 
   } 
   if (!is.null(e.weights) && any(!is.na(e.weights))) { 
@@ -753,7 +1679,7 @@ infomap.community <- function(graph, e.weights=NULL, v.weights=NULL,
   } else { 
     e.weights <- NULL 
   }
-  if (is.null(v.weights) && "weight" %in% list.vertex.attributes(graph)) { 
+  if (is.null(v.weights) && "weight" %in% vertex_attr_names(graph)) { 
     v.weights <- V(graph)$weight 
   } 
   if (!is.null(v.weights) && any(!is.na(v.weights))) { 
@@ -769,7 +1695,7 @@ infomap.community <- function(graph, e.weights=NULL, v.weights=NULL,
                v.weights, nb.trials,
                PACKAGE="igraph")
 
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
   res$vcount <- vcount(graph)
@@ -782,9 +1708,12 @@ infomap.community <- function(graph, e.weights=NULL, v.weights=NULL,
   res
 }
 
+#' @rdname communities
+#' @method plot communities
+#' @export
+
 plot.communities <- function(x, y,
-                             colbar=rainbow(length(x)),
-                             col=colbar[membership(x)],
+                             col=membership(x),
                              mark.groups=communities(x),
                              edge.color=c("black", "red")[crossing(x,y)+1],
                              ...) {
@@ -794,22 +1723,108 @@ plot.communities <- function(x, y,
        ...)  
 }
 
-dendPlot <- function(x, mode=getIgraphOpt("dend.plot.type"), ...)
-  UseMethod("dendPlot")
 
-dendPlot.communities <- function(x, 
-                                 mode=getIgraphOpt("dend.plot.type"), ...,
-                                 use.modularity=FALSE) {  
+
+#' @rdname plot_dendrogram.communities
+#' @aliases dendPlot
+#' @export
+
+plot_dendrogram <- function(x, mode=igraph_opt("dend.plot.type"), ...)
+  UseMethod("plot_dendrogram")
+
+
+
+#' Community structure dendrogram plots
+#' 
+#' Plot a hierarchical community structure as a dendrogram.
+#' 
+#' \code{plot_dendrogram} supports three different plotting functions, selected via
+#' the \code{mode} argument. By default the plotting function is taken from the
+#' \code{dend.plot.type} igraph option, and it has for possible values:
+#' \itemize{ \item \code{auto} Choose automatically between the plotting
+#' functions. As \code{plot.phylo} is the most sophisticated, that is choosen,
+#' whenever the \code{ape} package is available. Otherwise \code{plot.hclust}
+#' is used.  \item \code{phylo} Use \code{plot.phylo} from the \code{ape}
+#' package.  \item \code{hclust} Use \code{plot.hclust} from the \code{stats}
+#' package.  \item \code{dendrogram} Use \code{plot.dendrogram} from the
+#' \code{stats} package.  }
+#' 
+#' The different plotting functions take different sets of arguments. When
+#' using \code{plot.phylo} (\code{mode="phylo"}), we have the following syntax:
+#' \preformatted{
+#'     plot_dendrogram(x, mode="phylo", colbar = palette(),
+#'             edge.color = NULL, use.edge.length = FALSE, \dots)
+#' } The extra arguments not documented above: \itemize{
+#'   \item \code{colbar} Color bar for the edges.
+#'   \item \code{edge.color} Edge colors. If \code{NULL}, then the
+#'     \code{colbar} argument is used.
+#'   \item \code{use.edge.length} Passed to \code{plot.phylo}.
+#'   \item \code{dots} Attitional arguments to pass to \code{plot.phylo}.
+#' }
+#' 
+#' The syntax for \code{plot.hclust} (\code{mode="hclust"}): \preformatted{
+#'     plot_dendrogram(x, mode="hclust", rect = 0, colbar = palette(),
+#'             hang = 0.01, ann = FALSE, main = "", sub = "", xlab = "",
+#'             ylab = "", \dots)
+#' } The extra arguments not documented above: \itemize{
+#'   \item \code{rect} A numeric scalar, the number of groups to mark on
+#'     the dendrogram. The dendrogram is cut into exactly \code{rect}
+#'     groups and they are marked via the \code{rect.hclust} command. Set
+#'     this to zero if you don't want to mark any groups.
+#'   \item \code{colbar} The colors of the rectanges that mark the
+#'     vertex groups via the \code{rect} argument.
+#'   \item \code{hang} Where to put the leaf nodes, this corresponds to the
+#'     \code{hang} argument of \code{plot.hclust}.
+#'   \item \code{ann}  Whether to annotate the plot, the \code{ann}
+#'     argument of \code{plot.hclust}.
+#'   \item \code{main} The main title of the plot, the \code{main} argument
+#'     of \code{plot.hclust}.
+#'   \item \code{sub} The sub-title of the plot, the \code{sub} argument of
+#'     \code{plot.hclust}.
+#'   \item \code{xlab} The label on the horizontal axis, passed to
+#'     \code{plot.hclust}.
+#'   \item \code{ylab} The label on the vertical axis, passed to
+#'     \code{plot.hclust}.
+#'   \item \code{dots} Attitional arguments to pass to \code{plot.hclust}.
+#' }
+#' 
+#' The syntax for \code{plot.dendrogram} (\code{mode="dendrogram"}):
+#' \preformatted{
+#'     plot_dendrogram(x, \dots)
+#' } The extra arguments are simply passed to \code{as.dendrogram}.
+#' 
+#' @param x An object containing the community structure of a graph. See
+#' \code{\link{communities}} for details.
+#' @param mode Which dendrogram plotting function to use. See details below.
+#' @param \dots Additional arguments to supply to the dendrogram plotting
+#' function.
+#' @param use.modularity Logical scalar, whether to use the modularity values
+#' to define the height of the branches.
+#' @param palette The color palette to use for colored plots.
+#' @return Returns whatever the return value was from the plotting function,
+#' \code{plot.phylo}, \code{plot.dendrogram} or \code{plot.hclust}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @method plot_dendrogram communities
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' karate <- make_graph("Zachary")
+#' fc <- cluster_fast_greedy(karate)
+#' plot_dendrogram(fc)
+#' 
+plot_dendrogram.communities <- function(x, 
+                                 mode=igraph_opt("dend.plot.type"), ...,
+                                 use.modularity=FALSE,
+                                 palette=categorical_pal(8)) {
   mode <- igraph.match.arg(mode, c("auto", "phylo", "hclust", "dendrogram"))
 
+  old_palette <- palette(palette)
+  on.exit(palette(old_palette), add = TRUE)
+
   if (mode=="auto") {
-    value <- tryCatch(suppressWarnings(library("ape", character.only=TRUE,
-                                               logical.return=TRUE,
-                                               warn.conflicts=FALSE,
-                                               quietly=TRUE,
-                                               pos="package:base")),
-                      error=function(e) e)
-    mode <- if (value) "phylo" else "hclust"
+    have_ape <- requireNamespace("ape", quietly = TRUE)
+    mode <- if (have_ape) "phylo" else "hclust"
   }
   
   if (mode=="hclust") {
@@ -822,7 +1837,7 @@ dendPlot.communities <- function(x,
 }
 
 dendPlotHclust <- function(communities, rect=length(communities),
-                           colbar=rainbow(rect), hang=-1, ann=FALSE,
+                           colbar=palette(), hang=-1, ann=FALSE,
                            main="", sub="", xlab="", ylab="", ...,
                            use.modularity=FALSE) {
   hc <- as.hclust(communities, hang=hang, use.modularity=use.modularity)
@@ -840,14 +1855,14 @@ dendPlotDendrogram <- function(communities, hang=-1, ...,
        ...)
 }
 
-dendPlotPhylo <- function(communities, colbar=rainbow(length(communities)),
+dendPlotPhylo <- function(communities, colbar=palette(),
                           col=colbar[membership(communities)],
                           mark.groups=communities(communities),
                           use.modularity=FALSE, 
                           edge.color="#AAAAAAFF",
                           edge.lty=c(1,2), ...) {
   
-  phy <- asPhylo(communities, use.modularity=use.modularity)
+  phy <- as_phylo(communities, use.modularity=use.modularity)
 
   getedges <- function(tip) {
     repeat {      
@@ -877,27 +1892,100 @@ dendPlotPhylo <- function(communities, colbar=rainbow(length(communities)),
   plot(phy, edge.color=ecol, edge.lty=elty, tip.color=col, ...)
 }
 
+#' Compares community structures using various metrics
+#' 
+#' This function assesses the distance between two community structures.
+#' 
+#' 
+#' @aliases compare.communities compare.membership compare
+#' @param comm1 A \code{\link{communities}} object containing a community
+#' structure; or a numeric vector, the membership vector of the first community
+#' structure. The membership vector should contain the community id of each
+#' vertex, the numbering of the communities starts with one.
+#' @param comm2 A \code{\link{communities}} object containing a community
+#' structure; or a numeric vector, the membership vector of the second
+#' community structure, in the same format as for the previous argument.
+#' @param method Character scalar, the comparison method to use. Possible
+#' values: \sQuote{vi} is the variation of information (VI) metric of Meila
+#' (2003), \sQuote{nmi} is the normalized mutual information measure proposed
+#' by Danon et al. (2005), \sQuote{split.join} is the split-join distance of
+#' can Dongen (2000), \sQuote{rand} is the Rand index of Rand (1971),
+#' \sQuote{adjusted.rand} is the adjusted Rand index by Hubert and Arabie
+#' (1985).
+#' @return A real number.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @seealso \code{\link{cluster_walktrap}},
+#' \code{\link{cluster_edge_betweenness}},
+#' \code{\link{cluster_fast_greedy}}, \code{\link{cluster_spinglass}} for
+#' various community detection methods.
+#' @references Meila M: Comparing clusterings by the variation of information.
+#' In: Scholkopf B, Warmuth MK (eds.). \emph{Learning Theory and Kernel
+#' Machines: 16th Annual Conference on Computational Learning Theory and 7th
+#' Kernel Workshop}, COLT/Kernel 2003, Washington, DC, USA. Lecture Notes in
+#' Computer Science, vol. 2777, Springer, 2003. ISBN: 978-3-540-40720-1.
+#' 
+#' Danon L, Diaz-Guilera A, Duch J, Arenas A: Comparing community structure
+#' identification. \emph{J Stat Mech} P09008, 2005.
+#' 
+#' van Dongen S: Performance criteria for graph clustering and Markov cluster
+#' experiments. Technical Report INS-R0012, National Research Institute for
+#' Mathematics and Computer Science in the Netherlands, Amsterdam, May 2000.
+#' 
+#' Rand WM: Objective criteria for the evaluation of clustering methods.
+#' \emph{J Am Stat Assoc} 66(336):846-850, 1971.
+#' 
+#' Hubert L and Arabie P: Comparing partitions. \emph{Journal of
+#' Classification} 2:193-218, 1985.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_graph("Zachary")
+#' sg <- cluster_spinglass(g)
+#' le <- cluster_leading_eigen(g)
+#' compare(sg, le, method="rand")
+#' compare(membership(sg), membership(le))
+#' 
 compare <- function(comm1, comm2, method=c("vi", "nmi",
-                                       "split.join", "rand",
-                                       "adjusted.rand"))
+                                    "split.join", "rand",
+                                    "adjusted.rand"))
   UseMethod("compare")
 
-compare.communities <- function(comm1, comm2, method=c("vi", "nmi",
-                                                "split.join", "rand",
-                                                "adjusted.rand")) {
-  compare.numeric(comm1, comm2, method)
+#' @method compare communities
+#' @export
+
+compare.communities <- function(comm1, comm2,
+                                method=c("vi", "nmi", "split.join", "rand",
+                                  "adjusted.rand")) {
+
+  i_compare(comm1, comm2, method)
 }
 
-compare.numeric <- function(comm1, comm2, method=c("vi", "nmi",
-                                            "split.join", "rand",
-                                            "adjusted.rand")) {
+#' @method compare membership
+#' @export
+
+compare.membership <- function(comm1, comm2,
+                                method=c("vi", "nmi", "split.join", "rand",
+                                  "adjusted.rand")) {
+
+  i_compare(comm1, comm2, method)
+}
+
+#' @method compare default
+#' @export
+
+compare.default <- compare.membership
+
+i_compare <- function (comm1, comm2, method=c("vi", "nmi", "split.join",
+                                       "rand", "adjusted.rand")) {
+
   comm1 <- if (inherits(comm1, "communities")) {
-    membership(comm1)
+    as.numeric(membership(comm1))
   } else {
     as.numeric(comm1)
   }
   comm2 <- if (inherits(comm2, "communities")) {
-    membership(comm2)
+    as.numeric(membership(comm2))
   } else {
     as.numeric(comm2)
   }
@@ -908,10 +1996,157 @@ compare.numeric <- function(comm1, comm2, method=c("vi", "nmi",
                method, PACKAGE = "igraph")
   res  
 }
-                                
-compare.default <- function(comm1, comm2, method=c("vi", "nmi",
-                                            "split.join", "rand",
-                                            "adjusted.rand")) {
-  compare.numeric(as.numeric(comm1), as.numeric(comm2), method)
+
+#' Split-join distance of two community structures
+#'
+#' The split-join distance between partitions A and B is the sum of the
+#' projection distance of A from B and the projection distance of B from
+#' A. The projection distance is an asymmetric measure and it is defined as
+#' follows:
+#'
+#' First, each set in partition A is evaluated against all sets in
+#' partition B. For each set in partition A, the best matching set in
+#' partition B is found and the overlap size is calculated. (Matching is
+#' quantified by the size of the overlap between the two sets). Then, the
+#' maximal overlap sizes for each set in A are summed together and
+#' subtracted from the number of elements in A.
+#'
+#' The split-join distance will be returned as two numbers, the first is
+#' the projection distance of the first partition from the
+#' second, while the second number is the projection distance of the second
+#' partition from the first. This makes it easier to detect whether a
+#' partition is a subpartition of the other, since in this case, the
+#' corresponding distance will be zero.
+#'
+#' @param comm1 The first community structure.
+#' @param comm2 The second community structure.
+#' @return Two integer numbers, see details below.
+#'
+#' @references
+#' van Dongen S: Performance criteria for graph clustering and Markov
+#' cluster experiments. Technical Report INS-R0012, National Research
+#' Institute for Mathematics and Computer Science in the Netherlands,
+#' Amsterdam, May 2000.
+#'
+#' @export
+
+split_join_distance <- function(comm1, comm2) {
+  comm1 <- if (inherits(comm1, "communities")) {
+    as.numeric(membership(comm1))
+  } else {
+    as.numeric(comm1)
+  }
+  comm2 <- if (inherits(comm2, "communities")) {
+    as.numeric(membership(comm2))
+  } else {
+    as.numeric(comm2)
+  }
+  on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+  res <- .Call("R_igraph_split_join_distance", comm1, comm2,
+               PACKAGE = "igraph")
+  unlist(res)
+}
+
+#' Groups of a vertex partitioning
+#' 
+#' Create a list of vertex groups from some graph clustering or community
+#' structure.
+#' 
+#' Currently two methods are defined for this function. The default method
+#' works on the output of \code{\link{components}}. (In fact it works on any
+#' object that is a list with an entry called \code{membership}.)
+#' 
+#' The second method works on \code{\link{communities}} objects.
+#' 
+#' @aliases groups groups.default groups.communities
+#' @param x Some object that represents a grouping of the vertices. See details
+#' below.
+#' @return A named list of numeric or character vectors. The names are just
+#' numbers that refer to the groups. The vectors themselves are numeric or
+#' symbolic vertex ids.
+#' @seealso \code{\link{components}} and the various community finding
+#' functions.
+#' @examples
+#' g <- make_graph("Zachary")
+#' fgc <- cluster_fast_greedy(g)
+#' groups(fgc)
+#' 
+#' g2 <- make_ring(10) + make_full_graph(5)
+#' groups(components(g2))
+#' @export
+
+groups <- function(x)
+  UseMethod("groups")
+
+#' @method groups default
+#' @export
+
+groups.default <- function(x) {
+  vids <- names(x$membership)
+  if (is.null(vids)) vids <- seq_along(x$membership)
+  tapply(vids, x$membership, simplify=FALSE, function(x) x)
+}
+
+#' @method groups communities
+#' @export
+
+groups.communities <- function(x) {
+  m <- membership(x)
+  groups.default(list(membership = m))
+}
+
+#' @export
+
+communities <- groups.communities
+
+#' @method "[" communities
+#' @export
+
+`[.communities` <- function(x, i) {
+  groups(x)[i]
 }
 
+#' @method "[[" communities
+#' @export
+
+`[[.communities` <- function(x, i) {
+  groups(x)[[i]]
+}
+
+
+#' Contract several vertices into a single one
+#' 
+#' This function creates a new graph, by merging several vertices into one. The
+#' vertices in the new graph correspond to sets of vertices in the input graph.
+#' 
+#' The attributes of the graph are kept. Graph and edge attributes are
+#' unchanged, vertex attributes are combined, according to the
+#' \code{vertex.attr.comb} parameter.
+#' 
+#' @aliases contract.vertices contract
+#' @param graph The input graph, it can be directed or undirected.
+#' @param mapping A numeric vector that specifies the mapping. Its elements
+#' correspond to the vertices, and for each element the id in the new graph is
+#' given.
+#' @param vertex.attr.comb Specifies how to combine the vertex attributes in
+#' the new graph. Please see \code{\link{attribute.combination}} for details.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' g$name <- "Ring"
+#' V(g)$name <- letters[1:vcount(g)]
+#' E(g)$weight <- runif(ecount(g))
+#' 
+#' g2 <- contract(g, rep(1:5, each=2),
+#'                         vertex.attr.comb=toString)
+#' 
+#' ## graph and edge attributes are kept, vertex attributes are
+#' ## combined using the 'toString' function.
+#' print(g2, g=TRUE, v=TRUE, e=TRUE)
+#' 
+#' @export
+
+contract <- contract
diff --git a/R/components.R b/R/components.R
index ba6b5e4..80400c6 100644
--- a/R/components.R
+++ b/R/components.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -24,8 +23,10 @@
 # Connected components, subgraphs, kinda
 ###################################################################
 
-no.clusters <- function(graph, mode=c("weak", "strong")) {
-  if (!is.igraph(graph)) {
+#' @export
+
+count_components <- function(graph, mode=c("weak", "strong")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -36,13 +37,20 @@ no.clusters <- function(graph, mode=c("weak", "strong")) {
         PACKAGE="igraph")
 }
 
-cluster.distribution <- function(graph, cumulative=FALSE, mul.size=FALSE,
+#' @rdname components
+#' @param cumulative Logical, if TRUE the cumulative distirubution (relative
+#' frequency) is calculated.
+#' @param mul.size Logical. If TRUE the relative frequencies will be multiplied
+#' by the cluster sizes.
+#' @export
+
+component_distribution <- function(graph, cumulative=FALSE, mul.size=FALSE,
                                  ...) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   
-  cs <- clusters(graph, ...)$csize;
+  cs <- components(graph, ...)$csize;
   hi <- hist(cs, -1:max(cs), plot=FALSE)$density
   if (mul.size) {
     hi <- hi*1:max(cs)
@@ -57,8 +65,10 @@ cluster.distribution <- function(graph, cumulative=FALSE, mul.size=FALSE,
   res
 }
 
-is.connected <- function(graph, mode=c("weak", "strong")) {
-  if (!is.igraph(graph)) {
+#' @export
+
+is_connected <- function(graph, mode=c("weak", "strong")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -69,9 +79,41 @@ is.connected <- function(graph, mode=c("weak", "strong")) {
         PACKAGE="igraph")
 }
 
-decompose.graph <- function(graph, mode=c("weak", "strong"), max.comps=NA,
+
+
+#' Decompose a graph into components
+#' 
+#' Creates a separate graph for each component of a graph.
+#' 
+#' @aliases decompose.graph
+#' @param graph The original graph.
+#' @param mode Character constant giving the type of the components, wither
+#' \code{weak} for weakly connected components or \code{strong} for strongly
+#' connected components.
+#' @param max.comps The maximum number of components to return. The first
+#' \code{max.comps} components will be returned (which hold at least
+#' \code{min.vertices} vertices, see the next parameter), the others will be
+#' ignored. Supply \code{NA} here if you don't want to limit the number of
+#' components.
+#' @param min.vertices The minimum number of vertices a component should
+#' contain in order to place it in the result list. Eg. supply 2 here to ignore
+#' isolate vertices.
+#' @return A list of graph objects.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{is_connected}} to decide whether a graph is connected,
+#' \code{\link{components}} to calculate the connected components of a graph.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # the diameter of each component in a random graph
+#' g <- sample_gnp(1000, 1/1000)
+#' components <- decompose(g, min.vertices=2)
+#' sapply(components, diameter)
+#' 
+decompose <- function(graph, mode=c("weak", "strong"), max.comps=NA,
                       min.vertices=0) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -86,3 +128,75 @@ decompose.graph <- function(graph, mode=c("weak", "strong"), max.comps=NA,
         PACKAGE="igraph"
         )
 }
+
+
+#' Articulation points of a graph
+#' 
+#' Articuation points or cut vertices are vertices whose removal increases the
+#' number of connected components in a graph.
+#' 
+#' Articuation points or cut vertices are vertices whose removal increases the
+#' number of connected components in a graph. If the original graph was
+#' connected, then the removal of a single articulation point makes it
+#' undirected. If a graph contains no articulation points, then its vertex
+#' connectivity is at least two.
+#' 
+#' @aliases articulation.points articulation_points
+#' @param graph The input graph. It is treated as an undirected graph, even if
+#' it is directed.
+#' @return A numeric vector giving the vertex ids of the articulation points of
+#' the input graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{biconnected_components}}, \code{\link{components}},
+#' \code{\link{is_connected}}, \code{\link{vertex_connectivity}}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- disjoint_union( make_full_graph(5), make_full_graph(5) )
+#' clu <- components(g)$membership
+#' g <- add_edges(g, c(match(1, clu), match(2, clu)) )
+#' articulation_points(g)
+#' @export
+#' @include auto.R
+
+articulation_points <- articulation_points
+
+
+#' Biconnected components
+#' 
+#' Finding the biconnected components of a graph
+#' 
+#' A graph is biconnected if the removal of any single vertex (and its adjacent
+#' edges) does not disconnect it.
+#' 
+#' A biconnected component of a graph is a maximal biconnected subgraph of it.
+#' The biconnected components of a graph can be given by the partition of its
+#' edges: every edge is a member of exactly one biconnected component. Note
+#' that this is not true for vertices: the same vertex can be part of many
+#' biconnected components.
+#' 
+#' @aliases biconnected.components biconnected_components
+#' @param graph The input graph. It is treated as an undirected graph, even if
+#' it is directed.
+#' @return A named list with three components: \item{no}{Numeric scalar, an
+#' integer giving the number of biconnected components in the graph.}
+#' \item{tree_edges}{The components themselves, a list of numeric vectors. Each
+#' vector is a set of edge ids giving the edges in a biconnected component.
+#' These edges define a spanning tree of the component.}
+#' \item{component_edges}{A list of numeric vectors. It gives all edges in the
+#' components.} \item{components}{A list of numeric vectors, the vertices of
+#' the components.} \item{articulation_points}{The articulation points of the
+#' graph. See \code{\link{articulation_points}}.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{articulation_points}}, \code{\link{components}},
+#' \code{\link{is_connected}}, \code{\link{vertex_connectivity}}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- disjoint_union( make_full_graph(5), make_full_graph(5) )
+#' clu <- components(g)$membership
+#' g <- add_edges(g, c(which(clu==1), which(clu==2)))
+#' bc <- biconnected_components(g)
+#' @export
+
+biconnected_components <- biconnected_components
diff --git a/R/console.R b/R/console.R
index a891a72..5d50af4 100644
--- a/R/console.R
+++ b/R/console.R
@@ -22,12 +22,14 @@
 
 .igraph.pb <- NULL
 
+#' @export
+
 .igraph.progress <- function(percent, message, clean=FALSE) {
   if (clean) {
     if (!is.null(.igraph.pb)) { close(.igraph.pb) }
     return(invisible())
   }
-  type <- getIgraphOpt("verbose")
+  type <- igraph_opt("verbose")
   if (is.logical(type) && type) {
     .igraph.progress.txt(percent, message)
   } else {
@@ -38,8 +40,10 @@
   }
 }
 
+#' @export
+
 .igraph.status <- function(message) {
-  type <- getIgraphOpt("verbose")
+  type <- igraph_opt("verbose")
   if (is.logical(type) && type) {
     message(message, appendLF=FALSE)
   } else {
@@ -71,9 +75,9 @@
   pb <- get(".igraph.pb", asNamespace("igraph"))
   if (percent==0) {
     if (!is.null(pb)) { close(pb) }
-    pb <- tkProgressBar(min=0, max=100, title=message, label="0 %")
+    pb <- tcltk::tkProgressBar(min=0, max=100, title=message, label="0 %")
   }
-  setTkProgressBar(pb, percent, label=paste(percent, "%"))
+  tcltk::setTkProgressBar(pb, percent, label=paste(percent, "%"))
   if (percent==100) {
     close(pb);
     pb <- NULL
@@ -94,8 +98,8 @@
 
   ## Update progress bar
   pb$pb$set(pb$pb$widget, percent)
-  tkconfigure(pb$pb$label, text=substr(message, 1, 20))
-  tcl("update", "idletasks")
+  tcltk::tkconfigure(pb$pb$label, text=substr(message, 1, 20))
+  tcltk::tcl("update", "idletasks")
   
   ## Done
   assign(".igraph.pb", pb, envir=asNamespace("igraph"))  
@@ -104,49 +108,49 @@
 }
 
 .igraph.progress.tkconsole.create <- function(oldverb) {
-  console <- tktoplevel()
-  tktitle(console) <- "igraph console"
+  console <- tcltk::tktoplevel()
+  tcltk::tktitle(console) <- "igraph console"
 
-  fn <- tkfont.create(family="courier", size=8)
+  fn <- tcltk::tkfont.create(family="courier", size=8)
 
-  lfr <- tkframe(console)
-  image <- tkimage.create("photo", "img", format="gif",
+  lfr <- tcltk::tkframe(console)
+  image <- tcltk::tkimage.create("photo", "img", format="gif",
                           file=system.file("igraph2.gif", package="igraph"))
-  logo <- tklabel(lfr, relief="flat", padx=10, pady=10, image=image)
+  logo <- tcltk::tklabel(lfr, relief="flat", padx=10, pady=10, image=image)
   
-  scr <- tkscrollbar(console, repeatinterval=5,
-                     command=function(...) tkyview(txt, ...)) 
-  txt <- tktext(console, yscrollcommand=function(...) tkset(scr, ...),
+  scr <- tcltk::tkscrollbar(console, repeatinterval=5,
+                     command=function(...) tcltk::tkyview(txt, ...)) 
+  txt <- tcltk::tktext(console, yscrollcommand=function(...) tcltk::tkset(scr, ...),
                 width=60, height=7, font=fn)
-  tkconfigure(txt, state="disabled")
+  tcltk::tkconfigure(txt, state="disabled")
   pbar <- .igraph.progress.tkconsole.pbar(console)
 
-  bclear <- tkbutton(lfr, text="Clear", command=function() {
-    tkconfigure(txt, state="normal")
-    tkdelete(txt, "0.0", "end")
-    tkconfigure(txt, state="disabled")
+  bclear <- tcltk::tkbutton(lfr, text="Clear", command=function() {
+    tcltk::tkconfigure(txt, state="normal")
+    tcltk::tkdelete(txt, "0.0", "end")
+    tcltk::tkconfigure(txt, state="disabled")
   })
-  bstop  <- tkbutton(lfr, text="Stop",  command=function() {})
-  bclose <- tkbutton(lfr, text="Close", command=function() {
-    if (!is.na(oldverb) && getIgraphOpt("verbose") == "tkconsole") {
-      igraph.options(verbose=oldverb)
+  bstop  <- tcltk::tkbutton(lfr, text="Stop",  command=function() {})
+  bclose <- tcltk::tkbutton(lfr, text="Close", command=function() {
+    if (!is.na(oldverb) && igraph_opt("verbose") == "tkconsole") {
+      igraph_options(verbose=oldverb)
     }
-    tkdestroy(console) })
+    tcltk::tkdestroy(console) })
 
-  tkpack(logo, side="top", fill="none", expand=0, anchor="n",
+  tcltk::tkpack(logo, side="top", fill="none", expand=0, anchor="n",
          ipadx=10, ipady=10)
-  tkpack(bclear, side="top", fill="x", expand=0, padx=10)
-  ## tkpack(bstop, side="top", fill="x", expand=0, padx=10)
-  tkpack(bclose, side="top", fill="x", expand=0, padx=10)  
+  tcltk::tkpack(bclear, side="top", fill="x", expand=0, padx=10)
+  ## tcltk::tkpack(bstop, side="top", fill="x", expand=0, padx=10)
+  tcltk::tkpack(bclose, side="top", fill="x", expand=0, padx=10)  
   
-  tkpack(lfr, side="left", fill="none", expand=0, anchor="n")
-  tkpack(pbar$frame, side="bottom", fill="x", expand=0)
-  tkpack(scr, side="right", fill="y", expand=0)
-  tkpack(txt, side="left", fill="both", expand=1)
-
-  tkbind(console, "<Destroy>", function() {
-    if (!is.na(oldverb) && getIgraphOpt("verbose") == "tkconsole") {
-      igraph.options(verbose=oldverb)
+  tcltk::tkpack(lfr, side="left", fill="none", expand=0, anchor="n")
+  tcltk::tkpack(pbar$frame, side="bottom", fill="x", expand=0)
+  tcltk::tkpack(scr, side="right", fill="y", expand=0)
+  tcltk::tkpack(txt, side="left", fill="both", expand=1)
+
+  tcltk::tkbind(console, "<Destroy>", function() {
+    if (!is.na(oldverb) && igraph_opt("verbose") == "tkconsole") {
+      igraph_options(verbose=oldverb)
     }
     assign(".igraph.pb", NULL, envir=asNamespace("igraph"))
   })
@@ -167,14 +171,14 @@
       return()
     }
   }
-  tkconfigure(txt, state="normal")
+  tcltk::tkconfigure(txt, state="normal")
   now <- paste(sep="", substr(date(), 5, 19), ": ")
   s1 <- grepl("^ ", message)
-  if (!s1) { tkinsert(txt, "insert", now) }
-  tkinsert(txt, "insert", message)
-  tksee(txt, "end")
-  tkconfigure(txt, state="disabled")
-  tcl("update", "idletasks")
+  if (!s1) { tcltk::tkinsert(txt, "insert", now) }
+  tcltk::tkinsert(txt, "insert", message)
+  tcltk::tksee(txt, "end")
+  tcltk::tkconfigure(txt, state="disabled")
+  tcltk::tcl("update", "idletasks")
 }
 
 close.igraphconsole <- function(con, ...) {
@@ -185,40 +189,62 @@ close.igraphconsole <- function(con, ...) {
 
 .igraph.progress.tkconsole.pbar <- function(top) {
   useText <- FALSE
-  have_ttk <- as.character(tcl("info", "tclversion")) >= "8.5"
-  if (!have_ttk && as.character(tclRequire("PBar")) == "FALSE") 
+  have_ttk <- as.character(tcltk::tcl("info", "tclversion")) >= "8.5"
+  if (!have_ttk && as.character(tcltk::tclRequire("PBar")) == "FALSE") 
     useText <- TRUE
-  fn <- tkfont.create(family = "helvetica", size = 10)
-  frame <- tkframe(top)
+  fn <- tcltk::tkfont.create(family = "helvetica", size = 10)
+  frame <- tcltk::tkframe(top)
   if (useText) {
-    .lab <- tklabel(frame, text = " ", font = fn, anchor="w",
+    .lab <- tcltk::tklabel(frame, text = " ", font = fn, anchor="w",
                     padx = 20)
-    tkpack(.lab, side = "left", anchor="w", padx=5)
-    fn2 <- tkfont.create(family = "helvetica", size = 12)
-    .vlab <- tklabel(frame, text = "0%", font = fn2, padx = 20)
-    tkpack(.vlab, side = "right")
+    tcltk::tkpack(.lab, side = "left", anchor="w", padx=5)
+    fn2 <- tcltk::tkfont.create(family = "helvetica", size = 12)
+    .vlab <- tcltk::tklabel(frame, text = "0%", font = fn2, padx = 20)
+    tcltk::tkpack(.vlab, side = "right")
   } else {
-    .lab <- tklabel(frame, text = " ", font = fn, anchor="w",
+    .lab <- tcltk::tklabel(frame, text = " ", font = fn, anchor="w",
                     pady = 5)
-    tkpack(.lab, side = "top", anchor="w", padx=5)
-    tkpack(tklabel(frame, text = "", font = fn), side = "bottom")
-    .val <- tclVar()
+    tcltk::tkpack(.lab, side = "top", anchor="w", padx=5)
+    tcltk::tkpack(tcltk::tklabel(frame, text = "", font = fn), side = "bottom")
+    .val <- tcltk::tclVar()
     pBar <- if (have_ttk) {
-      ttkprogressbar(frame, length = 300, variable=.val)
+      tcltk::ttkprogressbar(frame, length = 300, variable=.val)
     } else {
-      tkwidget(frame, "ProgressBar", width = 300, variable=.val)
+      tcltk::tkwidget(frame, "ProgressBar", width = 300, variable=.val)
     }
-    tkpack(pBar, side = "bottom", anchor="w", padx=5)
+    tcltk::tkpack(pBar, side = "bottom", anchor="w", padx=5)
   }
-  get <- function(w) { return(tclvalue(.val)); }
-  set <- function(w, val) { tclvalue(.val) <<- val }
+  get <- function(w) { return(tcltk::tclvalue(.val)); }
+  set <- function(w, val) { tcltk::tclvalue(.val) <<- val }
   pb <- list(widget=pBar, get=get, set=set, label=.lab)
   list(frame=frame, pb=pb)
 }
 
-igraph.console <- function() {
-  oldverb <- getIgraphOpt("verbose")
-  igraph.options(verbose="tkconsole")
+#' The igraph console
+#' 
+#' The igraph console is a GUI windows that shows what the currently running
+#' igraph function is doing.
+#' 
+#' The console can be started by calling the \code{console} function.
+#' Then it stays open, until the user closes it.
+#' 
+#' Another way to start it to set the \code{verbose} igraph option to
+#' \dQuote{tkconsole} via \code{igraph_options}. Then the console (re)opens
+#' each time an igraph function supporting it starts; to close it, set the
+#' \code{verbose} option to another value.
+#' 
+#' The console is written in Tcl/Tk and required the \code{tcltk} package.
+#' 
+#' @aliases igraph.console
+#' @return \code{NULL}, invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{igraph_options}} and the \code{verbose} option.
+#' @keywords graphs
+#' @export
+
+console <- function() {
+  oldverb <- igraph_opt("verbose")
+  igraph_options(verbose="tkconsole")
   pb <- .igraph.progress.tkconsole.create(oldverb)
   assign(".igraph.pb", pb, envir=asNamespace("igraph"))  
   .igraph.progress.tkconsole.message("Console started.\n")
diff --git a/R/conversion.R b/R/conversion.R
index ca3c6c3..b1e30ba 100644
--- a/R/conversion.R
+++ b/R/conversion.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -23,7 +22,7 @@
 get.adjacency.dense <- function(graph, type=c("both", "upper", "lower"),
                                 attr=NULL, edges=FALSE, names=TRUE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   
@@ -36,10 +35,10 @@ get.adjacency.dense <- function(graph, type=c("both", "upper", "lower"),
                  as.logical(edges), PACKAGE="igraph")
   } else {
     attr <- as.character(attr)
-    if (! attr %in% list.edge.attributes(graph)) {
+    if (! attr %in% edge_attr_names(graph)) {
       stop("no such edge attribute")
     }
-    exattr <- get.edge.attribute(graph, attr)
+    exattr <- edge_attr(graph, attr)
     if (is.logical(exattr)) {
       res <- matrix(FALSE, nrow=vcount(graph), ncol=vcount(graph))
     } else if (is.character(exattr)) {
@@ -50,38 +49,38 @@ get.adjacency.dense <- function(graph, type=c("both", "upper", "lower"),
       stop("Sparse matrices must be either numeric or logical,",
            "and the edge attribute is not")
     }
-    if (is.directed(graph)) {
+    if (is_directed(graph)) {
       for (i in seq(length=ecount(graph))) {
-        e <- get.edge(graph, i)
-        res[ e[1], e[2] ] <- get.edge.attribute(graph, attr, i)
+        e <- ends(graph, i, names = FALSE)
+        res[ e[1], e[2] ] <- edge_attr(graph, attr, i)
       }
     } else {
       if (type==0) {
         ## upper
         for (i in seq(length=ecount(graph))) {
-          e <- get.edge(graph, i)
-          res[ min(e), max(e) ] <- get.edge.attribute(graph, attr, i)
+          e <- ends(graph, i, names = FALSE)
+          res[ min(e), max(e) ] <- edge_attr(graph, attr, i)
         }        
       } else if (type==1) {
         ## lower
         for (i in seq(length=ecount(graph))) {
-          e <- get.edge(graph, i)
-          res[ max(e), min(e) ] <- get.edge.attribute(graph, attr, i)
+          e <- ends(graph, i, names = FALSE)
+          res[ max(e), min(e) ] <- edge_attr(graph, attr, i)
         }        
       } else if (type==2) {
         ## both
         for (i in seq(length=ecount(graph))) {
-          e <- get.edge(graph, i)
-          res[ e[1], e[2] ] <- get.edge.attribute(graph, attr, i)
+          e <- ends(graph, i, names = FALSE)
+          res[ e[1], e[2] ] <- edge_attr(graph, attr, i)
           if (e[1] != e[2]) {
-            res[ e[2], e[1] ] <- get.edge.attribute(graph, attr, i)
+            res[ e[2], e[1] ] <- edge_attr(graph, attr, i)
           }
         }
       }
     }
   }
 
-  if (names && "name" %in% list.vertex.attributes(graph)) {
+  if (names && "name" %in% vertex_attr_names(graph)) {
     colnames(res) <- rownames(res) <- V(graph)$name
   }
   
@@ -91,7 +90,7 @@ get.adjacency.dense <- function(graph, type=c("both", "upper", "lower"),
 get.adjacency.sparse <- function(graph, type=c("both", "upper", "lower"),
                                  attr=NULL, edges=FALSE, names=TRUE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -99,15 +98,15 @@ get.adjacency.sparse <- function(graph, type=c("both", "upper", "lower"),
 
   vc <- vcount(graph)
   
-  el <- get.edgelist(graph, names=FALSE)
+  el <- as_edgelist(graph, names=FALSE)
   if (edges) {
     value <- seq_len(nrow(el))
   } else if (!is.null(attr)) {
     attr <- as.character(attr)
-    if (!attr %in% list.edge.attributes(graph)) {
+    if (!attr %in% edge_attr_names(graph)) {
       stop("no such edge attribute")
     }
-    value <- get.edge.attribute(graph, name=attr)
+    value <- edge_attr(graph, name=attr)
     if (!is.numeric(value) && !is.logical(value)) {
       stop("Sparse matrices must be either numeric or logical,",
            "and the edge attribute is not")
@@ -116,7 +115,7 @@ get.adjacency.sparse <- function(graph, type=c("both", "upper", "lower"),
     value <- rep(1, nrow(el))
   }
 
-  if (is.directed(graph)) {
+  if (is_directed(graph)) {
     res <- Matrix::sparseMatrix(dims=c(vc, vc), i=el[,1], j=el[,2], x=value)
   } else {
     if (type=="upper") {
@@ -135,17 +134,68 @@ get.adjacency.sparse <- function(graph, type=c("both", "upper", "lower"),
     }
   }
 
-  if (names && "name" %in% list.vertex.attributes(graph)) {
+  if (names && "name" %in% vertex_attr_names(graph)) {
     colnames(res) <- rownames(res) <- V(graph)$name
   }
 
   res
 }
 
-get.adjacency <- function(graph, type=c("both", "upper", "lower"),
-                          attr=NULL, edges=FALSE, names=TRUE, 
-                          sparse=getIgraphOpt("sparsematrices")) {
-  if (!is.igraph(graph)) {
+#' Convert a graph to an adjacency matrix
+#' 
+#' Sometimes it is useful to work with a standard representation of a
+#' graph, like an adjacency matrix.
+#' 
+#' \code{as_adjacency_matrix} returns the adjacency matrix of a graph, a
+#' regular matrix if \code{sparse} is \code{FALSE}, or a sparse matrix, as
+#' defined in the \sQuote{\code{Matrix}} package, if \code{sparse} if
+#' \code{TRUE}.
+#' 
+#' @aliases get.adjacency
+#' @param graph The graph to convert.
+#' @param type Gives how to create the adjacency matrix for undirected graphs.
+#' It is ignored for directed graphs. Possible values: \code{upper}: the upper
+#' right triangle of the matrix is used, \code{lower}: the lower left triangle
+#' of the matrix is used. \code{both}: the whole matrix is used, a symmetric
+#' matrix is returned.
+#' @param attr Either \code{NULL} or a character string giving an edge
+#' attribute name. If \code{NULL} a traditional adjacency matrix is returned.
+#' If not \code{NULL} then the values of the given edge attribute are included
+#' in the adjacency matrix. If the graph has multiple edges, the edge attribute
+#' of an arbitrarily chosen edge (for the multiple edges) is included. This
+#' argument is ignored if \code{edges} is \code{TRUE}.
+#' 
+#' Note that this works only for certain attribute types. If the \code{sparse}
+#' argumen is \code{TRUE}, then the attribute must be either logical or
+#' numeric. If the \code{sparse} argument is \code{FALSE}, then character is
+#' also allowed. The reason for the difference is that the \code{Matrix}
+#' package does not support character sparse matrices yet.
+#' @param edges Logical scalar, whether to return the edge ids in the matrix.
+#' For non-existant edges zero is returned.
+#' @param names Logical constant, whether to assign row and column names
+#' to the matrix. These are only assigned if the \code{name} vertex attribute
+#' is present in the graph.
+#' @param sparse Logical scalar, whether to create a sparse matrix. The
+#' \sQuote{\code{Matrix}} package must be installed for creating sparse
+#' matrices.
+#' @return A \code{vcount(graph)} by \code{vcount(graph)} (usually) numeric
+#' matrix.
+#'
+#' @seealso \code{\link{graph_from_adjacency_matrix}}, \code{\link{read_graph}}
+#' @examples
+#' 
+#' g <- sample_gnp(10, 2/10)
+#' as_adjacency_matrix(g)
+#' V(g)$name <- letters[1:vcount(g)]
+#' as_adjacency_matrix(g)
+#' E(g)$weight <- runif(ecount(g))
+#' as_adjacency_matrix(g, attr="weight")
+#' @export
+
+as_adjacency_matrix <- function(graph, type=c("both", "upper", "lower"),
+                                attr=NULL, edges=FALSE, names=TRUE, 
+                                sparse=igraph_opt("sparsematrices")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -156,23 +206,116 @@ get.adjacency <- function(graph, type=c("both", "upper", "lower"),
   }  
 }
 
-get.edgelist <- function(graph, names=TRUE) {
-  if (!is.igraph(graph)) {
+#' @export
+#' @rdname as_adjacency_matrix
+
+as_adj <- as_adjacency_matrix
+
+#' Convert a graph to an edge list
+#' 
+#' Sometimes it is useful to work with a standard representation of a
+#' graph, like an edge list.
+#' 
+#' \code{as_edgelist} returns the list of edges in a graph.
+#' 
+#' @aliases get.edgelist
+#' @param graph The graph to convert.
+#' @param names Whether to return a character matrix containing vertex
+#' names (ie. the \code{name} vertex attribute) if they exist or numeric
+#' vertex ids.
+#' @return A \code{gsize(graph)} by 2 numeric matrix.
+#' @seealso \code{\link{graph_from_adjacency_matrix}}, \code{\link{read_graph}}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(10, 2/10)
+#' as_edgelist(g)
+#'
+#' V(g)$name <- LETTERS[seq_len(gorder(g))]
+#' as_edgelist(g)
+#' 
+#' @export
+
+as_edgelist <- function(graph, names=TRUE) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- matrix(.Call("R_igraph_get_edgelist", graph, TRUE,
                       PACKAGE="igraph"), ncol=2)
   res <- res+1
-  if (names && "name" %in% list.vertex.attributes(graph)) {
+  if (names && "name" %in% vertex_attr_names(graph)) {
     res <- matrix(V(graph)$name[ res ], ncol=2)
   }
 
   res
 }
 
+
+
+#' Convert between directed and undirected graphs
+#' 
+#' \code{as.directed} converts an undirected graph to directed,
+#' \code{as.undirected} does the opposite, it converts a directed graph to
+#' undirected.
+#' 
+#' Conversion algorithms for \code{as.directed}: \describe{
+#' \item{"arbitrary"}{The number of edges in the graph stays the same, an
+#' arbitrarily directed edge is created for each undirected edge.}
+#' \item{"mutual"}{Two directed edges are created for each undirected
+#' edge, one in each direction.} }
+#' 
+#' Conversion algorithms for \code{as.undirected}: \describe{
+#' \item{"each"}{The number of edges remains constant, an undirected edge
+#' is created for each directed one, this version might create graphs with
+#' multiple edges.} \item{"collapse"}{One undirected edge will be created
+#' for each pair of vertices which are connected with at least one directed
+#' edge, no multiple edges will be created.} \item{"mutual"}{One
+#' undirected edge will be created for each pair of mutual edges. Non-mutual
+#' edges are ignored. This mode might create multiple edges if there are more
+#' than one mutual edge pairs between the same pair of vertices.  } }
+#' 
+#' @aliases as.directed as.undirected
+#' @param graph The graph to convert.
+#' @param mode Character constant, defines the conversion algorithm. For
+#' \code{as.directed} it can be \code{mutual} or \code{arbitrary}. For
+#' \code{as.undirected} it can be \code{each}, \code{collapse} or
+#' \code{mutual}. See details below.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{simplify}} for removing multiple and/or loop edges from
+#' a graph.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' as.directed(g, "mutual")
+#' g2 <- make_star(10)
+#' as.undirected(g)
+#' 
+#' # Combining edge attributes
+#' g3 <- make_ring(10, directed=TRUE, mutual=TRUE)
+#' E(g3)$weight <- seq_len(ecount(g3))
+#' ug3 <- as.undirected(g3)
+#' print(ug3, e=TRUE)
+#' \dontrun{
+#'   x11(width=10, height=5)
+#'   layout(rbind(1:2))
+#'   plot( g3, layout=layout_in_circle, edge.label=E(g3)$weight)
+#'   plot(ug3, layout=layout_in_circle, edge.label=E(ug3)$weight)
+#' }
+#' 
+#' g4 <- graph(c(1,2, 3,2,3,4,3,4, 5,4,5,4,
+#'               6,7, 7,6,7,8,7,8, 8,7,8,9,8,9,
+#'               9,8,9,8,9,9, 10,10,10,10))
+#' E(g4)$weight <- seq_len(ecount(g4))
+#' ug4 <- as.undirected(g4, mode="mutual",
+#'               edge.attr.comb=list(weight=length))
+#' print(ug4, e=TRUE)
+#' 
 as.directed <- function(graph, mode=c("mutual", "arbitrary")) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -184,8 +327,61 @@ as.directed <- function(graph, mode=c("mutual", "arbitrary")) {
         PACKAGE="igraph")
 }
 
-get.adjlist <- function(graph, mode=c("all", "out", "in", "total")) {
-  if (!is.igraph(graph)) {
+#' @rdname as.directed
+#' @param edge.attr.comb Specifies what to do with edge attributes, if
+#' \code{mode="collapse"} or \code{mode="mutual"}.  In these cases many edges
+#' might be mapped to a single one in the new graph, and their attributes are
+#' combined. Please see \code{\link{attribute.combination}} for details on
+#' this.
+#' @export
+
+as.undirected <- function(graph, mode=c("collapse", "each", "mutual"), edge.attr.comb=igraph_opt("edge.attr.comb")) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  mode <- switch(igraph.match.arg(mode), "collapse"=1, "each"=0, "mutual"=2)
+  edge.attr.comb <- igraph.i.attribute.combination(edge.attr.comb)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_to_undirected", graph, mode, edge.attr.comb,
+        PACKAGE="igraph")
+
+  res
+}
+
+
+#' Adjacency lists
+#' 
+#' Create adjacency lists from a graph, either for adjacent edges or for
+#' neighboring vertices
+#' 
+#' \code{as_adj_list} returns a list of numeric vectors, which include the ids
+#' of neighbor vertices (according to the \code{mode} argument) of all
+#' vertices.
+#' 
+#' \code{as_adj_edge_list} returns a list of numeric vectors, which include the
+#' ids of adjacent edgs (according to the \code{mode} argument) of all
+#' vertices.
+#' 
+#' @aliases as_adj_list get.adjedgelist
+#' @param graph The input graph.
+#' @param mode Character scalar, it gives what kind of adjacent edges/vertices
+#' to include in the lists. \sQuote{\code{out}} is for outgoing edges/vertices,
+#' \sQuote{\code{in}} is for incoming edges/vertices, \sQuote{\code{all}} is
+#' for both. This argument is ignored for undirected graphs.
+#' @return A list of numeric vectors.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{as_edgelist}}, \code{\link{as_adj}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' as_adj_list(g)
+#' as_adj_edge_list(g)
+#' 
+as_adj_list <- function(graph, mode=c("all", "out", "in", "total")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -194,13 +390,17 @@ get.adjlist <- function(graph, mode=c("all", "out", "in", "total")) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_get_adjlist", graph, mode,
                PACKAGE="igraph")
-  res <- lapply(res, function(x) x+1)
-  if (is.named(graph)) names(res) <- V(graph)$name
+  res <- lapply(res, function(x) V(graph)[x + 1])
+  if (is_named(graph)) names(res) <- V(graph)$name
   res
 }
 
-get.adjedgelist <- function(graph, mode=c("all", "out", "in", "total")) {
-  if (!is.igraph(graph)) {
+#' @rdname as_adj_list
+#' @aliases get.adjlist
+#' @export
+
+as_adj_edge_list <- function(graph, mode=c("all", "out", "in", "total")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -209,96 +409,173 @@ get.adjedgelist <- function(graph, mode=c("all", "out", "in", "total")) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_get_adjedgelist", graph, mode,
                PACKAGE="igraph")
-  res <- lapply(res, function(x) x+1)
-  if (is.named(graph)) names(res) <- V(graph)$name
+  res <- lapply(res, function(x) E(graph)[x + 1])
+  if (is_named(graph)) names(res) <- V(graph)$name
   res
 }
 
-igraph.from.graphNEL <- function(graphNEL, name=TRUE, weight=TRUE,
+#' Convert graphNEL objects from the graph package to igraph
+#' 
+#' The graphNEL class is defined in the \code{graph} package, it is another
+#' way to represent graphs. \code{graph_from_graphnel} takes a graphNEL
+#' graph and converts it to an igraph graph. It handles all
+#' graph/vertex/edge attributes. If the graphNEL graph has a vertex
+#' attribute called \sQuote{\code{name}} it will be used as igraph vertex
+#' attribute \sQuote{\code{name}} and the graphNEL vertex names will be
+#' ignored.
+#' 
+#' Because graphNEL graphs poorly support multiple edges, the edge
+#' attributes of the multiple edges are lost: they are all replaced by the
+#' attributes of the first of the multiple edges.
+#' 
+#' @aliases igraph.from.graphNEL
+#' @param graphNEL The graphNEL graph.
+#' @param name Logical scalar, whether to add graphNEL vertex names as an
+#' igraph vertex attribute called \sQuote{\code{name}}.
+#' @param weight Logical scalar, whether to add graphNEL edge weights as an
+#' igraph edge attribute called \sQuote{\code{weight}}. (graphNEL graphs are
+#' always weighted.)
+#' @param unlist.attrs Logical scalar. graphNEL attribute query functions
+#' return the values of the attributes in R lists, if this argument is
+#' \code{TRUE} (the default) these will be converted to atomic vectors,
+#' whenever possible, before adding them to the igraph graph.
+#' @return \code{graph_from_graphnel} returns an igraph graph object.
+#' @seealso \code{\link{as_graphnel}} for the other direction,
+#' \code{\link{as_adj}}, \code{\link{graph_from_adjacency_matrix}},
+#' \code{\link{as_adj_list}} and \code{\link{graph.adjlist}} for other
+#' graph representations.
+#' @examples
+#' \dontrun{
+#' ## Undirected
+#' g <- make_ring(10)
+#' V(g)$name <- letters[1:10]
+#' GNEL <- as_graphnel(g)
+#' g2 <- graph_from_graphnel(GNEL)
+#' g2
+#' 
+#' ## Directed
+#' g3 <- make_star(10, mode="in")
+#' V(g3)$name <- letters[1:10]
+#' GNEL2 <- as_graphnel(g3)
+#' g4 <- graph_from_graphnel(GNEL2)
+#' g4
+#' }
+#' #' @export
+
+graph_from_graphnel <- function(graphNEL, name=TRUE, weight=TRUE,
                                  unlist.attrs=TRUE) {
 
-  if (! "graph" %in% .packages()) {
-    library(graph, pos="package:base")
-  }
-
   if (!inherits(graphNEL, "graphNEL")) {
     stop("Not a graphNEL graph")
   }
   
-  al <- lapply(edgeL(graphNEL), "[[", "edges")
-  if (edgemode(graphNEL)=="undirected") {
+  al <- lapply(graph::edgeL(graphNEL), "[[", "edges")
+  if (graph::edgemode(graphNEL)=="undirected") {
     al <- mapply(SIMPLIFY=FALSE, seq_along(al), al, FUN=function(n, l) {
       c(l, rep(n, sum(l==n)))
     })
   }
-  mode <- if (edgemode(graphNEL)=="directed") "out" else "all"
-  g <- graph.adjlist(al, mode=mode, duplicate=TRUE)
+  mode <- if (graph::edgemode(graphNEL)=="directed") "out" else "all"
+  g <- graph_from_adj_list(al, mode=mode, duplicate=TRUE)
   if (name) {
-    V(g)$name <- nodes(graphNEL)
+    V(g)$name <- graph::nodes(graphNEL)
   }
 
   ## Graph attributes
   g.n <- names(graphNEL at graphData)
   g.n <- g.n [ g.n != "edgemode" ]
   for (n in g.n) {
-    g <- set.graph.attribute(g, n, graphNEL at graphData[[n]])
+    g <- set_graph_attr(g, n, graphNEL at graphData[[n]])
   }
   
   ## Vertex attributes
-  v.n <- names(nodeDataDefaults(graphNEL))
+  v.n <- names(graph::nodeDataDefaults(graphNEL))
   for (n in v.n) {
-    val <- unname(nodeData(graphNEL, attr=n))
+    val <- unname(graph::nodeData(graphNEL, attr=n))
     if (unlist.attrs && all(sapply(val, length)==1)) { val <- unlist(val) }
-    g <- set.vertex.attribute(g, n, value=val)
+    g <- set_vertex_attr(g, n, value=val)
   }
 
   ## Edge attributes
-  e.n <- names(edgeDataDefaults(graphNEL))
+  e.n <- names(graph::edgeDataDefaults(graphNEL))
   if (!weight) { e.n <- e.n [ e.n != "weight" ] }
   if (length(e.n) > 0) {
-    el <- get.edgelist(g)
+    el <- as_edgelist(g)
     el <- paste(sep="|", el[,1], el[,2])
     for (n in e.n) {
-      val <- unname(edgeData(graphNEL, attr=n)[el])
+      val <- unname(graph::edgeData(graphNEL, attr=n)[el])
       if (unlist.attrs && all(sapply(val, length)==1)) { val <- unlist(val) }
-      g <- set.edge.attribute(g, n, value=val)
+      g <- set_edge_attr(g, n, value=val)
     }
   }
   
   g 
 }
 
-igraph.to.graphNEL <- function(graph) {
-
-  if (!is.igraph(graph)) {
+#' Convert igraph graphs to graphNEL objects from the graph package
+#' 
+#' The graphNEL class is defined in the \code{graph} package, it is another
+#' way to represent graphs. These functions are provided to convert between
+#' the igraph and the graphNEL objects.
+#' 
+#' \code{as_graphnel} converts and igraph graph to a graphNEL graph. It
+#' converts all graph/vertex/edge attributes. If the igraph graph has a
+#' vertex attribute \sQuote{\code{name}}, then it will be used to assign
+#' vertex names in the graphNEL graph. Otherwise numeric igraph vertex ids
+#' will be used for this purpose.
+#' 
+#' @aliases igraph.to.graphNEL
+#' @param graph An igraph graph object.
+#' @return \code{as_graphnel} returns a graphNEL graph object.
+#' @seealso \code{\link{graph_from_graphnel}} for the other direction,
+#' \code{\link{as_adj}}, \code{\link{graph_from_adjacency_matrix}},
+#' \code{\link{as_adj_list}} and \code{\link{graph.adjlist}} for
+#' other graph representations.
+#' @examples
+#' ## Undirected
+#' \dontrun{
+#' g <- make_ring(10)
+#' V(g)$name <- letters[1:10]
+#' GNEL <- as_graphnel(g)
+#' g2 <- graph_from_graphnel(GNEL)
+#' g2
+#' 
+#' ## Directed
+#' g3 <- make_star(10, mode="in")
+#' V(g3)$name <- letters[1:10]
+#' GNEL2 <- as_graphnel(g3)
+#' g4 <- graph_from_graphnel(GNEL2)
+#' g4
+#' }
+#' #' @export
+
+as_graphnel <- function(graph) {
+
+  if (!is_igraph(graph)) {
     stop("Not an igraph graph")
   }
   
-  if (! "graph" %in% .packages()) {
-    library(graph, pos="package:base")
-  }
-
-  if ("name" %in% list.vertex.attributes(graph) &&
+  if ("name" %in% vertex_attr_names(graph) &&
       is.character(V(graph)$name)) {
     name <- V(graph)$name
   } else {
     name <- as.character(seq(vcount(graph)))    
   }
 
-  edgemode <- if (is.directed(graph)) "directed" else "undirected"  
+  edgemode <- if (is_directed(graph)) "directed" else "undirected"  
 
-  if ("weight" %in% list.edge.attributes(graph) &&
+  if ("weight" %in% edge_attr_names(graph) &&
       is.numeric(E(graph)$weight)) {
-    al <- get.adjedgelist(graph, "out")
+    al <- lapply(as_adj_edge_list(graph, "out"), as.vector)
     for (i in seq(along=al)) {
-      edges <- get.edges(graph, al[[i]])
+      edges <- ends(graph, al[[i]], names = FALSE)
       edges <- ifelse( edges[,2]==i, edges[,1], edges[,2])
       weights <- E(graph)$weight[al[[i]]]
       al[[i]] <- list(edges=edges, weights=weights)
     }
   } else {
-    al <- get.adjlist(graph, "out")
-    al <- lapply(al, function(x) list(edges=x))
+    al <- as_adj_list(graph, "out")
+    al <- lapply(al, function(x) list(edges=as.vector(x)))
   }  
   
   names(al) <- name
@@ -307,38 +584,38 @@ igraph.to.graphNEL <- function(graph) {
   ## Add graph attributes (other than 'directed')
   ## Are this "officially" supported at all?
 
-  g.n <- list.graph.attributes(graph)
+  g.n <- graph_attr_names(graph)
   if ("directed" %in% g.n) {
     warning("Cannot add graph attribute `directed'")
     g.n <- g.n[ g.n != "directed" ]
   }
   for (n in g.n) {
-    res at graphData[[n]] <- get.graph.attribute(graph, n)
+    res at graphData[[n]] <- graph_attr(graph, n)
   }
 
   ## Add vertex attributes (other than 'name', that is already
   ## added as vertex names)
   
-  v.n <- list.vertex.attributes(graph)
+  v.n <- vertex_attr_names(graph)
   v.n <- v.n[ v.n != "name" ]
   for (n in v.n) {
-    nodeDataDefaults(res, attr=n) <- NA
-    nodeData(res, attr=n) <- get.vertex.attribute(graph, n)
+    graph::nodeDataDefaults(res, attr=n) <- NA
+    graph::nodeData(res, attr=n) <- vertex_attr(graph, n)
   }
 
   ## Add edge attributes (other than 'weight')
   
-  e.n <- list.edge.attributes(graph)
+  e.n <- edge_attr_names(graph)
   e.n <- e.n[ e.n != "weight" ]
   if (length(e.n) > 0) {
-    el <- get.edgelist(graph)
+    el <- as_edgelist(graph)
     el <- paste(sep="|", el[,1], el[,2])
     for (n in e.n) {
-      edgeDataDefaults(res, attr=n) <- NA
+      graph::edgeDataDefaults(res, attr=n) <- NA
       res at edgeData@data[el] <- mapply(function(x,y) {
         xx <- c(x,y); names(xx)[length(xx)] <- n; xx },
                                       res at edgeData@data[el],
-                                      get.edge.attribute(graph, n),
+                                      edge_attr(graph, n),
                                       SIMPLIFY=FALSE)
     }
   }
@@ -354,7 +631,7 @@ get.incidence.dense <- function(graph, types, names, attr) {
     res <- .Call("R_igraph_get_incidence", graph, types,
                  PACKAGE="igraph")
 
-    if (names && "name" %in% list.vertex.attributes(graph)) {
+    if (names && "name" %in% vertex_attr_names(graph)) {
       rownames(res$res) <- V(graph)$name[ res$row_ids+1 ]
       colnames(res$res) <- V(graph)$name[ res$col_ids+1 ]
     } else {
@@ -366,7 +643,7 @@ get.incidence.dense <- function(graph, types, names, attr) {
   } else {
 
     attr <- as.character(attr)
-    if (!attr %in% list.edge.attributes(graph)) {
+    if (!attr %in% edge_attr_names(graph)) {
       stop("no such edge attribute")
     }
 
@@ -380,16 +657,16 @@ get.incidence.dense <- function(graph, types, names, attr) {
     recode[types]  <- seq_len(n2)
     
     for (i in seq(length=ecount(graph))) {
-      eo <- get.edge(graph, i)
+      eo <- ends(graph, i, names = FALSE)
       e <- recode[eo]
       if (!types[eo[1]]) {
-        res[ e[1], e[2] ] <- get.edge.attribute(graph, attr, i)
+        res[ e[1], e[2] ] <- edge_attr(graph, attr, i)
       } else{
-        res[ e[2], e[1] ] <- get.edge.attribute(graph, attr, i)
+        res[ e[2], e[1] ] <- edge_attr(graph, attr, i)
       }
     }
 
-    if (names && "name" %in% list.vertex.attributes(graph)) {
+    if (names && "name" %in% vertex_attr_names(graph)) {
       rownames(res) <- V(graph)$name[ which(!types) ]
       colnames(res) <- V(graph)$name[ which( types) ]
     } else {
@@ -408,7 +685,7 @@ get.incidence.sparse <- function(graph, types, names, attr) {
     stop("Invalid types vector")
   }
 
-  el <- get.edgelist(graph, names=FALSE)
+  el <- as_edgelist(graph, names=FALSE)
   if (any(types[el[,1]] == types[el[,2]])) {
     stop("Invalid types vector, not a bipartite graph")
   }
@@ -429,17 +706,17 @@ get.incidence.sparse <- function(graph, types, names, attr) {
 
   if (!is.null(attr)) {
     attr <- as.character(attr)
-    if (!attr %in% list.edge.attributes(graph)) {
+    if (!attr %in% edge_attr_names(graph)) {
       stop("no such edge attribute")
     }
-    value <- get.edge.attribute(graph, name=attr)
+    value <- edge_attr(graph, name=attr)
   } else { 
     value <- rep(1, nrow(el))
   }
 
   res <- Matrix::spMatrix(n1, n2, i=el[,1], j=el[,2], x=value)
 
-  if (names && "name" %in% list.vertex.attributes(graph)) {
+  if (names && "name" %in% vertex_attr_names(graph)) {
     rownames(res) <- V(graph)$name[which(!types)]
     colnames(res) <- V(graph)$name[which(types)]
   } else {
@@ -449,11 +726,51 @@ get.incidence.sparse <- function(graph, types, names, attr) {
   res
 }
 
-get.incidence <- function(graph, types=NULL, attr=NULL,
+
+
+#' Incidence matrix of a bipartite graph
+#' 
+#' This function can return a sparse or dense incidence matrix of a bipartite
+#' network. The incidence matrix is an \eqn{n} times \eqn{m} matrix, \eqn{n}
+#' and \eqn{m} are the number of vertices of the two kinds.
+#' 
+#' Bipartite graphs have a \code{type} vertex attribute in igraph, this is
+#' boolean and \code{FALSE} for the vertices of the first kind and \code{TRUE}
+#' for vertices of the second kind.
+#'
+#' @aliases get.incidence
+#' @param graph The input graph. The direction of the edges is ignored in
+#' directed graphs.
+#' @param types An optional vertex type vector to use instead of the
+#' \code{type} vertex attribute. You must supply this argument if the graph has
+#' no \code{type} vertex attribute.
+#' @param attr Either \code{NULL} or a character string giving an edge
+#' attribute name. If \code{NULL}, then a traditional incidence matrix is
+#' returned. If not \code{NULL} then the values of the given edge attribute are
+#' included in the incidence matrix. If the graph has multiple edges, the edge
+#' attribute of an arbitrarily chosen edge (for the multiple edges) is
+#' included.
+#' @param names Logical scalar, if \code{TRUE} and the vertices in the graph
+#' are named (i.e. the graph has a vertex attribute called \code{name}), then
+#' vertex names will be added to the result as row and column names. Otherwise
+#' the ids of the vertices are used as row and column names.
+#' @param sparse Logical scalar, if it is \code{TRUE} then a sparse matrix is
+#' created, you will need the \code{Matrix} package for this.
+#' @return A sparse or dense matrix.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{graph_from_incidence_matrix}} for the opposite operation.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_bipartite_graph( c(0,1,0,1,0,0), c(1,2,2,3,3,4) )
+#' as_incidence_matrix(g)
+#' 
+as_incidence_matrix <- function(graph, types=NULL, attr=NULL,
                           names=TRUE, sparse=FALSE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) { 
     types <- V(graph)$type 
   } 
   if (!is.null(types)) { 
@@ -472,20 +789,26 @@ get.incidence <- function(graph, types=NULL, attr=NULL,
   }
 }
 
-get.data.frame <- function(x, what=c("edges", "vertices", "both")) {
+#' @rdname graph_from_data_frame
+#' @param x An igraph object.
+#' @param what Character constant, whether to return info about vertices,
+#' edges, or both. The default is \sQuote{edges}.
+#' @export
+
+as_data_frame <- function(x, what=c("edges", "vertices", "both")) {
 
-  if (!is.igraph(x)) { stop("Not a graph object") }
+  if (!is_igraph(x)) { stop("Not a graph object") }
   what <- igraph.match.arg(what)
 
   if (what %in% c("vertices", "both")) {
     ver <- .Call("R_igraph_mybracket2", x, 9L, 3L, PACKAGE="igraph")
     class(ver) <- "data.frame"
-    rn <- if (is.named(x)) { V(x)$name } else { seq_len(vcount(x)) }
+    rn <- if (is_named(x)) { V(x)$name } else { seq_len(vcount(x)) }
     rownames(ver) <- rn
   }
 
   if (what %in% c("edges", "both")) {
-    el <- get.edgelist(x)
+    el <- as_edgelist(x)
     edg <- c(list(from=el[,1]), list(to=el[,2]),
              .Call("R_igraph_mybracket2", x, 9L, 4L, PACKAGE="igraph"))
     class(edg) <- "data.frame"
@@ -500,3 +823,105 @@ get.data.frame <- function(x, what=c("edges", "vertices", "both")) {
     edg
   }
 }
+
+
+#' Create graphs from adjacency lists
+#' 
+#' An adjacency list is a list of numeric vectors, containing the neighbor
+#' vertices for each vertex. This function creates an igraph graph object from
+#' such a list.
+#' 
+#' Adjacency lists are handy if you intend to do many (small) modifications to
+#' a graph. In this case adjacency lists are more efficient than igraph graphs.
+#' 
+#' The idea is that you convert your graph to an adjacency list by
+#' \code{\link{as_adj_list}}, do your modifications to the graphs and finally
+#' create again an igraph graph by calling \code{graph_from_adj_list}.
+#' 
+#' @aliases graph.adjlist graph_from_adj_list
+#' @param adjlist The adjacency list. It should be consistent, i.e. the maximum
+#' throughout all vectors in the list must be less than the number of vectors
+#' (=the number of vertices in the graph). Note that the list is expected to be
+#' 0-indexed.
+#' @param mode Character scalar, it specifies whether the graph to create is
+#' undirected (\sQuote{all} or \sQuote{total}) or directed; and in the latter
+#' case, whether it contains the outgoing (\sQuote{out}) or the incoming
+#' (\sQuote{in}) neighbors of the vertices.
+#' @param duplicate Logical scalar. For undirected graphs it gives whether
+#' edges are included in the list twice. E.g. if it is \code{TRUE} then for an
+#' undirected \code{{A,B}} edge \code{graph_from_adj_list} expects \code{A}
+#' included in the neighbors of \code{B} and \code{B} to be included in the
+#' neighbors of \code{A}.
+#' 
+#' This argument is ignored if \code{mode} is \code{out} or \code{in}.
+#' @return An igraph graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{as_edgelist}}
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Directed
+#' g <- make_ring(10, dir=TRUE)
+#' al <- as_adj_list(g, mode="out")
+#' g2 <- graph_from_adj_list(al)
+#' graph.isomorphic(g, g2)
+#' 
+#' ## Undirected
+#' g <- make_ring(10)
+#' al <- as_adj_list(g)
+#' g2 <- graph_from_adj_list(al, mode="all")
+#' graph.isomorphic(g, g2)
+#' ecount(g2)
+#' g3 <- graph_from_adj_list(al, mode="all", duplicate=FALSE)
+#' ecount(g3)
+#' which_multiple(g3)
+#' @export
+
+graph_from_adj_list <- graph_from_adj_list
+
+
+#' Convert a graph to a long data frame
+#'
+#' A long data frame contains all metadata about both the vertices
+#' and edges of the graph. It contains one row for each edge, and
+#' all metadata about that edge and its incident vertices are included
+#' in that row. The names of the columns that contain the metadata
+#' of the incident vertices are prefixed with \code{from_} and \code{to_}.
+#' The first two columns are always named \code{from} and \code{to} and
+#' they contain the numeric ids of the incident vertices. The rows are
+#' listed in the order of numeric vertex ids.
+#'
+#' @param graph Input graph
+#' @return A long data frame.
+#'
+#' @export
+#' @examples
+#' g <- make_(ring(10),
+#'         with_vertex_(name = letters[1:10], color = "red"),
+#'         with_edge_(weight = 1:10, color = "green")
+#'       )
+#' as_long_data_frame(g)
+
+as_long_data_frame <- function(graph) {
+
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+
+  ver <- .Call("R_igraph_mybracket2", graph, 9L, 3L, PACKAGE="igraph")
+  class(ver) <- "data.frame"
+  rn <- if (is_named(graph)) { V(graph)$name } else { seq_len(vcount(graph)) }
+  rownames(ver) <- rn
+
+  el <- as_edgelist(graph, names = FALSE)
+  edg <- c(list(from=el[,1]), list(to=el[,2]),
+           .Call("R_igraph_mybracket2", graph, 9L, 4L, PACKAGE="igraph"))
+  class(edg) <- "data.frame"
+  rownames(edg) <- seq_len(ecount(graph))
+
+  ver2 <- ver
+  names(ver) <- paste0("from_", names(ver))
+  names(ver2) <- paste0("to_", names(ver2))
+
+  edg <- cbind(edg, ver[ el[,1], ], ver2[ el[,2], ])
+
+  edg
+}
diff --git a/R/data_frame.R b/R/data_frame.R
new file mode 100644
index 0000000..cbd0062
--- /dev/null
+++ b/R/data_frame.R
@@ -0,0 +1,254 @@
+
+## ----------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2005-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------
+
+#' Creating igraph graphs from data frames or vice-versa
+#'
+#' This function creates an igraph graph from one or two data frames containing
+#' the (symbolic) edge list and edge/vertex attributes.
+#'
+#' \code{graph_from_data_frame} creates igraph graphs from one or two data frames.
+#' It has two modes of operatation, depending whether the \code{vertices}
+#' argument is \code{NULL} or not.
+#'
+#' If \code{vertices} is \code{NULL}, then the first two columns of \code{d}
+#' are used as a symbolic edge list and additional columns as edge attributes.
+#' The names of the attributes are taken from the names of the columns.
+#'
+#' If \code{vertices} is not \code{NULL}, then it must be a data frame giving
+#' vertex metadata. The first column of \code{vertices} is assumed to contain
+#' symbolic vertex names, this will be added to the graphs as the
+#' \sQuote{\code{name}} vertex attribute. Other columns will be added as
+#' additional vertex attributes. If \code{vertices} is not \code{NULL} then the
+#' symbolic edge list given in \code{d} is checked to contain only vertex names
+#' listed in \code{vertices}.
+#'
+#' Typically, the data frames are exported from some speadsheat software like
+#' Excel and are imported into R via \code{\link{read.table}},
+#' \code{\link{read.delim}} or \code{\link{read.csv}}.
+#'
+#' \code{as_data_frame} converts the igraph graph into one or more data
+#' frames, depending on the \code{what} argument.
+#'
+#' If the \code{what} argument is \code{edges} (the default), then the edges of
+#' the graph and also the edge attributes are returned. The edges will be in
+#' the first two columns, named \code{from} and \code{to}. (This also denotes
+#' edge direction for directed graphs.)  For named graphs, the vertex names
+#' will be included in these columns, for other graphs, the numeric vertex ids.
+#' The edge attributes will be in the other columns. It is not a good idea to
+#' have an edge attribute named \code{from} or \code{to}, because then the
+#' column named in the data frame will not be unique. The edges are listed in
+#' the order of their numeric ids.
+#'
+#' If the \code{what} argument is \code{vertices}, then vertex attributes are
+#' returned. Vertices are listed in the order of their numeric vertex ids.
+#'
+#' If the \code{what} argument is \code{both}, then both vertex and edge data
+#' is returned, in a list with named entries \code{vertices} and \code{edges}.
+#'
+#' @aliases graph_from_data_frame graph.data.frame as_data_frame get.data.frame
+#' @param d A data frame containing a symbolic edge list in the first two
+#' columns. Additional columns are considered as edge attributes.  Since
+#' version 0.7 this argument is coerced to a data frame with
+#' \code{as.data.frame}.
+#' @param directed Logical scalar, whether or not to create a directed graph.
+#' @param vertices A data frame with vertex metadata, or \code{NULL}. See
+#' details below. Since version 0.7 this argument is coerced to a data frame
+#' with \code{as.data.frame}, if not \code{NULL}.
+#' @return An igraph graph object for \code{graph_from_data_frame}, and either a
+#' data frame or a list of two data frames named \code{edges} and
+#' \code{vertices} for \code{as.data.frame}.
+#' @note For \code{graph_from_data_frame} \code{NA} elements in the first two
+#' columns \sQuote{d} are replaced by the string \dQuote{NA} before creating
+#' the graph. This means that all \code{NA}s will correspond to a single
+#' vertex.
+#'
+#' \code{NA} elements in the first column of \sQuote{vertices} are also
+#' replaced by the string \dQuote{NA}, but the rest of \sQuote{vertices} is not
+#' touched. In other words, vertex names (=the first column) cannot be
+#' \code{NA}, but other vertex attributes can.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{graph_from_literal}}
+#' for another way to create graphs, \code{\link{read.table}} to read in tables
+#' from files.
+#' @keywords graphs
+#' @examples
+#'
+#' ## A simple example with a couple of actors
+#' ## The typical case is that these tables are read in from files....
+#' actors <- data.frame(name=c("Alice", "Bob", "Cecil", "David",
+#'                             "Esmeralda"),
+#'                      age=c(48,33,45,34,21),
+#'                      gender=c("F","M","F","M","F"))
+#' relations <- data.frame(from=c("Bob", "Cecil", "Cecil", "David",
+#'                                "David", "Esmeralda"),
+#'                         to=c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"),
+#'                         same.dept=c(FALSE,FALSE,TRUE,FALSE,FALSE,TRUE),
+#'                         friendship=c(4,5,5,2,1,1), advice=c(4,5,5,4,2,3))
+#' g <- graph_from_data_frame(relations, directed=TRUE, vertices=actors)
+#' print(g, e=TRUE, v=TRUE)
+#'
+#' ## The opposite operation
+#' as_data_frame(g, what="vertices")
+#' as_data_frame(g, what="edges")
+#'
+graph_from_data_frame <- function(d, directed=TRUE, vertices=NULL) {
+
+  d <- as.data.frame(d)
+  if (!is.null(vertices)) { vertices <- as.data.frame(vertices) }
+
+  if (ncol(d) < 2) {
+    stop("the data frame should contain at least two columns")
+  }
+
+  ## Handle if some elements are 'NA'
+  if (any(is.na(d[,1:2]))) {
+    warning("In `d' `NA' elements were replaced with string \"NA\"")
+    d[,1:2][ is.na(d[,1:2]) ] <- 'NA'
+  }
+  if (!is.null(vertices) && any(is.na(vertices[,1]))) {
+    warning("In `vertices[,1]' `NA' elements were replaced with string \"NA\"")
+    vertices[,1][is.na(vertices[,1])] <- 'NA'
+  }
+
+  names <- unique( c(as.character(d[,1]), as.character(d[,2])) )
+  if (!is.null(vertices)) {
+    names2 <- names
+    vertices <- as.data.frame(vertices)
+    if (ncol(vertices) < 1) {
+      stop("Vertex data frame contains no rows")
+    }
+    names <- as.character(vertices[,1])
+    if (any(duplicated(names))) {
+      stop("Duplicate vertex names")
+    }
+    if (any(! names2 %in% names)) {
+      stop("Some vertex names in edge list are not listed in vertex data frame")
+    }
+  }
+
+  # create graph
+  g <- make_empty_graph(n=0, directed=directed)
+
+  # vertex attributes
+  attrs <- list(name=names)
+  if (!is.null(vertices)) {
+    if (ncol(vertices) > 1) {
+      for (i in 2:ncol(vertices)) {
+        newval <- vertices[,i]
+        if (class(newval) == "factor") {
+          newval <- as.character(newval)
+        }
+        attrs[[ names(vertices)[i] ]] <- newval
+      }
+    }
+  }
+
+  # add vertices
+  g <- add_vertices(g, length(names), attr=attrs)
+
+  # create edge list
+  from <- as.character(d[,1])
+  to <- as.character(d[,2])
+  edges <- rbind(match(from, names), match(to,names))
+
+  # edge attributes
+  attrs <- list()
+  if (ncol(d) > 2) {
+    for (i in 3:ncol(d)) {
+      newval <- d[,i]
+      if (class(newval) == "factor") {
+        newval <- as.character(newval)
+      }
+      attrs[[ names(d)[i] ]] <- newval
+    }
+  }
+
+  # add the edges
+  g <- add_edges(g, edges, attr=attrs)
+  g
+}
+
+#' @rdname graph_from_data_frame
+#' @param ... Passed to \code{graph_from_data_frame}.
+#' @export
+
+from_data_frame <- function(...) constructor_spec(graph_from_data_frame, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a graph from an edge list matrix
+#'
+#' \code{graph_from_edgelist} creates a graph from an edge list. Its argument
+#' is a two-column matrix, each row defines one edge. If it is
+#' a numeric matrix then its elements are interpreted as vertex ids. If
+#' it is a character matrix then it is interpreted as symbolic vertex
+#' names and a vertex id will be assigned to each name, and also a
+#' \code{name} vertex attribute will be added.
+#'
+#' @aliases graph.edgelist
+#' @concept Edge list
+#' @param el The edge list, a two column matrix, character or numeric.
+#' @param directed Whether to create a directed graph.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' el <- matrix( c("foo", "bar", "bar", "foobar"), nc = 2, byrow = TRUE)
+#' graph_from_edgelist(el)
+#'
+#' # Create a ring by hand
+#' graph_from_edgelist(cbind(1:10, c(2:10, 1)))
+
+graph_from_edgelist <- function(el, directed=TRUE) {
+
+  if (!is.matrix(el) || ncol(el) != 2) {
+    stop("graph_from_edgelist expects a matrix with two columns")
+  }
+
+  if (nrow(el) == 0) {
+    res <- make_empty_graph(directed=directed)
+  } else {
+    if (is.character(el)) {
+      ## symbolic edge list
+      names <- unique(as.character(t(el)))
+      ids <- seq(names)
+      names(ids) <- names
+      res <- graph( unname(ids[t(el)]), directed=directed)
+      rm(ids)
+      V(res)$name <- names
+    } else {
+      ## normal edge list
+      res <- graph( t(el), directed=directed )
+    }
+  }
+
+  res
+}
+
+#' @rdname graph_from_edgelist
+#' @param ... Passed to \code{graph_from_edgelist}.
+#' @export
+
+from_edgelist <- function(...) constructor_spec(graph_from_edgelist, ...)
diff --git a/R/decomposition.R b/R/decomposition.R
index 89340ca..5cb0fc6 100644
--- a/R/decomposition.R
+++ b/R/decomposition.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -24,9 +23,66 @@
 # Graph decomposition
 ###################################################################
 
-is.chordal <- function(graph, alpha = NULL, alpham1 = NULL,
+
+
+#' Chordality of a graph
+#' 
+#' A graph is chordal (or triangulated) if each of its cycles of four or more
+#' nodes has a chord, which is an edge joining two nodes that are not adjacent
+#' in the cycle. An equivalent definition is that any chordless cycles have at
+#' most three nodes.
+#' 
+#' The chordality of the graph is decided by first performing maximum
+#' cardinality search on it (if the \code{alpha} and \code{alpham1} arguments
+#' are \code{NULL}), and then calculating the set of fill-in edges.
+#' 
+#' The set of fill-in edges is empty if and only if the graph is chordal.
+#' 
+#' It is also true that adding the fill-in edges to the graph makes it chordal.
+#'
+#' @aliases is.chordal
+#' @param graph The input graph. It may be directed, but edge directions are
+#' ignored, as the algorithm is defined for undirected graphs.
+#' @param alpha Numeric vector, the maximal chardinality ordering of the
+#' vertices. If it is \code{NULL}, then it is automatically calculated by
+#' calling \code{\link{max_cardinality}}, or from \code{alpham1} if
+#' that is given..
+#' @param alpham1 Numeric vector, the inverse of \code{alpha}. If it is
+#' \code{NULL}, then it is automatically calculated by calling
+#' \code{\link{max_cardinality}}, or from \code{alpha}.
+#' @param fillin Logical scalar, whether to calculate the fill-in edges.
+#' @param newgraph Logical scalar, whether to calculate the triangulated graph.
+#' @return A list with three members: \item{chordal}{Logical scalar, it is
+#' \code{TRUE} iff the input graph is chordal.} \item{fillin}{If requested,
+#' then a numeric vector giving the fill-in edges. \code{NULL} otherwise.}
+#' \item{newgraph}{If requested, then the triangulated graph, an \code{igraph}
+#' object. \code{NULL} otherwise.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{max_cardinality}}
+#' @references Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
+#' linear-time algorithms to test chordality of graphs, test acyclicity of
+#' hypergraphs, and selectively reduce acyclic hypergraphs.  \emph{SIAM Journal
+#' of Computation} 13, 566--579.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## The examples from the Tarjan-Yannakakis paper
+#' g1 <- graph_from_literal(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
+#'                 E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
+#'                 I-A:H)
+#' max_cardinality(g1)
+#' is_chordal(g1, fillin=TRUE)
+#' 
+#' g2 <- graph_from_literal(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
+#'                 E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
+#'                 I-G:H:J, J-H:I)
+#' max_cardinality(g2)
+#' is_chordal(g2, fillin=TRUE)
+#' 
+is_chordal <- function(graph, alpha = NULL, alpham1 = NULL,
                        fillin = FALSE, newgraph = FALSE) {
-    if (!is.igraph(graph)) {
+    if (!is_igraph(graph)) {
         stop("Not a graph object")
     }
     if (!is.null(alpha)) 
diff --git a/R/degseq.R b/R/degseq.R
new file mode 100644
index 0000000..e6a39a1
--- /dev/null
+++ b/R/degseq.R
@@ -0,0 +1,89 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' Check if a degree sequence is valid for a multi-graph
+#' 
+#' \code{is_degseq} checks whether the given vertex degrees (in- and
+#' out-degrees for directed graphs) can be realized by a graph. Note that the
+#' graph does not have to be simple, it may contain loop and multiple edges.
+#' For undirected graphs, it also checks whether the sum of degrees is even.
+#' For directed graphs, the function checks whether the lengths of the two
+#' degree vectors are equal and whether their sums are also equal. These are
+#' known sufficient and necessary conditions for a degree sequence to be valid.
+#' 
+#' @aliases is.degree.sequence is_degseq
+#' @param out.deg Integer vector, the degree sequence for undirected graphs, or
+#' the out-degree sequence for directed graphs.
+#' @param in.deg \code{NULL} or an integer vector. For undireted graphs, it
+#' should be \code{NULL}. For directed graphs it specifies the in-degrees.
+#' @return A logical scalar.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @references Hakimi SL: On the realizability of a set of integers as degrees
+#' of the vertices of a simple graph. \emph{J SIAM Appl Math} 10:496-506, 1962.
+#' 
+#' PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm to
+#' realize graphical degree sequences of directed graphs.  \emph{The Electronic
+#' Journal of Combinatorics} 17(1):R66, 2010.
+#' @keywords graphs
+#'
+#' @family graphical degree sequences
+#' 
+#' g <- sample_gnp(100, 2/100)
+#' is_degseq(degree(g))
+#' is_graphical(degree(g))
+#' @export
+#' @include auto.R
+
+is_degseq <- is_degseq
+
+#' Is a degree sequence graphical?
+#' 
+#' Determine whether the given vertex degrees (in- and out-degrees for
+#' directed graphs) can be reliazed in a simple graph, i.e. a graph without
+#' multiple or loop edges.
+#' 
+#' @aliases is.graphical.degree.sequence
+#' @param out.deg Integer vector, the degree sequence for undirected graphs, or
+#' the out-degree sequence for directed graphs.
+#' @param in.deg \code{NULL} or an integer vector. For undireted graphs, it
+#' should be \code{NULL}. For directed graphs it specifies the in-degrees.
+#' @return A logical scalar.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @references Hakimi SL: On the realizability of a set of integers as degrees
+#' of the vertices of a simple graph. \emph{J SIAM Appl Math} 10:496-506, 1962.
+#' 
+#' PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm to
+#' realize graphical degree sequences of directed graphs.  \emph{The Electronic
+#' Journal of Combinatorics} 17(1):R66, 2010.
+#' @keywords graphs
+#' 
+#' @family graphical degree sequences
+#'
+#' g <- sample_gnp(100, 2/100)
+#' is_degseq(degree(g))
+#' is_graphical(degree(g))
+#' @export
+#' @include auto.R
+
+is_graphical <- is_graphical
diff --git a/R/demo.R b/R/demo.R
index d5e3ce0..8c0934e 100644
--- a/R/demo.R
+++ b/R/demo.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,9 +19,36 @@
 #
 ###################################################################
 
-igraphdemo <- function(which) {
-  require(igraph)
-  require(tcltk)
+
+
+#' Run igraph demos, step by step
+#' 
+#' Run one of the accompanying igraph demos, somewhat interactively, using a Tk
+#' window.
+#' 
+#' This function provides a somewhat nicer interface to igraph demos that come
+#' with the package, than the standard \code{\link{demo}} function. Igraph
+#' demos are divided into chunks and \code{igraph_demo} runs them chunk by
+#' chunk, with the possibility of inspecting the workspace between two chunks.
+#' 
+#' The \code{tcltk} package is needed for \code{igraph_demo}.
+#'
+#' @aliases igraphdemo
+#' @param which If not given, then the names of the available demos are listed.
+#' Otherwise it should be either a filename or the name of an igraph demo.
+#' @return Returns \code{NULL}, invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{demo}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' igraph_demo()
+#' if (interactive()) {
+#'   igraph_demo("centrality")
+#' }
+#' 
+igraph_demo <- function(which) {
   
   if (missing(which)) {
     demodir <- system.file("demo", package="igraph")
@@ -45,14 +71,14 @@ igraphdemo <- function(which) {
   }
   
   .igraphdemo.next <- function(top, txt) {
-    act <- as.character(tktag.nextrange(txt, "active", "0.0"))
+    act <- as.character(tcltk::tktag.nextrange(txt, "active", "0.0"))
     if (length(act)==0) {
       return()
     }
 
     options(keep.source=TRUE)
     
-    text <- tclvalue(tkget(txt, act[1], act[2]))
+    text <- tcltk::tclvalue(tcltk::tkget(txt, act[1], act[2]))
     cat("=======================================================\n");
 
     expr <- parse(text=text)
@@ -71,19 +97,19 @@ igraphdemo <- function(which) {
     cat("> -------------------------------------------------------\n");
     cat(options()$prompt)
     
-    tktag.remove(txt, "activechunk", act[1], act[2])
-    tktag.remove(txt, "active", act[1], act[2])
+    tcltk::tktag.remove(txt, "activechunk", act[1], act[2])
+    tcltk::tktag.remove(txt, "active", act[1], act[2])
 
-    nex <- as.character(tktag.nextrange(txt, "activechunk", act[1]))
+    nex <- as.character(tcltk::tktag.nextrange(txt, "activechunk", act[1]))
     if (length(nex)!=0) {
-      tktag.add(txt, "active", nex[1], nex[2])
-      tksee(txt, paste(sep="", as.numeric(nex[2]), ".0"))
-      tksee(txt, paste(sep="", as.numeric(nex[1]), ".0"))
+      tcltk::tktag.add(txt, "active", nex[1], nex[2])
+      tcltk::tksee(txt, paste(sep="", as.numeric(nex[2]), ".0"))
+      tcltk::tksee(txt, paste(sep="", as.numeric(nex[1]), ".0"))
     }
   }
   
   .igraphdemo.close <- function(top) {
-    tkdestroy(top)
+    tcltk::tkdestroy(top)
   }
   
   .igraphdemo.reset <- function(top, txt, which) {
@@ -101,55 +127,55 @@ igraphdemo <- function(which) {
       ch <- c(ch, length(demolines)+1)
     }
     
-    tkconfigure(txt, state="normal")
-    tkdelete(txt, "0.0", "end")
-    tkinsert(txt, "insert", paste(demolines, collapse="\n"))
-    tkconfigure(txt, state="disabled")
+    tcltk::tkconfigure(txt, state="normal")
+    tcltk::tkdelete(txt, "0.0", "end")
+    tcltk::tkinsert(txt, "insert", paste(demolines, collapse="\n"))
+    tcltk::tkconfigure(txt, state="disabled")
 
     for (i in seq_along(ch[-1])) {
       from <- paste(sep="", ch[i], ".0")
       to <- paste(sep="", ch[i+1]-1, ".0")
-      tktag.add(txt, "chunk", from, to)
-      tktag.add(txt, "activechunk", from, to)
+      tcltk::tktag.add(txt, "chunk", from, to)
+      tcltk::tktag.add(txt, "activechunk", from, to)
     }
-    tktag.configure(txt, "chunk", "-borderwidth", "1")
-    tktag.configure(txt, "chunk", "-relief", "sunken")
+    tcltk::tktag.configure(txt, "chunk", "-borderwidth", "1")
+    tcltk::tktag.configure(txt, "chunk", "-relief", "sunken")
     if (length(ch) >= 2) {
-      tktag.add(txt, "active", paste(sep="", ch[1], ".0"),
+      tcltk::tktag.add(txt, "active", paste(sep="", ch[1], ".0"),
                 paste(sep="", ch[2]-1, ".0"))
-      tktag.configure(txt, "active", "-foreground", "red")
-      tktag.configure(txt, "active", "-background", "lightgrey")
+      tcltk::tktag.configure(txt, "active", "-foreground", "red")
+      tcltk::tktag.configure(txt, "active", "-background", "lightgrey")
     }
 
     comm <- grep("^#", demolines)
     for (i in comm) {
-      tktag.add(txt, "comment", paste(sep="", i, ".0"),
+      tcltk::tktag.add(txt, "comment", paste(sep="", i, ".0"),
                 paste(sep="", i, ".end"))
     }
-    tktag.configure(txt, "comment", "-font", "bold")
-    tktag.configure(txt, "comment", "-foreground", "darkolivegreen")
+    tcltk::tktag.configure(txt, "comment", "-font", "bold")
+    tcltk::tktag.configure(txt, "comment", "-foreground", "darkolivegreen")
   }
 
-  top <- tktoplevel(background="lightgrey")
-  tktitle(top) <- paste("igraph demo:", which)
+  top <- tcltk::tktoplevel(background="lightgrey")
+  tcltk::tktitle(top) <- paste("igraph demo:", which)
   
-  main.menu <- tkmenu(top)
-  tkadd(main.menu, "command", label="Close", command=function()
+  main.menu <- tcltk::tkmenu(top)
+  tcltk::tkadd(main.menu, "command", label="Close", command=function()
         .igraphdemo.close(top))
-  tkadd(main.menu, "command", label="Reset", command=function()
+  tcltk::tkadd(main.menu, "command", label="Reset", command=function()
         .igraphdemo.reset(top, txt, which))
-  tkconfigure(top, "-menu", main.menu)
+  tcltk::tkconfigure(top, "-menu", main.menu)
 
-  scr <- tkscrollbar(top, repeatinterval=5,
-                     command=function(...) tkyview(txt,...))
-  txt <- tktext(top, yscrollcommand=function(...) tkset(scr, ...),
+  scr <- tcltk::tkscrollbar(top, repeatinterval=5,
+                     command=function(...) tcltk::tkyview(txt,...))
+  txt <- tcltk::tktext(top, yscrollcommand=function(...) tcltk::tkset(scr, ...),
                 width=80, height=40)
-  but <- tkbutton(top, text="Next", command=function()
+  but <- tcltk::tkbutton(top, text="Next", command=function()
                   .igraphdemo.next(top, txt))
   
-  tkpack(but, side="bottom", fill="x", expand=0)
-  tkpack(scr, side="right", fill="y", expand=0)
-  tkpack(txt, side="left", fill="both", expand=1)
+  tcltk::tkpack(but, side="bottom", fill="x", expand=0)
+  tcltk::tkpack(scr, side="right", fill="y", expand=0)
+  tcltk::tkpack(txt, side="left", fill="both", expand=1)
 
   .igraphdemo.reset(top, txt, which)
   
diff --git a/R/embedding.R b/R/embedding.R
new file mode 100644
index 0000000..d2a75d9
--- /dev/null
+++ b/R/embedding.R
@@ -0,0 +1,347 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' Spectral Embedding of Adjacency Matrices
+#' 
+#' Spectral decomposition of the adjacency matrices of graphs.
+#' 
+#' This function computes a \code{no}-dimensional Euclidean representation of
+#' the graph based on its adjacency matrix, \eqn{A}. This representation is
+#' computed via the singular value decomposition of the adjacency matrix,
+#' \eqn{A=UDV^T}.In the case, where the graph is a random dot product graph
+#' generated using latent position vectors in \eqn{R^{no}} for each vertex, the
+#' embedding will provide an estimate of these latent vectors.
+#' 
+#' For undirected graphs the latent positions are calculated as
+#' \eqn{X=U^{no}D^{1/2}}{U[no] sqrt(D[no])}, where \eqn{U^{no}}{U[no]} equals
+#' to the first \code{no} columns of \eqn{U}, and \eqn{D^{1/2}}{sqrt(D[no])} is
+#' a diagonal matrix containing the top \code{no} singular values on the
+#' diagonal.
+#' 
+#' For directed graphs the embedding is defined as the pair
+#' \eqn{X=U^{no}D^{1/2}}{U[no] sqrt(D[no])} and \eqn{Y=V^{no}D^{1/2}}{V[no]
+#' sqrt(D[no])}. (For undirected graphs \eqn{U=V}, so it is enough to keep one
+#' of them.)
+#' 
+#' @param graph The input graph, directed or undirected.
+#' @param no An integer scalar. This value is the embedding dimension of the
+#' spectral embedding. Should be smaller than the number of vertices. The
+#' largest \code{no}-dimensional non-zero singular values are used for the
+#' spectral embedding.
+#' @param weights Optional positive weight vector for calculating weighted
+#' closeness. If the graph has a \code{weight} edge attribute, then this is
+#' used by default.
+#' @param which Which eigenvalues (or singular values, for directed graphs) to
+#' use. \sQuote{lm} means the ones with the largest magnitude, \sQuote{la} is
+#' the ones (algebraic) largest, and \sQuote{sa} is the (algebraic) smallest
+#' eigenvalues. The default is \sQuote{lm}. Note that for directed graphs
+#' \sQuote{la} and \sQuote{lm} are the equivalent, because the singular values
+#' are used for the ordering.
+#' @param scaled Logical scalar, if \code{FALSE}, then \eqn{U} and \eqn{V} are
+#' returned instead of \eqn{X} and \eqn{Y}.
+#' @param cvec A numeric vector, its length is the number vertices in the
+#' graph. This vector is added to the diagonal of the adjacency matrix.
+#' @param options A named list containing the parameters for the SVD
+#' computation algorithm in ARPACK. By default, the list of values is assigned
+#' the values given by \code{\link{igraph.arpack.default}}.
+#' @return A list containing with entries: \item{X}{Estimated latent positions,
+#' an \code{n} times \code{no} matrix, \code{n} is the number of vertices.}
+#' \item{Y}{\code{NULL} for undirected graphs, the second half of the latent
+#' positions for directed graphs, an \code{n} times \code{no} matrix, \code{n}
+#' is the number of vertices.} \item{D}{The eigenvalues (for undirected graphs)
+#' or the singular values (for directed graphs) calculated by the algorithm.}
+#' \item{options}{A named list, information about the underlying ARPACK
+#' computation. See \code{\link{arpack}} for the details.}
+#' @seealso \code{\link{sample_dot_product}}
+#' @references Sussman, D.L., Tang, M., Fishkind, D.E., Priebe, C.E.  A
+#' Consistent Adjacency Spectral Embedding for Stochastic Blockmodel Graphs,
+#' \emph{Journal of the American Statistical Association}, Vol. 107(499), 2012
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A small graph
+#' lpvs <- matrix(rnorm(200), 20, 10)
+#' lpvs <- apply(lpvs, 2, function(x) { return (abs(x)/sqrt(sum(x^2))) })
+#' RDP <- sample_dot_product(lpvs)
+#' embed <- embed_adjacency_matrix(RDP, 5)
+#' @export
+#' @include auto.R
+
+embed_adjacency_matrix <- embed_adjacency_matrix
+
+
+#' Dimensionality selection for singular values using profile likelihood.
+#' 
+#' Select the number of significant singular values, by finding the
+#' \sQuote{elbow} of the scree plot, in a principled way.
+#' 
+#' The input of the function is a numeric vector which contains the measure of
+#' \sQuote{importance} for each dimension.
+#' 
+#' For spectral embedding, these are the singular values of the adjacency
+#' matrix. The singular values are assumed to be generated from a Gaussian
+#' mixture distribution with two components that have different means and same
+#' variance. The dimensionality \eqn{d} is chosen to maximize the likelihood
+#' when the \eqn{d} largest singular values are assigned to one component of
+#' the mixture and the rest of the singular values assigned to the other
+#' component.
+#' 
+#' 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 to know their border. See
+#' examples below.
+#' 
+#' @param sv A numeric vector, the ordered singular values.
+#' @return A numeric scalar, the estimate of \eqn{d}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{embed_adjacency_matrix}}
+#' @references M. Zhu, and A. Ghodsi (2006). Automatic dimensionality selection
+#' from the scree plot via the use of profile likelihood. \emph{Computational
+#' Statistics and Data Analysis}, Vol. 51, 918--930.
+#' @keywords graphs
+#' @examples
+#' 
+#' # Generate the two groups of singular values with 
+#' # Gaussian mixture of two components that have different means
+#' sing.vals  <- c( rnorm (10, mean=1, sd=1), rnorm(10, mean=3, sd=1) )
+#' dim.chosen <- dim_select(sing.vals)
+#' dim.chosen
+#' 
+#' # Sample random vectors with multivariate normal distribution
+#' # and normalize to unit length
+#' lpvs <- matrix(rnorm(200), 10, 20)
+#' lpvs <- apply(lpvs, 2, function(x) { (abs(x) / sqrt(sum(x^2))) })
+#' RDP.graph  <- sample_dot_product(lpvs)
+#' dim_select( embed_adjacency_matrix(RDP.graph, 10)$D )
+#' 
+#' # Sample random vectors with the Dirichlet distribution
+#' lpvs.dir    <- sample_dirichlet(n=20, rep(1, 10))
+#' RDP.graph.2 <- sample_dot_product(lpvs.dir)
+#' dim_select( embed_adjacency_matrix(RDP.graph.2, 10)$D )
+#' 
+#' # Sample random vectors from hypersphere with radius 1.
+#' lpvs.sph    <- sample_sphere_surface(dim=10, n=20, radius=1)
+#' RDP.graph.3 <- sample_dot_product(lpvs.sph)
+#' dim_select( embed_adjacency_matrix(RDP.graph.3, 10)$D )
+#' 
+#' @export
+
+dim_select <- dim_select
+
+
+#' Spectral Embedding of the Laplacian of a Graph
+#' 
+#' Spectral decomposition of Laplacian matrices of graphs.
+#' 
+#' This function computes a \code{no}-dimensional Euclidean representation of
+#' the graph based on its Laplacian matrix, \eqn{L}. This representation is
+#' computed via the singular value decomposition of the Laplacian matrix.
+#' 
+#' They are essentially doing the same as \code{\link{embed_adjacency_matrix}},
+#' but work on the Laplacian matrix, instead of the adjacency matrix.
+#' 
+#' @param graph The input graph, directed or undirected.
+#' @param no An integer scalar. This value is the embedding dimension of the
+#' spectral embedding. Should be smaller than the number of vertices. The
+#' largest \code{no}-dimensional non-zero singular values are used for the
+#' spectral embedding.
+#' @param weights Optional positive weight vector for calculating weighted
+#' closeness. If the graph has a \code{weight} edge attribute, then this is
+#' used by default.
+#' @param which Which eigenvalues (or singular values, for directed graphs) to
+#' use. \sQuote{lm} means the ones with the largest magnitude, \sQuote{la} is
+#' the ones (algebraic) largest, and \sQuote{sa} is the (algebraic) smallest
+#' eigenvalues. The default is \sQuote{lm}. Note that for directed graphs
+#' \sQuote{la} and \sQuote{lm} are the equivalent, because the singular values
+#' are used for the ordering.
+#' @param degmode TODO
+#' @param type The type of the Laplacian to use. Various definitions exist for
+#' the Laplacian of a graph, and one can choose between them with this
+#' argument.
+#' 
+#' Possible values: \code{D-A} means \eqn{D-A} where \eqn{D} is the degree
+#' matrix and \eqn{A} is the adjacency matrix; \code{DAD} means
+#' \eqn{D^{1/2}}{D^1/2} times \eqn{A} times \eqn{D^{1/2}{D^1/2}},
+#' \eqn{D^{1/2}}{D^1/2} is the inverse of the square root of the degree matrix;
+#' \code{I-DAD} means \eqn{I-D^{1/2}}{I-D^1/2}, where \eqn{I} is the identity
+#' matrix.  \code{OAP} is \eqn{O^{1/2}AP^{1/2}}{O^1/2 A P^1/2}, where
+#' \eqn{O^{1/2}}{O^1/2} is the inverse of the square root of the out-degree
+#' matrix and \eqn{P^{1/2}}{P^1/2} is the same for the in-degree matrix.
+#' 
+#' \code{OAP} is not defined for undireted graphs, and is the only defined type
+#' for directed graphs.
+#' 
+#' The default (i.e. type \code{default}) is to use \code{D-A} for undirected
+#' graphs and \code{OAP} for directed graphs.
+#' @param scaled Logical scalar, if \code{FALSE}, then \eqn{U} and \eqn{V} are
+#' returned instead of \eqn{X} and \eqn{Y}.
+#' @param options A named list containing the parameters for the SVD
+#' computation algorithm in ARPACK. By default, the list of values is assigned
+#' the values given by \code{\link{igraph.arpack.default}}.
+#' @return A list containing with entries: \item{X}{Estimated latent positions,
+#' an \code{n} times \code{no} matrix, \code{n} is the number of vertices.}
+#' \item{Y}{\code{NULL} for undirected graphs, the second half of the latent
+#' positions for directed graphs, an \code{n} times \code{no} matrix, \code{n}
+#' is the number of vertices.} \item{D}{The eigenvalues (for undirected graphs)
+#' or the singular values (for directed graphs) calculated by the algorithm.}
+#' \item{options}{A named list, information about the underlying ARPACK
+#' computation. See \code{\link{arpack}} for the details.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{embed_adjacency_matrix}},
+#' \code{\link{sample_dot_product}}
+#' @references Sussman, D.L., Tang, M., Fishkind, D.E., Priebe, C.E.  A
+#' Consistent Adjacency Spectral Embedding for Stochastic Blockmodel Graphs,
+#' \emph{Journal of the American Statistical Association}, Vol. 107(499), 2012
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A small graph
+#' lpvs <- matrix(rnorm(200), 20, 10)
+#' lpvs <- apply(lpvs, 2, function(x) { return (abs(x)/sqrt(sum(x^2))) })
+#' RDP <- sample_dot_product(lpvs)
+#' embed <- embed_laplacian_matrix(RDP, 5)
+
+embed_laplacian_matrix <- embed_laplacian_matrix
+
+
+#' Sample vectors uniformly from the surface of a sphere
+#'
+#' Sample finite-dimensional vectors to use as latent position vectors in
+#' random dot product graphs
+#'
+#' \code{sample_sphere_surface} generates uniform samples from \eqn{S^{dim-1}}
+#' (the \code{(dim-1)}-sphere) with radius \code{radius}, i.e. the Euclidean
+#' norm of the samples equal \code{radius}.
+#' 
+#' @param dim Integer scalar, the dimension of the random vectors.
+#' @param n Integer scalar, the sample size.
+#' @param radius Numeric scalar, the radius of the sphere to sample.
+#' @param positive Logical scalar, whether to sample from the positive orthant
+#'   of the sphere.
+#' @return A \code{dim} (length of the \code{alpha} vector for
+#' \code{sample_dirichlet}) times \code{n} matrix, whose columns are the sample
+#' vectors.
+#'
+#' @family latent position vector samplers
+#' 
+#' @export
+#' @examples
+#' lpvs.sph    <- sample_sphere_surface(dim=10, n=20, radius=1)
+#' RDP.graph.3 <- sample_dot_product(lpvs.sph)
+#' vec.norm    <- apply(lpvs.sph, 2, function(x) { sum(x^2) })
+#' vec.norm
+
+sample_sphere_surface <- function(dim, n=1, radius=1, positive=TRUE) {
+  # Argument checks
+  dim <- as.integer(dim)
+  n <- as.integer(n)
+  radius <- as.numeric(radius)
+  positive <- as.logical(positive)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_sample_sphere_surface", dim, n, radius, positive,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' Sample vectors uniformly from the volume of a sphere
+#'
+#' Sample finite-dimensional vectors to use as latent position vectors in
+#' random dot product graphs
+#'
+#' \code{sample_sphere_volume} generates uniform samples from \eqn{S^{dim-1}}
+#' (the \code{(dim-1)}-sphere) i.e. the Euclidean norm of the samples is
+#' smaller or equal to \code{radius}.
+#' 
+#' @param dim Integer scalar, the dimension of the random vectors.
+#' @param n Integer scalar, the sample size.
+#' @param radius Numeric scalar, the radius of the sphere to sample.
+#' @param positive Logical scalar, whether to sample from the positive orthant
+#'   of the sphere.
+#' @return A \code{dim} (length of the \code{alpha} vector for
+#' \code{sample_dirichlet}) times \code{n} matrix, whose columns are the sample
+#' vectors.
+#'
+#' @family latent position vector samplers
+#' 
+#' @export
+#' @examples
+#' lpvs.sph.vol <- sample_sphere_volume(dim=10, n=20, radius=1)
+#' RDP.graph.4  <- sample_dot_product(lpvs.sph.vol)
+#' vec.norm     <- apply(lpvs.sph.vol, 2, function(x) { sum(x^2) })
+#' vec.norm
+
+sample_sphere_volume <- function(dim, n=1, radius=1, positive=TRUE) {
+  # Argument checks
+  dim <- as.integer(dim)
+  n <- as.integer(n)
+  radius <- as.numeric(radius)
+  positive <- as.logical(positive)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_sample_sphere_volume", dim, n, radius, positive,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' Sample from a Dirichlet distribution
+#'
+#' Sample finite-dimensional vectors to use as latent position vectors in
+#' random dot product graphs
+#'
+#' \code{sample_dirichlet} generates samples from the Dirichlet distribution
+#' with given \eqn{\alpha}{alpha} parameter. The sample is drawn from
+#' \code{length(alpha)-1}-simplex.
+#' 
+#' @param n Integer scalar, the sample size.
+#' @param alpha Numeric vector, the vector of \eqn{\alpha}{alpha} parameter for
+#' the Dirichlet distribution.
+#' @return A \code{dim} (length of the \code{alpha} vector for
+#' \code{sample_dirichlet}) times \code{n} matrix, whose columns are the sample
+#' vectors.
+#'
+#' @family latent position vector samplers
+#' 
+#' @export
+#' @examples
+#' lpvs.dir    <- sample_dirichlet(n=20, alpha=rep(1, 10))
+#' RDP.graph.2 <- sample_dot_product(lpvs.dir)
+#' colSums(lpvs.dir)
+
+sample_dirichlet <- function(n, alpha) {
+  # Argument checks
+  n <- as.integer(n)
+  alpha <- as.numeric(alpha)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_sample_dirichlet", n, alpha,
+        PACKAGE="igraph")
+
+  res
+}
diff --git a/R/epi.R b/R/epi.R
index 8d2e07b..9e748d5 100644
--- a/R/epi.R
+++ b/R/epi.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,9 +19,15 @@
 #
 ###################################################################
 
+#' @export
+
 time_bins <- function(x, middle=TRUE)
   UseMethod("time_bins")
 
+#' @method time_bins sir
+#' @rdname sir
+#' @export
+
 time_bins.sir <- function(x, middle=TRUE) {
   sir <- x
   if (!inherits(sir, "sir")) {
@@ -39,6 +44,11 @@ time_bins.sir <- function(x, middle=TRUE) {
   res
 }
 
+#' @importFrom stats median
+#' @method median sir
+#' @rdname sir
+#' @export
+
 median.sir <- function(x, na.rm=FALSE) {
   sir <- x
   if (!inherits(sir, "sir")) {
@@ -55,6 +65,11 @@ median.sir <- function(x, na.rm=FALSE) {
   list(NS=NS, NI=NI, NR=NR)
 }
 
+#' @importFrom stats quantile
+#' @method quantile sir
+#' @rdname sir
+#' @export
+
 quantile.sir <- function(x, comp=c("NI", "NS", "NR"), prob, ...) {
   sir <- x
   if (!inherits(sir, "sir")) {
@@ -81,6 +96,53 @@ quantile.sir <- function(x, comp=c("NI", "NS", "NR"), prob, ...) {
 # Outputs:  None.  Just produces the plot of all compartment curves, 
 #           with median and quantiles.
 
+
+
+#' Plotting the results on multiple SIR model runs
+#' 
+#' This function can conveniently plot the results of multiple SIR model
+#' simulations.
+#' 
+#' The number of susceptible/infected/recovered individuals is plotted over
+#' time, for multiple simulations.
+#' 
+#' @param x The output of the SIR simulation, coming from the \code{\link{sir}}
+#' function.
+#' @param comp Character scalar, which component to plot. Either \sQuote{NI}
+#' (infected, default), \sQuote{NS} (susceptible) or \sQuote{NR} (recovered).
+#' @param median Logical scalar, whether to plot the (binned) median.
+#' @param quantiles A vector of (binned) quantiles to plot.
+#' @param color Color of the individual simulation curves.
+#' @param median_color Color of the median curve.
+#' @param quantile_color Color(s) of the quantile curves. (It is recycled if
+#' needed and non-needed entries are ignored if too long.)
+#' @param lwd.median Line width of the median.
+#' @param lwd.quantile Line width of the quantile curves.
+#' @param lty.quantile Line type of the quantile curves.
+#' @param xlim The x limits, a two-element numeric vector. If \code{NULL}, then
+#' it is calculated from the data.
+#' @param ylim The y limits, a two-element numeric vector. If \code{NULL}, then
+#' it is calculated from the data.
+#' @param xlab The x label.
+#' @param ylab The y label. If \code{NULL} then it is automatically added based
+#' on the \code{comp} argument.
+#' @param \dots Additional arguments are passed to \code{plot}, that is run
+#' before any of the curves are added, to create the figure.
+#' @return Nothing.
+#' @author Eric Kolaczyk (\url{http://math.bu.edu/people/kolaczyk/}) and Gabor
+#' Csardi \email{csardi.gabor@@gmail.com}.
+#' @seealso \code{\link{sir}} for running the actual simulation.
+#' @references Bailey, Norman T. J. (1975). The mathematical theory of
+#' infectious diseases and its applications (2nd ed.). London: Griffin.
+#' @method plot sir
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnm(100, 100)
+#' sm <- sir(g, beta=5, gamma=1)
+#' plot(sm)
+#' 
 plot.sir <- function(x, comp=c("NI", "NS", "NR"),
                      median=TRUE, quantiles=c(0.1, 0.9), color=NULL,
                      median_color=NULL, quantile_color=NULL,
diff --git a/R/fit.R b/R/fit.R
index d3a9ffd..de2d752 100644
--- a/R/fit.R
+++ b/R/fit.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -25,7 +24,105 @@
 # this is a common degree distribution in networks
 ###################################################################
 
-power.law.fit <- function(x, xmin=NULL, start=2, force.continuous=FALSE,
+
+
+#' Fitting a power-law distribution function to discrete data
+#' 
+#' \code{fit_power_law} fits a power-law distribution to a data set.
+#' 
+#' This function fits a power-law distribution to a vector containing samples
+#' from a distribution (that is assumed to follow a power-law of course). In a
+#' power-law distribution, it is generally assumed that \eqn{P(X=x)} is
+#' proportional to \eqn{x^{-alpha}}{x^-alpha}, where \eqn{x} is a positive
+#' number and \eqn{\alpha}{alpha} is greater than 1. In many real-world cases,
+#' the power-law behaviour kicks in only above a threshold value
+#' \eqn{x_{min}}{xmin}. The goal of this function is to determine
+#' \eqn{\alpha}{alpha} if \eqn{x_{min}}{xmin} is given, or to determine
+#' \eqn{x_{min}}{xmin} and the corresponding value of \eqn{\alpha}{alpha}.
+#' 
+#' \code{fit_power_law} provides two maximum likelihood implementations.  If
+#' the \code{implementation} argument is \sQuote{\code{R.mle}}, then the BFGS
+#' optimization (see \link[stats4]{mle}) algorithm is applied.  The additional
+#' arguments are passed to the mle function, so it is possible to change the
+#' optimization method and/or its parameters.  This implementation can
+#' \emph{not} to fit the \eqn{x_{min}}{xmin} argument, so use the
+#' \sQuote{\code{plfit}} implementation if you want to do that.
+#' 
+#' The \sQuote{\code{plfit}} implementation also uses the maximum likelihood
+#' principle to determine \eqn{\alpha}{alpha} for a given \eqn{x_{min}}{xmin};
+#' When \eqn{x_{min}}{xmin} is not given in advance, the algorithm will attempt
+#' to find itsoptimal value for which the \eqn{p}-value of a Kolmogorov-Smirnov
+#' test between the fitted distribution and the original sample is the largest.
+#' The function uses the method of Clauset, Shalizi and Newman to calculate the
+#' parameters of the fitted distribution. See references below for the details.
+#'
+#' @aliases power.law.fit
+#' @param x The data to fit, a numeric vector. For implementation
+#' \sQuote{\code{R.mle}} the data must be integer values. For the
+#' \sQuote{\code{plfit}} implementation non-integer values might be present and
+#' then a continuous power-law distribution is fitted.
+#' @param xmin Numeric scalar, or \code{NULL}. The lower bound for fitting the
+#' power-law. If \code{NULL}, the smallest value in \code{x} will be used for
+#' the \sQuote{\code{R.mle}} implementation, and its value will be
+#' automatically determined for the \sQuote{\code{plfit}} implementation. This
+#' argument makes it possible to fit only the tail of the distribution.
+#' @param start Numeric scalar. The initial value of the exponent for the
+#' minimizing function, for the \sQuote{\code{R.mle}} implementation. Ususally
+#' it is safe to leave this untouched.
+#' @param force.continuous Logical scalar. Whether to force a continuous
+#' distribution for the \sQuote{\code{plfit}} implementation, even if the
+#' sample vector contains integer values only (by chance). If this argument is
+#' false, igraph will assume a continuous distribution if at least one sample
+#' is non-integer and assume a discrete distribution otherwise.
+#' @param implementation Character scalar. Which implementation to use. See
+#' details below.
+#' @param \dots Additional arguments, passed to the maximum likelihood
+#' optimizing function, \code{\link[stats4]{mle}}, if the \sQuote{\code{R.mle}}
+#' implementation is chosen. It is ignored by the \sQuote{\code{plfit}}
+#' implementation.
+#' @return Depends on the \code{implementation} argument. If it is
+#' \sQuote{\code{R.mle}}, then an object with class \sQuote{\code{mle}}. It can
+#' be used to calculate confidence intervals and log-likelihood. See
+#' \code{\link[stats4]{mle-class}} for details.
+#' 
+#' If \code{implementation} is \sQuote{\code{plfit}}, then the result is a
+#' named list with entries: \item{continuous}{Logical scalar, whether the
+#' fitted power-law distribution was continuous or discrete.}
+#' \item{alpha}{Numeric scalar, the exponent of the fitted power-law
+#' distribution.} \item{xmin}{Numeric scalar, the minimum value from which the
+#' power-law distribution was fitted. In other words, only the values larger
+#' than \code{xmin} were used from the input vector.} \item{logLik}{Numeric
+#' scalar, the log-likelihood of the fitted parameters.} \item{KS.stat}{Numeric
+#' scalar, the test statistic of a Kolmogorov-Smirnov test that compares the
+#' fitted distribution with the input vector. Smaller scores denote better
+#' fit.} \item{KS.p}{Numeric scalar, the p-value of the Kolmogorov-Smirnov
+#' test. Small p-values (less than 0.05) indicate that the test rejected the
+#' hypothesis that the original data could have been drawn from the fitted
+#' power-law distribution.}
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link[stats4]{mle}}
+#' @references Power laws, Pareto distributions and Zipf's law, M. E. J.
+#' Newman, \emph{Contemporary Physics}, 46, 323-351, 2005.
+#' 
+#' Aaron Clauset, Cosma R .Shalizi and Mark E.J. Newman: Power-law
+#' distributions in empirical data. SIAM Review 51(4):661-703, 2009.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # This should approximately yield the correct exponent 3
+#' g <- barabasi.game(1000) # increase this number to have a better estimate
+#' d <- degree(g, mode="in")
+#' fit1 <- fit_power_law(d+1, 10)
+#' fit2 <- fit_power_law(d+1, 10, implementation="R.mle")
+#' 
+#' fit1$alpha
+#' stats4::coef(fit2)
+#' fit1$logLik
+#' stats4::logLik(fit2)
+#' 
+fit_power_law <- function(x, xmin=NULL, start=2, force.continuous=FALSE,
                           implementation=c("plfit", "R.mle"), ...) {
 
   implementation <- igraph.match.arg(implementation)
@@ -47,8 +144,6 @@ power.law.fit.old <- function(x, xmin=NULL, start=2, ...) {
     stop("vector should be at least of length two")
   }  
 
-  require(stats4)
-  
   if (is.null(xmin)) { xmin <- min(x) }
   
   n <- length(x)
@@ -71,7 +166,21 @@ power.law.fit.old <- function(x, xmin=NULL, start=2, ...) {
      -n*log(C)+alpha*sum(log(x))
   }
 
-  alpha <- mle(mlogl, start=list(alpha=start), ...)
+  alpha <- stats4::mle(mlogl, start=list(alpha=start), ...)
 
   alpha
 }
+
+power.law.fit.new <- function(data, xmin=-1, force.continuous=FALSE) {
+  # Argument checks
+  data <- as.numeric(data)
+  xmin <- as.numeric(xmin)
+  force.continuous <- as.logical(force.continuous)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_power_law_fit", data, xmin, force.continuous,
+        PACKAGE="igraph")
+
+  res
+}
diff --git a/R/flow.R b/R/flow.R
index e2260cd..124394a 100644
--- a/R/flow.R
+++ b/R/flow.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,14 +19,75 @@
 #
 ###################################################################
 
-graph.mincut <- function(graph, source=NULL, target=NULL, capacity=NULL,
+#' Minimum cut in a graph
+#' 
+#' \code{min_cut} calculates the minimum st-cut between two vertices in a graph
+#' (if the \code{source} and \code{target} arguments are given) or the minimum
+#' cut of the graph (if both \code{source} and \code{target} are \code{NULL}).
+#' 
+#' The minimum st-cut between \code{source} and \code{target} is the minimum
+#' total weight of edges needed to remove to eliminate all paths from
+#' \code{source} to \code{target}.
+#' 
+#' The minimum cut of a graph is the minimum total weight of the edges needed
+#' to remove to separate the graph into (at least) two components. (Which is to
+#' make the graph \emph{not} strongly connected in the directed case.)
+#' 
+#' The maximum flow between two vertices in a graph is the same as the minimum
+#' st-cut, so \code{max_flow} and \code{min_cut} essentially calculate the same
+#' quantity, the only difference is that \code{min_cut} can be invoked without
+#' giving the \code{source} and \code{target} arguments and then minimum of all
+#' possible minimum cuts is calculated.
+#' 
+#' For undirected graphs the Stoer-Wagner algorithm (see reference below) is
+#' used to calculate the minimum cut.
+#' 
+#' @aliases graph.mincut
+#' @param graph The input graph.
+#' @param source The id of the source vertex.
+#' @param target The id of the target vertex (sometimes also called sink).
+#' @param capacity Vector giving the capacity of the edges. If this is
+#' \code{NULL} (the default) then the \code{capacity} edge attribute is used.
+#' @param value.only Logical scalar, if \code{TRUE} only the minumum cut value
+#' is returned, if \code{FALSE} the edges in the cut and a the two (or more)
+#' partitions are also returned.
+#' @return For \code{min_cut} a numeric constant, the value of the minimum
+#' cut, except if \code{value.only = FALSE}. In this case a named list with
+#' components:
+#'   \item{value}{Numeric scalar, the cut value.}
+#'   \item{cut}{Numeric vector, the edges in the cut.}
+#'   \item{partition1}{The vertices in the first partition after the cut
+#'     edges are removed. Note that these vertices might be actually in
+#'     different components (after the cut edges are removed), as the graph
+#'     may fall apart into more than two components.}
+#'   \item{partition2}{The vertices in the second partition
+#'     after the cut edges are removed. Note that these vertices might be
+#'     actually in different components (after the cut edges are removed), as
+#'     the graph may fall apart into more than two components.}
+#' @seealso \code{\link{max_flow}} for the related maximum flow
+#'   problem, \code{\link{distances}}, \code{\link{edge_connectivity}},
+#'   \code{\link{vertex_connectivity}}
+#' @references M. Stoer and F. Wagner: A simple min-cut algorithm,
+#' \emph{Journal of the ACM}, 44 585-591, 1997.
+#' @examples
+#' g <- make_ring(100)
+#' min_cut(g, capacity=rep(1,vcount(g)))
+#' min_cut(g, value.only=FALSE, capacity=rep(1,vcount(g)))
+#' 
+#' g2 <- graph( c(1,2,2,3,3,4, 1,6,6,5,5,4, 4,1) )
+#' E(g2)$capacity <- c(3,1,2, 10,1,3, 2)
+#' min_cut(g2, value.only=FALSE)
+#' @export
+#' @include auto.R
+
+min_cut <- function(graph, source=NULL, target=NULL, capacity=NULL,
                          value.only=TRUE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   if (is.null(capacity)) {
-    if ("capacity" %in% list.edge.attributes(graph)) {
+    if ("capacity" %in% edge_attr_names(graph)) {
       capacity <- E(graph)$capacity
     }
   }
@@ -51,6 +111,13 @@ graph.mincut <- function(graph, source=NULL, target=NULL, capacity=NULL,
       res$cut <- res$cut + 1
       res$partition1 <- res$partition1 + 1
       res$partition2 <- res$partition2 + 1
+
+      if (igraph_opt("return.vs.es")) {
+        res$cut <- create_es(graph, res$cut)
+        res$partition1 <- create_vs(graph, res$partition1)
+        res$partition2 <- create_vs(graph, res$partition2)
+      }
+
       res
     }
   } else {
@@ -66,9 +133,85 @@ graph.mincut <- function(graph, source=NULL, target=NULL, capacity=NULL,
   res
 }
 
-vertex.connectivity <- function(graph, source=NULL, target=NULL, checks=TRUE) {
 
-  if (!is.igraph(graph)) {
+
+#' Vertex connectivity.
+#' 
+#' The vertex connectivity of a graph or two vertices, this is recently also
+#' called group cohesion.
+#' 
+#' The vertex connectivity of two vertices (\code{source} and \code{target}) in
+#' a directed graph is the minimum number of vertices needed to remove from the
+#' graph to eliminate all (directed) paths from \code{source} to \code{target}.
+#' \code{vertex_connectivity} calculates this quantity if both the
+#' \code{source} and \code{target} arguments are given and they're not
+#' \code{NULL}.
+#' 
+#' The vertex connectivity of a graph is the minimum vertex connectivity of all
+#' (ordered) pairs of vertices in the graph. In other words this is the minimum
+#' number of vertices needed to remove to make the graph not strongly
+#' connected. (If the graph is not strongly connected then this is zero.)
+#' \code{vertex_connectivity} calculates this quantitty if neither the
+#' \code{source} nor \code{target} arguments are given. (Ie. they are both
+#' \code{NULL}.)
+#' 
+#' A set of vertex disjoint directed paths from \code{source} to \code{vertex}
+#' is a set of directed paths between them whose vertices do not contain common
+#' vertices (apart from \code{source} and \code{target}). The maximum number of
+#' vertex disjoint paths between two vertices is the same as their vertex
+#' connectivity in most cases (if the two vertices are not connected by an
+#' edge).
+#' 
+#' The cohesion of a graph (as defined by White and Harary, see references), is
+#' the vertex connectivity of the graph. This is calculated by
+#' \code{cohesion}.
+#' 
+#' These three functions essentially calculate the same measure(s), more
+#' precisely \code{vertex_connectivity} is the most general, the other two are
+#' included only for the ease of using more descriptive function names.
+#' 
+#' @aliases vertex.connectivity vertex.disjoint.paths cohesion vertex_connectivity
+#'   vertex_disjoint_paths graph.cohesion
+#' @param graph,x The input graph.
+#' @param source The id of the source vertex, for \code{vertex_connectivity} it
+#' can be \code{NULL}, see details below.
+#' @param target The id of the target vertex, for \code{vertex_connectivity} it
+#' can be \code{NULL}, see details below.
+#' @param checks Logical constant. Whether to check that the graph is connected
+#' and also the degree of the vertices. If the graph is not (strongly)
+#' connected then the connectivity is obviously zero. Otherwise if the minimum
+#' degree is one then the vertex connectivity is also one. It is a good idea to
+#' perform these checks, as they can be done quickly compared to the
+#' connectivity calculation itself.  They were suggested by Peter McMahan,
+#' thanks Peter.
+#' @param ... Ignored.
+#' @return A scalar real value.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{max_flow}}, \code{\link{edge_connectivity}},
+#' \code{\link{edge_disjoint_paths}}, \code{\link{adhesion}}
+#' @references White, Douglas R and Frank Harary 2001. The Cohesiveness of
+#' Blocks In Social Networks: Node Connectivity and Conditional Density.
+#' \emph{Sociological Methodology} 31 (1) : 305-359.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- barabasi.game(100, m=1)
+#' g <- delete_edges(g, E(g)[ 100 %--% 1 ])
+#' g2 <- barabasi.game(100, m=5)
+#' g2 <- delete_edges(g2, E(g2)[ 100 %--% 1])
+#' vertex_connectivity(g, 100, 1)
+#' vertex_connectivity(g2, 100, 1)
+#' vertex_disjoint_paths(g2, 100, 1)
+#' 
+#' g <- sample_gnp(50, 5/50)
+#' g <- as.directed(g)
+#' g <- induced_subgraph(g, subcomponent(g, 1))
+#' cohesion(g)
+#' 
+vertex_connectivity <- function(graph, source=NULL, target=NULL, checks=TRUE) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -86,9 +229,74 @@ vertex.connectivity <- function(graph, source=NULL, target=NULL, checks=TRUE) {
   }
 }
 
-edge.connectivity <- function(graph, source=NULL, target=NULL, checks=TRUE) {
 
-  if (!is.igraph(graph)) {
+
+#' Edge connectivity.
+#' 
+#' The edge connectivity of a graph or two vertices, this is recently also
+#' called group adhesion.
+#' 
+#' The edge connectivity of a pair of vertices (\code{source} and
+#' \code{target}) is the minimum number of edges needed to remove to eliminate
+#' all (directed) paths from \code{source} to \code{target}.
+#' \code{edge_connectivity} calculates this quantity if both the \code{source}
+#' and \code{target} arguments are given (and not \code{NULL}).
+#' 
+#' The edge connectivity of a graph is the minimum of the edge connectivity of
+#' every (ordered) pair of vertices in the graph.  \code{edge_connectivity}
+#' calculates this quantity if neither the \code{source} nor the \code{target}
+#' arguments are given (ie. they are both \code{NULL}).
+#' 
+#' A set of edge disjoint paths between two vertices is a set of paths between
+#' them containing no common edges. The maximum number of edge disjoint paths
+#' between two vertices is the same as their edge connectivity.
+#' 
+#' The adhesion of a graph is the minimum number of edges needed to remove to
+#' obtain a graph which is not strongly connected. This is the same as the edge
+#' connectivity of the graph.
+#' 
+#' The three functions documented on this page calculate similar properties,
+#' more precisely the most general is \code{edge_connectivity}, the others are
+#' included only for having more descriptive function names.
+#' 
+#' @aliases edge.connectivity edge_disjoint_paths graph.adhesion adhesion
+#'   edge_connectivity edge.disjoint.paths
+#' @param graph The input graph.
+#' @param source The id of the source vertex, for \code{edge_connectivity} it
+#' can be \code{NULL}, see details below.
+#' @param target The id of the target vertex, for \code{edge_connectivity} it
+#' can be \code{NULL}, see details below.
+#' @param checks Logical constant. Whether to check that the graph is connected
+#' and also the degree of the vertices. If the graph is not (strongly)
+#' connected then the connectivity is obviously zero. Otherwise if the minimum
+#' degree is one then the edge connectivity is also one. It is a good idea to
+#' perform these checks, as they can be done quickly compared to the
+#' connectivity calculation itself.  They were suggested by Peter McMahan,
+#' thanks Peter.
+#' @return A scalar real value.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{max_flow}}, \code{\link{vertex_connectivity}},
+#' \code{\link{vertex_disjoint_paths}}, \code{\link{cohesion}}
+#' @references Douglas R. White and Frank Harary: The cohesiveness of blocks in
+#' social networks: node connectivity and conditional density, TODO: citation
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- barabasi.game(100, m=1)
+#' g2 <- barabasi.game(100, m=5)
+#' edge_connectivity(g, 100, 1)
+#' edge_connectivity(g2, 100, 1)
+#' edge_disjoint_paths(g2, 100, 1)
+#' 
+#' g <- sample_gnp(50, 5/50)
+#' g <- as.directed(g)
+#' g <- induced_subgraph(g, subcomponent(g, 1))
+#' adhesion(g)
+#' 
+edge_connectivity <- function(graph, source=NULL, target=NULL, checks=TRUE) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -106,9 +314,11 @@ edge.connectivity <- function(graph, source=NULL, target=NULL, checks=TRUE) {
   }
 }
 
-edge.disjoint.paths <- function(graph, source, target) {
+#' @export
+
+edge_disjoint_paths <- function(graph, source, target) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -118,9 +328,11 @@ edge.disjoint.paths <- function(graph, source, target) {
         PACKAGE="igraph")
 }
 
-vertex.disjoint.paths <- function(graph, source=NULL, target=NULL) {
+#' @export
 
-  if (!is.igraph(graph)) {
+vertex_disjoint_paths <- function(graph, source=NULL, target=NULL) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -130,9 +342,11 @@ vertex.disjoint.paths <- function(graph, source=NULL, target=NULL) {
         PACKAGE="igraph")
 }
 
-graph.adhesion <- function(graph, checks=TRUE) {
+#' @export
+
+adhesion <- function(graph, checks=TRUE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   
@@ -141,14 +355,405 @@ graph.adhesion <- function(graph, checks=TRUE) {
         PACKAGE="igraph")
 }
 
-graph.cohesion <- function(graph, checks=TRUE) {
+#' @rdname vertex_connectivity
+#' @method cohesion igraph
+#' @export
 
-  if (!is.igraph(graph)) {
+cohesion.igraph <- function(x, checks=TRUE, ...) {
+
+  if (!is_igraph(x)) {
     stop("Not a graph object")
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_cohesion", graph, as.logical(checks),
+  .Call("R_igraph_cohesion", x, as.logical(checks),
         PACKAGE="igraph")
 }
 
+#' List all (s,t)-cuts of a graph
+#' 
+#' List all (s,t)-cuts in a directed graph.
+#' 
+#' Given a \eqn{G} directed graph and two, different and non-ajacent vertices,
+#' \eqn{s} and \eqn{t}, an \eqn{(s,t)}-cut is a set of edges, such that after
+#' removing these edges from \eqn{G} there is no directed path from \eqn{s} to
+#' \eqn{t}.
+#' 
+#' @aliases stCuts st_cuts
+#' @param graph The input graph. It must be directed.
+#' @param source The source vertex.
+#' @param target The target vertex.
+#' @return A list with entries: \item{cuts}{A list of numeric vectors
+#' containing edge ids. Each vector is an \eqn{(s,t)}-cut.}
+#' \item{partition1s}{A list of numeric vectors containing vertex ids, they
+#' correspond to the edge cuts. Each vertex set is a generator of the
+#' corresponding cut, i.e. in the graph \eqn{G=(V,E)}, the vertex set \eqn{X}
+#' and its complementer \eqn{V-X}, generates the cut that contains exactly the
+#' edges that go from \eqn{X} to \eqn{V-X}.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{st_min_cuts}} to list all minimum cuts.
+#' @references JS Provan and DR Shier: A Paradigm for listing (s,t)-cuts in
+#' graphs, \emph{Algorithmica} 15, 351--372, 1996.
+#' @keywords graphs
+#' @examples
+#' 
+#' # A very simple graph
+#' g <- graph_from_literal(a -+ b -+ c -+ d -+ e)
+#' st_cuts(g, source="a", target="e")
+#' 
+#' # A somewhat more difficult graph
+#' g2 <- graph_from_literal(s --+ a:b, a:b --+ t,
+#'                    a --+ 1:2:3, 1:2:3 --+ b)
+#' st_cuts(g2, source="s", target="t")
+#' @export
+#' @include auto.R
+
+st_cuts <- st_cuts
+
+
+#' List all minimum \eqn{(s,t)}-cuts of a graph
+#' 
+#' Listing all minimum \eqn{(s,t)}-cuts of a directed graph, for given \eqn{s}
+#' and \eqn{t}.
+#' 
+#' Given a \eqn{G} directed graph and two, different and non-ajacent vertices,
+#' \eqn{s} and \eqn{t}, an \eqn{(s,t)}-cut is a set of edges, such that after
+#' removing these edges from \eqn{G} there is no directed path from \eqn{s} to
+#' \eqn{t}.
+#' 
+#' The size of an \eqn{(s,t)}-cut is defined as the sum of the capacities (or
+#' weights) in the cut. For unweighed (=equally weighted) graphs, this is
+#' simply the number of edges.
+#' 
+#' An \eqn{(s,t)}-cut is minimum if it is of the smallest possible size.
+#' 
+#' @aliases st_min_cuts stMincuts
+#' @param graph The input graph. It must be directed.
+#' @param source The id of the source vertex.
+#' @param target The id of the target vertex.
+#' @param capacity Numeric vector giving the edge capacities. If this is
+#' \code{NULL} and the graph has a \code{weight} edge attribute, then this
+#' attribute defines the edge capacities. For forcing unit edge capacities,
+#' even for graphs that have a \code{weight} edge attribute, supply \code{NA}
+#' here.
+#' @return A list with entries: \item{value}{Numeric scalar, the size of the
+#' minimum cut(s).} \item{cuts}{A list of numeric vectors containing edge ids.
+#' Each vector is a minimum \eqn{(s,t)}-cut.} \item{partition1s}{A list of
+#' numeric vectors containing vertex ids, they correspond to the edge cuts.
+#' Each vertex set is a generator of the corresponding cut, i.e. in the graph
+#' \eqn{G=(V,E)}, the vertex set \eqn{X} and its complementer \eqn{V-X},
+#' generates the cut that contains exactly the edges that go from \eqn{X} to
+#' \eqn{V-X}.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{st_cuts}}, \code{\link{min_separators}}
+#' @references JS Provan and DR Shier: A Paradigm for listing (s,t)-cuts in
+#' graphs, \emph{Algorithmica} 15, 351--372, 1996.
+#' @keywords graphs
+#' @examples
+#' 
+#' # A difficult graph, from the Provan-Shier paper
+#' g <- graph_from_literal(s --+ a:b, a:b --+ t,
+#'                a --+ 1:2:3:4:5, 1:2:3:4:5 --+ b)
+#' st_min_cuts(g, source="s", target="t")
+#' @export
+#' @include auto.R
+
+st_min_cuts <- st_min_cuts
+
+
+#' Dominator tree
+#' 
+#' Dominator tree of a directed graph.
+#' 
+#' A flowgraph is a directed graph with a distinguished start (or root) vertex
+#' \eqn{r}, such that for any vertex \eqn{v}, there is a path from \eqn{r} to
+#' \eqn{v}. A vertex \eqn{v} dominates another vertex \eqn{w} (not equal to
+#' \eqn{v}), if every path from \eqn{r} to \eqn{w} contains \eqn{v}. Vertex
+#' \eqn{v} is the immediate dominator or \eqn{w},
+#' \eqn{v=\textrm{idom}(w)}{v=idom(w)}, if \eqn{v} dominates \eqn{w} and every
+#' other dominator of \eqn{w} dominates \eqn{v}. The edges
+#' \eqn{{(\textrm{idom}(w), w)| w \ne r}}{{(idom(w),w)| w is not r}} form a
+#' directed tree, rooted at \eqn{r}, called the dominator tree of the graph.
+#' Vertex \eqn{v} dominates vertex \eqn{w} if and only if \eqn{v} is an
+#' ancestor of \eqn{w} in the dominator tree.
+#' 
+#' This function implements the Lengauer-Tarjan algorithm to construct the
+#' dominator tree of a directed graph. For details see the reference below.
+#' 
+#' @aliases dominator.tree dominator_tree
+#' @param graph A directed graph. If it is not a flowgraph, and it contains
+#' some vertices not reachable from the root vertex, then these vertices will
+#' be collected and returned as part of the result.
+#' @param root The id of the root (or source) vertex, this will be the root of
+#' the tree.
+#' @param mode Constant, must be \sQuote{\code{in}} or \sQuote{\code{out}}. If
+#' it is \sQuote{\code{in}}, then all directions are considered as opposite to
+#' the original one in the input graph.
+#' @return A list with components: \item{dom}{ A numeric vector giving the
+#' immediate dominators for each vertex. For vertices that are unreachable from
+#' the root, it contains \code{NaN}. For the root vertex itself it contains
+#' minus one.  } \item{domtree}{ A graph object, the dominator tree. Its vertex
+#' ids are the as the vertex ids of the input graph. Isolate vertices are the
+#' ones that are unreachable from the root.  } \item{leftout}{ A numeric vector
+#' containing the vertex ids that are unreachable from the root.  }
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Thomas Lengauer, Robert Endre Tarjan: A fast algorithm for
+#' finding dominators in a flowgraph, \emph{ACM Transactions on Programming
+#' Languages and Systems (TOPLAS)} I/1, 121--141, 1979.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## The example from the paper
+#' g <- graph_from_literal(R-+A:B:C, A-+D, B-+A:D:E, C-+F:G, D-+L,
+#'                E-+H, F-+I, G-+I:J, H-+E:K, I-+K, J-+I,
+#'                K-+I:R, L-+H)
+#' dtree <- dominator_tree(g, root="R")
+#' layout <- layout_as_tree(dtree$domtree, root="R")
+#' layout[,2] <- -layout[,2]
+#' plot(dtree$domtree, layout=layout, vertex.label=V(dtree$domtree)$name)
+#' @export
+
+dominator_tree <- dominator_tree
+
+
+#' Minimum size vertex separators
+#' 
+#' List all vertex sets that are minimal (s,t) separators for some s and t, in
+#' an undirected graph.
+#' 
+#' A \eqn{(s,t)} vertex separator is a set of vertices, such that after their
+#' removal from the graph, there is no path between \eqn{s} and \eqn{t} in the
+#' graph.
+#' 
+#' A \eqn{(s,t)} vertex separator is minimal if none of its subsets is an
+#' \eqn{(s,t)} vertex separator.
+#' 
+#' @aliases minimal.st.separators min_st_separators
+#' @param graph The input graph. It may be directed, but edge directions are
+#' ignored.
+#' @return A list of numeric vectors. Each vector contains a vertex set
+#' (defined by vertex ids), each vector is an (s,t) separator of the input
+#' graph, for some \eqn{s} and \eqn{t}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Anne Berry, Jean-Paul Bordat and Olivier Cogis: Generating All
+#' the Minimal Separators of a Graph, In: Peter Widmayer, Gabriele Neyer and
+#' Stephan Eidenbenz (editors): \emph{Graph-theoretic concepts in computer
+#' science}, 1665, 167--172, 1999. Springer.
+#' @keywords graphs
+#' @examples
+#' 
+#' ring <- make_ring(4)
+#' min_st_separators(ring)
+#' 
+#' chvatal <- make_graph("chvatal")
+#' min_st_separators(chvatal)
+
+min_st_separators <- min_st_separators
+
+
+#' Maximum flow in a graph
+#' 
+#' In a graph where each edge has a given flow capacity the maximal flow
+#' between two vertices is calculated.
+#' 
+#' \code{max_flow} calculates the maximum flow between two vertices in a
+#' weighted (ie. valued) graph. A flow from \code{source} to \code{target} is
+#' an assignment of non-negative real numbers to the edges of the graph,
+#' satisfying two properties: (1) for each edge the flow (ie. the assigned
+#' number) is not more than the capacity of the edge (the \code{capacity}
+#' parameter or edge attribute), (2) for every vertex, except the source and
+#' the target the incoming flow is the same as the outgoing flow. The value of
+#' the flow is the incoming flow of the \code{target} vertex. The maximum flow
+#' is the flow of maximum value.
+#' 
+#' @aliases graph.maxflow
+#' @param graph The input graph.
+#' @param source The id of the source vertex.
+#' @param target The id of the target vertex (sometimes also called sink).
+#' @param capacity Vector giving the capacity of the edges. If this is
+#' \code{NULL} (the default) then the \code{capacity} edge attribute is used.
+#' @return A named list with components:
+#'   \item{value}{A numeric scalar, the value of the maximum flow.}
+#'   \item{flow}{A numeric vector, the flow itself, one entry for each
+#'     edge. For undirected graphs this entry is bit trickier, since for
+#'     these the flow direction is not predetermined by the edge
+#'     direction. For these graphs the elements of the this vector can be
+#'     negative, this means that the flow goes from the bigger vertex id to
+#'     the smaller one. Positive values mean that the flow goes from 
+#'     the smaller vertex id to the bigger one.}
+#'   \item{cut}{A numeric vector of edge ids, the minimum cut corresponding
+#'     to the maximum flow.} 
+#'   \item{partition1}{A numeric vector of vertex ids, the vertices in the
+#'     first partition of the minimum cut corresponding to the maximum
+#'     flow.} 
+#'   \item{partition2}{A numeric vector of vertex ids, the vertices in the
+#'     second partition of the minimum cut corresponding to the maximum
+#'     flow.}
+#'   \item{stats}{A list with some statistics from the push-relabel
+#'     algorithm. Five integer values currently: \code{nopush} is the
+#'     number of push operations, \code{norelabel} the number of
+#'     relabelings, \code{nogap} is the number of times the gap heuristics
+#'     was used, \code{nogapnodes} is the total number of gap nodes omitted
+#'     because of the gap heuristics and \code{nobfs} is the number of
+#'     times a global breadth-first-search update was performed to assign
+#'     better height (=distance) values to the vertices.}
+#' @seealso \code{\link{min_cut}} for minimum cut calculations,
+#'   \code{\link{distances}}, \code{\link{edge_connectivity}},
+#'   \code{\link{vertex_connectivity}}
+#' @references A. V. Goldberg and R. E. Tarjan: A New Approach to the Maximum
+#' Flow Problem \emph{Journal of the ACM} 35:921-940, 1988.
+#' @examples
+#' 
+#' E <- rbind( c(1,3,3), c(3,4,1), c(4,2,2), c(1,5,1), c(5,6,2), c(6,2,10))
+#' colnames(E) <- c("from", "to", "capacity")
+#' g1 <- graph_from_data_frame(as.data.frame(E))
+#' max_flow(g1, source=V(g1)["1"], target=V(g1)["2"])
+#' @export
+#' @include auto.R
+
+max_flow <- max_flow
+
+
+#' Vertex separators
+#' 
+#' Check whether a given set of vertices is a vertex separator.
+#' 
+#' \code{is_separator} decides whether the supplied vertex set is a vertex
+#' separator. A vertex set is a vertex separator if its removal results a
+#' disconnected graph.
+#' 
+#' In the special case of a fully connected graph with \eqn{n} vertices, each
+#' set of \eqn{n-1} vertices is considered to be a vertex separator.
+#' 
+#' @aliases is.separator
+#' @param graph The input graph. It may be directed, but edge directions are
+#'   ignored.
+#' @param candidate A numeric vector giving the vertex ids of the candidate
+#'   separator.
+#' @return A logical scalar, whether the supplied vertex set is a (minimal)
+#'   vertex separator or not.
+#' @seealso \code{\link{is_min_separator}}, \code{\link{min_separators}}
+#'   lists all vertex separator of minimum size.
+#' @export
+
+is_separator <- is_separator
+
+
+#' Minumal vertex separators
+#' 
+#' Check whether a given set of vertices is a minimal vertex separator.
+#' 
+#' \code{is_min_separator} decides whether the supplied vertex set is a minimal
+#' vertex separator. A minimal vertex separator is a vertex separator, such
+#' that none of its subsets is a vertex separator.
+#' 
+#' In the special case of a fully connected graph with \eqn{n} vertices, each
+#' set of \eqn{n-1} vertices is considered to be a vertex separator.
+#' 
+#' @aliases is.minimal.separator
+#' @param graph The input graph. It may be directed, but edge directions are
+#' ignored.
+#' @param candidate A numeric vector giving the vertex ids of the candidate
+#' separator.
+#' @return A logical scalar, whether the supplied vertex set is a (minimal)
+#' vertex separator or not.
+#' @seealso \code{\link{min_separators}} lists all vertex separator of minimum
+#' size.
+#' @examples
+#' # The graph from the Moody-White paper
+#' mw <- graph_from_literal(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
+#'                 5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
+#'                 10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
+#'                 17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
+#'                 21-22:23, 22-23)
+#' 
+#' # Cohesive subgraphs
+#' mw1 <- induced_subgraph(mw, as.character(c(1:7, 17:23)))
+#' mw2 <- induced_subgraph(mw, as.character(7:16))
+#' mw3 <- induced_subgraph(mw, as.character(17:23))
+#' mw4 <- induced_subgraph(mw, as.character(c(7,8,11,14)))
+#' mw5 <- induced_subgraph(mw, as.character(1:7))
+#' 
+#' check.sep <- function(G) {
+#'   sep <- min_separators(G)
+#'   sapply(sep, is_min_separator, graph=G)
+#' }
+#' 
+#' check.sep(mw)
+#' check.sep(mw1)
+#' check.sep(mw2)
+#' check.sep(mw3)
+#' check.sep(mw4)
+#' check.sep(mw5)
+#'
+#' @export
+
+is_min_separator <- is_min_separator
+
+
+#' Minimum size vertex separators
+#' 
+#' Find all vertex sets of minimal size whose removal separates the graph into
+#' more components
+#' 
+#' This function implements the Kanevsky algorithm for finding all minimal-size
+#' vertex separators in an undirected graph. See the reference below for the
+#' details.
+#' 
+#' In the special case of a fully connected input graph with \eqn{n} vertices,
+#' all subsets of size \eqn{n-1} are listed as the result.
+#'
+#' @aliases minimum.size.separators
+#' @param graph The input graph. It may be directed, but edge directions are
+#' ignored.
+#' @return A list of numeric vectors. Each numeric vector is a vertex
+#' separator.
+#' @seealso \code{\link{is.separator}}
+#' @references Arkady Kanevsky: Finding all minimum-size separating vertex sets
+#' in a graph. \emph{Networks} 23 533--541, 1993.
+#' 
+#' JS Provan and DR Shier: A Paradigm for listing (s,t)-cuts in graphs,
+#' \emph{Algorithmica} 15, 351--372, 1996.
+#' 
+#' J. Moody and D. R. White. Structural cohesion and embeddedness: A
+#' hierarchical concept of social groups. \emph{American Sociological Review},
+#' 68 103--127, Feb 2003.
+#' @export
+#' @examples
+#' # The graph from the Moody-White paper
+#' mw <- graph.formula(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
+#'                     5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
+#'                     10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
+#'                     17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
+#'                     21-22:23, 22-23)
+#' 
+#' # Cohesive subgraphs
+#' mw1 <- induced.subgraph(mw, as.character(c(1:7, 17:23)))
+#' mw2 <- induced.subgraph(mw, as.character(7:16))
+#' mw3 <- induced.subgraph(mw, as.character(17:23))
+#' mw4 <- induced.subgraph(mw, as.character(c(7,8,11,14)))
+#' mw5 <- induced.subgraph(mw, as.character(1:7))
+#' 
+#' min_separators(mw)
+#' min_separators(mw1)
+#' min_separators(mw2)
+#' min_separators(mw3)
+#' min_separators(mw4)
+#' min_separators(mw5)
+#' 
+#' # Another example, the science camp network
+#' camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
+#'                       Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
+#'                       Holly   - Carol:Pat:Pam:Jennie:Bill,
+#'                       Bill    - Pauline:Michael:Lee:Holly,
+#'                       Pauline - Bill:Jennie:Ann,
+#'                       Jennie  - Holly:Michael:Lee:Ann:Pauline,
+#'                       Michael - Bill:Jennie:Ann:Lee:John,
+#'                       Ann     - Michael:Jennie:Pauline,
+#'                       Lee     - Michael:Bill:Jennie,
+#'                       Gery    - Pat:Steve:Russ:John,
+#'                       Russ    - Steve:Bert:Gery:John,
+#'                       John    - Gery:Russ:Michael)
+#' min_separators(camp)
+
+min_separators <- min_separators
diff --git a/R/foreign.R b/R/foreign.R
index a3d64c7..65871aa 100644
--- a/R/foreign.R
+++ b/R/foreign.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -66,7 +65,43 @@ write.graph.fromraw <- function(buffer, file) {
   invisible(NULL)
 }
 
-read.graph <- function(file, format=c("edgelist", "pajek", "ncol", "lgl",
+
+
+#' Reading foreign file formats
+#' 
+#' The \code{read_graph} function is able to read graphs in various
+#' representations from a file, or from a http connection. Currently some
+#' simple formats are supported.
+#' 
+#' The \code{read_graph} function may have additional arguments depending on
+#' the file format (the \code{format} argument). See the details separately for
+#' each file format, below.
+#' 
+#' @aliases read.graph LGL Pajek GraphML GML DL UCINET
+#' @param file The connection to read from. This can be a local file, or a
+#' \code{http} or \code{ftp} connection. It can also be a character string with
+#' the file name or URI.
+#' @param format Character constant giving the file format. Right now
+#' \code{as_edgelist}, \code{pajek}, \code{graphml}, \code{gml}, \code{ncol},
+#' \code{lgl}, \code{dimacs} and \code{graphdb} are supported, the default is
+#' \code{edgelist}. As of igraph 0.4 this argument is case insensitive.
+#' @param \dots Additional arguments, see below.
+#' @return A graph object.
+#' @section Edge list format: This format is a simple text file with numeric
+#' vertex ids defining the edges. There is no need to have newline characters
+#' between the edges, a simple space will also do.
+#' 
+#' Additional arguments: \describe{ \item{n}{The number of vertices in the
+#' graph. If it is smaller than or equal to the largest integer in the file,
+#' then it is ignored; so it is safe to set it to zero (the default).}
+#' \item{directed}{Logical scalar, whether to create a directed graph. The
+#' default value is \code{TRUE}.} }
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{write_graph}}
+#' @keywords graphs
+#' @export
+
+read_graph <- function(file, format=c("edgelist", "pajek", "ncol", "lgl",
                                "graphml", "dimacs", "graphdb", "gml", "dl"),
                        ...) {
 
@@ -93,10 +128,43 @@ read.graph <- function(file, format=c("edgelist", "pajek", "ncol", "lgl",
   res
 }
 
-write.graph <- function(graph, file, format=c("edgelist", "pajek", "ncol", "lgl",
+
+
+#' Writing the graph to a file in some format
+#' 
+#' \code{write_graph} is a general function for exporting graphs to foreign
+#' file formats, however not many formats are implemented right now.
+#' 
+#' @aliases write.graph
+#' @param graph The graph to export.
+#' @param file A connection or a string giving the file name to write the graph
+#' to.
+#' @param format Character string giving the file format. Right now
+#' \code{pajek}, \code{graphml}, \code{dot}, \code{gml}, \code{edgelist},
+#' \code{lgl}, \code{ncol} and \code{dimacs} are implemented. As of igraph 0.4
+#' this argument is case insensitive.
+#' @param \dots Other, format specific arguments, see below.
+#' @return A NULL, invisibly.
+#' @section Edge list format: The \code{edgelist} format is a simple text file,
+#' with one edge in a line, the two vertex ids separated by a space character.
+#' The file is sorted by the first and the second column. This format has no
+#' additional arguments.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{read_graph}}
+#' @references Adai AT, Date SV, Wieland S, Marcotte EM. LGL: creating a map of
+#' protein function with an algorithm for visualizing very large biological
+#' networks. \emph{J Mol Biol.} 2004 Jun 25;340(1):179-90.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' \dontrun{write_graph(g, "/tmp/g.txt", "edgelist")}
+#' 
+write_graph <- function(graph, file, format=c("edgelist", "pajek", "ncol", "lgl",
                                        "graphml", "dimacs", "gml", "dot", "leda"), ...) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   if (!is.character(file) || length(grep("://", file, fixed=TRUE)) > 0 ||
@@ -138,7 +206,7 @@ read.graph.edgelist <- function(file, n=0,
                                 directed=TRUE, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (edgelist format)")
+    stop("Unknown arguments to read_graph (edgelist format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_read_graph_edgelist", file,
@@ -149,7 +217,7 @@ read.graph.edgelist <- function(file, n=0,
 write.graph.edgelist <- function(graph, file, ...) {
   
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (edgelist format)")
+    stop("Unknown arguments to write_graph (edgelist format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_write_graph_edgelist", graph, file,
@@ -165,7 +233,7 @@ read.graph.ncol <- function(file, predef=character(0), names=TRUE,
                             directed=FALSE, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (NCOL format)")
+    stop("Unknown arguments to read_graph (NCOL format)")
   }
   weights <- switch(igraph.match.arg(weights), "no"=0, "yes"=1, "auto"=2)
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -177,12 +245,12 @@ read.graph.ncol <- function(file, predef=character(0), names=TRUE,
 write.graph.ncol <- function(graph, file, 
                              names="name", weights="weight", ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (NCOL format)")
+    stop("Unknown arguments to write_graph (NCOL format)")
   }
   names <- as.character(names)
   weights <- as.character(weights)
-  if (length(names)==0 || ! names %in% list.vertex.attributes(graph)) { names <- NULL }
-  if (length(weights)==0 || ! weights %in% list.edge.attributes(graph)) { weights <- NULL }
+  if (length(names)==0 || ! names %in% vertex_attr_names(graph)) { names <- NULL }
+  if (length(weights)==0 || ! weights %in% edge_attr_names(graph)) { weights <- NULL }
   
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_write_graph_ncol", graph, file,
@@ -196,7 +264,7 @@ read.graph.lgl <- function(file, names=TRUE,
                             ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (LGL format)")
+    stop("Unknown arguments to read_graph (LGL format)")
   }
   weights <- switch(igraph.match.arg(weights), "no"=0, "yes"=1, "auto"=2)
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -209,12 +277,12 @@ write.graph.lgl <- function(graph, file,
                             names="name", weights="weight",
                             isolates=FALSE, ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (LGL format)")
+    stop("Unknown arguments to write_graph (LGL format)")
   }
   names <- as.character(names)
   weights <- as.character(weights)
-  if (length(names)==0 || ! names %in% list.vertex.attributes(graph)) { names <- NULL }
-  if (length(weights)==0 || ! weights %in% list.edge.attributes(graph)) { weights <- NULL }
+  if (length(names)==0 || ! names %in% vertex_attr_names(graph)) { names <- NULL }
+  if (length(weights)==0 || ! weights %in% edge_attr_names(graph)) { weights <- NULL }
   
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_write_graph_lgl", graph, file,
@@ -225,15 +293,15 @@ write.graph.lgl <- function(graph, file,
 read.graph.pajek <- function(file, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (Pajek format)")
+    stop("Unknown arguments to read_graph (Pajek format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_read_graph_pajek", file,
                PACKAGE="igraph")
-  if ("type" %in% list.vertex.attributes(res)) {
+  if ("type" %in% vertex_attr_names(res)) {
     type <- as.logical(V(res)$type)
-    res <- remove.vertex.attribute(res, "type")
-    res <- set.vertex.attribute(res, "type", value=type)
+    res <- delete_vertex_attr(res, "type")
+    res <- set_vertex_attr(res, "type", value=type)
   }
   res
 }
@@ -241,7 +309,7 @@ read.graph.pajek <- function(file, ...) {
 write.graph.pajek <- function(graph, file, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (Pajek format)")
+    stop("Unknown arguments to write_graph (Pajek format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_write_graph_pajek", graph, file,
@@ -251,20 +319,20 @@ write.graph.pajek <- function(graph, file, ...) {
 read.graph.dimacs <- function(file, directed=TRUE, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (DIMACS format)")
+    stop("Unknown arguments to read_graph (DIMACS format)")
   }
   res <- .Call("R_igraph_read_graph_dimacs", file, as.logical(directed),
                PACKAGE="igraph")
   if (res[[1]][1] == "max") {
     graph <- res[[2]]
-    graph <- set.graph.attribute(graph, "problem", res[[1]])
-    graph <- set.graph.attribute(graph, "source", res[[3]])
-    graph <- set.graph.attribute(graph, "target", res[[4]])
+    graph <- set_graph_attr(graph, "problem", res[[1]])
+    graph <- set_graph_attr(graph, "source", res[[3]])
+    graph <- set_graph_attr(graph, "target", res[[4]])
     E(graph)$capacity <- res[[5]]
     graph
   } else if (res[[1]][1] == "edge") {
     graph <- res[[2]]
-    graph <- set.graph.attribute(graph, "problem", res[[1]])
+    graph <- set_graph_attr(graph, "problem", res[[1]])
     V(graph)$label <- res[[3]]
     graph
   }
@@ -274,13 +342,13 @@ write.graph.dimacs <- function(graph, file,
                                source=NULL, target=NULL, capacity=NULL, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (DIMACS format)")
+    stop("Unknown arguments to write_graph (DIMACS format)")
   }
   if (is.null(source)) {
-    source <- get.graph.attribute(graph, "source")
+    source <- graph_attr(graph, "source")
   }
   if (is.null(target)) {
-    target <- get.graph.attribute(graph, "target")
+    target <- graph_attr(graph, "target")
   }
   if (is.null(capacity)) {
     capacity <- E(graph)$capacity
@@ -299,7 +367,7 @@ write.graph.dimacs <- function(graph, file,
 read.graph.graphml <- function(file, index=0, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (GraphML format)")
+    stop("Unknown arguments to read_graph (GraphML format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_read_graph_graphml", file, as.numeric(index),
@@ -309,7 +377,7 @@ read.graph.graphml <- function(file, index=0, ...) {
 write.graph.graphml <- function(graph, file, prefixAttr=TRUE, ...) {
 
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (GraphML format)")
+    stop("Unknown arguments to write_graph (GraphML format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_write_graph_graphml", graph, file, as.logical(prefixAttr),
@@ -322,7 +390,7 @@ write.graph.graphml <- function(graph, file, prefixAttr=TRUE, ...) {
 
 read.graph.gml <- function(file, ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (GML format)")
+    stop("Unknown arguments to read_graph (GML format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_read_graph_gml", file,
@@ -331,7 +399,7 @@ read.graph.gml <- function(file, ...) {
 
 write.graph.gml <- function(graph, file, id=NULL, creator=NULL, ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (GML format)")
+    stop("Unknown arguments to write_graph (GML format)")
   }
   if (!is.null(id)) {
     id <- as.numeric(id)
@@ -350,7 +418,7 @@ write.graph.gml <- function(graph, file, id=NULL, creator=NULL, ...) {
 
 read.graph.dl <- function(file, directed=TRUE, ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (DL format)")
+    stop("Unknown arguments to read_graph (DL format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_read_graph_dl", file, as.logical(directed),
@@ -363,7 +431,7 @@ read.graph.dl <- function(file, directed=TRUE, ...) {
 
 write.graph.dot <- function(graph, file, ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (DOT format)")
+    stop("Unknown arguments to write_graph (DOT format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_write_graph_dot", graph, file,
@@ -375,7 +443,73 @@ write.graph.dot <- function(graph, file, ...) {
 # isomorphic problems
 ################################################################
 
-graph.graphdb <- function(url=NULL,
+
+
+#' Load a graph from the graph database for testing graph isomorphism.
+#' 
+#' This function downloads a graph from a database created for the evaluation
+#' of graph isomorphism testing algothitms.
+#' 
+#' \code{graph_from_graphdb} reads a graph from the graph database from an FTP or
+#' HTTP server or from a local copy. It has two modes of operation:
+#' 
+#' If the \code{url} argument is specified then it should the complete path to
+#' a local or remote graph database file. In this case we simply call
+#' \code{\link{read_graph}} with the proper arguments to read the file.
+#' 
+#' If \code{url} is \code{NULL}, and this is the default, then the filename is
+#' assembled from the \code{base}, \code{prefix}, \code{type}, \code{nodes},
+#' \code{pair} and \code{which} arguments.
+#' 
+#' Unfortunately the original graph database homepage is now defunct, but see
+#' its old version at
+#' \url{http://web.archive.org/web/20090215182331/http://amalfi.dis.unina.it/graph/db/doc/graphdbat.html}
+#' for the actual format of a graph database file and other information.
+#'
+#' @aliases graph.graphdb
+#' @param url If not \code{NULL} it is a complete URL with the file to import.
+#' @param prefix Gives the prefix. See details below. Possible values:
+#' \code{iso}, \code{i2}, \code{si4}, \code{si6}, \code{mcs10}, \code{mcs30},
+#' \code{mcs50}, \code{mcs70}, \code{mcs90}.
+#' @param type Gives the graph type identifier. See details below. Possible
+#' values: \code{r001}, \code{r005}, \code{r01}, \code{r02}, \code{m2D},
+#' \code{m2Dr2}, \code{m2Dr4}, \code{m2Dr6} \code{m3D}, \code{m3Dr2},
+#' \code{m3Dr4}, \code{m3Dr6}, \code{m4D}, \code{m4Dr2}, \code{m4Dr4},
+#' \code{m4Dr6}, \code{b03}, \code{b03m}, \code{b06}, \code{b06m}, \code{b09},
+#' \code{b09m}.
+#' @param nodes The number of vertices in the graph.
+#' @param pair Specifies which graph of the pair to read. Possible values:
+#' \code{A} and \code{B}.
+#' @param which Gives the number of the graph to read. For every graph type
+#' there are a number of actual graphs in the database. This argument specifies
+#' which one to read.
+#' @param base The base address of the database. See details below.
+#' @param compressed Logical constant, if TRUE than the file is expected to be
+#' compressed by gzip. If \code{url} is \code{NULL} then a \sQuote{\code{.gz}}
+#' suffix is added to the filename.
+#' @param directed Logical constant, whether to create a directed graph.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{read_graph}}, \code{\link{graph.isomorphic.vf2}}
+#' @references M. De Santo, P. Foggia, C. Sansone, M. Vento: A large database
+#' of graphs and its use for benchmarking graph isomorphism algorithms,
+#' \emph{Pattern Recognition Letters}, Volume 24, Issue 8 (May 2003)
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' \dontrun{
+#' g <- graph_from_graphdb(prefix="iso", type="r001", nodes=20, pair="A",
+#'   which=10, compressed=TRUE)
+#' g2 <- graph_from_graphdb(prefix="iso", type="r001", nodes=20, pair="B",
+#'   which=10, compressed=TRUE)
+#' graph.isomorphic.vf2(g, g2)	% should be TRUE
+#' g3 <- graph_from_graphdb(url=paste(sep="/",
+#'                               "http://cneurocvs.rmki.kfki.hu",
+#'                               "graphdb/gzip/iso/bvg/b06m",
+#'                               "iso_b06m_m200.A09.gz"))
+#' }
+graph_from_graphdb <- function(url=NULL,
                           prefix="iso", type="r001", nodes=NULL, pair="A", which=0,
                           base="http://cneurocvs.rmki.kfki.hu/graphdb/gzip",
                           compressed=TRUE, directed=TRUE) {
@@ -430,7 +564,7 @@ graph.graphdb <- function(url=NULL,
 
 read.graph.graphdb <- function(file, directed=TRUE, ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to read.graph (GraphDB format)")
+    stop("Unknown arguments to read_graph (GraphDB format)")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_read_graph_graphdb", file, as.logical(directed),
@@ -440,7 +574,7 @@ read.graph.graphdb <- function(file, directed=TRUE, ...) {
 write.graph.leda <- function(graph, file, vertex.attr=NULL, edge.attr=NULL,
                              ...) {
   if (length(list(...))>0) {
-    stop("Unknown arguments to write.graph (LEDA format)")
+    stop("Unknown arguments to write_graph (LEDA format)")
   }
   if (!is.null(vertex.attr)) { vertex.attr <- as.character(vertex.attr) }
   if (!is.null(edge.attr))   { edge.attr   <- as.character(edge.attr)   }
diff --git a/R/games.R b/R/games.R
index 2b7247f..cbb4f7d 100644
--- a/R/games.R
+++ b/R/games.R
@@ -1,32 +1,122 @@
 
-#   IGraph R package
-#   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
-#   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
-#
-###################################################################
-
-ba.game <- function(n, power=1, m=NULL, out.dist=NULL, out.seq=NULL,
+## -----------------------------------------------------------------
+##   IGraph R package
+##   Copyright (C) 2005-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------
+
+#' Generate scale-free graphs according to the Barabasi-Albert model
+#' 
+#' The BA-model is a very simple stochastic algorithm for building a graph.
+#' 
+#' This is a simple stochastic algorithm to generate a graph. It is a discrete
+#' time step model and in each time step a single vertex is added.
+#' 
+#' We start with a single vertex and no edges in the first time step. Then we
+#' add one vertex in each time step and the new vertex initiates some edges to
+#' old vertices. The probability that an old vertex is chosen is given by
+#' \deqn{P[i] \sim k_i^\alpha+a}{P[i] ~ k[i]^alpha + a} where \eqn{k_i}{k[i]}
+#' is the in-degree of vertex \eqn{i} in the current time step (more precisely
+#' the number of adjacent edges of \eqn{i} which were not initiated by \eqn{i}
+#' itself) and \eqn{\alpha}{alpha} and \eqn{a} are parameters given by the
+#' \code{power} and \code{zero.appeal} arguments.
+#' 
+#' The number of edges initiated in a time step is given by the \code{m},
+#' \code{out.dist} and \code{out.seq} arguments. If \code{out.seq} is given and
+#' not NULL then it gives the number of edges to add in a vector, the first
+#' element is ignored, the second is the number of edges to add in the second
+#' time step and so on. If \code{out.seq} is not given or null and
+#' \code{out.dist} is given and not NULL then it is used as a discrete
+#' distribution to generate the number of edges in each time step. Its first
+#' element is the probability that no edges will be added, the second is the
+#' probability that one edge is added, etc. (\code{out.dist} does not need to
+#' sum up to one, it normalized automatically.) \code{out.dist} should contain
+#' non-negative numbers and at east one element should be positive.
+#' 
+#' If both \code{out.seq} and \code{out.dist} are omitted or NULL then \code{m}
+#' will be used, it should be a positive integer constant and \code{m} edges
+#' will be added in each time step.
+#' 
+#' \code{sample_pa} generates a directed graph by default, set
+#' \code{directed} to \code{FALSE} to generate an undirected graph. Note that
+#' even if an undirected graph is generated \eqn{k_i}{k[i]} denotes the number
+#' of adjacent edges not initiated by the vertex itself and not the total (in-
+#' + out-) degree of the vertex, unless the \code{out.pref} argument is set to
+#' \code{TRUE}.
+#' 
+#' @aliases sample_pa barabasi.game ba.game
+#' @param n Number of vertices.
+#' @param power The power of the preferential attachment, the default is one,
+#' ie. linear preferential attachment.
+#' @param m Numeric constant, the number of edges to add in each time step This
+#' argument is only used if both \code{out.dist} and \code{out.seq} are omitted
+#' or NULL.
+#' @param out.dist Numeric vector, the distribution of the number of edges to
+#' add in each time step. This argument is only used if the \code{out.seq}
+#' argument is omitted or NULL.
+#' @param out.seq Numeric vector giving the number of edges to add in each time
+#' step. Its first element is ignored as no edges are added in the first time
+#' step.
+#' @param out.pref Logical, if true the total degree is used for calculating
+#' the citation probability, otherwise the in-degree is used.
+#' @param zero.appeal The \sQuote{attractiveness} of the vertices with no
+#' adjacent edges. See details below.
+#' @param directed Whether to create a directed graph.
+#' @param algorithm The algorithm to use for the graph generation.
+#' \code{psumtree} uses a partial prefix-sum tree to generate the graph, this
+#' algorithm can handle any \code{power} and \code{zero.appeal} values and
+#' never generates multiple edges.  \code{psumtree-multiple} also uses a
+#' partial prefix-sum tree, but the generation of multiple edges is allowed.
+#' Before the 0.6 version igraph used this algorithm if \code{power} was not
+#' one, or \code{zero.appeal} was not one.  \code{bag} is the algorithm that
+#' was previously (before version 0.6) used if \code{power} was one and
+#' \code{zero.appeal} was one as well. It works by putting the ids of the
+#' vertices into a bag (mutliset, really), exactly as many times as their
+#' (in-)degree, plus once more. Then the required number of cited vertices are
+#' drawn from the bag, with replacement. This method might generate multiple
+#' edges. It only works if \code{power} and \code{zero.appeal} are equal one.
+#' @param start.graph \code{NULL} or an igraph graph. If a graph, then the
+#' supplied graph is used as a starting graph for the preferential attachment
+#' algorithm. The graph should have at least one vertex. If a graph is supplied
+#' here and the \code{out.seq} argument is not \code{NULL}, then it should
+#' contain the out degrees of the new vertices only, not the ones in the
+#' \code{start.graph}.
+#' @return A graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_gnp}}
+#' @references Barabasi, A.-L. and Albert R. 1999. Emergence of scaling in
+#' random networks \emph{Science}, 286 509--512.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_pa(10000)
+#' degree_distribution(g)
+#' 
+
+sample_pa <- function(n, power=1, m=NULL, out.dist=NULL, out.seq=NULL,
                     out.pref=FALSE, zero.appeal=1,
                     directed=TRUE, algorithm=c("psumtree",
                                      "psumtree-multiple", "bag"),
                     start.graph=NULL) {
 
-  if (!is.null(start.graph) && !is.igraph(start.graph)) {
+  if (!is.null(start.graph) && !is_igraph(start.graph)) {
     stop("`start.graph' not an `igraph' object")
   }
   
@@ -77,7 +167,7 @@ ba.game <- function(n, power=1, m=NULL, out.dist=NULL, out.seq=NULL,
                zero.appeal, directed, algorithm1, start.graph,
                PACKAGE="igraph")
   
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Barabasi graph"
     res$power <- power
     res$m <- m
@@ -88,11 +178,173 @@ ba.game <- function(n, power=1, m=NULL, out.dist=NULL, out.seq=NULL,
   res
 }
 
-barabasi.game <- ba.game
+#' @rdname sample_pa
+#' @param ... Passed to \code{sample_pa}.
+#' @export
+
+pa <- function(...) constructor_spec(sample_pa, ...)
+
+
+## -----------------------------------------------------------------
+
+
+#' Generate random graphs according to the G(n,p) Erdos-Renyi model
+#' 
+#' This model is very simple, every possible edge is created with the same
+#' constant probability.
+#' 
+#'
+#' The graph has \sQuote{n} vertices and for each edge the
+#' probability that it is present in the graph is \sQuote{p}.
+#' 
+#' @param n The number of vertices in the graph.
+#' @param p The probability for drawing an edge between two
+#'   arbitrary vertices (G(n,p) graph).
+#' @param directed Logical, whether the graph will be directed, defaults to
+#'   FALSE.
+#' @param loops Logical, whether to add loop edges, defaults to FALSE.
+#' @return A graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_gnm}}, \code{\link{sample_pa}}
+#' @references Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
+#' Mathematicae} 6, 290--297 (1959).
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(1000, 1/1000)
+#' degree_distribution(g)
+
+sample_gnp <- function(n, p, directed = FALSE, loops = FALSE) {
+
+  type <- "gnp"
+  type1 <- switch(type, "gnp"=0, "gnm"=1)
+  
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_erdos_renyi_game", as.numeric(n), as.numeric(type1),
+               as.numeric(p), as.logical(directed), as.logical(loops),
+               PACKAGE="igraph")
+
+  if (igraph_opt("add.params")) {
+    res$name <- sprintf("Erdos renyi (%s) graph", type)
+    res$type <- type
+    res$loops <- loops
+    res$p <- p
+  }
+  res
+}
+
+#' @rdname sample_gnp
+#' @param ... Passed to \code{sample_app}.
+#' @export
+
+gnp <- function(...) constructor_spec(sample_gnp, ...)
+
+## -----------------------------------------------------------------
+
+
 
+#' Generate random graphs according to the G(n,m) Erdos-Renyi model
+#' 
+#' This model is very simple, every possible edge is created with the same
+#' constant probability.
+#' 
+#' The graph has \sQuote{n} vertices and \sQuote{m} edges,
+#' and the \sQuote{m} edges are chosen uniformly randomly from the set of all
+#' possible edges. This set includes loop edges as well if the \code{loops}
+#' parameter is TRUE.
+#' 
+#' @param n The number of vertices in the graph.
+#' @param m The number of edges in the graph.
+#' @param directed Logical, whether the graph will be directed, defaults to
+#' FALSE.
+#' @param loops Logical, whether to add loop edges, defaults to FALSE.
+#' @return A graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_gnp}}, \code{\link{sample_pa}}
+#' @references Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
+#' Mathematicae} 6, 290--297 (1959).
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnm(1000, 1000)
+#' degree_distribution(g)
+
+sample_gnm <- function(n, m, directed = FALSE, loops = FALSE) {
+
+  type <- "gnm"
+  type1 <- switch(type, "gnp"=0, "gnm"=1)
+  
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_erdos_renyi_game", as.numeric(n), as.numeric(type1),
+               as.numeric(m), as.logical(directed), as.logical(loops),
+               PACKAGE="igraph")
+
+  if (igraph_opt("add.params")) {
+    res$name <- sprintf("Erdos renyi (%s) graph", type)
+    res$type <- type
+    res$loops <- loops
+    res$m <- m
+  }
+  res
+}
+
+#' @rdname sample_gnm
+#' @param ... Passed to \code{sample_app}.
+#' @export
+
+gnm <- function(...) constructor_spec(sample_gnm, ...)
+
+## -----------------------------------------------------------------
+
+#' Generate random graphs according to the Erdos-Renyi model
+#' 
+#' This model is very simple, every possible edge is created with the same
+#' constant probability.
+#' 
+#' In G(n,p) graphs, the graph has \sQuote{n} vertices and for each edge the
+#' probability that it is present in the graph is \sQuote{p}.
+#' 
+#' In G(n,m) graphs, the graph has \sQuote{n} vertices and \sQuote{m} edges,
+#' and the \sQuote{m} edges are chosen uniformly randomly from the set of all
+#' possible edges. This set includes loop edges as well if the \code{loops}
+#' parameter is TRUE.
+#' 
+#' \code{random.graph.game} is an alias to this function.
+#'
+#' @section Deprecated:
+#'
+#' Since igraph version 0.8.0, both \code{erdos.renyi.game} and
+#' \code{random.graph.game} are deprecated, and \code{\link{sample_gnp}} and
+#' \code{\link{sample_gnm}} should be used instead.
+#' 
+#' @aliases erdos.renyi.game random.graph.game
+#' @param n The number of vertices in the graph.
+#' @param p.or.m Either the probability for drawing an edge between two
+#' arbitrary vertices (G(n,p) graph), or the number of edges in the graph (for
+#' G(n,m) graphs).
+#' @param type The type of the random graph to create, either \code{gnp}
+#' (G(n,p) graph) or \code{gnm} (G(n,m) graph).
+#' @param directed Logical, whether the graph will be directed, defaults to
+#' FALSE.
+#' @param loops Logical, whether to add loop edges, defaults to FALSE.
+#' @param \dots Additional arguments, ignored.
+#' @return A graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_pa}}
+#' @references Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
+#' Mathematicae} 6, 290--297 (1959).
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- erdos.renyi.game(1000, 1/1000)
+#' degree_distribution(g)
+#' 
 erdos.renyi.game <- function(n, p.or.m, type=c("gnp", "gnm"),
                              directed=FALSE, loops=FALSE, ...) {
-  
+
   type <- igraph.match.arg(type)
   type1 <- switch(type, "gnp"=0, "gnm"=1)
 
@@ -101,7 +353,7 @@ erdos.renyi.game <- function(n, p.or.m, type=c("gnp", "gnm"),
                as.numeric(p.or.m), as.logical(directed), as.logical(loops),
                PACKAGE="igraph")
 
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- sprintf("Erdos renyi (%s) graph", type)
     res$type <- type
     res$loops <- loops
@@ -111,12 +363,91 @@ erdos.renyi.game <- function(n, p.or.m, type=c("gnp", "gnm"),
   res
 }
 
+#' @export
+
 random.graph.game <- erdos.renyi.game
 
-degree.sequence.game <- function(out.deg, in.deg=NULL,
+## -----------------------------------------------------------------
+
+#' Generate random graphs with a given degree sequence
+#' 
+#' It is often useful to create a graph with given vertex degrees. This is
+#' exactly what \code{sample_degseq} does.
+#' 
+#' The \dQuote{simple} method connects the out-stubs of the edges (undirected
+#' graphs) or the out-stubs and in-stubs (directed graphs) together. This way
+#' loop edges and also multiple edges may be generated. This method is not
+#' adequate if one needs to generate simple graphs with a given degree
+#' sequence. The multiple and loop edges can be deleted, but then the degree
+#' sequence is distorted and there is nothing to ensure that the graphs are
+#' sampled uniformly.
+#' 
+#' The \dQuote{simple.no.multiple} method is similar to \dQuote{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 eventually succeed if the provided degree sequence is
+#' graphical, but there is no upper bound on the number of iterations.
+#' 
+#' The \dQuote{vl} method is a more sophisticated generator. The algorithm and
+#' the implementation was done by Fabien Viger and Matthieu Latapy. This
+#' generator always generates undirected, connected simple graphs, it is an
+#' error to pass the \code{in.deg} argument to it.  The algorithm relies on
+#' first creating an initial (possibly unconnected) simple undirected graph
+#' with the given degree sequence (if this is possible at all). Then some
+#' rewiring is done to make the graph connected. Finally a Monte-Carlo
+#' algorithm is used to randomize the graph. The \dQuote{vl} samples from the
+#' undirected, connected simple graphs unformly. See
+#' \url{http://www-rp.lip6.fr/~latapy/FV/generation.html} for details.
+#'
+#' @aliases degree.sequence.game
+#' @param out.deg Numeric vector, the sequence of degrees (for undirected
+#' graphs) or out-degrees (for directed graphs). For undirected graphs its sum
+#' should be even. For directed graphs its sum should be the same as the sum of
+#' \code{in.deg}.
+#' @param in.deg For directed graph, the in-degree sequence. By default this is
+#' \code{NULL} and an undirected graph is created.
+#' @param method Character, the method for generating the graph. Right now the
+#' \dQuote{simple}, \dQuote{simple.no.multiple} and \dQuote{vl} methods are
+#' implemented.
+#' @return The new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_gnp}}, \code{\link{sample_pa}},
+#' \code{\link{simplify}} to get rid of the multiple and/or loops edges.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## The simple generator
+#' g <- sample_degseq(rep(2,100))
+#' degree(g)
+#' is_simple(g)   # sometimes TRUE, but can be FALSE
+#' g2 <- sample_degseq(1:10, 10:1)
+#' degree(g2, mode="out")
+#' degree(g2, mode="in")
+#' 
+#' ## The vl generator
+#' g3 <- sample_degseq(rep(2,100), method="vl")
+#' degree(g3)
+#' is_simple(g3)  # always TRUE
+#' 
+#' ## Exponential degree distribution
+#' ## Note, that we correct the degree sequence if its sum is odd
+#' degs <- sample(1:100, 100, replace=TRUE, prob=exp(-0.5*(1:100)))
+#' if (sum(degs) %% 2 != 0) { degs[1] <- degs[1] + 1 }
+#' g4 <- sample_degseq(degs, method="vl")
+#' all(degree(g4) == degs)
+#' 
+#' ## Power-law degree distribution
+#' ## Note, that we correct the degree sequence if its sum is odd
+#' degs <- sample(1:100, 100, replace=TRUE, prob=(1:100)^-2)
+#' if (sum(degs) %% 2 != 0) { degs[1] <- degs[1] + 1 }
+#' g5 <- sample_degseq(degs, method="vl")
+#' all(degree(g5) == degs)
+
+sample_degseq <- function(out.deg, in.deg=NULL,
                                  method=c("simple", "vl",
-                                   "simple.no.multiple"),
-                                 ...) {
+                                   "simple.no.multiple")) {
 
   method <- igraph.match.arg(method)
   method1 <- switch(method, "simple"=0, "vl"=1, "simple.no.multiple"=2)
@@ -126,19 +457,54 @@ degree.sequence.game <- function(out.deg, in.deg=NULL,
   res <- .Call("R_igraph_degree_sequence_game", as.numeric(out.deg),
                in.deg, as.numeric(method1),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Degree sequence random graph"
     res$method <- method
   }
   res
 }
 
-growing.random.game <- function(n, m=1, directed=TRUE, citation=FALSE) {
+#' @rdname sample_degseq
+#' @param ... Passed to \code{sample_degree}.
+#' @export
+
+degseq <- function(...) constructor_spec(sample_degseq, ...)
+
+
+## -----------------------------------------------------------------
+
+#' Growing random graph generation
+#' 
+#' This function creates a random graph by simulating its stochastic evolution.
+#' 
+#' This is discrete time step model, in each time step a new vertex is added to
+#' the graph and \code{m} new edges are created. If \code{citation} is
+#' \code{FALSE} these edges are connecting two uniformly randomly chosen
+#' vertices, otherwise the edges are connecting new vertex to uniformly
+#' randomly chosen old vertices.
+#'
+#' @aliases growing.random.game
+#' @param n Numeric constant, number of vertices in the graph.
+#' @param m Numeric constant, number of edges added in each time step.
+#' @param directed Logical, whether to create a directed graph.
+#' @param citation Logical. If \code{TRUE} a citation graph is created, ie. in
+#' each time step the added edges are originating from the new vertex.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_pa}}, \code{\link{sample_gnp}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_growing(500, citation=FALSE)
+#' g2 <- sample_growing(500, citation=TRUE)
+#' 
+sample_growing <- function(n, m=1, directed=TRUE, citation=FALSE) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_growing_random_game", as.numeric(n), as.numeric(m),
                as.logical(directed), as.logical(citation),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Growing random graph"
     res$m <- m
     res$citation <- citation
@@ -146,7 +512,113 @@ growing.random.game <- function(n, m=1, directed=TRUE, citation=FALSE) {
   res
 }
 
-aging.prefatt.game <- function(n, pa.exp, aging.exp, m=NULL, aging.bin=300,
+#' @rdname sample_growing
+#' @param ... Passed to \code{sample_app}.
+#' @export
+
+growing <- function(...) constructor_spec(sample_growing, ...)
+
+## -----------------------------------------------------------------
+
+
+#' Generate an evolving random graph with preferential attachment and aging
+#' 
+#' This function creates a random graph by simulating its evolution. Each time
+#' a new vertex is added it creates a number of links to old vertices and the
+#' probability that an old vertex is cited depends on its in-degree
+#' (preferential attachment) and age.
+#' 
+#' This is a discrete time step model of a growing graph. We start with a
+#' network containing a single vertex (and no edges) in the first time step.
+#' Then in each time step (starting with the second) a new vertex is added and
+#' it initiates a number of edges to the old vertices in the network. The
+#' probability that an old vertex is connected to is proportional to \deqn{P[i]
+#' \sim (c\cdot k_i^\alpha+a)(d\cdot l_i^\beta+b)\cdot }{% P[i] ~ (c k[i]^alpha
+#' + a) (d l[i]^beta + a)}
+#' 
+#' Here \eqn{k_i}{k[i]} is the in-degree of vertex \eqn{i} in the current time
+#' step and \eqn{l_i}{l[i]} is the age of vertex \eqn{i}. The age is simply
+#' defined as the number of time steps passed since the vertex is added, with
+#' the extension that vertex age is divided to be in \code{aging.bin} bins.
+#' 
+#' \eqn{c}, \eqn{\alpha}{alpha}, \eqn{a}, \eqn{d}, \eqn{\beta}{beta} and
+#' \eqn{b} are parameters and they can be set via the following arguments:
+#' \code{pa.exp} (\eqn{\alpha}{alpha}, mandatory argument), \code{aging.exp}
+#' (\eqn{\beta}{beta}, mandatory argument), \code{zero.deg.appeal} (\eqn{a},
+#' optional, the default value is 1), \code{zero.age.appeal} (\eqn{b},
+#' optional, the default is 0), \code{deg.coef} (\eqn{c}, optional, the default
+#' is 1), and \code{age.coef} (\eqn{d}, optional, the default is 1).
+#' 
+#' The number of edges initiated in each time step is governed by the \code{m},
+#' \code{out.seq} and \code{out.pref} parameters. If \code{out.seq} is given
+#' then it is interpreted as a vector giving the number of edges to be added in
+#' each time step. It should be of length \code{n} (the number of vertices),
+#' and its first element will be ignored. If \code{out.seq} is not given (or
+#' NULL) and \code{out.dist} is given then it will be used as a discrete
+#' probability distribution to generate the number of edges. Its first element
+#' gives the probability that zero edges are added at a time step, the second
+#' element is the probability that one edge is added, etc. (\code{out.seq}
+#' should contain non-negative numbers, but if they don't sum up to 1, they
+#' will be normalized to sum up to 1. This behavior is similar to the
+#' \code{prob} argument of the \code{sample} command.)
+#' 
+#' By default a directed graph is generated, but it \code{directed} is set to
+#' \code{FALSE} then an undirected is created. Even if an undirected graph is
+#' generaed \eqn{k_i}{k[i]} denotes only the adjacent edges not initiated by
+#' the vertex itself except if \code{out.pref} is set to \code{TRUE}.
+#' 
+#' If the \code{time.window} argument is given (and not NULL) then
+#' \eqn{k_i}{k[i]} means only the adjacent edges added in the previous
+#' \code{time.window} time steps.
+#' 
+#' This function might generate graphs with multiple edges.
+#' 
+#' @aliases sample_pa_age aging.prefatt.game aging.barabasi.game aging.ba.game
+#' @param n The number of vertices in the graph.
+#' @param pa.exp The preferantial attachment exponent, see the details below.
+#' @param aging.exp The exponent of the aging, usually a non-positive number,
+#' see details below.
+#' @param m The number of edges each new vertex creates (except the very first
+#' vertex). This argument is used only if both the \code{out.dist} and
+#' \code{out.seq} arguments are NULL.
+#' @param aging.bin The number of bins to use for measuring the age of
+#' vertices, see details below.
+#' @param out.dist The discrete distribution to generate the number of edges to
+#' add in each time step if \code{out.seq} is NULL. See details below.
+#' @param out.seq The number of edges to add in each time step, a vector
+#' containing as many elements as the number of vertices. See details below.
+#' @param out.pref Logical constant, whether to include edges not initiated by
+#' the vertex as a basis of preferential attachment. See details below.
+#' @param directed Logical constant, whether to generate a directed graph. See
+#' details below.
+#' @param zero.deg.appeal The degree-dependent part of the
+#' \sQuote{attractiveness} of the vertices with no adjacent edges. See also
+#' details below.
+#' @param zero.age.appeal The age-dependent part of the \sQuote{attrativeness}
+#' of the vertices with age zero. It is usually zero, see details below.
+#' @param deg.coef The coefficient of the degree-dependent
+#' \sQuote{attractiveness}. See details below.
+#' @param age.coef The coefficient of the age-dependent part of the
+#' \sQuote{attractiveness}. See details below.
+#' @param time.window Integer constant, if NULL only adjacent added in the last
+#' \code{time.windows} time steps are counted as a basis of the preferential
+#' attachment. See also details below.
+#' @return A new graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_pa}}, \code{\link{sample_gnp}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # The maximum degree for graph with different aging exponents
+#' g1 <- sample_pa_age(10000, pa.exp=1, aging.exp=0, aging.bin=1000)
+#' g2 <- sample_pa_age(10000, pa.exp=1, aging.exp=-1,   aging.bin=1000)
+#' g3 <- sample_pa_age(10000, pa.exp=1, aging.exp=-3,   aging.bin=1000)
+#' max(degree(g1))
+#' max(degree(g2))
+#' max(degree(g3))
+
+sample_pa_age <- function(n, pa.exp, aging.exp, m=NULL, aging.bin=300,
                                out.dist=NULL, out.seq=NULL,
                                out.pref=FALSE, directed=TRUE,
                                zero.deg.appeal=1, zero.age.appeal=0,
@@ -221,7 +693,7 @@ aging.prefatt.game <- function(n, pa.exp, aging.exp, m=NULL, aging.bin=300,
           time.window,
           PACKAGE="igraph")
   }
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Aging Barabasi graph"
     res$pa.exp <- pa.exp
     res$aging.exp <- aging.exp
@@ -237,9 +709,55 @@ aging.prefatt.game <- function(n, pa.exp, aging.exp, m=NULL, aging.bin=300,
   res
 }
 
-aging.barabasi.game <- aging.ba.game <- aging.prefatt.game
+#' @rdname sample_pa_age
+#' @param ... Passed to \code{sample_pa_age}.
+#' @export
+
+pa_age <- function(...) constructor_spec(sample_pa_age, ...)
+
+## -----------------------------------------------------------------
+
+#' Graph generation based on different vertex types
+#' 
+#' These functions implement evolving network models based on different vertex
+#' types.
+#' 
+#' For \code{sample_traits_callaway} the simulation goes like this: in each
+#' discrete time step a new vertex is added to the graph. The type of this
+#' vertex is generated based on \code{type.dist}. Then two vertices are
+#' selected uniformly randomly from the graph. The probability that they will
+#' be connected depends on the types of these vertices and is taken from
+#' \code{pref.matrix}. Then another two vertices are selected and this is
+#' repeated \code{edges.per.step} times in each time step.
+#' 
+#' For \code{sample_traits} the simulation goes like this: a single vertex is
+#' added at each time step. This new vertex tries to connect to \code{k}
+#' vertices in the graph. The probability that such a connection is realized
+#' depends on the types of the vertices involved and is taken from
+#' \code{pref.matrix}.
+#' 
+#' @aliases sample_traits_callaway sample_traits callaway.traits.game
+#' establishment.game
+#' @param nodes The number of vertices in the graph.
+#' @param types The number of different vertex types.
+#' @param edge.per.step The number of edges to add to the graph per time step.
+#' @param type.dist The distribution of the vertex types. This is assumed to be
+#' stationary in time.
+#' @param pref.matrix A matrix giving the preferences of the given vertex
+#' types. These should be probabilities, ie. numbers between zero and one.
+#' @param directed Logical constant, whether to generate directed graphs.
+#' @param k The number of trials per time step, see details below.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # two types of vertices, they like only themselves
+#' g1 <- sample_traits_callaway(1000, 2, pref.matrix=matrix( c(1,0,0,1), nc=2))
+#' g2 <- sample_traits(1000, 2, k=2, pref.matrix=matrix( c(1,0,0,1), nc=2))
 
-callaway.traits.game <- function(nodes, types, edge.per.step=1,
+sample_traits_callaway <- function(nodes, types, edge.per.step=1,
                                  type.dist=rep(1, types),
                                  pref.matrix=matrix(1, types, types),
                                  directed=FALSE) {
@@ -251,7 +769,7 @@ callaway.traits.game <- function(nodes, types, edge.per.step=1,
                                             types),
                as.logical(directed),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Trait-based Callaway graph"
     res$types <- types
     res$edge.per.step <- edge.per.step
@@ -261,7 +779,17 @@ callaway.traits.game <- function(nodes, types, edge.per.step=1,
   res
 }
 
-establishment.game <- function(nodes, types, k=1, type.dist=rep(1, types),
+#' @rdname sample_traits_callaway
+#' @param ... Passed to the constructor, \code{sample_traits} or
+#'   \code{sample_traits_callaway}.
+#' @export
+
+traits_callaway <- function(...) constructor_spec(sample_traits_callaway, ...)
+
+#' @rdname sample_traits_callaway
+#' @export
+
+sample_traits <- function(nodes, types, k=1, type.dist=rep(1, types),
                                pref.matrix=matrix(1, types, types),
                                directed=FALSE) {
 
@@ -271,7 +799,7 @@ establishment.game <- function(nodes, types, k=1, type.dist=rep(1, types),
                matrix(as.double(pref.matrix), types, types),
                as.logical(directed),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Trait-based growing graph"
     res$types <- types
     res$k <- k
@@ -281,7 +809,44 @@ establishment.game <- function(nodes, types, k=1, type.dist=rep(1, types),
   res
 }
 
-grg.game <- function(nodes, radius, torus=FALSE, coords=FALSE) {
+#' @rdname sample_traits_callaway
+#' @export
+
+traits <- function(...) constructor_spec(sample_traits, ...)
+
+## -----------------------------------------------------------------
+
+#' Geometric random graphs
+#' 
+#' Generate a random graph based on the distance of random point on a unit
+#' square
+#' 
+#' First a number of points are dropped on a unit square, these points
+#' correspond to the vertices of the graph to create. Two points will be
+#' connected with an undirected edge if they are closer to each other in
+#' Euclidean norm than a given radius. If the \code{torus} argument is
+#' \code{TRUE} then a unit area torus is used instead of a square.
+#'
+#' @aliases grg.game
+#' @param nodes The number of vertices in the graph.
+#' @param radius The radius within which the vertices will be connected by an
+#' edge.
+#' @param torus Logical constant, whether to use a torus instead of a square.
+#' @param coords Logical scalar, whether to add the positions of the vertices
+#' as vertex attributes called \sQuote{\code{x}} and \sQuote{\code{y}}.
+#' @return A graph object. If \code{coords} is \code{TRUE} then with vertex
+#' attributes \sQuote{\code{x}} and \sQuote{\code{y}}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}, first version was
+#' written by Keith Briggs (\url{http://keithbriggs.info/}).
+#' @seealso \code{\link{sample_gnp}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_grg(1000, 0.05, torus=FALSE)
+#' g2 <- sample_grg(1000, 0.05, torus=TRUE)
+#' 
+sample_grg <- function(nodes, radius, torus=FALSE, coords=FALSE) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_grg_game", as.double(nodes), as.double(radius),
                as.logical(torus), as.logical(coords),
@@ -290,7 +855,7 @@ grg.game <- function(nodes, radius, torus=FALSE, coords=FALSE) {
     V(res[[1]])$x <- res[[2]]
     V(res[[1]])$y <- res[[3]]
   }
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res[[1]]$name <- "Geometric random graph"
     res[[1]]$radius <- radius
     res[[1]]$torus <- torus
@@ -298,7 +863,66 @@ grg.game <- function(nodes, radius, torus=FALSE, coords=FALSE) {
   res[[1]]
 }
 
-preference.game <- function(nodes, types, type.dist=rep(1, types),
+#' @rdname sample_grg
+#' @param ... Passed to \code{sample_grg}.
+#' @export
+
+grg <- function(...) constructor_spec(sample_grg, ...)
+
+## -----------------------------------------------------------------
+
+
+#' Trait-based random generation
+#' 
+#' Generation of random graphs based on different vertex types.
+#' 
+#' Both models generate random graphs with given vertex types. For
+#' \code{sample_pref} the probability that two vertices will be connected
+#' depends on their type and is given by the \sQuote{pref.matrix} argument.
+#' This matrix should be symmetric to make sense but this is not checked. The
+#' distribution of the different vertes types is given by the
+#' \sQuote{type.dist} vector.
+#' 
+#' For \code{sample_asym_pref} each vertex has an in-type and an
+#' out-type and a directed graph is created. The probability that a directed
+#' edge is realized from a vertex with a given out-type to a vertex with a
+#' given in-type is given in the \sQuote{pref.matrix} argument, which can be
+#' asymmetric. The joint distribution for the in- and out-types is given in the
+#' \sQuote{type.dist.matrix} argument.
+#' 
+#' @aliases sample_pref sample_asym_pref preference.game asymmetric.preference.game
+#' @param nodes The number of vertices in the graphs.
+#' @param types The number of different vertex types.
+#' @param type.dist The distribution of the vertex types, a numeric vector of
+#' length \sQuote{types} containing non-negative numbers. The vector will be
+#' normed to obtain probabilities.
+#' @param fixed.sizes Fix the number of vertices with a given vertex type
+#' label. The \code{type.dist} argument gives the group sizes (i.e. number of
+#' vertices with the different labels) in this case.
+#' @param type.dist.matrix The joint distribution of the in- and out-vertex
+#' types.
+#' @param pref.matrix A square matrix giving the preferences of the vertex
+#' types. The matrix has \sQuote{types} rows and columns.
+#' @param directed Logical constant, whether to create a directed graph.
+#' @param loops Logical constant, whether self-loops are allowed in the graph.
+#' @return An igraph graph.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com} for the R interface
+#' @seealso \code{\link{sample_traits}}.
+#' \code{\link{sample_traits_callaway}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' pf <- matrix( c(1, 0, 0, 1), nr=2)
+#' g <- sample_pref(20, 2, pref.matrix=pf)
+#' \dontrun{tkplot(g, layout=layout_with_fr)}
+#' 
+#' pf <- matrix( c(0, 1, 0, 0), nr=2)
+#' g <- sample_asym_pref(20, 2, pref.matrix=pf)
+#' \dontrun{tkplot(g, layout=layout_in_circle)}
+#' 
+sample_pref <- function(nodes, types, type.dist=rep(1, types),
                             fixed.sizes=FALSE,
                             pref.matrix=matrix(1, types, types),
                             directed=FALSE, loops=FALSE) {
@@ -315,7 +939,7 @@ preference.game <- function(nodes, types, type.dist=rep(1, types),
                as.logical(directed), as.logical(loops),
                PACKAGE="igraph")
   V(res[[1]])$type <- res[[2]]+1
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res[[1]]$name <- "Preference random graph"
     res[[1]]$types <- types
     res[[1]]$type.dist <- type.dist
@@ -326,10 +950,20 @@ preference.game <- function(nodes, types, type.dist=rep(1, types),
   res[[1]]
 }
 
-asymmetric.preference.game <- function(nodes, types,
-                                  type.dist.matrix=matrix(1, types,types),
-                                  pref.matrix=matrix(1, types, types),
-                                  loops=FALSE) {
+#' @rdname sample_pref
+#' @param ... Passed to the constructor, \code{sample_pref} or
+#'   \code{sample_asym_pref}.
+#' @export
+
+pref <- function(...) constructor_spec(sample_pref, ...)
+
+#' @rdname sample_pref
+#' @export
+
+sample_asym_pref <- function(nodes, types,
+                        type.dist.matrix=matrix(1, types,types),
+                        pref.matrix=matrix(1, types, types),
+                        loops=FALSE) {
   
   if (nrow(pref.matrix) != types || ncol(pref.matrix) != types) {
     stop("Invalid size for preference matrix")
@@ -345,7 +979,7 @@ asymmetric.preference.game <- function(nodes, types,
                matrix(as.double(pref.matrix), types, types),
                as.logical(loops),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Asymmetric preference random graph"
     res$types <- types
     res$type.dist.matrix <- type.dist.matrix
@@ -354,8 +988,16 @@ asymmetric.preference.game <- function(nodes, types,
   }
 }
 
-connect.neighborhood <- function(graph, order, mode=c("all", "out", "in", "total")) {
-  if (!is.igraph(graph)) {
+#' @rdname sample_pref
+#' @export
+
+asym_pref <- function(...) constructor_spec(sample_asym_pref, ...)
+
+## -----------------------------------------------------------------
+
+
+connect <- function(graph, order, mode=c("all", "out", "in", "total")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -367,17 +1009,42 @@ connect.neighborhood <- function(graph, order, mode=c("all", "out", "in", "total
         PACKAGE="igraph")
 }
 
-rewire.edges <- function(graph, prob, loops=FALSE, multiple=FALSE) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_rewire_edges", graph, as.numeric(prob), as.logical(loops),
-        as.logical(multiple),
-        PACKAGE="igraph")
-}
 
-watts.strogatz.game <- function(dim, size, nei, p, loops=FALSE,
+#' The Watts-Strogatz small-world model
+#' 
+#' Generate a graph according to the Watts-Strogatz network model.
+#' 
+#' First a lattice is created with the given \code{dim}, \code{size} and
+#' \code{nei} arguments. Then the edges of the lattice are rewired uniformly
+#' randomly with probability \code{p}.
+#' 
+#' Note that this function might create graphs with loops and/or multiple
+#' edges. You can use \code{\link{simplify}} to get rid of these.
+#'
+#' @aliases watts.strogatz.game
+#' @param dim Integer constant, the dimension of the starting lattice.
+#' @param size Integer constant, the size of the lattice along each dimension.
+#' @param nei Integer constant, the neighborhood within which the vertices of
+#' the lattice will be connected.
+#' @param p Real constant between zero and one, the rewiring probability.
+#' @param loops Logical scalar, whether loops edges are allowed in the
+#' generated graph.
+#' @param multiple Logical scalar, whether multiple edges are allowed int the
+#' generated graph.
+#' @return A graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{make_lattice}}, \code{\link{rewire}}
+#' @references Duncan J Watts and Steven H Strogatz: Collective dynamics of
+#' \sQuote{small world} networks, Nature 393, 440-442, 1998.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_smallworld(1, 100, 5, 0.05)
+#' mean_distance(g)
+#' transitivity(g, type="average")
+#' 
+sample_smallworld <- function(dim, size, nei, p, loops=FALSE,
                                 multiple=FALSE) {
   
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -385,7 +1052,7 @@ watts.strogatz.game <- function(dim, size, nei, p, loops=FALSE,
                as.numeric(size), as.numeric(nei), as.numeric(p),
                as.logical(loops), as.logical(multiple),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Watts-Strogatz random graph"
     res$dim <- dim
     res$size <- size
@@ -397,14 +1064,53 @@ watts.strogatz.game <- function(dim, size, nei, p, loops=FALSE,
   res
 }
 
-lastcit.game <- function(n, edges=1, agebins=n/7100, pref=(1:(agebins+1))^-3,
-                         directed=TRUE) {
+#' @rdname sample_smallworld
+#' @param ... Passed to \code{sample_smallworld}.
+#' @export
+
+smallworld <- function(...) constructor_spec(sample_smallworld, ...)
+
+## -----------------------------------------------------------------
+
+#' Random citation graphs
+#' 
+#' \code{sample_last_cit} creates a graph, where vertices age, and
+#' gain new connections based on how long ago their last citation
+#' happened.
+#'
+#' \code{sample_cit_cit_types} is a stochastic block model where the
+#' graph is growing.
+#'
+#' \code{sample_cit_types} is similarly a growing stochastic block model,
+#' but the probability of an edge depends on the (potentiall) cited
+#' vertex only.
+#' 
+#' @aliases cited.type.game sample_cit_types citing.cited.type.game
+#' sample_cit_cit_types sample_last_cit lastcit.game
+#' @param n Number of vertices.
+#' @param edges Number of edges per step.
+#' @param agebins Number of aging bins.
+#' @param pref Vector (\code{sample_last_cit} and \code{sample_cit_types} or
+#' matrix (\code{sample_cit_cit_types}) giving the (unnormalized) citation
+#' probabilities for the different vertex types.
+#' @param directed Logical scalar, whether to generate directed networks.
+#' @param types Vector of length \sQuote{\code{n}}, the types of the vertices.
+#' Types are numbered from zero.
+#' @param attr Logical scalar, whether to add the vertex types to the generated
+#' graph as a vertex attribute called \sQuote{\code{type}}.
+#' @return A new graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+
+sample_last_cit <- function(n, edges=1, agebins=n/7100, pref=(1:(agebins+1))^-3,
+                       directed=TRUE) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_lastcit_game", as.numeric(n), as.numeric(edges),
                as.numeric(agebins),
                as.numeric(pref), as.logical(directed),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Random citation graph based on last citation"
     res$edges <- edges
     res$agebins <- agebins
@@ -412,7 +1118,16 @@ lastcit.game <- function(n, edges=1, agebins=n/7100, pref=(1:(agebins+1))^-3,
   res
 }
 
-cited.type.game <- function(n, edges=1, types=rep(0, n),
+#' @rdname sample_last_cit
+#' @param ... Passed to the actual constructor.
+#' @export
+
+last_cit <- function(...) constructor_spec(sample_last_cit, ...)
+
+#' @rdname sample_last_cit
+#' @export
+
+sample_cit_types <- function(n, edges=1, types=rep(0, n),
                             pref=rep(1, length(types)),
                             directed=TRUE, attr=TRUE) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -422,14 +1137,22 @@ cited.type.game <- function(n, edges=1, types=rep(0, n),
   if (attr) {
     V(res)$type <- types
   }
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Random citation graph (cited type)"
     res$edges <- edges
   }
   res
 }
 
-citing.cited.type.game <- function(n, edges=1, types=rep(0, n),
+#' @rdname sample_last_cit
+#' @export
+
+cit_types <- function(...) constructor_spec(sample_cit_types, ...)
+
+#' @rdname sample_last_cit
+#' @export
+
+sample_cit_cit_types <- function(n, edges=1, types=rep(0, n),
                                    pref=matrix(1, nrow=length(types),
                                      ncol=length(types)),
                                    directed=TRUE, attr=TRUE) {
@@ -442,30 +1165,70 @@ citing.cited.type.game <- function(n, edges=1, types=rep(0, n),
   if (attr) {
     V(res)$type <- types
   }
-  if (getIgraphOpt("add.params")) {
+  if (igraph_opt("add.params")) {
     res$name <- "Random citation graph (citing & cited type)"
     res$edges <- edges
   }
   res
 }
 
+#' @rdname sample_last_cit
+#' @export
 
-simple.interconnected.islands.game <- function(islands.n, islands.size, islands.pin, n.inter) {
-  
+cit_cit_types <- function(...) constructor_spec(sample_cit_cit_types, ...)
 
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call(	"R_igraph_simple_interconnected_islands_game", 
-		as.numeric(islands.n), 
-		as.numeric(islands.size),
-        	as.numeric(islands.pin), 
-		as.numeric(n.inter),
-        	PACKAGE="igraph")
-}
+## -----------------------------------------------------------------
 
 
-bipartite.random.game <- function(n1, n2, type=c("gnp", "gnm"), p, m,
-                                  directed=FALSE, mode=c("out", "in",
-                                                    "all")) {
+#' Bipartite random graphs
+#' 
+#' Generate bipartite graphs using the Erdos-Renyi model
+#' 
+#' Similarly to unipartite (one-mode) networks, we can define the $G(n,p)$, and
+#' $G(n,m)$ graph classes for bipartite graphs, via their generating process.
+#' In $G(n,p)$ every possible edge between top and bottom vertices is realized
+#' with probablity $p$, independently of the rest of the edges. In $G(n,m)$, we
+#' uniformly choose $m$ edges to realize.
+#'
+#' @aliases bipartite.random.game
+#' @param n1 Integer scalar, the number of bottom vertices.
+#' @param n2 Integer scalar, the number of top vertices.
+#' @param type Character scalar, the type of the graph, \sQuote{gnp} creates a
+#' $G(n,p)$ graph, \sQuote{gnm} creates a $G(n,m)$ graph. See details below.
+#' @param p Real scalar, connection probability for $G(n,p)$ graphs. Should not
+#' be given for $G(n,m)$ graphs.
+#' @param m Integer scalar, the number of edges for $G(n,p)$ graphs. Should not
+#' be given for $G(n,p)$ graphs.
+#' @param directed Logical scalar, whether to create a directed graph. See also
+#' the \code{mode} argument.
+#' @param mode Character scalar, specifies how to direct the edges in directed
+#' graphs. If it is \sQuote{out}, then directed edges point from bottom
+#' vertices to top vertices. If it is \sQuote{in}, edges point from top
+#' vertices to bottom vertices. \sQuote{out} and \sQuote{in} do not generate
+#' mutual edges. If this argument is \sQuote{all}, then each edge direction is
+#' considered independently and mutual edges might be generated. This argument
+#' is ignored for undirected graphs.
+#' @return A bipartite igraph graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_gnp}} for the unipartite version.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## empty graph
+#' sample_bipartite(10, 5, p=0)
+#' 
+#' ## full graph
+#' sample_bipartite(10, 5, p=1)
+#' 
+#' ## random bipartite graph
+#' sample_bipartite(10, 5, p=.1)
+#' 
+#' ## directed bipartite graph, G(n,m)
+#' sample_bipartite(10, 5, type="Gnm", m=20, directed=TRUE, mode="all")
+#' 
+sample_bipartite <- function(n1, n2, type=c("gnp", "gnm"), p, m,
+                     directed=FALSE, mode=c("out", "in", "all")) {
   
   n1 <- as.integer(n1)
   n2 <- as.integer(n2)
@@ -492,16 +1255,508 @@ bipartite.random.game <- function(n1, n2, type=c("gnp", "gnm"), p, m,
   if (type=="gnp") {      
     res <- .Call("R_igraph_bipartite_game_gnp", n1, n2, p, directed, mode,
                  PACKAGE="igraph")
-    res <- set.vertex.attribute(res$graph, "type", value=res$types)
+    res <- set_vertex_attr(res$graph, "type", value=res$types)
     res$name <- "Bipartite Gnp random graph"
     res$p <- p
   } else if (type=="gnm") {
     res <- .Call("R_igraph_bipartite_game_gnm", n1, n2, m, directed, mode,
                  PACKAGE="igraph")
-    res <- set.vertex.attribute(res$graph, "type", value=res$types)
+    res <- set_vertex_attr(res$graph, "type", value=res$types)
     res$name <- "Bipartite Gnm random graph"
     res$m <- m
   }
 
   res
 }
+
+#' @rdname sample_bipartite
+#' @param ... Passed to \code{sample_bipartite}.
+#' @export
+
+bipartite <- function(...) constructor_spec(sample_bipartite, ...)
+
+
+#' Sample stochastic block model
+#' 
+#' Sampling from the stochastic block model of networks
+#' 
+#' This function samples graphs from a stochastic block model by (doing the
+#' equivalent of) Bernoulli trials for each potential edge with the
+#' probabilities given by the Bernoulli rate matrix, \code{pref.matrix}.
+#' 
+#' @aliases sample_sbm sbm.game sbm
+#' @param n Number of vertices in the graph.
+#' @param pref.matrix The matrix giving the Bernoulli rates.  This is a
+#' \eqn{K\times K}{KxK} matrix, where \eqn{K} is the number of groups. The
+#' probability of creating an edge between vertices from groups \eqn{i} and
+#' \eqn{j} is given by element \eqn{(i,j)}. For undirected graphs, this matrix
+#' must be symmetric.
+#' @param block.sizes Numeric vector giving the number of vertices in each
+#' group. The sum of the vector must match the number of vertices.
+#' @param directed Logical scalar, whether to generate a directed graph.
+#' @param loops Logical scalar, whether self-loops are allowed in the graph.
+#' @param \dots Passed to \code{sample_sbm}.
+#' @return An igraph graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_gnp}}, \code{\link{sample_gnm}}
+#' @references Faust, K., & Wasserman, S. (1992a). Blockmodels: Interpretation
+#' and evaluation. \emph{Social Networks}, 14, 5--61.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Two groups with not only few connection between groups
+#' pm <- cbind( c(.1, .001), c(.001, .05) )
+#' g <- sample_sbm(1000, pref.matrix=pm, block.sizes=c(300,700))
+#' g
+#' @export
+
+sample_sbm <- sample_sbm
+
+#' @export
+
+sbm <- function(...) constructor_spec(sample_sbm, ...)
+
+## -----------------------------------------------------------------
+
+#' Sample the hierarchical stochastic block model
+#' 
+#' Sampling from a hierarchical stochastic block model of networks.
+#' 
+#' The function generates a random graph according to the hierarchical
+#' stochastic block model.
+#' 
+#' @aliases sample_hierarchical_sbm hierarchical_sbm
+#' @param n Integer scalar, the number of vertices.
+#' @param m Integer scalar, the number of vertices per block. \code{n / m} must
+#' be integer. Alternatively, an integer vector of block sizes, if not all the
+#' blocks have equal sizes.
+#' @param rho Numeric vector, the fraction of vertices per cluster, within a
+#' block. Must sum up to 1, and \code{rho * m} must be integer for all elements
+#' of rho. Alternatively a list of rho vectors, one for each block, if they are
+#' not the same for all blocks.
+#' @param C A square, symmetric numeric matrix, the Bernoulli rates for the
+#' clusters within a block. Its size must mach the size of the \code{rho}
+#' vector. Alternatively, a list of square matrices, if the Bernoulli rates
+#' differ in different blocks.
+#' @param p Numeric scalar, the Bernoulli rate of connections between vertices
+#' in different blocks.
+#' @param \dots Passed to \code{sample_hierarchical_sbm}.
+#' @return An igraph graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sbm.game}}
+#' @keywords graphs, random graphs
+#' @examples
+#' 
+#' ## Ten blocks with three clusters each
+#' C <- matrix(c(1  , 3/4,   0,
+#'               3/4,   0, 3/4,
+#'               0  , 3/4, 3/4), nrow=3)
+#' g <- sample_hierarchical_sbm(100, 10, rho=c(3, 3, 4)/10, C=C, p=1/20)
+#' g
+#' if (require(Matrix)) { image(g[]) }
+#' @export
+
+sample_hierarchical_sbm <- function(n, m, rho, C, p) {
+
+  mlen <- length(m)
+  rholen <- if (is.list(rho)) length(rho) else 1
+  Clen <- if (is.list(C)) length(C) else 1
+
+  commonlen <- unique(c(mlen, rholen, Clen))
+
+  if (length(commonlen) == 1 && commonlen == 1) {
+    hsbm.1.game(n, m, rho, C, p)
+  } else {
+    commonlen <- setdiff(commonlen, 1)
+    if (length(commonlen) != 1) {
+      stop("Lengths of `m', `rho' and `C' must match")
+    }
+    m <- rep(m, length.out=commonlen)
+    rho <- if (is.list(rho)) {
+      rep(rho, length.out=commonlen)
+    } else {
+      rep(list(rho), length.out=commonlen)
+    }
+    C <- if (is.list(C)) {
+      rep(C, length.out=commonlen)
+    } else {
+      rep(list(C), length.out=commonlen)
+    }
+    hsbm.list.game(n, m, rho, C, p)
+  }  
+}
+
+#' @export
+
+hierarchical_sbm <- function(...)
+  constructor_spec(sample_hierarchical_sbm, ...)
+
+## -----------------------------------------------------------------
+
+
+#' Generate random graphs according to the random dot product graph model
+#' 
+#' In this model, each vertex is represented by a latent position vector.
+#' Probability of an edge between two vertices are given by the dot product of
+#' their latent position vectors.
+#' 
+#' The dot product of the latent position vectors should be in the [0,1]
+#' interval, otherwise a warning is given. For negative dot products, no edges
+#' are added; dot products that are larger than one always add an edge.
+#' 
+#' @aliases sample_dot_product dot_product
+#' @param vecs A numeric matrix in which each latent position vector is a
+#' column.
+#' @param directed A logical scalar, TRUE if the generated graph should be
+#' directed.
+#' @param \dots Passed to \code{sample_dot_product}.
+#' @return An igraph graph object which is the generated random dot product
+#' graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{sample_dirichlet}}, \code{\link{sample_sphere_surface}}
+#' and \code{\link{sample_sphere_volume}} for sampling position vectors.
+#' @references Christine Leigh Myers Nickel: Random dot product graphs, a model
+#' for social networks. Dissertation, Johns Hopkins University, Maryland, USA,
+#' 2006.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A randomly generated  graph
+#' lpvs <- matrix(rnorm(200), 20, 10)
+#' lpvs <- apply(lpvs, 2, function(x) { return (abs(x)/sqrt(sum(x^2))) })
+#' g <- sample_dot_product(lpvs)
+#' g
+#' 
+#' ## Sample latent vectors from the surface of the unit sphere
+#' lpvs2 <- sample_sphere_surface(dim=5, n=20)
+#' g2 <- sample_dot_product(lpvs2)
+#' g2
+#' @export
+
+sample_dot_product <- sample_dot_product
+
+#' @export
+
+dot_product <- function(...) constructor_spec(sample_dot_product, ...)
+
+
+#' A graph with subgraphs that are each a random graph.
+#' 
+#' Create a number of Erdos-Renyi random graphs with identical parameters, and
+#' connect them with the specified number of edges.
+#' 
+#' 
+#' @aliases interconnected.islands.game sample_islands
+#' @param islands.n The number of islands in the graph.
+#' @param islands.size The size of islands in the graph.
+#' @param islands.pin The probability to create each possible edge into each
+#' island.
+#' @param n.inter The number of edges to create between two islands.
+#' @return An igraph graph.
+#' @author Samuel Thiriot (\url{https://www.linkedin.com/in/samthiriot})
+#' @seealso \code{\link{sample_gnp}}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_islands(3, 10, 5/10, 1)
+#' oc <- cluster_optimal(g)
+#' oc
+#' @export
+
+sample_islands <- sample_islands
+
+
+#' Create a random regular graph
+#' 
+#' Generate a random graph where each vertex has the same degree.
+#' 
+#' This game generates a directed or undirected random graph where the degrees
+#' of vertices are equal to a predefined constant k. For undirected graphs, at
+#' least one of k and the number of vertices must be even.
+#' 
+#' The game simply uses \code{\link{sample_degseq}} with appropriately
+#' constructed degree sequences.
+#' 
+#' @aliases sample_k_regular k.regular.game
+#' @param no.of.nodes Integer scalar, the number of vertices in the generated
+#' graph.
+#' @param k Integer scalar, the degree of each vertex in the graph, or the
+#' out-degree and in-degree in a directed graph.
+#' @param directed Logical scalar, whether to create a directed graph.
+#' @param multiple Logical scalar, whether multiple edges are allowed.
+#' @return An igraph graph.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @seealso \code{\link{sample_degseq}} for a generator with prescribed degree
+#' sequence.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A simple ring
+#' ring <- sample_k_regular(10, 2)
+#' plot(ring)
+#' 
+#' ## k-regular graphs on 10 vertices, with k=1:9
+#' k10 <- lapply(1:9, sample_k_regular, no.of.nodes=10)
+#' 
+#' layout(matrix(1:9, nrow=3, byrow=TRUE))
+#' sapply(k10, plot, vertex.label=NA)
+#' @export
+
+sample_k_regular <- sample_k_regular
+
+
+#' Random graphs from vertex fitness scores
+#' 
+#' This function generates a non-growing random graph with edge probabilities
+#' proportional to node fitness scores.
+#' 
+#' This game generates a directed or undirected random graph where the
+#' probability of an edge between vertices \eqn{i} and \eqn{j} depends on the
+#' fitness scores of the two vertices involved. For undirected graphs, each
+#' vertex has a single fitness score. For directed graphs, each vertex has an
+#' out- and an in-fitness, and the probability of an edge from \eqn{i} to
+#' \eqn{j} depends on the out-fitness of vertex \eqn{i} and the in-fitness of
+#' vertex \eqn{j}.
+#' 
+#' The generation process goes as follows. We start from \eqn{N} disconnected
+#' nodes (where \eqn{N} is given by the length of the fitness vector). Then we
+#' randomly select two vertices \eqn{i} and \eqn{j}, with probabilities
+#' proportional to their fitnesses. (When the generated graph is directed,
+#' \eqn{i} is selected according to the out-fitnesses and \eqn{j} is selected
+#' according to the in-fitnesses). If the vertices are not connected yet (or if
+#' multiple edges are allowed), we connect them; otherwise we select a new
+#' pair. This is repeated until the desired number of links are created.
+#' 
+#' It can be shown that the \emph{expected} degree of each vertex will be
+#' proportional to its fitness, although the actual, observed degree will not
+#' be. If you need to generate a graph with an exact degree sequence, consider
+#' \code{\link{sample_degseq}} instead.
+#' 
+#' This model is commonly used to generate static scale-free networks. To
+#' achieve this, you have to draw the fitness scores from the desired power-law
+#' distribution. Alternatively, you may use \code{\link{sample_fitness_pl}}
+#' which generates the fitnesses for you with a given exponent.
+#' 
+#' @aliases sample_fitness static.fitness.game
+#' @param no.of.edges The number of edges in the generated graph.
+#' @param fitness.out A numeric vector containing the fitness of each vertex.
+#' For directed graphs, this specifies the out-fitness of each vertex.
+#' @param fitness.in If \code{NULL} (the default), the generated graph will be
+#' undirected. If not \code{NULL}, then it should be a numeric vector and it
+#' specifies the in-fitness of each vertex.
+#' 
+#' If this argument is not \code{NULL}, then a directed graph is generated,
+#' otherwise an undirected one.
+#' @param loops Logical scalar, whether to allow loop edges in the graph.
+#' @param multiple Logical scalar, whether to allow multiple edges in the
+#' graph.
+#' @return An igraph graph, directed or undirected.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @references Goh K-I, Kahng B, Kim D: Universal behaviour of load
+#' distribution in scale-free networks. \emph{Phys Rev Lett} 87(27):278701,
+#' 2001.
+#' @keywords graphs
+#' @examples
+#' 
+#' N <- 10000
+#' g <- sample_fitness(5*N, sample((1:50)^-2, N, replace=TRUE))
+#' degree_distribution(g)
+#' \dontrun{plot(degree_distribution(g, cumulative=TRUE), log="xy")}
+
+sample_fitness <- sample_fitness
+
+
+#' Scale-free random graphs, from vertex fitness scores
+#' 
+#' This function generates a non-growing random graph with expected power-law
+#' degree distributions.
+#' 
+#' This game generates a directed or undirected random graph where the degrees
+#' of vertices follow power-law distributions with prescribed exponents. For
+#' directed graphs, the exponents of the in- and out-degree distributions may
+#' be specified separately.
+#' 
+#' The game simply uses \code{\link{sample_fitness}} with appropriately
+#' constructed fitness vectors. In particular, the fitness of vertex \eqn{i} is
+#' \eqn{i^{-alpha}}{i^(-alpha)}, where \eqn{alpha = 1/(gamma-1)} and gamma is
+#' the exponent given in the arguments.
+#' 
+#' To remove correlations between in- and out-degrees in case of directed
+#' graphs, the in-fitness vector will be shuffled after it has been set up and
+#' before \code{\link{sample_fitness}} is called.
+#' 
+#' Note that significant finite size effects may be observed for exponents
+#' smaller than 3 in the original formulation of the game. This function
+#' provides an argument that lets you remove the finite size effects by
+#' assuming that the fitness of vertex \eqn{i} is
+#' \eqn{(i+i_0-1)^{-alpha}}{(i+i0-1)^(-alpha)} where \eqn{i_0}{i0} is a
+#' constant chosen appropriately to ensure that the maximum degree is less than
+#' the square root of the number of edges times the average degree; see the
+#' paper of Chung and Lu, and Cho et al for more details.
+#' 
+#' @aliases sample_fitness_pl static.power.law.game
+#' @param no.of.nodes The number of vertices in the generated graph.
+#' @param no.of.edges The number of edges in the generated graph.
+#' @param exponent.out Numeric scalar, the power law exponent of the degree
+#' distribution. For directed graphs, this specifies the exponent of the
+#' out-degree distribution. It must be greater than or equal to 2. If you pass
+#' \code{Inf} here, you will get back an Erdos-Renyi random network.
+#' @param exponent.in Numeric scalar. If negative, the generated graph will be
+#' undirected. If greater than or equal to 2, this argument specifies the
+#' exponent of the in-degree distribution. If non-negative but less than 2, an
+#' error will be generated.
+#' @param loops Logical scalar, whether to allow loop edges in the generated
+#' graph.
+#' @param multiple Logical scalar, whether to allow multiple edges in the
+#' generated graph.
+#' @param finite.size.correction Logical scalar, whether to use the proposed
+#' finite size correction of Cho et al., see references below.
+#' @return An igraph graph, directed or undirected.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @references Goh K-I, Kahng B, Kim D: Universal behaviour of load
+#' distribution in scale-free networks. \emph{Phys Rev Lett} 87(27):278701,
+#' 2001.
+#' 
+#' Chung F and Lu L: Connected components in a random graph with given degree
+#' sequences. \emph{Annals of Combinatorics} 6, 125-145, 2002.
+#' 
+#' Cho YS, Kim JS, Park J, Kahng B, Kim D: Percolation transitions in
+#' scale-free networks under the Achlioptas process. \emph{Phys Rev Lett}
+#' 103:135702, 2009.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_fitness_pl(10000, 30000, 2.2, 2.3)
+#' \dontrun{plot(degree_distribution(g, cumulative=TRUE, mode="out"), log="xy")}
+
+sample_fitness_pl <- sample_fitness_pl
+
+
+#' Forest Fire Network Model
+#' 
+#' This is a growing network model, which resembles of how the forest fire
+#' spreads by igniting trees close by.
+#' 
+#' The forest fire model intends to reproduce the following network
+#' characteristics, observed in real networks: \itemize{ \item Heavy-tailed
+#' in-degree distribution.  \item Heavy-tailed out-degree distribution.  \item
+#' Communities.  \item Densification power-law. The network is densifying in
+#' time, according to a power-law rule.  \item Shrinking diameter. The diameter
+#' of the network decreases in time.  }
+#' 
+#' The network is generated in the following way. One vertex is added at a
+#' time. This vertex connects to (cites) \code{ambs} vertices already present
+#' in the network, chosen uniformly random. Now, for each cited vertex \eqn{v}
+#' we do the following procedure: \enumerate{ \item We generate two random
+#' number, \eqn{x} and \eqn{y}, that are geometrically distributed with means
+#' \eqn{p/(1-p)} and \eqn{rp(1-rp)}. (\eqn{p} is \code{fw.prob}, \eqn{r} is
+#' \code{bw.factor}.) The new vertex cites \eqn{x} outgoing neighbors and
+#' \eqn{y} incoming neighbors of \eqn{v}, from those which are not yet cited by
+#' the new vertex. If there are less than \eqn{x} or \eqn{y} such vertices
+#' available then we cite all of them.  \item The same procedure is applied to
+#' all the newly cited vertices.  }
+#' 
+#' @aliases sample_forestfire forest.fire.game
+#' @param nodes The number of vertices in the graph.
+#' @param fw.prob The forward burning probability, see details below.
+#' @param bw.factor The backward burning ratio. The backward burning
+#' probability is calculated as \code{bw.factor*fw.prob}.
+#' @param ambs The number of ambassador vertices.
+#' @param directed Logical scalar, whether to create a directed graph.
+#' @return A simple graph, possibly directed if the \code{directed} argument is
+#' \code{TRUE}.
+#' @note The version of the model in the published paper is incorrect in the
+#' sense that it cannot generate the kind of graphs the authors claim. A
+#' corrected version is available from
+#' \url{http://www.cs.cmu.edu/~jure/pubs/powergrowth-tkdd.pdf}, our
+#' implementation is based on this.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{barabasi.game}} for the basic preferential attachment
+#' model.
+#' @references Jure Leskovec, Jon Kleinberg and Christos Faloutsos. Graphs over
+#' time: densification laws, shrinking diameters and possible explanations.
+#' \emph{KDD '05: Proceeding of the eleventh ACM SIGKDD international
+#' conference on Knowledge discovery in data mining}, 177--187, 2005.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_forestfire(10000, fw.prob=0.37, bw.factor=0.32/0.37)
+#' dd1 <- degree_distribution(g, mode="in")
+#' dd2 <- degree_distribution(g, mode="out")
+#' plot(seq(along=dd1)-1, dd1, log="xy")
+#' points(seq(along=dd2)-1, dd2, col=2, pch=2)
+
+sample_forestfire <- sample_forestfire
+
+
+#' Generate a new random graph from a given graph by randomly
+#' adding/removing edges
+#' 
+#' Sample a new graph by perturbing the adjacency matrix of a given graph
+#' and shuffling its vertices.
+#' 
+#' Please see the reference given below.
+#' 
+#' @param old.graph The original graph.
+#' @param corr A scalar in the unit interval, the target Pearson
+#' correlation between the adjacency matrices of the original the generated
+#' graph (the adjacency matrix being used as a vector).
+#' @param p A numeric scalar, the probability of an edge between two
+#' vertices, it must in the open (0,1) interval.
+#' @param permutation A numeric vector, a permutation vector that is
+#' applied on the vertices of the first graph, to get the second graph.  If
+#' \code{NULL}, the vertices are not permuted.
+#' @return An unweighted graph of the same size as \code{old.graph} such
+#' that the correlation coefficient between the entries of the two
+#' adjacency matrices is \code{corr}.  Note each pair of corresponding
+#' matrix entries is a pair of correlated Bernoulli random variables.
+#' 
+#' @seealso \code{\link{sample_correlated_gnp_pair}},
+#'   \code{\link{sample_gnp}}
+#' @references Lyzinski, V., Fishkind, D. E., Priebe, C. E. (2013).  Seeded
+#' graph matching for correlated Erdos-Renyi graphs.
+#' \url{http://arxiv.org/abs/1304.7844}
+#' @examples
+#' g <- sample_gnp(1000, .1)
+#' g2 <- sample_correlated_gnp(g, corr = 0.5)
+#' cor(as.vector(g[]), as.vector(g2[]))
+#' g
+#' g2
+
+sample_correlated_gnp <- sample_correlated_gnp
+
+
+#' Sample a pair of correlated G(n,p) random graphs
+#' 
+#' Sample a new graph by perturbing the adjacency matrix of a given graph and
+#' shuffling its vertices.
+#' 
+#' Please see the reference given below.
+#' 
+#' @param n Numeric scalar, the number of vertices for the sampled graphs.
+#' @param corr A scalar in the unit interval, the target Pearson correlation
+#' between the adjacency matrices of the original the generated graph (the
+#' adjacency matrix being used as a vector).
+#' @param p A numeric scalar, the probability of an edge between two vertices,
+#' it must in the open (0,1) interval.
+#' @param directed Logical scalar, whether to generate directed graphs.
+#' @param permutation A numeric vector, a permutation vector that is applied on
+#' the vertices of the first graph, to get the second graph.  If \code{NULL},
+#' the vertices are not permuted.
+#' @return A list of two igraph objects, named \code{graph1} and
+#' \code{graph2}, which are two graphs whose adjacency matrix entries are
+#' correlated with \code{corr}.
+#' 
+#' @seealso \code{\link{sample_correlated_gnp}},
+#'   \code{\link{sample_gnp}}.
+#' @references Lyzinski, V., Fishkind, D. E., Priebe, C. E. (2013).  Seeded
+#' graph matching for correlated Erdos-Renyi graphs.
+#' \url{http://arxiv.org/abs/1304.7844}
+#' @keywords graphs,random graphs
+#' @examples
+#' gg <- sample_correlated_gnp_pair(n = 10, corr = .8, p = .5,
+#'            directed = FALSE)
+#' gg
+#' cor(as.vector(gg[[1]][]), as.vector(gg[[2]][]))
+
+sample_correlated_gnp_pair <- sample_correlated_gnp_pair
diff --git a/R/glet.R b/R/glet.R
index 2719705..d28ee05 100644
--- a/R/glet.R
+++ b/R/glet.R
@@ -1,8 +1,86 @@
 
-graphlets.candidate.basis <- function(graph, weights=NULL) {
+#' Graphlet decomposition of a graph
+#' 
+#' Graphlet decomposition models a weighted undirected graph via the union of
+#' potentially overlapping dense social groups.  This is done by a two-step
+#' algorithm. In the first step a candidate set of groups (a candidate basis)
+#' is created by finding cliques if the thresholded input graph. In the second
+#' step these the graph is projected on the candidate basis, resulting a weight
+#' coefficient for each clique in the candidate basis.
+#' 
+#' igraph contains three functions for performing the graph decomponsition of a
+#' graph. The first is \code{graphlets}, which performed both steps on the
+#' method and returns a list of subgraphs, with their corresponding weights.
+#' The second and third functions correspond to the first and second steps of
+#' the algorithm, and they are useful if the user wishes to perform them
+#' individually: \code{graphlet_basis} and \code{graphlet_proj}.
+#' 
+#' @aliases graphlets graphlets.project graphlet_proj graphlet_basis
+#' graphlets.candidate.basis
+#' @param graph The input graph, edge directions are ignored. Only simple graph
+#' (i.e. graphs without self-loops and multiple edges) are supported.
+#' @param weights Edge weights. If the graph has a \code{weight} edge attribute
+#' and this argument is \code{NULL} (the default), then the \code{weight} edge
+#' attribute is used.
+#' @param niter Integer scalar, the number of iterations to perform.
+#' @param cliques A list of vertex ids, the graphlet basis to use for the
+#' projection.
+#' @param Mu Starting weights for the projection.
+#' @return \code{graphlets} returns a list with two members: \item{cliques}{A
+#' list of subgraphs, the candidate graphlet basis. Each subgraph is give by a
+#' vector of vertex ids.} \item{Mu}{The weights of the subgraphs in graphlet
+#' basis.}
+#' 
+#' \code{graphlet_basis} returns a list of two elements: \item{cliques}{A list
+#' of subgraphs, the candidate graphlet basis. Each subgraph is give by a
+#' vector of vertex ids.} \item{thresholds}{The weight thresholds used for
+#' finding the subgraphs.}
+#' 
+#' \code{graphlet_proj} return a numeric vector, the weights of the graphlet
+#' basis subgraphs.
+#' @examples
+#' 
+#' ## Create an example graph first
+#' D1 <- matrix(0, 5, 5)
+#' D2 <- matrix(0, 5, 5)
+#' D3 <- matrix(0, 5, 5)
+#' D1[1:3, 1:3] <- 2
+#' D2[3:5, 3:5] <- 3
+#' D3[2:5, 2:5] <- 1
+#'   
+#' g <- simplify(graph_from_adjacency_matrix(D1 + D2 + D3,
+#'       mode="undirected", weighted=TRUE))
+#' V(g)$color <- "white"
+#' E(g)$label <- E(g)$weight
+#' E(g)$label.cex <- 2
+#' E(g)$color <- "black"
+#' layout(matrix(1:6, nrow=2, byrow=TRUE))
+#' co <- layout_with_kk(g)
+#' par(mar=c(1,1,1,1))
+#' plot(g, layout=co)
+#' 
+#' ## Calculate graphlets
+#' gl <- graphlets(g, niter=1000)
+#' 
+#' ## Plot graphlets
+#' for (i in 1:length(gl$cliques)) {
+#'   sel <- gl$cliques[[i]]
+#'   V(g)$color <- "white"
+#'   V(g)[sel]$color <- "#E495A5"
+#'   E(g)$width <- 1
+#'   E(g)[ V(g)[sel] %--% V(g)[sel] ]$width <- 2
+#'   E(g)$label <- ""
+#'   E(g)[ width == 2 ]$label <- round(gl$Mu[i], 2)
+#'   E(g)$color <- "black"
+#'   E(g)[ width == 2 ]$color <- "#E495A5"
+#'   plot(g, layout=co)
+#' }
+#' #' @export
+
+graphlet_basis <- function(graph, weights=NULL) {
   ## Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -23,11 +101,14 @@ graphlets.candidate.basis <- function(graph, weights=NULL) {
   res
 }
 
-graphlets.project <- function(graph, weights=NULL, cliques, niter=1000,
+#' @rdname graphlet_basis
+#' @export
+
+graphlet_proj <- function(graph, weights=NULL, cliques, niter=1000,
                               Mu=rep(1, length(cliques))) {
   # Argument checks
   if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -60,7 +141,7 @@ function() {
     E(g)$color <- "black"
     plot.new()
     layout(matrix(1:6, nrow=2, byrow=TRUE))
-    co <- layout.kamada.kawai(g)
+    co <- layout_with_kk(g)
     par(mar=c(1,1,1,1))
     plot(g, layout=co)
     for (i in 1:length(gl$Bc)) {
@@ -84,15 +165,15 @@ function() {
   D2[3:5, 3:5] <- 3
   D3[2:5, 2:5] <- 1
   
-  g <- graph.adjacency(D1 + D2 + D3, mode="undirected", weighted=TRUE)
+  g <- graph_from_adjacency_matrix(D1 + D2 + D3, mode="undirected", weighted=TRUE)
   gl <- graphlets(g, iter=1000)
 
   fitandplot(g, gl)
 
   ## Project another graph on the graphlets
   set.seed(42)
-  g2 <- set.edge.attribute(g, "weight", value=sample(E(g)$weight))
-  gl2 <- graphlets.project(g2, gl$Bc, 1000)
+  g2 <- set_edge_attr(g, "weight", value=sample(E(g)$weight))
+  gl2 <- graphlet_proj(g2, gl$Bc, 1000)
   fitandplot(g2, gl2)
   
 }
diff --git a/R/hrg.R b/R/hrg.R
index ad5807d..1efab72 100644
--- a/R/hrg.R
+++ b/R/hrg.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,9 +19,101 @@
 #
 ###################################################################
 
-hrg.fit <- function(graph, hrg=NULL, start=FALSE, steps=0) {
+#' Hierarchical random graphs
+#' 
+#' Fitting and sampling hierarchical random graph models.
+#' 
+#' A hierarchical random graph is an ensemble of undirected graphs with \eqn{n}
+#' vertices. It is defined via a binary tree with \eqn{n} leaf and \eqn{n-1}
+#' internal vertices, where the internal vertices are labeled with
+#' probabilities.  The probability that two vertices are connected in the
+#' random graph is given by the probability label at their closest common
+#' ancestor.
+#' 
+#' Please see references below for more about hierarchical random graphs.
+#' 
+#' igraph contains functions for fitting HRG models to a given network
+#' (\code{fit_hrg}, for generating networks from a given HRG ensemble
+#' (\code{sample_hrg}), converting an igraph graph to a HRG and back
+#' (\code{hrg}, \code{hrg_tree}), for calculating a consensus tree from a set
+#' of sampled HRGs (\code{consensus_tree}) and for predicting missing edges in
+#' a network based on its HRG models (\code{predict_edges}).
+#' 
+#' The igraph HRG implementation is heavily based on the code published by
+#' Aaron Clauset, at his website (not functional any more).
+#' 
+#' @name hrg-methods
+#' @family hierarchical random graph functions
+NULL
+
+#' Fit a hierarchical random graph model
+#'
+#' \code{fit_hrg} fits a HRG to a given graph. It takes the specified
+#' \code{steps} number of MCMC steps to perform the fitting, or a convergence
+#' criteria if the specified number of steps is zero. \code{fit_hrg} can start
+#' from a given HRG, if this is given in the \code{hrg} argument and the
+#' \code{start} argument is \code{TRUE}.
+#'
+#' @aliases hrg.fit
+#' @param graph The graph to fit the model to. Edge directions are ignored in
+#' directed graphs.
+#' @param hrg A hierarchical random graph model, in the form of an
+#' \code{igraphHRG} object. \code{fit_hrg} allows this to be \code{NULL}, in
+#' which case a random starting point is used for the fitting.
+#' @param start Logical, whether to start the fitting/sampling from the
+#' supplied \code{igraphHRG} object, or from a random starting point.
+#' @param steps The number of MCMC steps to make. If this is zero, then the
+#' MCMC procedure is performed until convergence.
+#' @return \code{fit_hrg} returns an \code{igraphHRG} object. This is a list
+#' with the following members:
+#'   \item{left}{Vector that contains the left children of the internal
+#'     tree vertices. The first vertex is always the root vertex, so the
+#'     first element of the vector is the left child of the root
+#'     vertex. Internal vertices are denoted with negative numbers, starting
+#'     from -1 and going down, i.e. the root vertex is -1. Leaf vertices
+#'     are denoted by non-negative number, starting from zero and up.}
+#'   \item{right}{Vector that contains the right children of the vertices,
+#'     with the same encoding as the \code{left} vector.}
+#'   \item{prob}{The connection probabilities attached to the internal
+#'     vertices, the first number belongs to the root vertex (i.e. internal
+#'     vertex -1), the second to internal vertex -2, etc.}
+#'   \item{edges}{The number of edges in the subtree below the given
+#'     internal vertex.}
+#'   \item{vertices}{The number of vertices in the subtree below the
+#'     given internal vertex, including itself.}
+#' @references A. Clauset, C. Moore, and M.E.J. Newman. Hierarchical structure
+#' and the prediction of missing links in networks. \emph{Nature} 453, 98--101
+#' (2008);
+#' 
+#' A. Clauset, C. Moore, and M.E.J. Newman. Structural Inference of Hierarchies
+#' in Networks. In E. M. Airoldi et al. (Eds.): ICML 2006 Ws, \emph{Lecture
+#' Notes in Computer Science} 4503, 1--13. Springer-Verlag, Berlin Heidelberg
+#' (2007).
+#' @examples
+#' ## We are not running these examples any more, because they
+#' ## take a long time (~15 seconds) to run and this is against the CRAN
+#' ## repository policy. Copy and paste them by hand to your R prompt if
+#' ## you want to run them.
+#' 
+#' \dontrun{
+#' ## A graph with two dense groups
+#' g <- sample_gnp(10, p=1/2) + sample_gnp(10, p=1/2)
+#' hrg <- fit_hrg(g)
+#' hrg
+#' 
+#' ## The consensus tree for it
+#' consensus_tree(g, hrg=hrg, start=TRUE)
+#' 
+#' ## Prediction of missing edges
+#' g2 <- make_full_graph(4) + (make_full_graph(4) - path(1,2))
+#' predict_edges(g2)
+#' }
+#' @export
+#' @family hierarchical random graph functions
+
+fit_hrg <- function(graph, hrg=NULL, start=FALSE, steps=0) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   if (is.null(hrg)) { 
     hrg <- list(left=c(), right=c(), prob=c(), edges=c(), 
                 vertices=c()) 
@@ -37,7 +128,7 @@ hrg.fit <- function(graph, hrg=NULL, start=FALSE, steps=0) {
   res <- .Call("R_igraph_hrg_fit", graph, hrg, start, steps,
                PACKAGE="igraph")
   
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$names <- V(graph)$name
   }
 
@@ -45,41 +136,155 @@ hrg.fit <- function(graph, hrg=NULL, start=FALSE, steps=0) {
   res
 }
 
-hrg.consensus <- function(graph, hrg=NULL, start=FALSE, num.samples=10000) {
-  
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-
-  if (is.null(hrg)) {
-    hrg <- list(left=c(), right=c(), prob=c(), edges=c(), vertices=c())
-  }
-  hrg <- lapply(hrg[c("left","right","prob","edges","vertices")], as.numeric)
-  start <- as.logical(start)
-  num.samples <- as.integer(num.samples)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_hrg_consensus", graph, hrg, start, num.samples,
-        PACKAGE="igraph")
-  res$parents <- res$parents + 1
-  res <- list(consensus=list(parents=res$parents, weights=res$weights),
-              hrg=res$hrg)
-  class(res$consensus) <- "igraphHRGConsensus"
-  class(res$hrg) <- "igraphHRG"
-
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-    res$hrg$names <- V(graph)$name
-    res$consensus$names <- V(graph)$name
-  }
-  
-  res
-}
 
-hrg.predict <- function(graph, hrg=NULL, start=FALSE, num.samples=10000,
+#' Create a consensus tree from several hierarchical random graph models
+#'
+#' \code{consensus_tree} creates a consensus tree from several fitted
+#' hierarchical random graph models, using phylogeny methods. If the \code{hrg}
+#' argument is given and \code{start} is set to \code{TRUE}, then it starts
+#' sampling from the given HRG. Otherwise it optimizes the HRG log-likelihood
+#' first, and then samples starting from the optimum.
+#' 
+#' @aliases hrg.consensus
+#' @param graph The graph the models were fitted to.
+#' @param hrg A hierarchical random graph model, in the form of an
+#'   \code{igraphHRG} object. \code{consensus_tree} allows this to be
+#'   \code{NULL} as well, then a HRG is fitted to the graph first, from a
+#'   random starting point.
+#' @param start Logical, whether to start the fitting/sampling from the
+#'   supplied \code{igraphHRG} object, or from a random starting point.
+#' @param num.samples Number of samples to use for consensus generation or
+#' missing edge prediction.
+#' @return \code{consensus_tree} returns a list of two objects. The first
+#' is an \code{igraphHRGConsensus} object, the second is an
+#' \code{igraphHRG} object.  The \code{igraphHRGConsensus} object has the
+#' following members:
+#'   \item{parents}{For each vertex, the id of its parent vertex is stored,
+#'     or zero, if the vertex is the root vertex in the tree. The first n
+#'     vertex ids (from 0) refer to the original vertices of the graph, the
+#'     other ids refer to vertex groups.}
+#'   \item{weights}{Numeric vector, counts the number of times a given tree
+#'     split occured in the generated network samples, for each internal
+#'     vertices. The order is the same as in the \code{parents} vector.}
+
+#' @include auto.R
+#' @family hierarchical random graph functions
+#' @export
+
+consensus_tree <- consensus_tree
+
+
+#' Create a hierarchical random graph from an igraph graph
+#' 
+#' \code{hrg} creates a HRG from an igraph graph. The igraph graph must be
+#' a directed binary tree, with \eqn{n-1} internal and \eqn{n} leaf
+#' vertices. The \code{prob} argument contains the HRG probability labels
+#' for each vertex; these are ignored for leaf vertices.
+#'
+#' @aliases hrg.create
+#' @param graph The igraph graph to create the HRG from.
+#' @param prob A vector of probabilities, one for each vertex, in the order of
+#'   vertex ids.
+#' @return \code{hrg} returns an \code{igraphHRG} object.
+#'
+#' @family hierarchical random graph functions
+#' @export
+
+hrg <- hrg
+
+
+#' Create an igraph graph from a hierarchical random graph model
+#' 
+#' \code{hrg_tree} creates the corresponsing igraph tree of a hierarchical
+#' random graph model.
+#'
+#' @param hrg A hierarchical random graph model.
+#' @return An igraph graph.
+#'
+#' @family hierarchical random graph functions
+#' @export
+
+hrg_tree <- hrg_tree
+
+
+#' Sample from a hierarchical random graph model
+#'
+#' \code{sample_hrg} samples a graph from a given hierarchical random graph
+#' model.
+#'
+#' @aliases hrg.game
+#' @param hrg A hierarchical random graph model.
+#' @return An igraph graph.
+#'
+#' @family hierarchical random graph functions
+#' @export
+
+sample_hrg <- sample_hrg
+
+#' Predict edges based on a hierarchical random graph model
+#' 
+#' \code{predict_edges} uses a hierarchical random graph model to predict
+#' missing edges from a network. This is done by sampling hierarchical models
+#' around the optimum model, proportionally to their likelihood. The MCMC
+#' sampling is stated from \code{hrg}, if it is given and the \code{start}
+#' argument is set to \code{TRUE}. Otherwise a HRG is fitted to the graph
+#' first.
+#'
+#' @aliases hrg.predict
+#' @param graph The graph to fit the model to. Edge directions are ignored in
+#' directed graphs.
+#' @param hrg A hierarchical random graph model, in the form of an
+#' \code{igraphHRG} object. \code{predict_edges}s allow this to be
+#' \code{NULL} as well, then a HRG is fitted to the graph first, from a
+#' random starting point.
+#' @param start Logical, whether to start the fitting/sampling from the
+#' supplied \code{igraphHRG} object, or from a random starting point.
+#' @param num.samples Number of samples to use for consensus generation or
+#' missing edge prediction.
+#' @param num.bins Number of bins for the edge probabilities. Give a higher
+#' number for a more accurate prediction.
+#' @return A list with entries:
+#'   \item{edges}{The predicted edges, in a two-column matrix of vertex
+#'     ids.}
+#'   \item{prob}{Probabilities of these edges, according to the fitted
+#'     model.}
+#'   \item{hrg}{The (supplied or fitted) hierarchical random graph model.}
+#'
+#' @references A. Clauset, C. Moore, and M.E.J. Newman. Hierarchical structure
+#' and the prediction of missing links in networks. \emph{Nature} 453, 98--101
+#' (2008);
+#' 
+#' A. Clauset, C. Moore, and M.E.J. Newman. Structural Inference of Hierarchies
+#' in Networks. In E. M. Airoldi et al. (Eds.): ICML 2006 Ws, \emph{Lecture
+#' Notes in Computer Science} 4503, 1--13. Springer-Verlag, Berlin Heidelberg
+#' (2007).
+#' @examples
+#' ## We are not running these examples any more, because they
+#' ## take a long time (~15 seconds) to run and this is against the CRAN
+#' ## repository policy. Copy and paste them by hand to your R prompt if
+#' ## you want to run them.
+#' 
+#' \dontrun{
+#' ## A graph with two dense groups
+#' g <- sample_gnp(10, p=1/2) + sample_gnp(10, p=1/2)
+#' hrg <- fit_hrg(g)
+#' hrg
+#' 
+#' ## The consensus tree for it
+#' consensus_tree(g, hrg=hrg, start=TRUE)
+#' 
+#' ## Prediction of missing edges
+#' g2 <- make_full_graph(4) + (make_full_graph(4) - path(1,2))
+#' predict_edges(g2)
+#' }
+#' @export
+#' @family hierarchical random graph functions
+
+predict_edges <- function(graph, hrg=NULL, start=FALSE, num.samples=10000,
                         num.bins=25) {
   
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   if (is.null(hrg)) { 
     hrg <- list(left=c(), right=c(), prob=c(), edges=c(), 
                 vertices=c()) 
@@ -99,9 +304,36 @@ hrg.predict <- function(graph, hrg=NULL, start=FALSE, num.samples=10000,
   res
 }
 
+
+
+#' Conversion to igraph
+#' 
+#' These fucntions convert various objects to igraph graphs.
+#' 
+#' You can use \code{as.igraph} to convert various objects to igraph graphs.
+#' Right now the following objects are supported: \itemize{ \item codeigraphHRG
+#' These objects are created by the \code{\link{fit_hrg}} and
+#' \code{\link{consensus_tree}} functions.  }
+#' 
+#' @aliases as.igraph as.igraph.igraphHRG
+#' @param x The object to convert.
+#' @param \dots Additional arguments. None currently.
+#' @return All these functions return an igraph graph.
+#' @export
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_full_graph(5) + make_full_graph(5)
+#' hrg <- fit_hrg(g)
+#' as.igraph(hrg)
+#' 
 as.igraph <- function(x, ...)
   UseMethod("as.igraph")
 
+#' @method as.igraph igraphHRG
+#' @export
+
 as.igraph.igraphHRG <- function(x, ...) {
   ovc <- length(x$left)+1L
   ivc <- ovc-1L
@@ -152,6 +384,8 @@ buildMerges <- function(object) {
   merges
 } 
 
+#' @method as.dendrogram igraphHRG
+
 as.dendrogram.igraphHRG <- function(object, hang=0.01, ...) {
 
   nMerge <- length(object$left)
@@ -214,6 +448,9 @@ as.dendrogram.igraphHRG <- function(object, hang=0.01, ...) {
   z
 }
 
+#' @importFrom stats as.hclust
+#' @method as.hclust igraphHRG
+
 as.hclust.igraphHRG <- function(x, ...) {
   merge3 <- buildMerges(x)
 
@@ -252,8 +489,9 @@ as.hclust.igraphHRG <- function(x, ...) {
   res  
 }
 
-asPhylo.igraphHRG <- function(x, ...) {
-  require(ape, quietly=TRUE)
+#' @method as_phylo igraphHRG
+
+as_phylo.igraphHRG <- function(x, ...) {
 
   ovc <- length(x$left)+1L
   ivc <- ovc-1L
@@ -270,16 +508,90 @@ asPhylo.igraphHRG <- function(x, ...) {
   reorder(obj)
 }
 
-dendPlot.igraphHRG <- function(x, mode=getIgraphOpt("dend.plot.type"), ...) {
+
+
+#' HRG dendrogram plot
+#' 
+#' Plot a hierarchical random graph as a dendrogram.
+#' 
+#' \code{plot_dendrogram} supports three different plotting functions, selected via
+#' the \code{mode} argument. By default the plotting function is taken from the
+#' \code{dend.plot.type} igraph option, and it has for possible values:
+#' \itemize{ \item \code{auto} Choose automatically between the plotting
+#' functions. As \code{plot.phylo} is the most sophisticated, that is choosen,
+#' whenever the \code{ape} package is available. Otherwise \code{plot.hclust}
+#' is used.  \item \code{phylo} Use \code{plot.phylo} from the \code{ape}
+#' package.  \item \code{hclust} Use \code{plot.hclust} from the \code{stats}
+#' package.  \item \code{dendrogram} Use \code{plot.dendrogram} from the
+#' \code{stats} package.  }
+#' 
+#' The different plotting functions take different sets of arguments. When
+#' using \code{plot.phylo} (\code{mode="phylo"}), we have the following syntax:
+#' \preformatted{
+#'     plot_dendrogram(x, mode="phylo", colbar = rainbow(11, start=0.7,
+#'             end=0.1), edge.color = NULL, use.edge.length = FALSE, \dots)
+#' } The extra arguments not documented above: \itemize{
+#'   \item \code{colbar} Color bar for the edges.
+#'   \item \code{edge.color} Edge colors. If \code{NULL}, then the
+#'     \code{colbar} argument is used.
+#'   \item \code{use.edge.length} Passed to \code{plot.phylo}.
+#'   \item \code{dots} Attitional arguments to pass to \code{plot.phylo}.
+#' }
+#' 
+#' The syntax for \code{plot.hclust} (\code{mode="hclust"}): \preformatted{
+#'     plot_dendrogram(x, mode="hclust", rect = 0, colbar = rainbow(rect),
+#'             hang = 0.01, ann = FALSE, main = "", sub = "", xlab = "",
+#'             ylab = "", \dots)
+#' } The extra arguments not documented above: \itemize{
+#'   \item \code{rect} A numeric scalar, the number of groups to mark on
+#'     the dendrogram. The dendrogram is cut into exactly \code{rect}
+#'     groups and they are marked via the \code{rect.hclust} command. Set
+#'     this to zero if you don't want to mark any groups.
+#'   \item \code{colbar} The colors of the rectanges that mark the
+#'     vertex groups via the \code{rect} argument.
+#'   \item \code{hang} Where to put the leaf nodes, this corresponds to the
+#'     \code{hang} argument of \code{plot.hclust}.
+#'   \item \code{ann} Whether to annotate the plot, the \code{ann} argument
+#'     of \code{plot.hclust}.
+#'   \item \code{main} The main title of the plot, the \code{main} argument
+#'     of \code{plot.hclust}.
+#'   \item \code{sub} The sub-title of the plot, the \code{sub} argument of
+#'     \code{plot.hclust}.
+#'   \item \code{xlab} The label on the horizontal axis, passed to
+#'     \code{plot.hclust}.
+#'   \item \code{ylab} The label on the vertical axis, passed to
+#'     \code{plot.hclust}.
+#'   \item \code{dots} Attitional arguments to pass to \code{plot.hclust}.
+#' }
+#' 
+#' The syntax for \code{plot.dendrogram} (\code{mode="dendrogram"}):
+#' \preformatted{
+#'     plot_dendrogram(x, \dots)
+#' } The extra arguments are simply passed to \code{as.dendrogram}.
+#'
+#' @aliases hrg.dendrogram
+#' @param x An \code{igraphHRG}, a hierarchical random graph, as returned by
+#' the \code{\link{fit_hrg}} function.
+#' @param mode Which dendrogram plotting function to use. See details below.
+#' @param \dots Additional arguments to supply to the dendrogram plotting
+#' function.
+#' @return Returns whatever the return value was from the plotting function,
+#' \code{plot.phylo}, \code{plot.dendrogram} or \code{plot.hclust}.
+#' @method plot_dendrogram igraphHRG
+#' @export
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_full_graph(5) + make_full_graph(5)
+#' hrg <- fit_hrg(g)
+#' plot_dendrogram(hrg)
+#' 
+plot_dendrogram.igraphHRG <- function(x, mode=igraph_opt("dend.plot.type"), ...) {
 
   if (mode=="auto") {
-    value <- tryCatch(suppressWarnings(library("ape", character.only=TRUE,
-                                               logical.return=TRUE,
-                                               warn.conflicts=FALSE,
-                                               quietly=TRUE,
-                                               pos="package:base")),
-                      error=function(e) e)
-    mode <- if (value) "phylo" else "hclust"
+    have_ape <- requireNamespace("ape", quietly = TRUE)
+    mode <- if (have_ape) "phylo" else "hclust"
   }
 
   if (mode=="hclust") {
@@ -310,13 +622,58 @@ hrgPlotDendrogram <- function(x, ...) {
 hrgPlotPhylo <- function(x, colbar=rainbow(11, start=.7, end=.1),
                          edge.color=NULL, use.edge.length=FALSE, ...) {
   vc <- length(x$left)+1
-  phy <- asPhylo(x)
+  phy <- as_phylo(x)
   br <- seq(0,1,length=length(colbar)) ; br[1] <- -1
   cc <- as.integer(cut(x$prob[phy$edge[,1] - vc], breaks=br))
   if (is.null(edge.color)) { edge.color <- colbar[cc] }
   plot(phy, edge.color=edge.color, use.edge.length=use.edge.length, ...)
 }
 
+#' Print a hierarchical random graph model to the screen
+#'
+#' \code{igraphHRG} objects can be printed to the screen in two forms: as
+#' a tree or as a list, depending on the \code{type} argument of the
+#' print function. By default the \code{auto} type is used, which selects
+#' \code{tree} for small graphs and \code{simple} (=list) for bigger
+#' ones. The \code{tree} format looks like
+#'  this: \preformatted{Hierarchical random graph, at level 3:
+#' g1        p=   0  
+#' '- g15    p=0.33  1 
+#'    '- g13 p=0.88  6  3  9  4  2  10 7  5  8 
+#' '- g8     p= 0.5  
+#'    '- g16 p= 0.2  20 14 17 19 11 15 16 13
+#'    '- g5  p=   0  12 18  }
+#' This is a graph with 20 vertices, and the
+#' top three levels of the fitted hierarchical random graph are
+#' printed. The root node of the HRG is always vertex group #1
+#' (\sQuote{\code{g1}} in the the printout). Vertex pairs in the left
+#' subtree of \code{g1} connect to vertices in the right subtree with
+#' probability zero, according to the fitted model. \code{g1} has two
+#' subgroups, \code{g15} and \code{g8}. \code{g15} has a subgroup of a
+#' single vertex (vertex 1), and another larger subgroup that contains
+#' vertices 6, 3, etc. on lower levels, etc.
+#' The \code{plain} printing is simpler and faster to produce, but less
+#' visual: \preformatted{Hierarchical random graph:
+#' g1  p=0.0 -> g12 g10   g2  p=1.0 -> 7 10      g3  p=1.0 -> g18 14    
+#' g4  p=1.0 -> g17 15    g5  p=0.4 -> g15 17    g6  p=0.0 -> 1 4       
+#' g7  p=1.0 -> 11 16     g8  p=0.1 -> g9 3      g9  p=0.3 -> g11 g16   
+#' g10 p=0.2 -> g4 g5     g11 p=1.0 -> g6 5      g12 p=0.8 -> g8 8      
+#' g13 p=0.0 -> g14 9     g14 p=1.0 -> 2 6       g15 p=0.2 -> g19 18    
+#' g16 p=1.0 -> g13 g2    g17 p=0.5 -> g7 13     g18 p=1.0 -> 12 19     
+#' g19 p=0.7 -> g3 20}
+#' It lists the two subgroups of each internal node, in
+#' as many columns as the screen width allows.
+#' 
+#' @param x \code{igraphHRG} object to print.
+#' @param type How to print the dendrogram, see details below.
+#' @param level The number of top levels to print from the dendrogram.
+#' @param ... Additional arguments, not used currently.
+#' @return The hierarchical random graph model itself, invisibly.
+#' 
+#' @method print igraphHRG
+#' @export
+#' @family hierarchical random graph functions
+
 print.igraphHRG <- function(x, type=c("auto", "tree", "plain"),
                             level=3, ...) {
 
@@ -452,8 +809,27 @@ print2.igraphHRG <- function(x, ...) {
   invisible(x)
 }
 
-# TODO: print as a tree
-
+## TODO: print as a tree
+
+#' Print a hierarchical random graph consensus tree to the screen
+#'
+#' Consensus dendrograms (\code{igraphHRGConsensus} objects) are printed
+#' simply by listing the children of each internal node of the
+#' dendrogram: \preformatted{HRG consensus tree:
+#' g1 -> 11 12 13 14 15 16 17 18 19 20
+#' g2 -> 1  2  3  4  5  6  7  8  9  10   
+#' g3 -> g1 g2}
+#' The root of the dendrogram is \code{g3} (because it has no incoming
+#' edges), and it has two subgroups, \code{g1} and \code{g2}.
+#'
+#' @param x \code{igraphHRGConsensus} object to print.
+#' @param ... Ignored.
+#' @return The input object, invisibly, to allow method chaining.
+#'
+#' @method print igraphHRGConsensus
+#' @export
+#' @family hierarchical random graph functions
+ 
 print.igraphHRGConsensus <- function(x, ...) {
   cat("HRG consensus tree:\n")
   n <- length(x$parents) - length(x$weights)
diff --git a/R/igraph-package.R b/R/igraph-package.R
new file mode 100644
index 0000000..88d630f
--- /dev/null
+++ b/R/igraph-package.R
@@ -0,0 +1,190 @@
+
+#' @useDynLib igraph
+#' @import methods
+#' @importFrom magrittr %>%
+#' @export make_bipartite_graph
+#' @export connect
+#' @export make_de_bruijn_graph
+#' @export make_full_bipartite_graph
+#' @export graph_from_adjacency_matrix
+#' @export graph_from_data_frame
+#' @export graph_from_incidence_matrix
+#' @export make_kautz_graph
+#' @export make_line_graph
+#' @export sample_asym_pref
+NULL
+
+#' Magrittr's pipes
+#'
+#' igraph re-exports the \code{\%>\%} operator of magrittr, because
+#' we find it very useful. Please see the documentation in the
+#' \code{magrittr} package.
+#'
+#' @param lhs Left hand side of the pipe.
+#' @param rhs Right hand side of the pipe.
+#' @return Result of applying the right hand side to the
+#'   result of the left hand side.
+#'
+#' @export
+#' @rdname pipe
+#' @examples
+#' make_ring(10) %>%
+#'   add_edges(c(1,6)) %>%
+#'   plot()
+
+`%>%` <- magrittr::`%>%`
+
+#' The igraph package
+#' 
+#' igraph is a library and R package for network analysis.
+#' 
+#' @rdname aaa-igraph-package
+#' @name igraph-package
+#' @aliases igraph-package igraph
+#' @docType package
+#'
+#' @section Introduction:
+#' The main goals of the igraph library is to provide a set of data types
+#' and functions for 1) pain-free implementation of graph algorithms, 2)
+#' fast handling of large graphs, with millions of vertices and edges, 3)
+#' allowing rapid prototyping via high level languages like R.
+#' 
+#' @section Igraph graphs:
+#'   Igraph graphs have a class \sQuote{\code{igraph}}. They are printed to
+#'   the screen in a special format, here is an example, a ring graph
+#'   created using \code{\link{make_ring}}: \preformatted{
+#'     IGRAPH U--- 10 10 -- Ring graph
+#'     + attr: name (g/c), mutual (g/x), circular (g/x)  }
+#'   \sQuote{\code{IGRAPH}} denotes that this is an igraph graph. Then
+#'   come four bits that denote the kind of the graph: the first is
+#'   \sQuote{\code{U}} for undirected and \sQuote{\code{D}} for directed
+#'   graphs. The second is \sQuote{\code{N}} for named graph (i.e. if the
+#'   graph has the \sQuote{\code{name}} vertex attribute set). The third is
+#'   \sQuote{\code{W}} for weighted graphs (i.e. if the
+#'   \sQuote{\code{weight}} edge attribute is set). The fourth is
+#'   \sQuote{\code{B}} for bipartite graphs (i.e. if the
+#'   \sQuote{\code{type}} vertex attribute is set).
+#' 
+#'   Then come two numbers, the number of vertices and the number of edges
+#'   in the graph, and after a double dash, the name of the graph (the
+#'   \sQuote{\code{name}} graph attribute) is printed if present. The
+#'   second line is optional and it contains all the attributes of the
+#'   graph. This graph has a \sQuote{\code{name}} graph attribute, of type
+#'   character, and two other graph attributes called
+#'   \sQuote{\code{mutual}} and \sQuote{\code{circular}}, of a complex
+#'   type. A complex type is simply anything that is not numeric or
+#'   character. See the documentation of \code{\link{print.igraph}} for
+#'   details.
+#' 
+#'   If you want to see the edges of the graph as well, then use the
+#'   \code{\link{str.igraph}} function, it is of course enough to type
+#'   \code{str} instead of \code{str.igraph}: \preformatted{    > str(g)
+#'     IGRAPH U--- 10 10 -- Ring graph
+#'     + attr: name (g/c), mutual (g/x), circular (g/x)
+#'     + edges:
+#'      [1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 6-- 7 7-- 8 8-- 9 9--10 1--10 }
+#'
+#' @section Creating graphs:
+#'   There are many functions in igraph for creating graphs, both
+#'   deterministic and stochastic; stochastic graph constructors are called
+#'   \sQuote{games}.
+#' 
+#'   To create small graphs with a given structure probably the
+#'   \code{\link{graph_from_literal}} function is easiest. It uses R's formula
+#'   interface, its manual page contains many examples. Another option is
+#'   \code{\link{graph}}, which takes numeric vertex ids directly.
+#'   \code{\link{graph.atlas}} creates graph from the Graph Atlas,
+#'   \code{\link{make_graph}} can create some special graphs.
+#' 
+#'   To create graphs from field data, \code{\link{graph_from_edgelist}},
+#'   \code{\link{graph_from_data_frame}} and \code{\link{graph_from_adjacency_matrix}} are
+#'   probably the best choices.
+#' 
+#'   The igraph package includes some classic random graphs like the
+#'   Erdos-Renyi GNP and GNM graphs (\code{\link{sample_gnp}}, \code{\link{sample_gnm}}) and
+#'   some recent  popular models, like preferential attachment
+#'   (\code{\link{sample_pa}}) and the small-world model
+#'   (\code{\link{sample_smallworld}}). 
+#'
+#' @section Vertex and edge IDs:
+#'   Vertices and edges have numerical vertex ids in igraph. Vertex ids are
+#'   always consecutive and they start with one. I.e. for a graph with
+#'   \eqn{n} vertices the vertex ids are between \eqn{1} and
+#'   \eqn{n}. If some operation changes the number of vertices in the
+#'   graphs, e.g. a subgraph is created via \code{\link{induced_subgraph}}, then
+#'   the vertices are renumbered to satisfty this criteria.
+#' 
+#'   The same is true for the edges as well, edge ids are always between
+#'   one and \eqn{m}, the total number of edges in the graph.
+#' 
+#'   It is often desirable to follow vertices along a number of graph
+#'   operations, and vertex ids don't allow this because of the
+#'   renumbering. The solution is to assign attributes to the
+#'   vertices. These are kept by all operations, if possible. See more
+#'   about attributes in the next section.
+#'
+#' @section Attributes:
+#'   In igraph it is possible to assign attributes to the vertices or edges
+#'   of a graph, or to the graph itself. igraph provides flexible
+#'   constructs for selecting a set of vertices or edges based on their
+#'   attribute values, see \code{\link{vertex_attr}},
+#'   \code{\link{V}} and \code{\link{E}} for details.
+#' 
+#'   Some vertex/edge/graph attributes are treated specially. One of them
+#'   is the \sQuote{name} attribute. This is used for printing the graph
+#'   instead of the numerical ids, if it exists. Vertex names can also be
+#'   used to specify a vector or set of vertices, in all igraph
+#'   functions. E.g. \code{\link{degree}} has a \code{v} argument
+#'   that gives the vertices for which the degree is calculated. This
+#'   argument can be given as a character vector of vertex names.
+#' 
+#'   Edges can also have a \sQuote{name} attribute, and this is treated
+#'   specially as well. Just like for vertices, edges can also be selected
+#'   based on their names, e.g. in the \code{\link{delete_edges}} and
+#'   other functions.
+#' 
+#'   We note here, that vertex names can also be used to select edges.
+#'   The form \sQuote{\code{from|to}}, where \sQuote{\code{from}} and
+#'   \sQuote{\code{to}} are vertex names, select a single, possibly
+#'   directed, edge going from \sQuote{\code{from}} to
+#'   \sQuote{\code{to}}. The two forms can also be mixed in the same edge
+#'   selector.
+#'   
+#'   Other attributes define visualization parameters, see
+#'   \code{\link{igraph.plotting}} for details.
+#' 
+#'   Attribute values can be set to any R object, but note that storing the
+#'   graph in some file formats might result the loss of complex attribute
+#'   values. All attribute values are preserved if you use
+#'   \code{\link[base]{save}} and \code{\link[base]{load}} to store/retrieve your
+#'   graphs.
+#'
+#' @section Visualization:
+#'   igraph provides three different ways for visualization. The first is
+#'   the \code{\link{plot.igraph}} function. (Actually you don't need to
+#'   write \code{plot.igraph}, \code{plot} is enough. This function uses
+#'   regular R graphics and can be used with any R device.
+#' 
+#'   The second function is \code{\link{tkplot}}, which uses a Tk GUI for
+#'   basic interactive graph manipulation. (Tk is quite resource hungry, so
+#'   don't try this for very large graphs.)
+#' 
+#'   The third way requires the \code{rgl} package and uses OpenGL. See the
+#'   \code{\link{rglplot}} function for the details.
+#' 
+#'   Make sure you read \code{\link{igraph.plotting}} before you start
+#'   plotting your graphs.
+#'
+#' @section File formats:
+#'   igraph can handle various graph file formats, usually both for reading
+#'   and writing. We suggest that you use the GraphML file format for your
+#'   graphs, except if the graphs are too big. For big graphs a simpler
+#'   format is recommended. See \code{\link{read_graph}} and
+#'   \code{\link{write_graph}} for details.
+#'
+#' @section Further information:
+#'   The igraph homepage is at \url{http://igraph.org}.
+#'   See especially the documentation section. Join the igraph-help mailing
+#'   list if you have questions or comments.
+
+ NULL
diff --git a/R/incidence.R b/R/incidence.R
new file mode 100644
index 0000000..96c85b4
--- /dev/null
+++ b/R/incidence.R
@@ -0,0 +1,242 @@
+
+## ----------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2005-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------
+
+graph.incidence.sparse <- function(incidence, directed, mode, multiple,
+                                   weighted) {
+  n1 <- nrow(incidence)
+  n2 <- ncol(incidence)
+  el <- Matrix::summary(incidence)
+  ## el <- summary(incidence)
+  el[,2] <- el[,2] + n1
+
+  if (!is.null(weighted)) {
+
+    if (is.logical(weighted) && weighted) {
+      weighted <- "weight"
+    }
+    if (!is.character(weighted)) {
+      stop("invalid value supplied for `weighted' argument, please see docs.")
+    }
+
+    if (!directed || mode==1) {
+      ## nothing do to
+    } else if (mode==2) {
+      el[,1:2] <- el[,c(2,1)]
+    } else if (mode==3) {
+      el <- rbind(el, el[,c(2,1,3)])
+    }
+
+    res <- make_empty_graph(n=n1+n2, directed=directed)
+    weight <- list(el[,3])
+    names(weight) <- weighted
+    res <- add_edges(res, edges=t(as.matrix(el[,1:2])), attr=weight)
+
+  } else {
+
+    if (multiple) {
+      el[,3] <- ceiling(el[,3])
+      el[,3][ el[,3] < 0 ] <- 0
+    } else {
+      el[,3] <- el[,3] != 0
+    }
+
+    if (!directed || mode==1) {
+      ## nothing do to
+    } else if (mode==2) {
+      el[,1:2] <- el[,c(2,1)]
+    } else if (mode==3) {
+      el <- rbind(el, el[,c(2,1,3)])
+    }
+
+    edges <- unlist(apply(el, 1, function(x) rep(unname(x[1:2]), x[3])))
+    res <- graph(n=n1+n2, edges, directed=directed)
+  }
+
+  set_vertex_attr(res, "type", value=c(rep(FALSE, n1), rep(TRUE, n2)))
+}
+
+graph.incidence.dense <- function(incidence, directed, mode, multiple,
+                                  weighted) {
+
+  if (!is.null(weighted)) {
+    if (is.logical(weighted) && weighted) {
+      weighted <- "weight"
+    }
+    if (!is.character(weighted)) {
+      stop("invalid value supplied for `weighted' argument, please see docs.")
+    }
+
+    n1 <- nrow(incidence)
+    n2 <- ncol(incidence)
+    no.edges <- sum(incidence != 0)
+    if (directed && mode==3) { no.edges <- no.edges * 2 }
+    edges <- numeric(2*no.edges)
+    weight <- numeric(no.edges)
+    ptr <- 1
+    for (i in seq_len(nrow(incidence))) {
+      for (j in seq_len(ncol(incidence))) {
+        if (incidence[i,j] != 0) {
+          if (!directed || mode==1) {
+            edges[2*ptr-1] <- i
+            edges[2*ptr] <- n1+j
+            weight[ptr] <- incidence[i,j]
+            ptr <- ptr + 1
+          } else if (mode==2) {
+            edges[2*ptr-1] <- n1+j
+            edges[2*ptr] <- i
+            weight[ptr] <- incidence[i,j]
+            ptr <- ptr + 1
+          } else if (mode==3) {
+            edges[2*ptr-1] <- i
+            edges[2*ptr] <- n1+j
+            weight[ptr] <- incidence[i,j]
+            ptr <- ptr + 1
+            edges[2*ptr-1] <- n1+j
+            edges[2*ptr] <- i
+          }
+        }
+      }
+    }
+    res <- make_empty_graph(n=n1+n2, directed=directed)
+    weight <- list(weight)
+    names(weight) <- weighted
+    res <- add_edges(res, edges, attr=weight)
+    res <- set_vertex_attr(res, "type",
+                                value=c(rep(FALSE, n1), rep(TRUE, n2)))
+
+  } else {
+
+    mode(incidence) <- "double"
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    ## Function call
+    res <- .Call("R_igraph_incidence", incidence, directed, mode, multiple,
+                 PACKAGE="igraph")
+    res <- set_vertex_attr(res$graph, "type", value=res$types)
+
+  }
+
+  res
+}
+
+#' Create graphs from an incidence matrix
+#'
+#' \code{graph_from_incidence_matrix} creates a bipartite igraph graph from an incidence
+#' matrix.
+#'
+#' Bipartite graphs have a \sQuote{\code{type}} vertex attribute in igraph,
+#' this is boolean and \code{FALSE} for the vertices of the first kind and
+#' \code{TRUE} for vertices of the second kind.
+#'
+#' \code{graph_from_incidence_matrix} can operate in two modes, depending on the
+#' \code{multiple} argument. If it is \code{FALSE} then a single edge is
+#' created for every non-zero element in the incidence matrix. If
+#' \code{multiple} is \code{TRUE}, then the matrix elements are rounded up to
+#' the closest non-negative integer to get the number of edges to create
+#' between a pair of vertices.
+#'
+#' @aliases graph.incidence
+#' @param incidence The input incidence matrix. It can also be a sparse matrix
+#' from the \code{Matrix} package.
+#' @param directed Logical scalar, whether to create a directed graph.
+#' @param mode A character constant, defines the direction of the edges in
+#' directed graphs, ignored for undirected graphs. If \sQuote{\code{out}}, then
+#' edges go from vertices of the first kind (corresponding to rows in the
+#' incidence matrix) to vertices of the second kind (columns in the incidence
+#' matrix). If \sQuote{\code{in}}, then the opposite direction is used. If
+#' \sQuote{\code{all}} or \sQuote{\code{total}}, then mutual edges are created.
+#' @param multiple Logical scalar, specifies how to interpret the matrix
+#' elements. See details below.
+#' @param weighted This argument specifies whether to create a weighted graph
+#' from the incidence matrix. If it is \code{NULL} then an unweighted graph is
+#' created and the \code{multiple} argument is used to determine the edges of
+#' the graph. If it is a character constant then for every non-zero matrix
+#' entry an edge is created and the value of the entry is added as an edge
+#' attribute named by the \code{weighted} argument. If it is \code{TRUE} then a
+#' weighted graph is created and the name of the edge attribute will be
+#' \sQuote{\code{weight}}.
+#' @param add.names A character constant, \code{NA} or \code{NULL}.
+#' \code{graph_from_incidence_matrix} can add the row and column names of the incidence
+#' matrix as vertex attributes. If this argument is \code{NULL} (the default)
+#' and the incidence matrix has both row and column names, then these are added
+#' as the \sQuote{\code{name}} vertex attribute. If you want a different vertex
+#' attribute for this, then give the name of the attributes as a character
+#' string. If this argument is \code{NA}, then no vertex attributes (other than
+#' type) will be added.
+#' @return A bipartite igraph graph. In other words, an igraph graph that has a
+#' vertex attribute \code{type}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{make_bipartite_graph}} for another way to create bipartite
+#' graphs
+#' @keywords graphs
+#' @examples
+#'
+#' inc <- matrix(sample(0:1, 15, repl=TRUE), 3, 5)
+#' colnames(inc) <- letters[1:5]
+#' rownames(inc) <- LETTERS[1:3]
+#' graph_from_incidence_matrix(inc)
+#'
+graph_from_incidence_matrix <- function(incidence, directed=FALSE,
+                            mode=c("all", "out", "in", "total"),
+                            multiple=FALSE, weighted=NULL,
+                            add.names=NULL) {
+  # Argument checks
+  directed <- as.logical(directed)
+  mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
+  multiple <- as.logical(multiple)
+
+  if (inherits(incidence, "Matrix")) {
+    res <- graph.incidence.sparse(incidence, directed=directed,
+                                  mode=mode, multiple=multiple,
+                                  weighted=weighted)
+  } else {
+    incidence <- as.matrix(incidence)
+    res <- graph.incidence.dense(incidence, directed=directed, mode=mode,
+                                 multiple=multiple, weighted=weighted)
+  }
+
+  ## Add names
+  if (is.null(add.names)) {
+    if (!is.null(rownames(incidence)) && !is.null(colnames(incidence))) {
+      add.names <- "name"
+    } else {
+      add.names <- NA
+    }
+  } else if (!is.na(add.names)) {
+    if (is.null(rownames(incidence)) || is.null(colnames(incidence))) {
+      warning("Cannot add row- and column names, at least one of them is missing")
+      add.names <- NA
+    }
+  }
+  if (!is.na(add.names)) {
+    res <- set_vertex_attr(res, add.names,
+                                value=c(rownames(incidence), colnames(incidence)))
+  }
+  res
+}
+
+#' @rdname graph_from_incidence_matrix
+#' @param ... Passed to \code{graph_from_incidence_matrix}.
+#' @export
+
+from_incidence_matrix <- function(...) constructor_spec(graph_from_incidence_matrix, ...)
diff --git a/R/indexing.R b/R/indexing.R
index e0884cb..4f934b4 100644
--- a/R/indexing.R
+++ b/R/indexing.R
@@ -55,10 +55,108 @@
 #               create an edge sequence
 
 
+#' Query and manipulate a graph as it were an adjacency matrix
+#'
+#' @details
+#' The single bracket indexes the (possibly weighted) adjacency matrix of
+#' the graph. Here is what you can do with it:
+#'
+#' \enumerate{
+#' \item Check whether there is an edge between two vertices (\eqn{v}
+#'   and \eqn{w}) in the graph: \preformatted{  graph[v, w]}
+#'    A numeric scalar is returned, one if the edge exists, zero
+#'     otherwise.
+#'   \item Extract the (sparse) adjacency matrix of the graph, or part of
+#'     it: \preformatted{  graph[]
+#' graph[1:3,5:6]
+#' graph[c(1,3,5),]}
+#'     The first variants returns the full adjacency matrix, the other
+#'     two return part of it.
+#'   \item The \code{from} and \code{to} arguments can be used to check
+#'     the existence of many edges. In this case, both \code{from} and
+#'     \code{to} must be present and they must have the same length. They
+#'     must contain vertex ids or names. A numeric vector is returned, of
+#'     the same length as \code{from} and \code{to}, it contains ones
+#'     for existing edges edges and zeros for non-existing ones.
+#'     Example: \preformatted{  graph[from=1:3, to=c(2,3,5)]}.
+#'   \item For weighted graphs, the \code{[} operator returns the edge
+#'     weights. For non-esistent edges zero weights are returned. Other
+#'     edge attributes can be queried as well, by giving the \code{attr}
+#'     argument. 
+#'   \item Querying edge ids instead of the existance of edges or edge
+#'     attributes. E.g. \preformatted{  graph[1, 2, edges=TRUE]}
+#'     returns the id of the edge between vertices 1 and 2, or zero if
+#'     there is no such edge.
+#'   \item Adding one or more edges to a graph. For this the element(s) of
+#'     the imaginary adjacency matrix must be set to a non-zero numeric
+#'     value (or \code{TRUE}): \preformatted{  graph[1, 2] <- 1
+#' graph[1:3,1] <- 1
+#' graph[from=1:3, to=c(2,3,5)] <- TRUE}
+#'     This does not affect edges that are already present in the graph,
+#'     i.e. no multiple edges are created.
+#'   \item Adding weighted edges to a graph. The \code{attr} argument
+#'     contains the name of the edge attribute to set, so it does not
+#'     have to be \sQuote{weight}: \preformatted{  graph[1, 2, attr="weight"]<- 5
+#' graph[from=1:3, to=c(2,3,5)] <- c(1,-1,4)}
+#'     If an edge is already present in the network, then only its
+#'     weigths or other attribute are updated. If the graph is already
+#'     weighted, then the \code{attr="weight"} setting is implicit, and
+#'     one does not need to give it explicitly.
+#'   \item Deleting edges. The replacement syntax allow the deletion of
+#'     edges, by specifying \code{FALSE} or \code{NULL} as the
+#'     replacement value: \preformatted{  graph[v, w] <- FALSE}
+#'     removes the edge from vertex \eqn{v} to vertex \eqn{w}.
+#'     As this can be used to delete edges between two sets of vertices,
+#'     either pairwise: \preformatted{  graph[from=v, to=w] <- FALSE}
+#'     or not: \preformatted{  graph[v, w] <- FALSE }
+#'     if \eqn{v} and \eqn{w} are vectors of edge ids or names.
+#' }
+#'
+#' \sQuote{\code{[}} allows logical indices and negative indices as well,
+#' with the usual R semantics. E.g. \preformatted{  graph[degree(graph)==0, 1] <- 1}
+#' adds an edge from every isolate vertex to vertex one,
+#' and \preformatted{  G <- make_empty_graph(10)
+#' G[-1,1] <- TRUE}
+#'  creates a star graph.
+#'
+#' Of course, the indexing operators support vertex names,
+#' so instead of a numeric vertex id a vertex can also be given to
+#' \sQuote{\code{[}} and \sQuote{\code{[[}}.
+#' 
+#' @param x The graph.
+#' @param i Index. Vertex ids or names or logical vectors. See details
+#'   below.
+#' @param j Index. Vertex ids or names or logical vectors. See details
+#'   below.
+#' @param ... Currently ignored.
+#' @param from A numeric or character vector giving vertex ids or
+#'   names. Together with the \code{to} argument, it can be used to
+#'   query/set a sequence of edges. See details below. This argument cannot
+#'   be present together with any of the \code{i} and \code{j} arguments
+#'   and if it is present, then the \code{to} argument must be present as
+#'   well.
+#' @param to A numeric or character vector giving vertex ids or
+#'   names. Together with the \code{from} argument, it can be used to
+#'   query/set a sequence of edges. See details below. This argument cannot
+#'   be present together with any of the \code{i} and \code{j} arguments
+#'   and if it is present, then the \code{from} argument must be present as
+#'   well.
+#' @param sparse Logical scalar, whether to return sparse matrices.
+#' @param edges Logical scalar, whether to return edge ids.
+#' @param drop Ignored.
+#' @param attr If not \code{NULL}, then it should be the name of an edge
+#'   attribute. This attribute is queried and returned.
+#' @return A scalar or matrix. See details below.
+#'
+#' @family structural queries
+#' 
+#' @method [ igraph
+#' @export
+
 `[.igraph` <- function(x, i, j, ..., from, to,
-                       sparse=getIgraphOpt("sparsematrices"),
+                       sparse=igraph_opt("sparsematrices"),
                        edges=FALSE, drop=TRUE,
-                       attr=if (is.weighted(x)) "weight" else NULL) {
+                       attr=if (is_weighted(x)) "weight" else NULL) {
   ## TODO: make it faster, don't need the whole matrix usually
 
   ################################################################
@@ -91,47 +189,119 @@
       ## nop
     } else if (!is.null(attr)) {
       if (any(res!=0)) {
-        res[res!=0] <- get.edge.attribute(x, attr, res[res!=0])
+        res[res!=0] <- edge_attr(x, attr, res[res!=0])
       }
     } else {
       res <- as.logical(res)+0
     }
     res
   } else if (missing(i) && missing(j)) {
-    get.adjacency(x, sparse=sparse, attr=attr, edges=edges)
+    as_adj(x, sparse=sparse, attr=attr, edges=edges)
   } else if (missing(j)) {
-    get.adjacency(x, sparse=sparse, attr=attr, edges=edges)[i,,drop=drop]
+    as_adj(x, sparse=sparse, attr=attr, edges=edges)[i,,drop=drop]
   } else if (missing(i)) {
-    get.adjacency(x, sparse=sparse, attr=attr, edges=edges)[,j,drop=drop]
+    as_adj(x, sparse=sparse, attr=attr, edges=edges)[,j,drop=drop]
   } else {
-    get.adjacency(x, sparse=sparse, attr=attr, edges=edges)[i,j,drop=drop]
+    as_adj(x, sparse=sparse, attr=attr, edges=edges)[i,j,drop=drop]
   }
 }
 
-`[[.igraph` <- function(x, i, j, ..., directed=TRUE,
+#' Query and manipulate a graph as it were an adjacency list
+#'
+#' @details
+#' The double bracket operator indexes the (imaginary) adjacency list
+#' of the graph. This can used for the following operations:
+#' \enumerate{
+#'   \item Querying the adjacent vertices for one or more
+#'     vertices: \preformatted{  graph[[1:3,]]
+#' graph[[,1:3]]}
+#'     The first form gives the successors, the second the predessors
+#'     or the 1:3 vertices. (For undirected graphs they are equivalent.)
+#'   \item Querying the incident edges for one or more vertices,
+#'     if the \code{edges} argument is set to
+#'     \code{TRUE}: \preformatted{  graph[[1:3, , edges=TRUE]]
+#' graph[[, 1:3, edges=TRUE]]}
+#'   \item Querying the edge ids between two sets or vertices,
+#'     if both indices are used. E.g. \preformatted{  graph[[v, w, edges=TRUE]]}
+#'     gives the edge ids of all the edges that exist from vertices
+#'     \eqn{v} to vertices \eqn{w}.
+#'  }
+#'
+#' The alternative argument names \code{from} and \code{to} can be used
+#' instead of the usual \code{i} and \code{j}, to make the code more
+#' readable: \preformatted{ graph[[from = 1:3]]
+#' graph[[from = v, to = w, edges = TRUE]]}
+#'
+#' \sQuote{\code{[[}} operators allows logical indices and negative indices
+#' as well, with the usual R semantics.
+#'
+#' Vertex names are also supported, so instead of a numeric vertex id a
+#' vertex can also be given to \sQuote{\code{[}} and \sQuote{\code{[[}}.
+#' 
+#' @param x The graph.
+#' @param i Index, integer, character or logical, see details below.
+#' @param j Index, integer, character or logical, see details below.
+#' @param from A numeric or character vector giving vertex ids or
+#'   names. Together with the \code{to} argument, it can be used to
+#'   query/set a sequence of edges. See details below. This argument cannot
+#'   be present together with any of the \code{i} and \code{j} arguments
+#'   and if it is present, then the \code{to} argument must be present as
+#'   well.
+#' @param to A numeric or character vector giving vertex ids or
+#'   names. Together with the \code{from} argument, it can be used to
+#'   query/set a sequence of edges. See details below. This argument cannot
+#'   be present together with any of the \code{i} and \code{j} arguments
+#'   and if it is present, then the \code{from} argument must be present as
+#'   well.
+#' @param ... Additional arguments are not used currently.
+#' @param directed Logical scalar, whether to consider edge directions
+#'   in directed graphs. It is ignored for undirected graphs.
+#' @param edges Logical scalar, whether to return edge ids.
+#' @param exact Ignored.
+#'
+#' @family structural queries
+#'
+#' @method [[ igraph
+#' @export
+
+`[[.igraph` <- function(x, i, j, from, to, ..., directed=TRUE,
                         edges=FALSE, exact=TRUE) {
-  ## TODO: make it faster, don't need the whole list usually
-  getfun <- if (edges) get.adjedgelist else get.adjlist
+
+  getfun <- if (edges) as_adj_edge_list else as_adj_list
+
+  if (!missing(i) && !missing(from)) stop("Cannot give both 'i' and 'from'")
+  if (!missing(j) && !missing(to)) stop("Cannot give both 'j' and 'to'")
+  if (missing(i) && ! missing(from)) i <- from
+  if (missing(j) && ! missing(to)) j <- to
+
   if (missing(i) && missing(j)) {
     mode <- if (directed) "out" else "all"
     getfun(x, mode=mode)
   } else if (missing(j)) {
     mode <- if (directed) "out" else "all"
-    getfun(x, mode=mode)[i]
+    if (!edges) {
+      adjacent_vertices(x, i, mode = if (directed) "out" else "all")
+    } else {
+      incident_edges(x, i, mode = if (directed) "out" else "all")
+    }
   } else if (missing(i)) {
-    mode <- if (directed) "in" else "all"
-    getfun(x, mode=mode)[j]
+    if (!edges) {
+      adjacent_vertices(x, j, mode = if (directed) "in" else "all")
+    } else {
+      incident_edges(x, j, mode = if (directed) "in" else "all")
+    }
   } else {
-    mode <- if (directed) "out" else "all"
-    i <- as.igraph.vs(x, i)
-    j <- as.igraph.vs(x, j)
     if (!edges) {
-      lapply(getfun(x, mode=mode)[i], intersect, j)
+      mode <- if (directed) "out" else "all"
+      lapply(adjacent_vertices(x, i, mode = mode), intersection, V(x)[j])
     } else {
-      ee <- get.adjedgelist(x, mode=mode)[i]
+      i <- as.igraph.vs(x, i)
+      j <- as.igraph.vs(x, j)
+      mode <- if (directed) "out" else "all"
+      ee <- incident_edges(x, i, mode = mode)
       lapply(seq_along(i), function(yy) {
         from <- i[yy]
-        el <- get.edges(x, ee[[yy]])
+        el <- ends(x, ee[[yy]], names = FALSE)
         other <- ifelse(el[,1]==from, el[,2], el[,1])
         ee[[yy]][other %in% j]
       })
@@ -140,8 +310,12 @@
   }
 }
 
+#' @method [<- igraph
+#' @family functions for manipulating graph structure
+#' @export
+
 `[<-.igraph` <- function(x, i, j, ..., from, to,
-                         attr=if (is.weighted(x)) "weight" else NULL,
+                         attr=if (is_weighted(x)) "weight" else NULL,
                          value) {
   ## TODO: rewrite this in C to make it faster
 
@@ -182,16 +356,16 @@
         (is.null(attr) && is.numeric(value) && value==0)) {
       ## Delete edges
       todel <- x[from=from, to=to, ..., edges=TRUE]
-      x <- delete.edges(x, todel)
+      x <- delete_edges(x, todel)
     } else {
       ## Addition or update of an attribute (or both)
       ids <- x[from=from, to=to, ..., edges=TRUE]
       if (any(ids==0)) {
-        x <- add.edges(x, rbind(from[ids==0], to[ids==0]))
+        x <- add_edges(x, rbind(from[ids==0], to[ids==0]))
       }
       if (!is.null(attr)) {
         ids <- x[from=from, to=to, ..., edges=TRUE]
-        x <- set.edge.attribute(x, attr, ids, value=value)
+        x <- set_edge_attr(x, attr, ids, value=value)
       }
     }
   } else if (is.null(value) ||
@@ -207,15 +381,15 @@
     } else {
       todel <- unlist(x[[i, j, ..., edges=TRUE]])
     }
-    x <- delete.edges(x, todel)
+    x <- delete_edges(x, todel)
   } else {
     ## Addition or update of an attribute (or both)
     i <- if (missing(i)) as.numeric(V(x)) else as.igraph.vs(x, i)
     j <- if (missing(j)) as.numeric(V(x)) else as.igraph.vs(x, j)
     if (length(i) != 0 && length(j) != 0) {
       ## Existing edges, and their endpoints
-      exe <- x[[i, j, ..., edges=TRUE]]
-      exv <- x[[i, j, ...]]
+      exe <- lapply(x[[i, j, ..., edges=TRUE]], as.vector)
+      exv <- lapply(x[[i, j, ...]], as.vector)
       toadd <- unlist(lapply(seq_along(exv), function(idx) {
         to <- setdiff(j, exv[[idx]])
         if (length(to!=0)) {
@@ -226,11 +400,11 @@
       }))
       ## Do the changes
       if (is.null(attr)) {
-        x <- add.edges(x, toadd)
+        x <- add_edges(x, toadd)
       } else {
-        x <- add.edges(x, toadd, attr=structure(list(value), names=attr))
-        toupdate <- unlist(x[[i, j, ..., edges=TRUE]])
-        x <- set.edge.attribute(x, attr, toupdate, value)
+        x <- add_edges(x, toadd, attr=structure(list(value), names=attr))
+        toupdate <- unlist(exe)
+        x <- set_edge_attr(x, attr, toupdate, value)
       }
     }    
   }
diff --git a/R/interface.R b/R/interface.R
index e90ae86..8eb478c 100644
--- a/R/interface.R
+++ b/R/interface.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -24,8 +23,42 @@
 # Structure building
 ###################################################################
 
-add.edges <- function(graph, edges, ..., attr=list()) {
-  if (!is.igraph(graph)) {
+#' Add edges to a graph
+#'
+#' The new edges are given as a vertex sequence, e.g. internal
+#' numeric vertex ids, or vertex names. The first edge points from
+#' \code{edges[1]} to \code{edges[2]}, the second from \code{edges[3]}
+#' to \code{edges[4]}, etc.
+#' 
+#' If attributes are supplied, and they are not present in the graph,
+#' their values for the original edges of the graph are set to \code{NA}.
+#' 
+#' @param graph The input graph
+#' @param edges The edges to add, a vertex sequence with even number
+#'   of vertices. 
+#' @param ... Additional arguments, they must be named,
+#'   and they will be added as edge attributes, for the newly added
+#'   edges. See also details below.
+#' @param attr A named list, its elements will be added
+#'   as edge attributes, for the newly added edges. See also details
+#'   below.
+#' @return The graph, with the edges (and attributes) added.
+#'
+#' @export
+#'
+#' @aliases add.edges
+#' @family functions for manipulating graph structure
+#' 
+#' @examples
+#' g <- make_empty_graph(n = 5) %>%
+#'   add_edges(c(1,2, 2,3, 3,4, 4,5)) %>%
+#'   set_edge_attr("color", value = "red") %>%
+#'   add_edges(c(5,1), color = "green")
+#' E(g)[[]]
+#' plot(g)
+
+add_edges <- function(graph, edges, ..., attr = list()) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -54,8 +87,37 @@ add.edges <- function(graph, edges, ..., attr=list()) {
   .Call("R_igraph_mybracket2_set", graph, 9L, 4L, eattrs, PACKAGE="igraph")
 }
 
-add.vertices <- function(graph, nv, ..., attr=list()) {
-  if (!is.igraph(graph)) {
+#' Add vertices to a graph
+#' 
+#' If attributes are supplied, and they are not present in the graph,
+#' their values for the original vertices of the graph are set to
+#' \code{NA}.
+#'
+#' @param graph The input graph.
+#' @param nv The number of vertices to add.
+#' @param ... Additional arguments, they must be named,
+#'   and they will be added as vertex attributes, for the newly added
+#'   vertices. See also details below.
+#' @param attr A named list, its elements will be added
+#'   as vertex attributes, for the newly added vertices. See also details
+#'   below.
+#' @return The graph, with the vertices (and attributes) added.
+#'
+#' @aliases add.vertices
+#' @family functions for manipulating graph structure
+#' 
+#' @export
+#' @examples
+#' g <- make_empty_graph() %>%
+#'   add_vertices(3, color = "red") %>%
+#'   add_vertices(2, color = "green") %>%
+#'   add_edges(c(1,2, 2,3, 3,4, 4,5))
+#' g
+#' V(g)[[]]
+#' plot(g)
+
+add_vertices <- function(graph, nv, ..., attr=list()) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -84,8 +146,27 @@ add.vertices <- function(graph, nv, ..., attr=list()) {
   .Call("R_igraph_mybracket2_set", graph, 9L, 3L, vattrs, PACKAGE="igraph")
 }
 
-delete.edges <- function(graph, edges) {
-  if (!is.igraph(graph)) {
+#' Delete edges from a graph
+#'
+#' @param graph The input graph.
+#' @param edges The edges to remove, specified as an edge sequence.
+#' @return The graph, with the edges removed.
+#'
+#' @aliases delete.edges
+#' @family functions for manipulating graph structure
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   delete_edges(seq(1, 9, by = 2))
+#' g
+#'
+#' g <- make_ring(10) %>%
+#'   delete_edges("10|1")
+#' g
+
+delete_edges <- function(graph, edges) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -93,8 +174,29 @@ delete.edges <- function(graph, edges) {
         PACKAGE="igraph")
 }
 
-delete.vertices <- function(graph, v) {
-  if (!is.igraph(graph)) {
+#' Delete vertices from a graph
+#' 
+#' @param graph The input graph.
+#' @param v The vertices to remove, a vertex sequence.
+#' @return The graph, with the vertices removed.
+#'
+#' @aliases delete.vertices
+#' @family functions for manipulating graph structure
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10])
+#' g
+#' V(g)
+#' 
+#' g2 <- delete_vertices(g, c(1,5)) %>%
+#'   delete_vertices("B")
+#' g2
+#' V(g2)
+
+delete_vertices <- function(graph, v) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -105,35 +207,95 @@ delete.vertices <- function(graph, v) {
 ###################################################################
 # Structure query
 ###################################################################
-  
-ecount <- function(graph) {
-  if (!is.igraph(graph)) {
+
+#' The size of the graph (number of edges)
+#'
+#' \code{ecount} of an alias of this function.
+#' 
+#' @param graph The graph.
+#' @return Numeric scalar, the number of edges.
+#'
+#' @aliases ecount
+#' @family structural queries
+#' 
+#' @export
+#' @examples
+#' g <- sample_gnp(100, 2/100)
+#' gsize(g)
+#' 
+#' # Number of edges in a G(n,p) graph
+#' replicate(100, sample_gnp(10, 1/2), simplify = FALSE) %>%
+#'   vapply(gsize, 0) %>%
+#'   hist()
+
+gsize <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_ecount", graph,
         PACKAGE="igraph")
 }
- 
-neighbors <- function(graph, v, mode=1) {
-  if (!is.igraph(graph)) {
+
+#' Neighboring (adjacent) vertices in a graph
+#'
+#' A vertex is a neighbor of another one (in other words, the two
+#' vertices are adjacent), if they are incident to the same edge.
+#'
+#' @param graph The input graph.
+#' @param v The vertex of which the adjacent vertices are queried.
+#' @param mode Whether to query outgoing (\sQuote{out}), incoming
+#'   (\sQuote{in}) edges, or both types (\sQuote{all}). This is
+#'   ignored for undirected graphs.
+#' @return A vertex sequence containing the neighbors of the input vertex.
+#'
+#' @family structural queries
+#' 
+#' @export
+#' @examples
+#' g <- make_graph("Zachary")
+#' n1 <- neighbors(g, 1)
+#' n34 <- neighbors(g, 34)
+#' intersection(n1, n34)
+
+neighbors <- function(graph, v, mode = c("out", "in", "all", "total")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   if (is.character(mode)) {
+    mode <- igraph.match.arg(mode)
     mode <- switch(mode, "out"=1, "in"=2, "all"=3, "total"=3)
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_neighbors", graph, as.igraph.vs(graph, v)-1,
                as.numeric(mode),
                PACKAGE="igraph")
-  res+1
+  V(graph)[res + 1]
 }
 
+#' Incident edges of a vertex in a graph
+#'
+#' @param graph The input graph.
+#' @param v The vertex of which the indicent edges are queried.
+#' @param mode Whether to query outgoing (\sQuote{out}), incoming
+#'   (\sQuote{in}) edges, or both types (\sQuote{all}). This is
+#'   ignored for undirected graphs.
+#' @return An edge sequence containing the incident edges of
+#'   the input vertex.
+#'
+#' @family structural queries
+#'
+#' @export
+#' @examples
+#' g <- make_graph("Zachary")
+#' incident(g, 1)
+#' incident(g, 34)
+
 incident <- function(graph, v, mode=c("all", "out", "in", "total")) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  if (is.directed(graph)) {
+  if (is_directed(graph)) {
     mode <- igraph.match.arg(mode)
     mode <- switch(mode, "out"=1, "in"=2, "all"=3, "total"=3)
   } else {
@@ -142,12 +304,31 @@ incident <- function(graph, v, mode=c("all", "out", "in", "total")) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_incident", graph, as.igraph.vs(graph, v)-1,
                as.numeric(mode),
-               PACKAGE="igraph")
-  res+1
+               PACKAGE="igraph") + 1L
+
+  if (igraph_opt("return.vs.es")) res <- create_es(graph, res)
+
+  res
 }  
 
-is.directed <- function(graph) {
-  if (!is.igraph(graph)) {
+#' Check whether a graph is directed
+#'
+#' @param graph The input graph
+#' @return Logical scalar, whether the graph is directed.
+#'
+#' @aliases is.directed
+#' @family structural queries
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' is_directed(g)
+#'
+#' g2 <- make_ring(10, directed = TRUE)
+#' is_directed(g2)
+
+is_directed <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -155,18 +336,100 @@ is.directed <- function(graph) {
         PACKAGE="igraph")
 }
 
-get.edges <- function(graph, es) {
-  if (!is.igraph(graph)) {
+#' Incident vertices of some graph edges
+#'
+#' @param graph The input graph
+#' @param es The sequence of edges to query
+#' @param names Whether to return vertex names or
+#'   numeric vertex ids. By default vertex names are used.
+#' @return A two column matrix of vertex names or vertex ids.
+#'
+#' @aliases get.edges get.edge
+#' @family structural queries
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(5)
+#' ends(g, E(g))
+
+ends <- function(graph, es, names = TRUE) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
+
+  es2 <- as.igraph.es(graph, na.omit(es)) - 1
+  res <- matrix(NA_integer_, ncol = length(es), nrow = 2)
+
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_edges", graph, as.igraph.es(graph, es)-1,
-               PACKAGE="igraph")
-  matrix(res, ncol=2, byrow=TRUE)+1
+
+  if (length(es) == 1) {
+    res[, !is.na(es)] <- .Call("R_igraph_get_edge", graph, es2,
+                 PACKAGE="igraph") + 1
+
+  } else  {
+    res[, !is.na(es)] <- .Call("R_igraph_edges", graph, es2,
+                 PACKAGE="igraph") + 1
+  }
+
+  if (names && is_named(graph)) {
+    res <- vertex_attr(graph, "name")[res]
+  }
+
+  matrix(res, ncol = 2, byrow = TRUE)
+}
+
+#' @export
+
+get.edges <- function(graph, es) {
+  ends(graph, es, names = FALSE)
 }
 
+
+#' Find the edge ids based on the incident vertices of the edges
+#' 
+#' Find the edges in an igraph graph that have the specified end points. This
+#' function handles multi-graph (graphs with multiple edges) and can consider
+#' or ignore the edge directions in directed graphs.
+#' 
+#' igraph vertex ids are natural numbers, starting from one, up to the number
+#' of vertices in the graph. Similarly, edges are also numbered from one, up to
+#' the number of edges.
+#' 
+#' This function allows finding the edges of the graph, via their incident
+#' vertices.
+#' 
+#' @param graph The input graph.
+#' @param vp The indicent vertices, given as vertex ids or symbolic vertex
+#' names. They are interpreted pairwise, i.e. the first and second are used for
+#' the first edge, the third and fourth for the second, etc.
+#' @param directed Logical scalar, whether to consider edge directions in
+#' directed graphs. This argument is ignored for undirected graphs.
+#' @param error Logical scalar, whether to report an error if an edge is not
+#' found in the graph. If \code{FALSE}, then no error is reported, and zero is
+#' returned for the non-existant edge(s).
+#' @param multi Logical scalar, whether to handle multiple edges properly. If
+#' \code{FALSE}, and a pair of vertices are given twice (or more), then always
+#' the same edge id is reported back for them. If \code{TRUE}, then the edge
+#' ids of multiple edges are correctly reported.
+#' @return A numeric vector of edge ids, one for each pair of input vertices.
+#' If there is no edge in the input graph for a given pair of vertices, then
+#' zero is reported. (If the \code{error} argument is \code{FALSE}.)
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @family structural queries
+#' 
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' ei <- get.edge.ids(g, c(1,2, 4,5))
+#' E(g)[ei]
+#' 
+#' ## non-existant edge
+#' get.edge.ids(g, c(2,1, 1,4, 5,4))
+#' 
 get.edge.ids <- function(graph, vp, directed=TRUE, error=FALSE, multi=FALSE) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -174,3 +437,99 @@ get.edge.ids <- function(graph, vp, directed=TRUE, error=FALSE, multi=FALSE) {
         as.logical(directed), as.logical(error), as.logical(multi),
         PACKAGE="igraph")+1
 }  
+
+
+#' Order (number of vertices) of a graph
+#'
+#' @param graph The graph
+#' @return Number of vertices, numeric scalar.
+#'
+#' @aliases vcount
+#' @family structural queries
+#' 
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' gorder(g)
+
+gorder <- gorder
+
+#' Adjacent vertices of multiple vertices in a graph
+#'
+#' This function is similar to \code{\link{neighbors}}, but it queries
+#' the adjacent vertices for multiple vertices at once.
+#'
+#' @param graph Input graph.
+#' @param v The vertices to query.
+#' @param mode Whether to query outgoing (\sQuote{out}), incoming
+#'   (\sQuote{in}) edges, or both types (\sQuote{all}). This is
+#'   ignored for undirected graphs.
+#' @return A list of vertex sequences.
+#'
+#' @family structural queries
+#' @export
+#' @examples
+#' g <- make_graph("Zachary")
+#' adjacent_vertices(g, c(1, 34))
+
+adjacent_vertices <- function(graph, v,
+                               mode = c("out", "in", "all", "total")) {
+
+  if (!is_igraph(graph)) stop("Not a graph object")
+
+  vv <- as.igraph.vs(graph, v) - 1
+  mode <- switch(match.arg(mode), "out" = 1, "in" = 2, "all" = 3, "total" = 3)
+
+  on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph") )
+
+  res <- .Call("R_igraph_adjacent_vertices", graph, vv, mode,
+               PACKAGE = "igraph")
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, function(x) create_vs(graph, x + 1))
+  }
+
+  if (is_named(graph)) names(res) <- V(graph)$name[vv + 1]
+
+  res
+}
+
+#' Incident edges of multiple vertices in a graph
+#'
+#' This function is similar to \code{\link{incident}}, but it
+#' queries multiple vertices at once.
+#'
+#' @param graph Input graph.
+#' @param v The vertices to query
+#' @param mode Whether to query outgoing (\sQuote{out}), incoming
+#'   (\sQuote{in}) edges, or both types (\sQuote{all}). This is
+#'   ignored for undirected graphs.
+#' @return A list of edge sequences.
+#'
+#' @family structural queries
+#' @export
+#' @examples
+#' g <- make_graph("Zachary")
+#' incident_edges(g, c(1, 34))
+
+incident_edges <- function(graph, v,
+                           mode = c("out", "in", "all", "total")) {
+
+  if (!is_igraph(graph)) stop("Not a graph object")
+
+  vv <- as.igraph.vs(graph, v) - 1
+  mode <- switch(match.arg(mode), "out" = 1, "in" = 2, "all" = 3, "total" = 3)
+
+  on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph") )
+
+  res <- .Call("R_igraph_incident_edges", graph, vv, mode,
+               PACKAGE = "igraph")
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, function(x) create_es(graph, x + 1))
+  }
+
+  if (is_named(graph)) names(res) <- V(graph)$name[vv + 1]
+
+  res
+}
diff --git a/R/iterators.R b/R/iterators.R
index eb77d11..223193a 100644
--- a/R/iterators.R
+++ b/R/iterators.R
@@ -24,24 +24,206 @@
 # Constructors
 ###################################################################
 
+update_es_ref <- update_vs_ref <- function(graph) {
+  env <- get_vs_ref(graph)
+  if (!is.null(env)) assign("me", graph, envir = env)
+}
+
+get_es_ref <- get_vs_ref <- function(graph) {
+  if (is_igraph(graph) && !warn_version(graph)) {
+    base::.Call("R_igraph_mybracket", graph, 10L, PACKAGE = "igraph")
+  } else {
+    NULL
+  }
+}
+
+get_es_graph <- get_vs_graph <- function(seq) {
+  at <- attr(seq, "env")
+  if (class(at) == "weakref") {
+    weak_ref_key(at)$me
+  } else if (class(at) == "environment") {
+    get("graph", envir = at)
+  } else {
+    NULL
+  }
+}
+
+has_es_graph <- has_vs_graph <- function(seq) {
+  !is.null(weak_ref_key(attr(seq, "env")))
+}
+
+get_es_graph_id <- get_vs_graph_id <- function(seq) {
+  new_g <- attr(seq, "graph")
+  if (!is.null(new_g)) {
+    new_g
+  } else if (!is.null(attr(seq, "env"))) {
+    get("graph", envir = attr(seq, "env"))
+  } else {
+    NULL
+  }
+}
+
+#' Decide if two graphs are identical
+#'
+#' This is similar to \code{identical} in the \code{base} package,
+#' but ignores the mutable piece of igraph objects, that might be
+#' different, even if the two graphs are identical.
+#' 
+#' @param g1,g2 The two graphs
+#' @return Logical scalar
+#' @export
+
+identical_graphs <- function(g1, g2) {
+  stopifnot(is_igraph(g1), is_igraph(g2))
+  base::.Call("R_igraph_identical_graphs", g1, g2, PACKAGE = "igraph");
+}
+
+add_vses_graph_ref <- function(vses, graph) {
+  ref <- get_vs_ref(graph)
+  if (!is.null(ref)) {
+    attr(vses, "env") <- make_weak_ref(ref, NULL)
+    attr(vses, "graph") <- get_graph_id(graph)
+  } else {
+    ne <- new.env()
+    assign("graph", graph, envir = ne)
+    attr(vses, "env") <- ne
+  }
+
+  vses
+}
+
+#' Vertices of a graph
+#'
+#' Create a vertex sequence (vs) containing all vertices of a graph.
+#'
+#' @details
+#' A vertex sequence is just what the name says it is: a sequence of
+#' vertices. Vertex sequences are usually used as igraph function arguments
+#' that refer to vertices of a graph.
+#' 
+#' A vertex sequence is tied to the graph it refers to: it really denoted
+#' the specific vertices of that graph, and cannot be used together with
+#' another graph.
+#' 
+#' At the implementation level, a vertex sequence is simply a vector
+#' containing numeric vertex ids, but it has a special class attribute
+#' which makes it possible to perform graph specific operations on it, like
+#' selecting a subset of the vertices based on graph structure, or vertex
+#' attributes.
+#'
+#' A vertex sequence is most often created by the \code{V()} function. The
+#' result of this includes all vertices in increasing vertex id order. A
+#' vertex sequence can be indexed by a numeric vector, just like a regular
+#' R vector. See \code{\link{[.igraph.vs}} and additional links to other
+#' vertex sequence operations below.
+#'
+#' @section Indexing vertex sequences:
+#' Vertex sequences mostly behave like regular vectors, but there are some
+#' additional indexing operations that are specific for them;
+#' e.g. selecting vertices based on graph structure, or based on vertex
+#' attributes. See \code{\link{[.igraph.vs}} for details.
+#'  
+#' @section Querying or setting attributes:
+#' Vertex sequences can be used to query or set attributes for the
+#' vertices in the sequence. See \code{\link{$.igraph.vs}} for details.
+#'
+#' @param graph The graph
+#' @return A vertex sequence containing all vertices, in the order
+#'   of their numeric vertex ids.
+#'
+#' @family vertex and edge sequences
+#' @export
+#' @examples
+#' # Vertex ids of an unnamed graph
+#' g <- make_ring(10)
+#' V(g)
+#'
+#' # Vertex ids of a named graph
+#' g2 <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = letters[1:10])
+#' V(g2)
+
 V <- function(graph) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  vc <- vcount(graph)
-  res <- seq_len(vc)
+
+  update_vs_ref(graph)
+
+  res <- seq_len(vcount(graph))
+  if (is_named(graph)) names(res) <- vertex_attr(graph)$name
   class(res) <- "igraph.vs"
-  ne <- new.env()
-  assign("graph", graph, envir=ne)
-  attr(res, "env") <- ne
-  res
+  add_vses_graph_ref(res, graph)
 }
 
+create_vs <- function(graph, idx, na_ok = FALSE) {
+  if (na_ok) idx <- ifelse(idx < 1 | idx > gorder(graph), NA, idx)
+  res <- simple_vs_index(V(graph), idx, na_ok = na_ok)
+  add_vses_graph_ref(res, graph)
+}
+
+#' Edges of a graph
+#'
+#' An edge sequence is a vector containing numeric edge ids, with a special
+#' class attribute that allows custom operations: selecting subsets of
+#' edges based on attributes, or graph structure, creating the
+#' intersection, union of edges, etc.
+#'
+#' @details
+#' Edge sequences are usually used as igraph function arguments that 
+#' refer to edges of a graph.
+#'
+#' An edge sequence is tied to the graph it refers to: it really denoted
+#' the specific edges of that graph, and cannot be used together with
+#' another graph.
+#'
+#' An edge sequence is most often created by the \code{E()} function. The
+#' result includes edges in increasing edge id order by default (if. none
+#' of the \code{P} and \code{path} arguments are used). An edge
+#' sequence can be indexed by a numeric vector, just like a regular R
+#' vector. See links to other edge sequence operations below.
+#'
+#' @section Indexing edge sequences:
+#' Edge sequences mostly behave like regular vectors, but there are some
+#' additional indexing operations that are specific for them;
+#' e.g. selecting edges based on graph structure, or based on edge
+#' attributes. See \code{\link{[.igraph.es}} for details.
+#'
+#' @section Querying or setting attributes:
+#' Edge sequences can be used to query or set attributes for the
+#' edges in the sequence. See \code{\link{$.igraph.es}} for details.
+#'
+#' @param graph The graph.
+#' @param P A list of vertices to select edges via pairs of vertices.
+#'   The first and second vertices select the first edge, the third
+#'   and fourth the second, etc.
+#' @param path A list of vertices, to select edges along a path.
+#'   Note that this only works reliable for simple graphs. If the graph
+#'   has multiple edges, one of them will be chosen arbitrarily to
+#'   be included in the edge sequence.
+#' @param directed Whether to consider edge directions in the \code{P}
+#'   argument, for directed graphs.
+#' @return An edge sequence of the graph.
+#'
+#' @export
+#' @family vertex and edge sequences
+#' @examples
+#' # Edges of an unnamed graph
+#' g <- make_ring(10)
+#' E(g)
+#'
+#' # Edges of a named graph
+#' g2 <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = letters[1:10])
+#' E(g2)
+
 E <- function(graph, P=NULL, path=NULL, directed=TRUE) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
+  update_es_ref(graph)
+
   if (!is.null(P) && !is.null(path)) {
     stop("Cannot give both `P' and `path' at the same time")
   }
@@ -60,208 +242,510 @@ E <- function(graph, P=NULL, path=NULL, directed=TRUE) {
                  as.logical(directed),
                  PACKAGE="igraph")+1
   }
+
+  if ("name" %in% edge_attr_names(graph)) {
+    names(res) <- edge_attr(graph)$name[res]
+  }
+  if (is.named(graph)) {
+    el <- ends(graph, es = res)
+    attr(res, "vnames") <- paste(el[,1], el[,2], sep = "|")
+  }
   
   class(res) <- "igraph.es"
-  ne <- new.env()
-  assign("graph", graph, envir=ne)
-  attr(res, "env") <- ne
-  res
+  add_vses_graph_ref(res, graph)
 }
 
-"[[.igraph.vs" <- function(x, i) {
-  if (length(i) != 1) {
-    stop("Invalid `[[` indexing, need single vertex")
-  }
-  if (is.numeric(i) || is.integer(i)) {
-    res <- i [ i %in% x ]
-    attributes(res) <- attributes(x)
-  } else if (is.character(i)) {
-    res <- as.igraph.vs(get("graph", attr(x, "env")), i)
-    attributes(res) <- attributes(x)
-  } else {
-    stop("Invalid `[[` indexing, index must be numeric of character scalar")
-  }
-  attr(res, "single") <- TRUE
+create_es <- function(graph, idx, na_ok = FALSE) {
+  if (na_ok) idx <- ifelse(idx < 1 | idx > gsize(graph), NA, idx)
+  simple_es_index(E(graph), idx)
+}
+
+simple_vs_index <- function(x, i, na_ok = FALSE) {
+  res <- unclass(x)[i]
+  if (!na_ok && any(is.na(res))) stop('Unknown vertex selected')
+  class(res) <- "igraph.vs"
   res
 }
 
-"[.igraph.vs" <- function(x, i) {
-  i <- substitute(i)
-  if (is.numeric(i) || is.integer(i)) {
-    # simple indexing by vertex ids
-    res <- i[ i %in% x ]
-    attributes(res) <- attributes(x)
-  } else if (is.logical(i)) {
-    # simple indexing by logical vector
-    res <- as.numeric(x) [ i ]
-    attributes(res) <- attributes(x)
-  } else if (is.character(i)) {
-    res <- as.igraph.vs(get("graph", attr(x, "env")), i)
-    attributes(res) <- attributes(x)
-  } else {
-    # language expression, we also do attribute based indexing
-    graph <- get("graph", attr(x, "env"))
-    nei <- function(v, mode=c("all", "in", "out", "total")) {
-      ## TRUE iff the vertex is a neighbor (any type)
-      ## of at least one vertex in v
-      mode <- igraph.match.arg(mode)
-      mode <- switch(mode, "out"=1, "in"=2, "all"=3, "total"=3)
-
-      if (is.logical(v)) {
-        v <- which(v)
-      }
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_vs_nei", graph, x, as.igraph.vs(graph, v)-1,
-                   as.numeric(mode),
-                   PACKAGE="igraph")
-      tmp[as.numeric(x)]
-    }
-    innei <- function(v, mode=c("in", "all", "out", "total")) {
-      nei(v, mode)
-    }
-    outnei <- function(v, mode=c("out", "all", "in", "total")) {
-      nei(v, mode)
-    }
-    inc <- adj <- function(e) {
-      ## TRUE iff the vertex (in the vs) is incident
-      ## to at least one edge in e
-      if (is.logical(e)) {
-        e <- which(e)
-      }
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_vs_adj", graph, x, as.igraph.es(graph, e)-1,
-                   as.numeric(3),
-                   PACKAGE="igraph")
-      tmp[as.numeric(x)]
+#' Indexing vertex sequences
+#'
+#' Vertex sequences can be indexed very much like a plain numeric R vector,
+#' with some extras.
+#'
+#' @details
+#' Vertex sequences can be indexed using both the single bracket and
+#' the double bracket operators, and they both work the same way.
+#' The only difference between them is that the double bracket operator
+#' marks the result for printing vertex attributes.
+#'
+#' @section Multiple indices:
+#' When using multiple indices within the bracket, all of them
+#' are evaluated independently, and then the results are concatenated
+#' using the \code{c()} function (except for the \code{na_ok} argument,
+#' which is special an must be named. E.g. \code{V(g)[1, 2, nei(1)]}
+#' is equivalent to \code{c(V(g)[1], V(g)[2], V(g)[nei(1)])}.
+#'
+#' @section Index types:
+#' Vertex sequences can be indexed with positive numeric vectors,
+#' negative numeric vectors, logical vectors, character vectors:
+#' \itemize{
+#'   \item When indexed with positive numeric vectors, the vertices at the
+#'     given positions in the sequence are selected. This is the same as
+#'     indexing a regular R atomic vector with positive numeric vectors.
+#'   \item When indexed with negative numeric vectors, the vertices at the
+#'     given positions in the sequence are omitted. Again, this is the same
+#'     as indexing a regular R atomic vector.
+#'   \item When indexed with a logical vector, the lengths of the vertex
+#'     sequence and the index must match, and the vertices for which the
+#'     index is \code{TRUE} are selected.
+#'   \item Named graphs can be indexed with character vectors,
+#'     to select vertices with the given names.
+#' }
+#' 
+#' @section Vertex attributes:
+#' When indexing vertex sequences, vertex attributes can be refered
+#' to simply by using their names. E.g. if a graph has a \code{name} vertex
+#' attribute, then \code{V(g)[name == "foo"]} is equivalent to
+#' \code{V(g)[V(g)$name == "foo"]}. See examples below.
+#'
+#' @section Special functions:
+#' There are some special igraph functions that can be used only
+#' in expressions indexing vertex sequences: \describe{
+#'   \item{\code{nei}}{takes a vertex sequence as its argument
+#'     and selects neighbors of these vertices. An optional \code{mode}
+#'     argument can be used to select successors (\code{mode="out"}), or
+#'     precedessors (\code{mode="in"}) in directed graphs.}
+#'   \item{\code{inc}}{Takes an edge sequence as an argument, and
+#'     selects vertices that have at least one incident edge in this
+#'     edge sequence.}
+#'   \item{\code{from}}{Similar to \code{inc}, but only considers the
+#'     tails of the edges.}
+#'   \item{\code{to}}{Similar to \code{inc}, but only considers the
+#'     heads of the edges.}
+#'   \item{\code{innei}, \code{outnei}}{\code{innei(v)} is a shorthand for
+#'     \code{nei(v, mode = "in")}, and \code{outnei(v)} is a shorthand for
+#'     \code{nei(v, mode = "out")}.
+#'   }
+#' }
+#' Note that multiple special functions can be used together, or with
+#' regular indices, and then their results are concatenated. See more
+#' examples below.
+#'
+#' @param x A vertex sequence.
+#' @param ... Indices, see details below.
+#' @param na_ok Whether it is OK to have \code{NA}s in the vertex
+#'   sequence.
+#' @return Another vertex sequence, referring to the same graph.
+#' 
+#' @method [ igraph.vs
+#' @name igraph-vs-indexing
+#' @export
+#' @family vertex and edge sequences
+#' @family vertex and edge sequence operations
+#' 
+#' @examples
+#' # -----------------------------------------------------------------
+#' # Setting attributes for subsets of vertices
+#' largest_comp <- function(graph) {
+#'   cl <- components(graph)
+#'   V(graph)[which.max(cl$csize) == cl$membership]
+#' }
+#' g <- sample_(gnp(100, 2/100),
+#'   with_vertex_(size = 3, label = ""),
+#'   with_graph_(layout = layout_with_fr)
+#' )
+#' giant_v <- largest_comp(g)
+#' V(g)$color <- "green"
+#' V(g)[giant_v]$color <- "red"
+#' plot(g)
+#'
+#' # -----------------------------------------------------------------
+#' # nei() special function
+#' g <- graph( c(1,2, 2,3, 2,4, 4,2) )
+#' V(g)[ nei( c(2,4) ) ]
+#' V(g)[ nei( c(2,4), "in") ]
+#' V(g)[ nei( c(2,4), "out") ]
+#'
+#' # -----------------------------------------------------------------
+#' # The same with vertex names
+#' g <- graph(~ A -+ B, B -+ C:D, D -+ B)
+#' V(g)[ nei( c('B', 'D') ) ]
+#' V(g)[ nei( c('B', 'D'), "in" ) ]
+#' V(g)[ nei( c('B', 'D'), "out" ) ]
+
+`[.igraph.vs` <- function(x, ..., na_ok = FALSE) {
+
+  args <- lazy_dots(..., .follow_symbols = FALSE)
+
+  ## If indexing has no argument at all, then we still get one,
+  ## but it is "empty", a name that is ""
+
+  if (length(args) < 1 ||
+      (length(args) == 1 && class(args[[1]]$expr) == "name" &&
+         as.character(args[[1]]$expr) == "")) {
+    return(x)
+  }
+
+  nei <- function(v, mode=c("all", "in", "out", "total")) {
+    ## TRUE iff the vertex is a neighbor (any type)
+    ## of at least one vertex in v
+    mode <- igraph.match.arg(mode)
+    mode <- switch(mode, "out"=1, "in"=2, "all"=3, "total"=3)
+
+    if (is.logical(v)) {
+      v <- which(v)
     }
-    from <- function(e) {
-      ## TRUE iff the vertex is the source of at least one edge in e
-      if (is.logical(e)) {
-        e <- which(e)
-      }
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_vs_adj", graph, x, as.igraph.es(graph, e)-1,
-                   as.numeric(1),
-                   PACKAGE="igraph")
-      tmp[as.numeric(x)]
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_vs_nei", graph, x, as.igraph.vs(graph, v)-1,
+                 as.numeric(mode),
+                 PACKAGE="igraph")
+    tmp[as.numeric(x)]
+  }
+  innei <- function(v, mode=c("in", "all", "out", "total")) {
+    nei(v, mode)
+  }
+  outnei <- function(v, mode=c("out", "all", "in", "total")) {
+    nei(v, mode)
+  }
+  inc <- adj <- function(e) {
+    ## TRUE iff the vertex (in the vs) is incident
+    ## to at least one edge in e
+    if (is.logical(e)) {
+      e <- which(e)
     }
-    to <- function(e) {
-      ## TRUE iff the vertex is the target of at least one edge in e
-      if (is.logical(e)) {
-        e <- which(e)
-      }
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_vs_adj", graph, x, as.igraph.es(graph, e)-1,
-                   as.numeric(2),
-                   PACKAGE="igraph")
-      tmp[as.numeric(x)]
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_vs_adj", graph, x, as.igraph.es(graph, e)-1,
+                 as.numeric(3),
+                 PACKAGE="igraph")
+    tmp[as.numeric(x)]
+  }
+  from <- function(e) {
+    ## TRUE iff the vertex is the source of at least one edge in e
+    if (is.logical(e)) {
+      e <- which(e)
     }
-    i <- eval(i, envir=c(.Call("R_igraph_mybracket2", graph, 9L, 3L,
-                   PACKAGE="igraph"), nei=nei, innei=innei,
-                   outnei=outnei, adj=adj, inc=inc, from=from, to=to),
-              enclos=parent.frame())
-    if (is.numeric(i) || is.integer(i)) {
-      i <- as.numeric(i)
-      res <- i[ i %in% x ]
-      attributes(res) <- attributes(x)
-    } else if (is.logical(i)) {
-      res <- as.numeric(x) [ i ]
-      attributes(res) <- attributes(x)
-    } else if (is.character(i)) {
-      res <- as.igraph.vs(get("graph", attr(x, "env")), i)
-      attributes(res) <- attributes(x)
-    } else {
-      stop("invalid indexing of vertex seq")
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_vs_adj", graph, x, as.igraph.es(graph, e)-1,
+                 as.numeric(1),
+                 PACKAGE="igraph")
+    tmp[as.numeric(x)]
+  }
+  to <- function(e) {
+    ## TRUE iff the vertex is the target of at least one edge in e
+    if (is.logical(e)) {
+      e <- which(e)
     }
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_vs_adj", graph, x, as.igraph.es(graph, e)-1,
+                 as.numeric(2),
+                 PACKAGE="igraph")
+    tmp[as.numeric(x)]
   }
 
-  res
-}
+  graph <- get_vs_graph(x)
+
+  if (is.null(graph)) {
+    res <- lapply(lazy_eval(args), simple_vs_index, x = x, na_ok = na_ok)
+
+  } else {
+
+    attrs <- vertex_attr(graph)
+    xvec <- as.vector(x)
+    for (i in seq_along(attrs)) attrs[[i]] <- attrs[[i]][xvec]
 
-"[[.igraph.es" <- function(x, i) {
-  if (length(i) != 1) {
-    stop("Invalid `[[` indexing, need single edge")
+    res <- lazy_eval(
+      args,
+      data =  c(attrs, nei = nei, innei = innei,
+        outnei = outnei, adj = adj, inc = inc, from = from, to = to)
+    )
+    res <- lapply(res, function(ii) {
+      if (is.null(ii)) return(NULL)
+      ii <- simple_vs_index(x, ii, na_ok)
+      attr(ii, "env") <- attr(x, "env")
+      attr(ii, "graph") <- attr(x, "graph")
+      class(ii) <- class(x)
+      ii
+    })
   }
-  if (is.numeric(i) || is.integer(i)) {
-    res <- i [ i %in% x ]
-    attributes(res) <- attributes(x)
-  } else if (is.character(i)) {
-    res <- as.igraph.es(get("graph", attr(x, "env")), i)
-    attributes(res) <- attributes(x)
+
+  res <- drop_null(res)
+  if (length(res)) {
+    do_call(c, res)
   } else {
-    stop("Invalid `[[` indexing, index must be numeric of character scalar")
+    x[FALSE]
   }
+}
+
+#' Select vertices and show their metadata
+#'
+#' The double bracket operator can be used on vertex sequences, to print
+#' the meta-data (vertex attributes) of the vertices in the sequence.
+#'
+#' @details
+#' Technically, when used with vertex sequences, the double bracket
+#' operator does exactly the same as the single bracket operator,
+#' but the resulting vertex sequence is printed differently: all
+#' attributes of the vertices in the sequence are printed as well.
+#'
+#' See \code{\link{[.igraph.vs}} for more about indexing vertex sequences.
+#' 
+#' @param x A vertex sequence.
+#' @param ... Additional arguments, passed to \code{[}.
+#' @return The double bracket operator returns another vertex sequence,
+#'   with meta-data (attribute) printing turned on. See details below.
+#' 
+#' @method [[ igraph.vs
+#' @name igraph-vs-indexing2
+#' @family vertex and edge sequences
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_vertex_attr("color", value = "red") %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10])
+#' V(g)
+#' V(g)[[]]
+#' V(g)[1:5]
+#' V(g)[[1:5]]
+
+`[[.igraph.vs` <- function(x, ...) {
+  res <- x[...]
+  attr(res, "single") <- TRUE
+  res
+}
+
+#' Select edges and show their metadata
+#'
+#' The double bracket operator can be used on edge sequences, to print
+#' the meta-data (edge attributes) of the edges in the sequence.
+#'
+#' @details
+#' Technically, when used with edge sequences, the double bracket
+#' operator does exactly the same as the single bracket operator,
+#' but the resulting edge sequence is printed differently: all
+#' attributes of the edges in the sequence are printed as well.
+#'
+#' See \code{\link{[.igraph.es}} for more about indexing edge sequences.
+#' 
+#' @param x An edge sequence.
+#' @param ... Additional arguments, passed to \code{[}.
+#' @return Another edge sequence, with metadata printing turned on.
+#' See details below.
+#'
+#' @method [[ igraph.es
+#' @name igraph-es-indexing2
+#' @family vertex and edge sequences
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10),
+#'   with_vertex_(name = LETTERS[1:10]),
+#'   with_edge_(weight = 1:10, color = "green"))
+#' E(g)
+#' E(g)[[]]
+#' E(g)[[inc('A')]]
+
+`[[.igraph.es` <- function(x, ...) {
+  res <- x[...]
   attr(res, "single") <- TRUE
   res
 }
 
-"[.igraph.es" <- function(x, i) {
-  i <- substitute(i)
-  if (is.numeric(i) || is.integer(i)) {
-    # simple indexing by vertex ids
-    res <- i[ i %in% x ]
-    attributes(res) <- attributes(x)    
-  } else if (is.logical(i)) {
-    # simple indexing by a logical vector
-    res <- as.numeric(x) [ i ]
-    attributes(res) <- attributes(x)
-  } else if (is.character(i)) {
-    res <- as.igraph.es(get("graph", attr(x, "env")), i)
-    attributes(res) <- attributes(x)
+simple_es_index <- function(x, i) {
+  if (!is.null(attr(x, "vnames"))) {
+    wh1 <- structure(seq_along(x), names = names(x))[i]
+    wh2 <- structure(seq_along(x), names = attr(x, "vnames"))[i]
+    wh <- ifelse(is.na(wh1), wh2, wh1)
+    res <- unclass(x)[wh]
+    names(res) <- names(x)[wh]
+    attr(res, "vnames") <- attr(x, "vnames")[wh]
   } else {
-    # language expression, we also do attribute based indexing
-    graph <- get("graph", attr(x, "env"))
-    i <- substitute(i)
-    inc <- adj <- function(v) {
-      ## TRUE iff the edge is incident to at least one vertex in v
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_es_adj", graph, x, as.igraph.vs(graph, v)-1,
-                   as.numeric(3),
-                   PACKAGE="igraph")
-      tmp[ as.numeric(x) ]
-    }
-    from <- function(v) {
-      ## TRUE iff the edge originates from at least one vertex in v
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_es_adj", graph, x, as.igraph.vs(graph, v)-1,
-                   as.numeric(1),
-                   PACKAGE="igraph")
-      tmp[ as.numeric(x) ]      
-    }
-    to <- function(v) {
-      ## TRUE iff the edge points to at least one vertex in v
-      on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-      tmp <- .Call("R_igraph_es_adj", graph, x, as.igraph.vs(graph, v)-1,
-                   as.numeric(2),
-                   PACKAGE="igraph")
-      tmp[ as.numeric(x) ]
-    }
-    i <- eval(i, envir=c(.Call("R_igraph_mybracket2", graph, 9L, 4L,
-                   PACKAGE="igraph"),
-                   inc=inc, adj=adj, from=from, to=to,
-                   .igraph.from=list(.Call("R_igraph_mybracket",
-                     graph, 3L, PACKAGE="igraph")[ as.numeric(x) ]),
-                   .igraph.to=list(.Call("R_igraph_mybracket",
-                     graph, 4L, PACKAGE="igraph")[as.numeric(x)]),
-                   .igraph.graph=list(graph),
-                   `%--%`=`%--%`, `%->%`=`%->%`, `%<-%`=`%<-%`),
-              enclos=parent.frame())
-    if (is.numeric(i) || is.integer(i)) {
-      i <- as.numeric(i)
-      res <- i[ i %in% x ]
-      attributes(res) <- attributes(x)
-    } else if (is.logical(i)) {
-      res <- as.numeric(x) [ i ]
-      attributes(res) <- attributes(x)
-    } else {
-      stop("invalid indexing of edge seq")
-    }
+    res <- unclass(x)[i]
   }
-  
+  if (anyNA(res)) stop('Unknown edge selected')
+
+  attr(res, "env") <- attr(x, "env")
+  attr(res, "graph") <- attr(x, "graph")
+  class(res) <- "igraph.es"
   res
+}
+
+#' Indexing edge sequences
+#'
+#' Edge sequences can be indexed very much like a plain numeric R vector,
+#' with some extras.
+#'
+#' @section Multiple indices:
+#' When using multiple indices within the bracket, all of them
+#' are evaluated independently, and then the results are concatenated
+#' using the \code{c()} function. E.g. \code{E(g)[1, 2, inc(1)]}
+#' is equivalent to \code{c(E(g)[1], E(g)[2], E(g)[inc(1)])}.
+#'
+#' @section Index types:
+#' Edge sequences can be indexed with positive numeric vectors,
+#' negative numeric vectors, logical vectors, character vectors:
+#' \itemize{
+#'   \item When indexed with positive numeric vectors, the edges at the
+#'     given positions in the sequence are selected. This is the same as
+#'     indexing a regular R atomic vector with positive numeric vectors.
+#'   \item When indexed with negative numeric vectors, the edges at the
+#'     given positions in the sequence are omitted. Again, this is the same
+#'     as indexing a regular R atomic vector.
+#'   \item When indexed with a logical vector, the lengths of the edge
+#'     sequence and the index must match, and the edges for which the
+#'     index is \code{TRUE} are selected.
+#'   \item Named graphs can be indexed with character vectors,
+#'     to select edges with the given names. Note that a graph may
+#'     have edge names and vertex names, and both can be used to select
+#'     edges. Edge names are simply used as names of the nuumeric
+#'     edge id vector. Vertex names effectively only work in graphs without
+#'     multiple edges, and must be separated with a \code{|} bar character
+#'     to select an edges that incident to the two given vertices. See
+#'     examples below.
+#' }
+#'
+#' @section Edge attributes:
+#' When indexing edge sequences, edge attributes can be refered
+#' to simply by using their names. E.g. if a graph has a \code{weight} edge
+#' attribute, then \code{E(G)[weight > 1]} selects all edges with a larger
+#' than one weight. See more examples below.
+#'
+#' @section Special functions:
+#' There are some special igraph functions that can be used
+#' only in expressions indexing edge sequences: \describe{
+#'   \item{\code{inc}}{takes a vertex sequence, and selects
+#'     all edges that have at least one incident vertex in the vertex
+#'     sequence.}
+#'   \item{\code{from}}{similar to \code{inc()}, but only
+#'     the tails of the edges are considered.}
+#'   \item{\code{to}}{is similar to \code{inc()}, but only
+#'     the heads of the edges are considered.}
+#'   \item{\code{\%--\%}}{a special operator that can be
+#'     used to select all edges between two sets of vertices. It ignores
+#'     the edge directions in directed graphs.}
+#'   \item{\code{\%->\%}}{similar to \code{\%--\%},
+#'     but edges \emph{from} the left hand side argument, pointing
+#'     \emph{to} the right hand side argument, are selected, in directed
+#'     graphs.}
+#'   \item{\code{\%<-\%}}{similar to \code{\%--\%},
+#'     but edges \emph{to} the left hand side argument, pointing
+#'     \emph{from} the right hand side argument, are selected, in directed
+#'     graphs.}
+#' }
+#' Note that multiple special functions can be used together, or with
+#' regular indices, and then their results are concatenated. See more
+#' examples below.
+#'
+#' @aliases %--% %<-% %->%
+#' @param x An edge sequence
+#' @param ... Indices, see details below.
+#' @return Another edge sequence, referring to the same graph.
+#' 
+#' @method [ igraph.es
+#' @name igraph-es-indexing
+#'
+#' @export
+#' @family vertex and edge sequences
+#' @family vertex and edge sequence operations
+#' @examples
+#' # special operators for indexing based on graph structure
+#' g <- sample_pa(100, power = 0.3)
+#' E(g) [ 1:3 %--% 2:6 ]
+#' E(g) [ 1:5 %->% 1:6 ]
+#' E(g) [ 1:3 %<-% 2:6 ]
+#'
+#' # the edges along the diameter
+#' g <- sample_pa(100, directed = FALSE)
+#' d <- get_diameter(g)
+#' E(g, path = d)
+#'
+#' # select edges based on attributes
+#' g <- sample_gnp(20, 3/20) %>%
+#'   set_edge_attr("weight", value = rnorm(gsize(.)))
+#' E(g)[[ weight < 0 ]]
+
+`[.igraph.es` <- function(x, ...) {
+
+  args <- lazy_dots(..., .follow_symbols = TRUE)
+
+  ## If indexing has no argument at all, then we still get one,
+  ## but it is "empty", a name that is ""
+
+  if (length(args) < 1 ||
+      (length(args) == 1 && class(args[[1]]$expr) == "name" &&
+         as.character(args[[1]]$expr) == "")) {
+    return(x)
+  }
+
+  inc <- adj <- function(v) {
+    ## TRUE iff the edge is incident to at least one vertex in v
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_es_adj", graph, x, as.igraph.vs(graph, v)-1,
+                 as.numeric(3),
+                 PACKAGE="igraph")
+    tmp[ as.numeric(x) ]
+  }
+  from <- function(v) {
+    ## TRUE iff the edge originates from at least one vertex in v
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_es_adj", graph, x, as.igraph.vs(graph, v)-1,
+                 as.numeric(1),
+                 PACKAGE="igraph")
+    tmp[ as.numeric(x) ]
+  }
+  to <- function(v) {
+    ## TRUE iff the edge points to at least one vertex in v
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    tmp <- .Call("R_igraph_es_adj", graph, x, as.igraph.vs(graph, v)-1,
+                 as.numeric(2),
+                 PACKAGE="igraph")
+    tmp[ as.numeric(x) ]
+  }
+
+  graph <- get_es_graph(x)
+
+  if (is.null(graph)) {
+    res <- lapply(lazy_eval(args), simple_es_index, x = x)
+
+  } else {
+
+    attrs <- edge_attr(graph)
+    xvec <- as.vector(x)
+    for (i in seq_along(attrs)) attrs[[i]] <- attrs[[i]][xvec]
+
+    res <- lazy_eval(
+        args,
+        data = c(attrs, inc = inc, adj = adj, from = from, to = to,
+          .igraph.from = list(.Call("R_igraph_mybracket",
+            graph, 3L, PACKAGE = "igraph")[ as.numeric(x) ]),
+          .igraph.to = list(.Call("R_igraph_mybracket",
+            graph, 4L, PACKAGE = "igraph")[as.numeric(x)]),
+          .igraph.graph = list(graph),
+          `%--%`=`%--%`, `%->%`=`%->%`, `%<-%`=`%<-%`)
+    )
+    res <- lapply(res, function(ii) {
+      if (is.null(ii)) return(NULL)
+      ii <- simple_es_index(x, ii)
+      attr(ii, "env") <- attr(x, "env")
+      attr(ii, "graph") <- attr(x, "graph")
+      class(ii) <- class(x)
+      ii
+    })
+  }
+
+  res <- drop_null(res)
+  if (length(res) == 1) {
+    res[[1]]
+  } else if (length(res)) {
+    do_call(c, res)
+  } else {
+    x[FALSE]
+  }
 } 
 
-"%--%" <- function(f, t) {  
+#' @export
+
+`%--%` <- function(f, t) {
   from <- get(".igraph.from", parent.frame())
   to <- get(".igraph.to", parent.frame())
   graph <- get(".igraph.graph", parent.frame())
@@ -270,58 +754,132 @@ E <- function(graph, P=NULL, path=NULL, directed=TRUE) {
   (from %in% f & to %in% t) | (to %in% f & from %in% t)
 }
 
-"%->%" <- function(f, t) {
+#' @export
+
+`%->%` <- function(f, t) {
   from <- get(".igraph.from", parent.frame())
   to <- get(".igraph.to", parent.frame())
   graph <- get(".igraph.graph", parent.frame())
   f <- as.igraph.vs(graph, f)-1
   t <- as.igraph.vs(graph, t)-1
-  if (is.directed(graph)) {
+  if (is_directed(graph)) {
     from %in% f & to %in% t
   } else {
     (from %in% f & to %in% t) | (to %in% f & from %in% t)
   }
 }
 
-"%<-%" <- function(t, value) {
+#' @export
+
+`%<-%` <- function(t, value) {
   from <- get(".igraph.from", parent.frame())
   to <- get(".igraph.to", parent.frame())
   graph <- get(".igraph.graph", parent.frame())
   value <- as.igraph.vs(graph, value)-1
   t <- as.igraph.vs(graph, t)-1
-  if (is.directed(graph)) {
+  if (is_directed(graph)) {
     from %in% value & to %in% t
   } else {
     (from %in% value & to %in% t) | (to %in% value & from %in% t)
   }
 }
 
-"[<-.igraph.vs" <- "[[<-.igraph.vs" <- function(x, i, value) {
+#' @param i Index.
+#' @method [[<- igraph.vs
+#' @name igraph-vs-attributes
+#' @export
+
+`[[<-.igraph.vs` <- function(x, i, value) {
   if (! "name"  %in% names(attributes(value)) ||
       ! "value" %in% names(attributes(value))) {
     stop("invalid indexing")
   }
+  if (is.null(get_vs_graph(x))) stop("Graph is unknown")
   value
 }
 
-"[<-.igraph.es" <- "[[<-.igraph.es" <- function(x, i, value) {
+#' @method [<- igraph.vs
+#' @name igraph-vs-attributes
+#' @export
+
+`[<-.igraph.vs` <-  `[[<-.igraph.vs`
+
+#' @param i Index.
+#' @method [[<- igraph.es
+#' @name igraph-es-attributes
+#' @export
+
+`[[<-.igraph.es` <- function(x, i, value) {
   if (! "name"  %in% names(attributes(value)) ||
       ! "value" %in% names(attributes(value))) {
     stop("invalid indexing")
   }
+  if (is.null(get_es_graph(x))) stop("Graph is unknown")
   value
 }  
 
-"$.igraph" <- function(x, name) {
-  get.graph.attribute(x, name)
-}
+#' @method [<- igraph.es
+#' @name igraph-es-attributes
+#' @export
 
-"$<-.igraph" <- function(x, name, value) {
-  set.graph.attribute(x, name, value)
-}
-  
-"$.igraph.vs" <- function(x, name) {
-  res <- get.vertex.attribute(get("graph", attr(x, "env")), name, x)
+`[<-.igraph.es` <-  `[[<-.igraph.es`
+
+#' Query or set attributes of the vertices in a vertex sequence
+#'
+#' The \code{$} operator is a syntactic sugar to query and set the
+#' attributes of the vertices in a vertex sequence.
+#'
+#' @details
+#' The query form of \code{$} is a shortcut for
+#' \code{\link{vertex_attr}}, e.g. \code{V(g)[idx]$attr} is equivalent
+#' to \code{vertex_attr(g, attr, V(g)[idx])}.
+#'
+#' The assignment form of \code{$} is a shortcut for
+#' \code{\link{set_vertex_attr}}, e.g. \code{V(g)[idx]$attr <- value} is
+#' equivalent to \code{g <- set_vertex_attr(g, attr, V(g)[idx], value)}.
+#' 
+#' @param x A vertex sequence. For \code{V<-} it is a graph.
+#' @param name Name of the vertex attribute to query or set.
+#' @return A vector or list, containing the values of
+#'   attribute \code{name} for the vertices in the vertex sequence.
+#'   For numeric, character or logical attributes, it is a vector of the
+#'   appropriate type, otherwise it is a list.
+#' 
+#' @method $ igraph.vs
+#' @name igraph-vs-attributes
+#'
+#' @export
+#' @family vertex and edge sequences
+#' @family graph attributes
+#' @examples
+#' g <- make_(ring(10),
+#'   with_vertex_(
+#'     name = LETTERS[1:10],
+#'     color = sample(1:2, 10, replace=TRUE)
+#'   )
+#' )
+#' V(g)$name
+#' V(g)$color
+#' V(g)$frame.color <- V(g)$color
+#'
+#' # color vertices of the largest component
+#' largest_comp <- function(graph) {
+#'   cl <- components(graph)
+#'   V(graph)[which.max(cl$csize) == cl$membership]
+#' }
+#' g <- sample_(gnp(100, 2/100),
+#'   with_vertex_(size = 3, label = ""),
+#'   with_graph_(layout = layout_with_fr)
+#' )
+#' giant_v <- largest_comp(g)
+#' V(g)$color <- "blue"
+#' V(g)[giant_v]$color <- "orange"
+#' plot(g)
+
+`$.igraph.vs` <- function(x, name) {
+  graph <- get_vs_graph(x)
+  if (is.null(graph)) stop("Graph is unknown")
+  res <- vertex_attr(graph, name, x)
   if ("single" %in% names(attributes(x)) && attr(x, "single")) {
     res[[1]]
   } else {
@@ -329,8 +887,51 @@ E <- function(graph, P=NULL, path=NULL, directed=TRUE) {
   }
 }
 
-"$.igraph.es" <- function(x, name) {
-  res <- get.edge.attribute(get("graph", attr(x, "env")), name, x)
+#' Query or set attributes of the edges in an edge sequence
+#'
+#' The \code{$} operator is a syntactic sugar to query and set
+#' edge attributes, for edges in an edge sequence.
+#'
+#' @details
+#' The query form of \code{$} is a shortcut for \code{\link{edge_attr}},
+#' e.g. \code{E(g)[idx]$attr} is equivalent to \code{edge_attr(g, attr,
+#' E(g)[idx])}.
+#'
+#' The assignment form of \code{$} is a shortcut for
+#' \code{\link{set_edge_attr}}, e.g. \code{E(g)[idx]$attr <- value} is
+#' equivalent to \code{g <- set_edge_attr(g, attr, E(g)[idx], value)}.
+#'
+#' @param x An edge sequence. For \code{E<-} it is a graph.
+#' @param name Name of the edge attribute to query or set.
+#' @return A vector or list, containing the values of the attribute
+#'   \code{name} for the edges in the sequence. For numeric, character or
+#'   logical attributes, it is a vector of the appropriate type, otherwise
+#'   it is a list. 
+#' 
+#' @method $ igraph.es
+#' @name igraph-es-attributes
+#'
+#' @export
+#' @family vertex and edge sequences
+#' @examples
+#' # color edges of the largest component
+#' largest_comp <- function(graph) {
+#'   cl <- components(graph)
+#'   V(graph)[which.max(cl$csize) == cl$membership]
+#' }
+#' g <- sample_(gnp(100, 1/100),
+#'   with_vertex_(size = 3, label = ""),
+#'   with_graph_(layout = layout_with_fr)
+#' )
+#' giant_v <- largest_comp(g)
+#' E(g)$color <- "orange"
+#' E(g)[giant_v %--% giant_v]$color <- "blue"
+#' plot(g)
+
+`$.igraph.es` <- function(x, name) {
+  graph <- get_es_graph(x)
+  if (is.null(graph)) stop("Graph is unknown")
+  res <- edge_attr(graph, name, x)
   if ("single" %in% names(attributes(x)) && attr(x, "single")) {
     res[[1]]
   } else {
@@ -338,75 +939,214 @@ E <- function(graph, P=NULL, path=NULL, directed=TRUE) {
   }
 }
 
-"$<-.igraph.vs" <- function(x, name, value) {
+#' @param value New value of the attribute, for the vertices in the
+#'   vertex sequence.
+#'
+#' @method $<- igraph.vs
+#' @name igraph-vs-attributes
+#' @export
+
+`$<-.igraph.vs` <- function(x, name, value) {
+  if (is.null(get_vs_graph(x))) stop("Graph is unknown")
   attr(x, "name") <- name
   attr(x, "value") <- value
   x
 }
 
-"$<-.igraph.es" <- function(x, name, value) {
+#' @param value New value of the attribute, for the edges in the edge
+#'   sequence.
+#' @method $<- igraph.es
+#' @name igraph-es-attributes
+#' @export
+#' @family vertex and edge sequences
+
+`$<-.igraph.es` <- function(x, name, value) {
+  if (is.null(get_es_graph(x))) stop("Graph is unknown")
   attr(x, "name") <- name
   attr(x, "value") <- value
   x
 }
 
-"V<-" <- function(x, value) {
-  if (!is.igraph(x)) {
+#' @name igraph-vs-attributes
+#' @export
+
+`V<-` <- function(x, value) {
+  if (!is_igraph(x)) {
     stop("Not a graph object")
   }
   if (! "name"  %in% names(attributes(value)) ||
       ! "value" %in% names(attributes(value))) {
     stop("invalid indexing")
   }
-  set.vertex.attribute(x, attr(value, "name"), index=value,
-                       value=attr(value, "value"))
+  i_set_vertex_attr(x, attr(value, "name"), index=value,
+                    value=attr(value, "value"), check = FALSE)
 }
 
-"E<-" <- function(x, path=NULL, P=NULL, directed=NULL, value) {
-  if (!is.igraph(x)) {
+#' @param path Select edges along a path, given by a vertex sequence See
+#'   \code{\link{E}}.
+#' @param P Select edges via pairs of vertices. See \code{\link{E}}.
+#' @param directed Whether to use edge directions for the \code{path} or
+#'   \code{P} arguments.
+#' @name igraph-es-attributes
+#' @export
+
+`E<-` <- function(x, path=NULL, P=NULL, directed=NULL, value) {
+  if (!is_igraph(x)) {
     stop("Not a graph object")
   }
   if (! "name"  %in% names(attributes(value)) ||
       ! "value" %in% names(attributes(value))) {
     stop("invalid indexing")
   }
-  set.edge.attribute(x, attr(value, "name"), index=value,
-                     value=attr(value, "value"))
+  i_set_edge_attr(x, attr(value, "name"), index=value,
+                  value=attr(value, "value"), check = FALSE)
 }
 
-print.igraph.vs <- function(x, ...) {
-  cat("Vertex sequence:\n")
-  graph <- get("graph", attr(x, "env"))
-  x <- as.numeric(x)
-  if ("name" %in% list.vertex.attributes(graph)) {
-    x <- V(graph)$name[x]
-  }
-  print(x)
-}
+#' @include printr.R
+
+head_print <- printr$head_print
+
+#' Show a vertex sequence on the screen
+#'
+#' For long vertex sequences, the printing is truncated to fit to the 
+#' screen. Use \code{print} explicitly and the \code{full} argument to
+#' see the full sequence.
+#'
+#' Vertex sequence created with the double bracket operator are
+#' printed differently, together with all attributes of the vertices
+#' in the sequence, as a table.
+#' 
+#' @param x A vertex sequence.
+#' @param full Whether to show the full sequence, or truncate the output
+#'   to the screen size.
+#' @param ... These arguments are currently ignored.
+#' @return The vertex sequence, invisibly.
+#' 
+#' @method print igraph.vs
+#' @export
+#' @family vertex and edge sequences
+#' @examples
+#' # Unnamed graphs
+#' g <- make_ring(10)
+#' V(g)
+#'
+#' # Named graphs
+#' g2 <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10])
+#' V(g2)
+#'
+#' # All vertices in the sequence
+#' g3 <- make_ring(1000)
+#' V(g3)
+#' print(V(g3), full = TRUE)
+#'
+#' # Metadata
+#' g4 <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10]) %>%
+#'   set_vertex_attr("color", value = "red")
+#' V(g4)[[]]
+#' V(g4)[[2:5, 7:8]]
+
+print.igraph.vs <- function(x, full = igraph_opt("print.full"), ...) {
+
+  graph <- get_vs_graph(x)
+  len <- length(x)
+
+  title <- "+ " %+% chr(len) %+% "/" %+%
+    (if (is.null(graph)) "?" else chr(vcount(graph))) %+%
+    (if (len == 1) " vertex" else " vertices") %+%
+    (if (!is.null(names(x))) ", named" else "") %+% ":\n"
+  cat(title)
+
+  if (!is.null(attr(x, "single")) && attr(x, "single") &&
+      !is.null(graph) && length(vertex_attr_names(graph) > 0)) {
+    ## Double bracket
+    va <- vertex_attr(graph)
+    if (all(sapply(va, is.atomic))) {
+      print(as.data.frame(va, stringsAsFactors =
+                            FALSE)[as.vector(x),, drop = FALSE])
+    } else {
+      print(lapply(va, "[", as.vector(x)))
+    }
 
-print.igraph.es <- function(x, ...) {
-  cat("Edge sequence:\n")
-  graph <- get("graph", attr(x, "env"))
-  if (is.directed(graph)) {
-    arrow <- "->"
   } else {
-    arrow <- "--"
-  }
-  x <- as.numeric(x)
-  el <- get.edges(graph, x)
-  if ("name" %in% list.vertex.attributes(graph)) {
-    el <- matrix(V(graph)$name[el], ncol=2)
+    ## Single bracket
+
+    x2 <- if (!is.null(names(x))) names(x) else as.vector(x)
+    if (length(x2)) {
+      if (is.logical(full) && full) {
+        print(x2, quote = FALSE)
+      }  else {
+        head_print(x2, omitted_footer = "+ ... omitted several vertices\n",
+                   quote = FALSE, max_lines = igraph_opt("auto.print.lines"))
+      }
+    }
   }
-  tab <- data.frame(e=paste(sep="", "[", x, "]"), row.names="e")
-  if (is.numeric(el)) { w <- nchar(max(el)) } else { w <- max(nchar(el)) }
-  tab[" "] <- paste(format(el[,1], width=w), arrow, format(el[,2], width=w))
-  print(tab)
+
+  invisible(x)
+}
+
+#' Print an edge sequence to the screen
+#'
+#' For long edge sequences, the printing is truncated to fit to the
+#' screen. Use \code{print} explicitly and the code{full} argument to
+#' see the full sequence.
+#'
+#' Edge sequences created with the double bracket operator are printed
+#' differently, together with all attributes of the edges in the sequence,
+#' as a table.
+#' 
+#' @param x An edge sequence.
+#' @param full Whether to show the full sequence, or truncate the output
+#'   to the screen size.
+#' @param ... Currently ignored.
+#' @return The edge sequence, invisibly.
+#' 
+#' @method print igraph.es
+#' @export
+#' @family vertex and edge sequences
+#' @examples
+#' # Unnamed graphs
+#' g <- make_ring(10)
+#' E(g)
+#'
+#' # Named graphs
+#' g2 <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10])
+#' E(g2)
+#'
+#' # All edges in a long sequence
+#' g3 <- make_ring(200)
+#' E(g3)
+#' E(g3) %>% print(full = TRUE)
+#'
+#' # Metadata
+#' g4 <- make_ring(10) %>%
+#'   set_vertex_attr("name", value = LETTERS[1:10]) %>%
+#'   set_edge_attr("weight", value = 1:10) %>%
+#'   set_edge_attr("color", value = "green")
+#' E(g4)
+#' E(g4)[[]]
+#' E(g4)[[1:5]]
+
+print.igraph.es <- function(x, full = igraph_opt("print.full"), ...) {
+  graph <- get_es_graph(x)
+  ml <- if (identical(full, TRUE)) NULL else igraph_opt("auto.print.lines")
+  .print.edges.compressed(x = graph, edges = x, max.lines = ml, names = TRUE,
+                          num = TRUE)
+  invisible(x)
 }
 
 # these are internal
 
 as.igraph.vs <- function(graph, v, na.ok=FALSE) {
-  if (is.character(v) && "name" %in% list.vertex.attributes(graph)) {
+  if (inherits(v, "igraph.vs") && !is.null(graph) &&
+      !warn_version(graph)) {
+    if (get_graph_id(graph) != get_vs_graph_id(v)) {
+      stop("Cannot use a vertex sequence from another graph.")
+    }
+  }
+  if (is.character(v) && "name" %in% vertex_attr_names(graph)) {
     v <- as.numeric(match(v, V(graph)$name))
     if (!na.ok && any(is.na(v))) {
       stop("Invalid vertex names")
@@ -428,6 +1168,12 @@ as.igraph.vs <- function(graph, v, na.ok=FALSE) {
 }
 
 as.igraph.es <- function(graph, e) {
+  if (inherits(e, "igraph.es") && !is.null(graph)
+      && !warn_version(graph)) {
+    if (get_graph_id(graph) != get_es_graph_id(e)) {
+      stop("Cannot use an edge sequence from another graph.")
+    }
+  }
   if (is.character(e)) {
     Pairs <- grep("|", e, fixed=TRUE)
     Names <- if (length(Pairs)==0) seq_along(e) else -Pairs
@@ -441,7 +1187,7 @@ as.igraph.es <- function(graph, e) {
         stop("Invalid edge name: ", e[Pairs][vl!=2][1])
       }
       vp <- unlist(vv)
-      if (! "name" %in% list.vertex.attributes(graph)) {
+      if (! "name" %in% vertex_attr_names(graph)) {
         vp <- as.numeric(vp)
       }
       res[Pairs] <- get.edge.ids(graph, vp)
@@ -449,7 +1195,7 @@ as.igraph.es <- function(graph, e) {
 
     ## Based on edge ids/names
     if (length(Names) != 0) {
-      if ("name" %in% list.edge.attributes(graph)) {
+      if ("name" %in% edge_attr_names(graph)) {
         res[Names] <- as.numeric(match(e[Names], E(graph)$name))
       } else {
         res[Names] <- as.numeric(e[Names])
@@ -464,3 +1210,384 @@ as.igraph.es <- function(graph, e) {
   }
   res
 }
+
+
+is_igraph_vs <- function(x) {
+  inherits(x, "igraph.vs")
+}
+
+
+is_igraph_es <- function(x) {
+  inherits(x, "igraph.es")
+}
+
+
+parse_op_args <- function(..., what, is_fun, as_fun, check_graph = TRUE) {
+
+  args <- list(...)
+
+  if (any(! sapply(args, is_fun))) stop("Not ", what, " sequence")
+
+  ## get the ids of all graphs
+  graph_id <- sapply(args, get_vs_graph_id) %>%
+    unique()
+
+  if (length(graph_id) != 1) {
+    warning("Combining vertex/edge sequences from different graphs.\n",
+            "This will not work in future igraph versions")
+  }
+
+  graphs <- args %>%
+    lapply(get_vs_graph) %>%
+    drop_null()
+
+  addresses <- graphs %>%
+    sapply(function(x) x %&&% address(x)) %>%
+    unique()
+
+  if (check_graph && length(addresses) >= 2) {
+    warning("Combining vertex/edge sequences from different graphs.\n",
+            "This will not work in future igraph versions")
+  }
+
+  graph <- if (length(graphs)) graphs[[1]] else NULL
+
+  args <- lapply(args, unclass)
+
+  list(graph = graph, args = args, id = graph_id)
+}
+
+
+parse_vs_op_args <- function(...) {
+  parse_op_args(..., what = "a vertex", is_fun = is_igraph_vs,
+                as_fun = as.igraph.vs)
+}
+
+
+parse_es_op_args <- function(...) {
+  parse_op_args(..., what = "an edge", is_fun = is_igraph_es,
+                as_fun = as.igraph.es)
+}
+
+
+create_op_result <- function(parsed, result, class, args) {
+  result <- add_vses_graph_ref(result, parsed$graph)
+  class(result) <- class
+  ## c() drops names for zero length vectors. Why???
+  if (! length(result) &&
+      any(sapply(args, function(x) !is.null(names(x))))) {
+    names(result) <- character()
+  }
+  result
+}
+
+
+#' Remove duplicate vertices from a vertex sequence
+#' 
+#' @param x A vertex sequence.
+#' @param incomparables a vector of values that cannot be compared.
+#'   Passed to base function \code{duplicated}. See details there.
+#' @param ... Passed to base function \code{duplicated()}.
+#' @return A vertex sequence with the duplicate vertices removed.
+#' 
+#' @method unique igraph.vs
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' V(g)[1, 1:5, 1:10, 5:10]
+#' V(g)[1, 1:5, 1:10, 5:10] %>% unique()
+
+unique.igraph.vs <- function(x, incomparables = FALSE, ...) {
+  x[!duplicated(x, incomparables = incomparables, ...)]
+}
+
+
+#' Remove duplicate edges from an edge sequence
+#' 
+#' @param x An edge sequence.
+#' @param incomparables a vector of values that cannot be compared.
+#'   Passed to base function \code{duplicated}. See details there.
+#' @param ... Passed to base function \code{duplicated()}.
+#' @return An edge sequence with the duplicate vertices removed.
+#' 
+#' @method unique igraph.es
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' E(g)[1, 1:5, 1:10, 5:10]
+#' E(g)[1, 1:5, 1:10, 5:10] %>% unique()
+
+unique.igraph.es <- function(x, incomparables = FALSE, ...) {
+  x[!duplicated(x, incomparables = incomparables, ...)]
+}
+
+
+#' Concatenate vertex sequences
+#'
+#' @param ... The vertex sequences to concatenate. They must
+#'   refer to the same graph.
+#' @param recursive Ignored, included for S3 compatibility with
+#'   the base \code{c} function.
+#' @return A vertex sequence, the input sequences concatenated.
+#'
+#' @method c igraph.vs
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' c(V(g)[1], V(g)['A'], V(g)[1:4])
+
+c.igraph.vs <- function(..., recursive = FALSE) {
+  parsed <- parse_vs_op_args(...)
+  res <- do_call(c, .args = parsed$args)
+  create_op_result(parsed, res, "igraph.vs", list(...))
+}
+
+
+#' Concatenate edge sequences
+#'
+#' @param ... The edge sequences to concatenate. They must
+#'   all refer to the same graph.
+#' @param recursive Ignored, included for S3 compatibility with the
+#'   base \code{c} function.
+#' @return An edge sequence, the input sequences concatenated.
+#' 
+#' @method c igraph.es
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' c(E(g)[1], E(g)['A|B'], E(g)[1:4])
+
+c.igraph.es <- function(..., recursive = FALSE) {
+  parsed <- parse_es_op_args(...)
+  res <- do_call(c, .args = parsed$args)
+  res <- create_op_result(parsed, res, "igraph.es", list(...))
+  attr(res, "vnames") <- do_call(c, .args = lapply(list(...), attr, "vnames"))
+  res
+}
+
+
+#' Union of vertex sequences
+#'
+#' @details
+#' They must belong to the same graph. Note that this function has
+#' \sQuote{set} semantics and the multiplicity of vertices is lost in the
+#' result. (This is to match the behavior of the based \code{unique}
+#' function.)
+#'
+#' @param ... The vertex sequences to take the union of.
+#' @return A vertex sequence that contains all vertices in the given
+#' sequences, exactly once.
+#'
+#' @method union igraph.vs
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' union(V(g)[1:6], V(g)[5:10])
+
+union.igraph.vs <- function(...) {
+  unique(c(...))
+}
+
+
+#' Union of edge sequences
+#'
+#' @details
+#' They must belong to the same graph. Note that this function has
+#' \sQuote{set} semantics and the multiplicity of edges is lost in the
+#' result. (This is to match the behavior of the based \code{unique}
+#' function.)
+#'
+#' @param ... The edge sequences to take the union of.
+#' @return An edge sequence that contains all edges in the given
+#' sequences, exactly once.
+#'
+#' @method union igraph.es
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' union(E(g)[1:6], E(g)[5:9], E(g)['A|J'])
+
+union.igraph.es <- union.igraph.vs
+
+
+#' Intersection of vertex sequences
+#'
+#' @details
+#' They must belong to the same graph. Note that this function has
+#' \sQuote{set} semantics and the multiplicity of vertices is lost in the
+#' result.
+#'
+#' @param ... The vertex sequences to take the intersection of.
+#' @return A vertex sequence that contains vertices that appear in all
+#' given sequences, each vertex exactly once.
+#'
+#' @method intersection igraph.vs
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' intersection(E(g)[1:6], E(g)[5:9])
+
+intersection.igraph.vs <- function(...) {
+  ifun <- function(x, y) {
+    unique(y[match(as.vector(x), y, 0L)])
+  }
+  Reduce(ifun, list(...))
+}
+
+
+#' Intersection of edge sequences
+#'
+#' @details
+#' They must belong to the same graph. Note that this function has
+#' \sQuote{set} semantics and the multiplicity of edges is lost in the
+#' result.
+#'
+#' @param ... The edge sequences to take the intersection of.
+#' @return An edge sequence that contains edges that appear in all
+#' given sequences, each edge exactly once.
+#'
+#' @method intersection igraph.es
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' intersection(E(g)[1:6], E(g)[5:9])
+
+intersection.igraph.es <- intersection.igraph.vs
+
+
+#' Difference of vertex sequences
+#'
+#' @details
+#' They must belong to the same graph. Note that this function has
+#' \sQuote{set} semantics and the multiplicity of vertices is lost in the
+#' result.
+#'
+#' @param big The \sQuote{big} vertex sequence.
+#' @param small The \sQuote{small} vertex sequence.
+#' @param ... Ignored, included for S3 signature compatibility.
+#' @return A vertex sequence that contains only vertices that are part of
+#' \code{big}, but not part of \code{small}.
+#'
+#' @method difference igraph.vs
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' difference(V(g), V(g)[6:10])
+
+difference.igraph.vs <- function(big, small, ...) {
+  if (!length(big)) {
+    big
+  } else {
+    big[ match(big, small, 0L) == 0L ]
+  }
+}
+
+
+#' Difference of edge sequences
+#'
+#' @details
+#' They must belong to the same graph. Note that this function has
+#' \sQuote{set} semantics and the multiplicity of edges is lost in the
+#' result.
+#'
+#' @param big The \sQuote{big} edge sequence.
+#' @param small The \sQuote{small} edge sequence.
+#' @param ... Ignored, included for S3 signature compatibility.
+#' @return An edge sequence that contains only edges that are part of
+#' \code{big}, but not part of \code{small}.
+#'
+#' @method difference igraph.es
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' difference(V(g), V(g)[6:10])
+
+difference.igraph.es <- difference.igraph.vs
+
+
+#' Reverse the order in a vertex sequence
+#'
+#' @param x The vertex sequence to reverse.
+#' @return The reversed vertex sequence.
+#' 
+#' @method rev igraph.vs
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' V(g) %>% rev()
+
+rev.igraph.vs <- function(x) {
+  x[rev(seq_along(x))]
+}
+
+
+#' Reverse the order in an edge sequence
+#'
+#' @param x The edge sequence to reverse.
+#' @return The reversed edge sequence.
+#' 
+#' @method rev igraph.es
+#' @family vertex and edge sequence operations
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+#' E(g)
+#' E(g) %>% rev()
+
+rev.igraph.es <- rev.igraph.vs
+
+#' Convert a vertex or edge sequence to an ordinary vector
+#'
+#' @details
+#' For graphs without names, a numeric vector is returned, containing the
+#' internal numeric vertex or edge ids.
+#'
+#' For graphs with names, and vertex sequences, the vertex names are
+#' returned in a character vector.
+#'
+#' For graphs with names and edge sequences, a character vector is
+#' returned, with the \sQuote{bar} notation: \code{a|b} means an edge from
+#' vertex \code{a} to vertex \code{b}.
+#'
+#' @param seq The vertex or edge sequence.
+#' @return A character or numeric vector, see details below.
+#'
+#' @export
+#' @examples
+#' g <- make_ring(10)
+#' as_ids(V(g))
+#' as_ids(E(g))
+#'
+#' V(g)$name <- letters[1:10]
+#' as_ids(V(g))
+#' as_ids(E(g))
+
+as_ids <- function(seq)
+  UseMethod("as_ids")
+
+#' @method as_ids igraph.vs
+#' @rdname as_ids
+#' @export
+
+as_ids.igraph.vs <- function(seq) {
+  names(seq) %||% as.vector(seq)
+}
+
+#' @method as_ids igraph.es
+#' @rdname as_ids
+#' @export
+
+as_ids.igraph.es <- function(seq) {
+  attr(seq, "vnames") %||% as.vector(seq)
+}
diff --git a/R/layout.R b/R/layout.R
index 6b96556..8ccdd3c 100644
--- a/R/layout.R
+++ b/R/layout.R
@@ -1,771 +1,1741 @@
 
-#   IGraph R package
-#   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
-#   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
-#
-###################################################################
-
-###################################################################
-# Layouts
-###################################################################
-
-layout.random <- function(graph, params, dim=2) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  if (dim==2) {
-    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-    .Call("R_igraph_layout_random", graph,
-          PACKAGE="igraph")
-  } else if (dim==3) {
-    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-    .Call("R_igraph_layout_random_3d", graph,
-          PACKAGE="igraph")
+## ----------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2003-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## ----------------------------------------------------------------
+
+
+## ----------------------------------------------------------------
+## This is the new layout API
+## ----------------------------------------------------------------
+
+
+#' Graph layouts
+#'
+#' This is a generic function to apply a layout function to
+#' a graph.
+#'
+#' There are two ways to calculate graph layouts in igraph.
+#' The first way is to call a layout function (they all have
+#' prefix \code{layout_} on a graph, to get the vertex coordinates.
+#'
+#' The second way (new in igraph 0.8.0), has two steps, and it
+#' is more flexible. First you call a layout specification
+#' function (the one without the \code{layout_} prefix, and
+#' then \code{layout_} (or \code{\link{add_layout_}}) to
+#' perform the layouting.
+#'
+#' The second way is preferred, as it is more flexible. It allows
+#' operations before and after the layouting. E.g. using the
+#' \code{component_wise} argument, the layout can be calculated
+#' separately for each component, and then merged to get the
+#' final results.
+#'
+#' @aliases layout
+#' @section Modifiers:
+#' Modifiers modify how a layout calculation is performed.
+#' Currently implemented modifyers: \itemize{
+#'   \item \code{component_wise} calculates the layout separately
+#'     for each component of the graph, and then merges
+#'     them.
+#'   \item \code{normalize} scales the layout to a square.
+#' }
+#'
+#' @param graph The input graph.
+#' @param layout The layout specification. It must be a call
+#'   to a layout specification function.
+#' @param ... Further modifiers, see a complete list below.
+#'   For the \code{print} methods, it is ignored.
+#' @return The return value of the layout function, usually a
+#'   two column matrix. For 3D layouts a three column matrix.
+#'
+#' @seealso \code{\link{add_layout_}} to add the layout to the
+#'   graph as an attribute.
+#' @export
+#' @family graph layouts
+#' @examples
+#' g <- make_ring(10) + make_full_graph(5)
+#' coords <- layout_(g, as_star())
+#' plot(g, layout = coords)
+
+layout_ <- function(graph, layout, ...) {
+
+  modifiers <- list(...)
+  stopifnot(all(sapply(modifiers, inherits,
+                       what = "igraph_layout_modifier")))
+
+  ids <- sapply(modifiers, "[[", "id")
+  stopifnot(all(ids %in% c("component_wise", "normalize")))
+  if (anyDuplicated(ids)) stop("Duplicate modifiers")
+  names(modifiers) <- ids
+
+  ## TODO: better, generic mechanism for modifiers
+  if ("component_wise" %in% ids) {
+    graph$id <- seq(vcount(graph))
+    comps <- decompose(graph)
+    coords <- lapply(comps, function(comp) {
+      do_call(layout$fun, list(graph = comp), layout$args)
+    })
+    all_coords <- merge_coords(
+      comps,
+      coords,
+      method = modifiers[["component_wise"]]$args$merge_method
+    )
+    all_coords[ unlist(sapply(comps, vertex_attr, "id")), ] <- all_coords[]
+    result <- all_coords
+
   } else {
-    stop("Invalid `dim' value");
+    result <- do_call(layout$fun, list(graph = graph), layout$args)
   }
+
+  if ("normalize" %in% ids) {
+    result <- do_call(norm_coords, list(result),
+                      modifiers[["normalize"]]$args)
+  }
+
+  result
 }
 
-layout.circle <- function(graph, params) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
+
+#' Add layout to graph
+#'
+#' @param graph The input graph.
+#' @param ... Additional arguments are passed to \code{\link{layout_}}.
+#' @param overwrite Whether to overwrite the layout of the graph,
+#'    if it already has one.
+#' @return The input graph, with the layout added.
+#'
+#' @seealso \code{\link{layout_}} for a description of the layout API.
+#' @export
+#' @family graph layouts
+#' @examples
+#' (make_star(11) + make_star(11)) %>%
+#'   add_layout_(as_star(), component_wise()) %>%
+#'   plot()
+
+add_layout_ <- function(graph, ..., overwrite = TRUE) {
+  if (overwrite && 'layout' %in% graph_attr_names(graph)) {
+    graph <- delete_graph_attr(graph, 'layout')
+  }
+  graph$layout <- layout_(graph, ...)
+  graph
+}
+
+
+layout_spec <- function(fun, ...) {
+  my_call <- match.call(sys.function(1), sys.call(1))
+  my_call[[1]] <- substitute(fun)
+  structure(
+    list(
+      fun = fun,
+      call_str = sub("(", "(<graph>, ", deparse(my_call), fixed = TRUE),
+      args = list(...)
+    ),
+    class = "igraph_layout_spec"
+  )
+}
+
+
+#' @rdname layout_
+#' @param x The layout specification
+#' @method print igraph_layout_spec
+#' @export
+
+print.igraph_layout_spec <- function(x, ...) {
+  cat(paste(
+    sep = "",
+    "igraph layout specification, see ?layout_:\n",
+    x$call_str, "\n"
+  ))
+}
+
+
+layout_modifier <- function(...) {
+  structure(
+    list(...),
+    class = "igraph_layout_modifier"
+  )
+}
+
+
+#' @rdname layout_
+#' @method print igraph_layout_modifier
+#' @export
+
+print.igraph_layout_modifier <- function(x, ...) {
+  cat(sep = "", "igraph layout modifier: ", x$id, ".\n")
+}
+
+#' Component-wise layout
+#'
+#' This is a layout modifier function, and it can be used
+#' to calculate the layout separately for each component
+#' of the graph.
+#'
+#' @param merge_method Merging algorithm, the \code{method}
+#'   argument of \code{\link{merge_coords}}.
+#'
+#' @family layout modifiers
+#' @family graph layouts
+#' @seealso \code{\link{merge_coords}}, \code{\link{layout_}}.
+#' @export
+#' @examples
+#' g <- make_ring(10) + make_ring(10)
+#' g %>%
+#'   add_layout_(in_circle(), component_wise()) %>%
+#'   plot()
+
+component_wise <- function(merge_method = "dla") {
+
+  args <- grab_args()
+
+  layout_modifier(
+    id = "component_wise",
+    args = args
+  )
+}
+
+#' Normalize layout
+#'
+#' Scale coordinates of a layout.
+#'
+#' @param xmin,xmax Minimum and maximum for x coordinates.
+#' @param ymin,ymax Minimum and maximum for y coordinates.
+#' @param zmin,zmax Minimum and maximum for z coordinates.
+#'
+#' @family layout modifiers
+#' @family graph layouts
+#' @seealso \code{\link{merge_coords}}, \code{\link{layout_}}.
+#' @export
+#' @examples
+#' layout_(make_ring(10), with_fr(), normalize())
+
+normalize <- function(xmin = -1, xmax = 1, ymin = xmin, ymax = xmax,
+                      zmin = xmin, zmax = xmax) {
+
+  args <- grab_args()
+
+  layout_modifier(
+    id = "normalize",
+    args = args
+  )
+}
+
+## ----------------------------------------------------------------
+## Layout definitions for the new API
+## ----------------------------------------------------------------
+
+
+#' Simple two-row layout for bipartite graphs
+#'
+#' Minimize edge-crossings in a simple two-row (or column) layout for bipartite
+#' graphs.
+#'
+#' The layout is created by first placing the vertices in two rows, according
+#' to their types. Then the positions within the rows are optimized to minimize
+#' edge crossings, using the Sugiyama algorithm (see
+#' \code{\link{layout_with_sugiyama}}).
+#'
+#' @aliases layout_as_bipartite layout.bipartite
+#' @param graph The bipartite input graph. It should have a logical
+#' \sQuote{\code{type}} vertex attribute, or the \code{types} argument must be
+#' given.
+#' @param types A logical vector, the vertex types. If this argument is
+#' \code{NULL} (the default), then the \sQuote{\code{type}} vertex attribute is
+#' used.
+#' @param hgap Real scalar, the minimum horizontal gap between vertices in the
+#' same layer.
+#' @param vgap Real scalar, the distance between the two layers.
+#' @param maxiter Integer scalar, the maximum number of iterations in the
+#' crossing minimization stage. 100 is a reasonable default; if you feel that
+#' you have too many edge crossings, increase this.
+#' @return A matrix with two columns and as many rows as the number of vertices
+#' in the input graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout_with_sugiyama}}
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+#' @examples
+#' # Random bipartite graph
+#' inc <- matrix(sample(0:1, 50, replace = TRUE, prob=c(2,1)), 10, 5)
+#' g <- graph_from_incidence_matrix(inc)
+#' plot(g, layout = layout_as_bipartite,
+#'      vertex.color=c("green","cyan")[V(g)$type+1])
+#'
+#' # Two columns
+#' g %>%
+#'   add_layout_(as_bipartite()) %>%
+#'   plot()
+
+layout_as_bipartite <- function(graph, types = NULL, hgap = 1, vgap = 1,
+                                maxiter = 100) {
+
+  ## Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) {
+    types <- V(graph)$type
+  }
+  if (!is.null(types)) {
+    if (!is.logical(types)) {
+      warning("vertex types converted to logical")
+    }
+    types <- as.logical(types)
+    if (any(is.na(types))) {
+      stop("`NA' is not allowed in vertex types")
+    }
+  } else {
+    stop("Not a bipartite graph, supply `types' argument")
   }
+  hgap <- as.numeric(hgap)
+  vgap <- as.numeric(vgap)
+  maxiter <- as.integer(maxiter)
+
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_layout_circle", graph,
+
+  ## Function call
+  res <- .Call("R_igraph_layout_bipartite", graph, types, hgap, vgap, maxiter,
+               PACKAGE="igraph")
+
+  res
+}
+
+
+#' @rdname layout_as_bipartite
+#' @param ... Arguments to pass to \code{layout_as_bipartite}.
+#' @export
+
+as_bipartite <- function(...) layout_spec(layout_as_bipartite, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' Generate coordinates to place the vertices of a graph in a star-shape
+#'
+#' A simple layout generator, that places one vertex in the center of a circle
+#' and the rest of the vertices equidistantly on the perimeter.
+#'
+#' It is possible to choose the vertex that will be in the center, and the
+#' order of the vertices can be also given.
+#'
+#' @aliases layout_as_star layout.star
+#' @param graph The graph to layout.
+#' @param center The id of the vertex to put in the center. By default it is
+#' the first vertex.
+#' @param order Numeric vector, the order of the vertices along the perimeter.
+#' The default ordering is given by the vertex ids.
+#' @return A matrix with two columns and as many rows as the number of vertices
+#' in the input graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout}} and \code{\link{layout.drl}} for other layout
+#' algorithms, \code{\link{plot.igraph}} and \code{\link{tkplot}} on how to
+#' plot graphs and \code{\link{star}} on how to create ring graphs.
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+#' @examples
+#'
+#' g <- make_star(10)
+#' layout_as_star(g)
+#'
+#' ## Alternative form
+#' layout_(g, as_star())
+
+layout_as_star <- function(graph, center=V(graph)[1], order=NULL) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  center <- as.igraph.vs(graph, center)
+  if (!is.null(order)) order <- as.numeric(order)-1
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_layout_star", graph, center-1, order,
         PACKAGE="igraph")
+
+  res
 }
 
-layout.sphere <- function(graph, params) {
-  if (!is.igraph(graph)) {
+
+#' @rdname layout_as_star
+#' @param ... Arguments to pass to \code{layout_as_star}.
+#' @export
+
+as_star <- function(...) layout_spec(layout_as_star, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' The Reingold-Tilford graph layout algorithm
+#'
+#' A tree-like layout, it is perfect for trees, acceptable for graphs with not
+#' too many cycles.
+#'
+#' Arranges the nodes in a tree where the given node is used as the root.  The
+#' tree is directed downwards and the parents are centered above its children.
+#' For the exact algorithm, the refernce below.
+#'
+#' If the given graph is not a tree, a breadth-first search is executed first
+#' to obtain a possible spanning tree.
+#'
+#' @param graph The input graph.
+#' @param root The index of the root vertex or root vertices.  If this is a
+#' non-empty vector then the supplied vertex ids are used as the roots of the
+#' trees (or a single tree if the graph is connected).  If it is an empty
+#' vector, then the root vertices are automatically calculated based on
+#' topological sorting, performed with the opposite mode than the \code{mode}
+#' argument. After the vertices have been sorted, one is selected from each
+#' component.
+#' @param circular Logical scalar, whether to plot the tree in a circular
+#' fashion. Defaults to \code{FALSE}, so the tree branches are going bottom-up
+#' (or top-down, see the \code{flip.y} argument.
+#' @param rootlevel This argument can be useful when drawing forests which are
+#' not trees (i.e. they are unconnected and have tree components). It specifies
+#' the level of the root vertices for every tree in the forest. It is only
+#' considered if the \code{roots} argument is not an empty vector.
+#' @param mode Specifies which edges to consider when building the tree.  If it
+#' is \sQuote{out}, then only the outgoing, if it is \sQuote{in}, then only the
+#' incoming edges of a parent are considered. If it is \sQuote{all} then all
+#' edges are used (this was the behavior in igraph 0.5 and before). This
+#' parameter also influences how the root vertices are calculated, if they are
+#' not given. See the \code{roots} parameter.
+#' @param flip.y Logical scalar, whether to flip the \sQuote{y} coordinates.
+#' The default is flipping because that puts the root vertex on the top.
+#' @return A numeric matrix with two columns, and one row for each vertex.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @references Reingold, E and Tilford, J (1981). Tidier drawing of trees.
+#' \emph{IEEE Trans. on Softw. Eng.}, SE-7(2):223--228.
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+#' @examples
+#'
+#' tree <- make_tree(20, 3)
+#' plot(tree, layout=layout_as_tree)
+#' plot(tree, layout=layout_as_tree(tree, flip.y=FALSE))
+#' plot(tree, layout=layout_as_tree(tree, circular=TRUE))
+#'
+#' tree2 <- make_tree(10, 3) + make_tree(10, 2)
+#' plot(tree2, layout=layout_as_tree)
+#' plot(tree2, layout=layout_as_tree(tree2, root=c(1,11),
+#'                                            rootlevel=c(2,1)))
+
+layout_as_tree <- function(graph, root=numeric(), circular=FALSE,
+                                    rootlevel=numeric(), mode="out",
+                                    flip.y=TRUE) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
+  root <- as.igraph.vs(graph, root)-1
+  circular <- as.logical(circular)
+  rootlevel <- as.double(rootlevel)
+  mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3,
+                 "total"=3)
+  flip.y <- as.logical(flip.y)
+
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_layout_sphere", graph,
-        PACKAGE="igraph")
+  res <- .Call("R_igraph_layout_reingold_tilford", graph, root, mode,
+               rootlevel, circular, PACKAGE="igraph")
+  if (flip.y) { res[,2] <- max(res[,2])-res[,2] }
+  res
 }
 
-layout.fruchterman.reingold <- function(graph, ..., dim=2,
-                                        params=list()) {
 
-  if (!is.igraph(graph)) {
+#' @rdname layout_as_tree
+#' @param ... Passed to \code{layout_as_tree}.
+#' @export
+
+as_tree <- function(...) layout_spec(layout_as_tree, ...)
+
+#' @export
+#' @rdname layout.deprecated
+
+layout.reingold.tilford <- function(..., params = list()) {
+  do_call(layout_as_tree, .args = c(list(...), params))
+}
+
+## ----------------------------------------------------------------
+
+
+#' Graph layout with vertices on a circle.
+#'
+#' Place vertices on a circle, in the order of their vertex ids.
+#'
+#' If you want to order the vertices differently, then permute them using the
+#' \code{\link{permute}} function.
+#'
+#' @param graph The input graph.
+#' @param order The vertices to place on the circle, in the order of their
+#' desired placement. Vertices that are not included here will be placed at
+#' (0,0).
+#' @return A numeric matrix with two columns, and one row for each vertex.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+#' @examples
+#'
+#' ## Place vertices on a circle, order them according to their
+#' ## community
+#' \dontrun{
+#' library(igraphdata)
+#' data(karate)
+#' karate_groups <- cluster_optimal(karate)
+#' coords <- layout_in_circle(karate, order =
+#'           order(membership(karate_groups)))
+#' V(karate)$label <- sub("Actor ", "", V(karate)$name)
+#' V(karate)$label.color <- membership(karate_groups)
+#' V(karate)$shape <- "none"
+#' plot(karate, layout = coords)
+#' }
+
+layout_in_circle <- function(graph, order=V(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  if (length(params)==0) {
-    params <- list(...)
-  }
+  order <- as.igraph.vs(graph, order) - 1L
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  .Call("R_igraph_layout_circle", graph, order,
+        PACKAGE="igraph")
+}
+
+#' @rdname layout_in_circle
+#' @param ... Passed to \code{layout_in_circle}.
+#' @export
+
+in_circle <- function(...) layout_spec(layout_in_circle, ...)
+
+#' @export
+#' @rdname layout.deprecated
+
+layout.circle <- function(..., params = list()) {
+  do_call(layout_in_circle, .args = c(list(...), params))
+}
+
+## ----------------------------------------------------------------
+
+
+#' Choose an appropriate graph layout algorithm automatically
+#'
+#' This function tries to choose an appropriate graph layout algorithm for the
+#' graph, automatically, based on a simple algorithm. See details below.
+#'
+#' \code{layout_nicely} tries to choose an appropriate layout function for the
+#' supplied graph, and uses that to generate the layout. The current
+#' implementation works like this: \enumerate{ \item If the graph has a graph
+#' attribute called \sQuote{layout}, then this is used. If this attribute is an
+#' R function, then it is called, with the graph and any other extra arguments.
+#' \item Otherwise, if the graph has vertex attributes called \sQuote{x} and
+#' \sQuote{y}, then these are used as coordinates. If the graph has an
+#' additional \sQuote{z} vertex attribute, that is also used.  \item Otherwise,
+#' if the graph is connected and has less than 1000 vertices, the
+#' Fruchterman-Reingold layout is used, by calling \code{layout_with_fr}.
+#' \item Otherwise the DrL layout is used, \code{layout_with_drl} is called.  }
+#'
+#' @aliases layout.auto
+#' @param graph The input graph
+#' @param dim Dimensions, should be 2 or 3.
+#' @param \dots For \code{layout_nicely} the extra arguments are passed to
+#'   the real layout function. For \code{nicely} all argument are passed to
+#'   \code{layout_nicely}.
+#' @return A numeric matrix with two or three columns.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{plot.igraph}}
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+
+layout_nicely <- function(graph, dim=2, ...) {
+
+  ## 1. If there is a 'layout' graph attribute, we just use that.
+  ## 2. Otherwise, if there are vertex attributes called 'x' and 'y',
+  ##    we use those (and the 'z' vertex attribute as well, if present).
+  ## 3. Otherwise, if the graph is small (<1000) we use
+  ##    the Fruchterman-Reingold layout.
+  ## 5. Otherwise we use the DrL layout generator.
+
+  if ("layout" %in% graph_attr_names(graph)) {
+    lay <- graph_attr(graph, "layout")
+    if (is.function(lay)) {
+      lay(graph, ...)
+    } else {
+      lay
+    }
+
+  } else if ( all(c("x", "y") %in% vertex_attr_names(graph)) ) {
+    if ("z" %in% vertex_attr_names(graph)) {
+      cbind(V(graph)$x, V(graph)$y, V(graph)$z)
+    } else {
+      cbind(V(graph)$x, V(graph)$y)
+    }
+
+  } else if (vcount(graph) < 1000) {
+    layout_with_fr(graph, dim=dim, ...)
 
-  if (dim==2) {
-    fn <- "R_igraph_layout_fruchterman_reingold"
-  } else if (dim==3 ){
-    fn <- "R_igraph_layout_fruchterman_reingold_3d"
   } else {
-    stop("Invalid `dim' argument");
+    layout_with_drl(graph, dim=dim, ...)
   }
-  
-  vc <- vcount(graph)
-  if (is.null(params$niter))     { params$niter      <- 500  }
-  if (is.null(params$maxdelta))  { params$maxdelta   <- vc   }
-  if (is.null(params$area))      { params$area       <- vc^2 }
-  if (is.null(params$coolexp))   { params$coolexp    <- 1.5  }
-  if (is.null(params$repulserad)){ params$repulserad <- params$area * vc }
-  if (is.null(params$weights))   {
-    params$weights <- NULL
+
+}
+
+
+#' @rdname layout_nicely
+#' @export
+
+nicely <- function(...) layout_spec(layout_nicely, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' Simple grid layout
+#'
+#' This layout places vertices on a rectangulat grid, in two or three
+#' dimensions.
+#'
+#' The function places the vertices on a simple rectangular grid, one after the
+#' other. If you want to change the order of the vertices, then see the
+#' \code{\link{permute}} function.
+#'
+#' @aliases layout_on_grid layout.grid layout.grid.3d
+#' @param graph The input graph.
+#' @param width The number of vertices in a single row of the grid. If this is
+#' zero or negative, then for 2d layouts the width of the grid will be the
+#' square root of the number of vertices in the graph, rounded up to the next
+#' integer. Similarly, it will be the cube root for 3d layouts.
+#' @param height The number of vertices in a single column of the grid, for
+#' three dimensional layouts. If this is zero or negative, then it is
+#' determinted automatically.
+#' @param dim Two or three. Whether to make 2d or a 3d layout.
+#' @return A two-column or three-column matrix.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @seealso \code{\link{layout}} for other layout generators
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+#' @examples
+#'
+#' g <- make_lattice( c(3,3) )
+#' layout_on_grid(g)
+#'
+#' g2 <- make_lattice( c(3,3,3) )
+#' layout_on_grid(g2, dim = 3)
+#'
+#' \dontrun{
+#' plot(g, layout=layout_on_grid)
+#' rglplot(g, layout=layout_on_grid(g, dim = 3))
+#' }
+
+layout_on_grid <- function(graph, width = 0, height = 0, dim = 2) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  width <- as.integer(width)
+  dim <- as.integer(dim)
+  stopifnot(dim == 2 || dim == 3)
+  if (dim == 3) { height <- as.integer(height) }
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  if (dim == 2) {
+    res <- .Call("R_igraph_layout_grid", graph, width,
+                 PACKAGE="igraph")
   } else {
-    params$weights <- as.numeric(params$weights)
-  }
-  if (!is.null(params$start)) {
-    params$start <- structure(as.numeric(params$start), dim=dim(params$start))
-  }
-  if (!is.null(params$minx)) {
-    params$minx <- as.double(params$minx)
-  }
-  if (!is.null(params$maxx)) {
-    params$maxx <- as.double(params$maxx)
-  }
-  if (!is.null(params$miny)) {
-    params$miny <- as.double(params$miny)
-  }
-  if (!is.null(params$maxy)) {
-    params$maxy <- as.double(params$maxy)
-  }
-  if (!is.null(params$minz)) {
-    params$minz <- as.double(params$minz)
-  }
-  if (!is.null(params$maxz)) {
-    params$maxz <- as.double(params$maxz)
+    res <- .Call("R_igraph_layout_grid_3d", graph, width, height,
+                 PACKAGE="igraph")
   }
-  
+
+  res
+}
+
+
+#' @rdname layout_on_grid
+#' @param ... Passed to \code{layout_on_grid}.
+#' @export
+
+on_grid <- function(...) layout_spec(layout_on_grid, ...)
+
+
+#' @rdname layout_on_grid
+#' @export
+
+layout.grid.3d <- function(graph, width=0, height=0) {
+  .Deprecated("layout_on_grid", msg = paste0("layout.grid.3d is deprecated from\n",
+      "igraph 0.8.0, please use layout_on_grid instead"))
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  width <- as.integer(width)
+  height <- as.integer(height)
+
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call(fn, graph,
-        as.double(params$niter), as.double(params$maxdelta),
-        as.double(params$area), as.double(params$coolexp),
-        as.double(params$repulserad), params$weights, params$start,
-        params$minx, params$maxx, params$miny, params$maxy,
-        params$minz, params$maxz,
+  # Function call
+  res <- .Call("R_igraph_layout_grid_3d", graph, width, height,
         PACKAGE="igraph")
+
+  res
 }
 
-layout.fruchterman.reingold.grid <- function(graph, ...,
-                                             params=list()) {
-  if (!is.igraph(graph)) {
+## ----------------------------------------------------------------
+
+
+#' Graph layout with vertices on the surface of a sphere
+#'
+#' Place vertices on a sphere, approximately uniformly, in the order of their
+#' vertex ids.
+#'
+#' \code{layout_on_sphere} places the vertices (approximately) uniformly on the
+#' surface of a sphere, this is thus a 3d layout. It is not clear however what
+#' \dQuote{uniformly on a sphere} means.
+#'
+#' If you want to order the vertices differently, then permute them using the
+#' \code{\link{permute}} function.
+#'
+#' @param graph The input graph.
+#' @return A numeric matrix with three columns, and one row for each vertex.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+
+layout_on_sphere <- function(graph) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  if (length(params)==0) {
-    params <- list(...)
-  }
-
-  vc <- vcount(graph)
-  if (is.null(params$niter))     { params$niter      <- 500  }
-  if (is.null(params$maxdelta))  { params$maxdelta   <- vc   }
-  if (is.null(params$area))      { params$area       <- vc^2 }
-  if (is.null(params$coolexp))   { params$coolexp    <- 1.5  }
-  if (is.null(params$repulserad)){ params$repulserad <- params$area * vc }
-  if (is.null(params$cellsize))  { params$cellsize   <-
-                                     (sqrt(sqrt(params$area))) }
-  if (is.null(params$weights))   {
-    params$weights <- NULL
-  } else {
-    params$weights <- as.numeric(params$weights)
-  }
-  if (!is.null(params$start)) {
-    params$start <- structure(as.numeric(params$start), dim=dim(params$start))
-  }
-  
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_layout_fruchterman_reingold_grid", graph,
-        as.double(params$niter), as.double(params$maxdelta),
-        as.double(params$area), as.double(params$coolexp),
-        as.double(params$repulserad), as.double(params$cellsize),
-        params$start, params$weights,
+  .Call("R_igraph_layout_sphere", graph,
         PACKAGE="igraph")
 }
-  
 
-# FROM SNA 0.5
 
-layout.kamada.kawai<-function(graph, ..., dim=2,
-                              params=list()) {
+#' @rdname layout_on_sphere
+#' @param ... Passed to \code{layout_on_sphere}.
+#' @export
+
+on_sphere <- function(...) layout_spec(layout_on_sphere, ...)
+
+#' @export
+#' @rdname layout.deprecated
 
-  if (!is.igraph(graph)) {
+layout.sphere <- function(..., params = list()) {
+  do_call(layout_on_sphere, .args = c(list(...), params))
+}
+
+## ----------------------------------------------------------------
+
+
+#' Randomly place vertices on a plane or in 3d space
+#'
+#' This function uniformly randomly places the vertices of the graph in two or
+#' three dimensions.
+#'
+#' Randomly places vertices on a [-1,1] square (in 2d) or in a cube (in 3d). It
+#' is probably a useless layout, but it can use as a starting point for other
+#' layout generators.
+#'
+#' @param graph The input graph.
+#' @param dim Integer scalar, the dimension of the space to use. It must be 2
+#' or 3.
+#' @return A numeric matrix with two or three columns.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+
+layout_randomly <- function(graph, dim=2) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  if (length(params)==0) {
-    params <- list(...)
-  }
-
   if (dim==2) {
-    fn <- "R_igraph_layout_kamada_kawai"
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    .Call("R_igraph_layout_random", graph,
+          PACKAGE="igraph")
   } else if (dim==3) {
-    fn <- "R_igraph_layout_kamada_kawai_3d"
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    .Call("R_igraph_layout_random_3d", graph,
+          PACKAGE="igraph")
   } else {
-    stop("Invalid `dim' parameter")
-  }
-  
-  vc <- vcount(graph)
-  if (is.null(params$niter))      { params$niter   <- 1000 }
-  if (is.null(params$sigma))      { params$sigma   <- vc/4 }
-  if (is.null(params$initemp))    { params$initemp <- 10   }
-  if (is.null(params$coolexp))    { params$coolexp <- 0.99 }
-  if (is.null(params$kkconst))    { params$kkconst <- vc^2 }
-  if (is.null(params$fixz))       { params$fixz    <- FALSE}
-  if (!is.null(params$start)) {
-    params$start <- structure(as.numeric(params$start), dim=dim(params$start))
+    stop("Invalid `dim' value");
   }
-  if (!is.null(params$minx)) {
-    params$minx <- as.double(params$minx)
+}
+
+#' @rdname layout_randomly
+#' @param ... Parameters to pass to \code{layout_randomly}.
+#' @export
+
+randomly <- function(...) layout_spec(layout_randomly, ...)
+
+#' Deprecated layout functions
+#'
+#' Please use the new names, see \code{\link{layout_}}.
+#'
+#' @param ... Passed to the new layout functions.
+#' @param params Passed to the new layout functions as arguments.
+#' @export
+#' @rdname layout.deprecated
+
+layout.random <- function(..., params = list()) {
+  do_call(layout_randomly, .args = c(list(...), params))
+}
+
+
+## ----------------------------------------------------------------
+
+
+
+#' The Davidson-Harel layout algorithm
+#'
+#' Place vertices of a graph on the plane, according to the simulated annealing
+#' algorithm by Davidson and Harel.
+#'
+#' This function implements the algorithm by Davidson and Harel, see Ron
+#' Davidson, David Harel: Drawing Graphs Nicely Using Simulated Annealing. ACM
+#' Transactions on Graphics 15(4), pp. 301-331, 1996.
+#'
+#' The algorithm uses simulated annealing and a sophisticated energy function,
+#' which is unfortunately hard to parameterize for different graphs. The
+#' original publication did not disclose any parameter values, and the ones
+#' below were determined by experimentation.
+#'
+#' The algorithm consists of two phases, an annealing phase, and a fine-tuning
+#' phase. There is no simulated annealing in the second phase.
+#'
+#' Our implementation tries to follow the original publication, as much as
+#' possible. The only major difference is that coordinates are explicitly kept
+#' within the bounds of the rectangle of the layout.
+#'
+#' @aliases layout.davidson.harel
+#' @param graph The graph to lay out. Edge directions are ignored.
+#' @param coords Optional starting positions for the vertices. If this argument
+#' is not \code{NULL} then it should be an appropriate matrix of starting
+#' coordinates.
+#' @param maxiter Number of iterations to perform in the first phase.
+#' @param fineiter Number of iterations in the fine tuning phase.
+#' @param cool.fact Cooling factor.
+#' @param weight.node.dist Weight for the node-node distances component of the
+#' energy function.
+#' @param weight.border Weight for the distance from the border component of
+#' the energy function. It can be set to zero, if vertices are allowed to sit
+#' on the border.
+#' @param weight.edge.lengths Weight for the edge length component of the
+#' energy function.
+#' @param weight.edge.crossings Weight for the edge crossing component of the
+#' energy function.
+#' @param weight.node.edge.dist Weight for the node-edge distance component of
+#' the energy function.
+#' @return A two- or three-column matrix, each row giving the coordinates of a
+#' vertex, according to the ids of the vertex ids.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout_with_fr}},
+#' \code{\link{layout_with_kk}} for other layout algorithms.
+#' @references Ron Davidson, David Harel: Drawing Graphs Nicely Using Simulated
+#' Annealing. \emph{ACM Transactions on Graphics} 15(4), pp. 301-331, 1996.
+#' @export
+#' @family graph layouts
+#' @examples
+#'
+#' set.seed(42)
+#' ## Figures from the paper
+#' g_1b <- make_star(19, mode="undirected") + path(c(2:19, 2)) +
+#'   path(c(seq(2, 18, by=2), 2))
+#' plot(g_1b, layout=layout_with_dh)
+#'
+#' g_2 <- make_lattice(c(8, 3)) + edges(1,8, 9,16, 17,24)
+#' plot(g_2, layout=layout_with_dh)
+#'
+#' g_3 <- make_empty_graph(n=70)
+#' plot(g_3, layout=layout_with_dh)
+#'
+#' g_4 <- make_empty_graph(n=70, directed=FALSE) + edges(1:70)
+#' plot(g_4, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_5a <- make_ring(24)
+#' plot(g_5a, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_5b <- make_ring(40)
+#' plot(g_5b, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_6 <- make_lattice(c(2,2,2))
+#' plot(g_6, layout=layout_with_dh)
+#'
+#' g_7 <- graph_from_literal(1:3:5 -- 2:4:6)
+#' plot(g_7, layout=layout_with_dh, vertex.label=V(g_7)$name)
+#'
+#' g_8 <- make_ring(5) + make_ring(10) + make_ring(5) +
+#'   edges(1,6, 2,8, 3, 10, 4,12, 5,14,
+#'         7,16, 9,17, 11,18, 13,19, 15,20)
+#' plot(g_8, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_9 <- make_lattice(c(3,2,2))
+#' plot(g_9, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_10 <- make_lattice(c(6,6))
+#' plot(g_10, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_11a <- make_tree(31, 2, mode="undirected")
+#' plot(g_11a, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_11b <- make_tree(21, 4, mode="undirected")
+#' plot(g_11b, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+#'
+#' g_12 <- make_empty_graph(n=37, directed=FALSE) +
+#'   path(1:5,10,22,31,37:33,27,16,6,1) + path(6,7,11,9,10) + path(16:22) +
+#'   path(27:31) + path(2,7,18,28,34) + path(3,8,11,19,29,32,35) +
+#'   path(4,9,20,30,36) + path(1,7,12,14,19,24,26,30,37) +
+#'   path(5,9,13,15,19,23,25,28,33) + path(3,12,16,25,35,26,22,13,3)
+#' plot(g_12,  layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+layout_with_dh <- function(graph, coords=NULL, maxiter=10,
+           fineiter=max(10, log2(vcount(graph))), cool.fact=0.75,
+           weight.node.dist=1.0, weight.border=0.0,
+           weight.edge.lengths=edge_density(graph) / 10,
+           weight.edge.crossings=1.0 - sqrt(edge_density(graph)),
+           weight.node.edge.dist=0.2 * (1-edge_density(graph))) {
+
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(coords)) {
+    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
+    use.seed <- TRUE
+  } else {
+    coords <- matrix(ncol=2, nrow=0)
+    use.seed <- FALSE
   }
-  if (!is.null(params$maxx)) {
-    params$maxx <- as.double(params$maxx)
+  maxiter <- as.integer(maxiter)
+  fineiter <- as.integer(fineiter)
+  cool.fact <- as.numeric(cool.fact)
+  weight.node.dist <- as.numeric(weight.node.dist)
+  weight.border <- as.numeric(weight.border)
+  weight.edge.lengths <- as.numeric(weight.edge.lengths)
+  weight.edge.crossings <- as.numeric(weight.edge.crossings)
+  weight.node.edge.dist <- as.numeric(weight.node.edge.dist)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_layout_davidson_harel", graph, coords, use.seed,
+               maxiter, fineiter, cool.fact, weight.node.dist,
+               weight.border, weight.edge.lengths, weight.edge.crossings,
+               weight.node.edge.dist, PACKAGE="igraph")
+
+  res
+}
+
+
+#' @rdname layout_with_dh
+#' @param ... Passed to \code{layout_with_dh}.
+#' @export
+
+with_dh <- function(...) layout_spec(layout_with_dh, ...)
+
+
+
+## ----------------------------------------------------------------
+
+
+#' The Fruchterman-Reingold layout algorithm
+#'
+#' Place vertices on the plane using the force-directed layout algorithm by
+#' Fruchterman and Reingold.
+#'
+#' See the referenced paper below for the details of the algorithm.
+#'
+#' This function was rewritten from scratch in igraph version 0.8.0.
+#'
+#' @param graph The graph to lay out. Edge directions are ignored.
+#' @param coords Optional starting positions for the vertices. If this argument
+#' is not \code{NULL} then it should be an appropriate matrix of starting
+#' coordinates.
+#' @param dim Integer scalar, 2 or 3, the dimension of the layout.  Two
+#' dimensional layouts are places on a plane, three dimensional ones in the 3d
+#' space.
+#' @param niter Integer scalar, the number of iterations to perform.
+#' @param start.temp Real scalar, the start temperature. This is the maximum
+#' amount of movement alloved along one axis, within one step, for a vertex.
+#' Currently it is decreased linearly to zero during the iteration.
+#' @param grid Character scalar, whether to use the faster, but less accurate
+#' grid based implementation of the algorithm. By default (\dQuote{auto}), the
+#' grid-based implementation is used if the graph has more than one thousand
+#' vertices.
+#' @param weights A vector giving edge weights. The \code{weight} edge
+#' attribute is used by default, if present. If weights are given, then the
+#' attraction along the edges will be multiplied by the given edge weights.
+#' @param minx If not \code{NULL}, then it must be a numeric vector that gives
+#' lower boundaries for the \sQuote{x} coordinates of the vertices. The length
+#' of the vector must match the number of vertices in the graph.
+#' @param maxx Similar to \code{minx}, but gives the upper boundaries.
+#' @param miny Similar to \code{minx}, but gives the lower boundaries of the
+#' \sQuote{y} coordinates.
+#' @param maxy Similar to \code{minx}, but gives the upper boundaries of the
+#' \sQuote{y} coordinates.
+#' @param minz Similar to \code{minx}, but gives the lower boundaries of the
+#' \sQuote{z} coordinates.
+#' @param maxz Similar to \code{minx}, but gives the upper boundaries of the
+#' \sQuote{z} coordinates.
+#' @param coolexp,maxdelta,area,repulserad These arguments are not supported
+#' from igraph version 0.8.0 and are ignored (with a warning).
+#' @param maxiter A deprecated synonym of \code{niter}, for compatibility.
+#' @return A two- or three-column matrix, each row giving the coordinates of a
+#' vertex, according to the ids of the vertex ids.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout_with_drl}}, \code{\link{layout_with_kk}} for
+#' other layout algorithms.
+#' @references Fruchterman, T.M.J. and Reingold, E.M. (1991). Graph Drawing by
+#' Force-directed Placement. \emph{Software - Practice and Experience},
+#' 21(11):1129-1164.
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+#' @examples
+#'
+#' # Fixing ego
+#' g <- sample_pa(20, m=2)
+#' minC <- rep(-Inf, vcount(g))
+#' maxC <- rep(Inf, vcount(g))
+#' minC[1] <- maxC[1] <- 0
+#' co <- layout_with_fr(g, minx=minC, maxx=maxC,
+#'                                   miny=minC, maxy=maxC)
+#' co[1,]
+#' plot(g, layout=co, vertex.size=30, edge.arrow.size=0.2,
+#'      vertex.label=c("ego", rep("", vcount(g)-1)), rescale=FALSE,
+#'      xlim=range(co[,1]), ylim=range(co[,2]), vertex.label.dist=0,
+#'      vertex.label.color="red")
+#' axis(1)
+#' axis(2)
+#'
+layout_with_fr <- function(graph, coords=NULL, dim=2,
+                            niter=500, start.temp=sqrt(vcount(graph)),
+                            grid=c("auto", "grid", "nogrid"), weights=NULL,
+                            minx=NULL, maxx=NULL, miny=NULL, maxy=NULL,
+                            minz=NULL, maxz=NULL,
+                            coolexp, maxdelta, area, repulserad, maxiter) {
+
+                                        # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(coords)) {
+    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
   }
-  if (!is.null(params$miny)) {
-    params$miny <- as.double(params$miny)
+  dim <- as.integer(dim)
+  if (dim != 2L && dim != 3L) {
+    stop("Dimension must be two or three")
   }
-  if (!is.null(params$maxy)) {
-    params$maxy <- as.double(params$maxy)
+  if (!missing(niter) && !missing(maxiter)) {
+    stop("Both `niter' and `maxiter' are given, give only one of them")
   }
-  if (!is.null(params$minz)) {
-    params$minz <- as.double(params$minz)
+  if (!missing(maxiter)) niter <- maxiter
+  niter <- as.integer(niter)
+  start.temp <- as.numeric(start.temp)
+
+  grid <- igraph.match.arg(grid)
+  grid <- switch(grid, "grid"=0L, "nogrid"=1L, "auto"=2L)
+
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
+    weights <- E(graph)$weight
   }
-  if (!is.null(params$maxz)) {
-    params$maxz <- as.double(params$maxz)
+  if (!is.null(weights) && any(!is.na(weights))) {
+    weights <- as.numeric(weights)
+  } else {
+    weights <- NULL
   }
-  if (params$fixz && dim==2) {
-    warning("`fixz' works for 3D only, ignored.")
+  if (!is.null(minx)) minx <- as.numeric(minx)
+  if (!is.null(maxx)) maxx <- as.numeric(maxx)
+  if (!is.null(miny)) miny <- as.numeric(miny)
+  if (!is.null(maxy)) maxy <- as.numeric(maxy)
+  if (!is.null(minz)) minz <- as.numeric(minz)
+  if (!is.null(maxz)) maxz <- as.numeric(maxz)
+  if (!missing(coolexp)) {
+    warning("Argument `coolexp' is deprecated and has no effect")
   }
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call(fn, graph,
-        as.double(params$niter), as.double(params$initemp),
-        as.double(params$coolexp), as.double(params$kkconst),
-        as.double(params$sigma), params$start, as.logical(params$fixz),
-        params$minx, params$maxx, params$miny, params$maxy,
-        params$minz, params$maxz,
-        PACKAGE="igraph")
-}
-
-layout.graphopt <- function(graph, ..., 
-                            params=list()) {
-  
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
+  if (!missing(maxdelta)) {
+    warning("Argument `maxdelta' is deprecated and has no effect")
   }
-  if (length(params)==0) {
-    params <- list(...)
+  if (!missing(area)) {
+    warning("Argument `area' is deprecated and has no effect")
   }
-
-  vc <- vcount(graph)
-  if (is.null(params$niter))            { params$niter           <- 500   }
-  if (is.null(params$charge))           { params$charge          <- 0.001 }
-  if (is.null(params$mass))             { params$mass            <- 30    }
-  if (is.null(params$spring.length))    { params$spring.length   <- 0     }
-  if (is.null(params$spring.constant))  { params$spring.constant <- 1     }
-  if (is.null(params$max.sa.movement))  { params$max.sa.movement <- 5     }
-  if (!is.null(params$start)) {
-    params$start <- structure(as.numeric(params$start), dim=dim(params$start))
+  if (!missing(repulserad)) {
+    warning("Argument `repulserad' is deprecated and has no effect")
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_layout_graphopt", graph,
-        as.double(params$niter), as.double(params$charge),
-        as.double(params$mass), as.double(params$spring.length),
-        as.double(params$spring.constant), params$max.sa.movement,
-        params$start,
-        PACKAGE="igraph")
+  if (dim==2) {
+    res <- .Call("R_igraph_layout_fruchterman_reingold", graph, coords,
+                 niter, start.temp, weights, minx, maxx, miny, maxy, grid,
+                 PACKAGE="igraph")
+  } else {
+    res <- .Call("R_igraph_layout_fruchterman_reingold_3d", graph, coords,
+                 niter, start.temp, weights, minx, maxx, miny, maxy,
+                 minz, maxz, PACKAGE="igraph")
+  }
+  res
 }
 
-layout.lgl <- function(graph, ..., params=list()) {
 
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  if (length(params)==0) {
-    params <- list(...)
-  }
+#' @rdname layout_with_fr
+#' @param ... Passed to \code{layout_with_fr}.
+#' @export
 
-  vc <- vcount(graph)
-  if (is.null(params$maxiter))   { params$maxiter    <- 150  }
-  if (is.null(params$maxdelta))  { params$maxdelta   <- vc   }
-  if (is.null(params$area))      { params$area       <- vc^2 }
-  if (is.null(params$coolexp))   { params$coolexp    <- 1.5  }
-  if (is.null(params$repulserad)){ params$repulserad <- params$area * vc }
-  if (is.null(params$cellsize))  { params$cellsize   <-
-                                     (sqrt(sqrt(params$area))) }
-  if (is.null(params$root))      {
-    params$root <- -1
-  } else {
-    params$root <- as.igraph.vs(graph, params$root)-1
-  }
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_layout_lgl", graph, as.double(params$maxiter),
-        as.double(params$maxdelta), as.double(params$area),
-        as.double(params$coolexp), as.double(params$repulserad),
-        as.double(params$cellsize), params$root,
-        PACKAGE="igraph")
+with_fr <- function(...) layout_spec(layout_with_fr, ...)
+
+#' @export
+#' @rdname layout.deprecated
+
+layout.fruchterman.reingold <- function(..., params = list()) {
+  do_call(layout_with_fr, .args = c(list(...), params))
 }
 
-layout.reingold.tilford <- function(graph, ..., params=list()) {
+## ----------------------------------------------------------------
+
+
+#' The GEM layout algorithm
+#'
+#' Place vertices on the plane using the GEM force-directed layout algorithm.
+#'
+#' See the referenced paper below for the details of the algorithm.
+#'
+#' @aliases layout.gem
+#' @param graph The input graph. Edge directions are ignored.
+#' @param coords If not \code{NULL}, then the starting coordinates should be
+#' given here, in a two or three column matrix, depending on the \code{dim}
+#' argument.
+#' @param maxiter The maximum number of iterations to perform. Updating a
+#' single vertex counts as an iteration.  A reasonable default is 40 * n * n,
+#' where n is the number of vertices. The original paper suggests 4 * n * n,
+#' but this usually only works if the other parameters are set up carefully.
+#' @param temp.max The maximum allowed local temperature. A reasonable default
+#' is the number of vertices.
+#' @param temp.min The global temperature at which the algorithm terminates
+#' (even before reaching \code{maxiter} iterations). A reasonable default is
+#' 1/10.
+#' @param temp.init Initial local temperature of all vertices. A reasonable
+#' default is the square root of the number of vertices.
+#' @return A numeric matrix with two columns, and as many rows as the number of
+#' vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout_with_fr}},
+#' \code{\link{plot.igraph}}, \code{\link{tkplot}}
+#' @references Arne Frick, Andreas Ludwig, Heiko Mehldau: A Fast Adaptive
+#' Layout Algorithm for Undirected Graphs, \emph{Proc. Graph Drawing 1994},
+#' LNCS 894, pp. 388-403, 1995.
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+#' @examples
+#'
+#' set.seed(42)
+#' g <- make_ring(10)
+#' plot(g, layout=layout_with_gem)
+#'
+layout_with_gem <- function(graph, coords=NULL, maxiter=40*vcount(graph)^2,
+                       temp.max=vcount(graph), temp.min=1/10,
+                       temp.init=sqrt(vcount(graph))) {
 
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  if (length(params)==0) {
-    params <- list(...)
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(coords)) {
+    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
+    use.seed <- TRUE
+  } else {
+    coords <- matrix(ncol=2, nrow=0)
+    use.seed <- FALSE
   }
 
-  if (is.null(params$root))          { params$root       <- 1          }
-  if (is.null(params$circular))      { params$circular   <- FALSE      }
-  if (is.null(params$rootlevel))     { params$rootlevel  <- numeric()  }
-  if (is.null(params$mode))          { params$mode       <- "out"      }
-  if (is.null(params$flip.y))        { params$flip.y     <- TRUE       }
-  params$mode <- tolower(params$mode)
-  params$mode <- switch(params$mode, "out"=1, "in"=2, "all"=3, "total"=3)
+  maxiter <- as.integer(maxiter)
+  temp.max <- as.numeric(temp.max)
+  temp.min <- as.numeric(temp.min)
+  temp.init <- as.numeric(temp.init)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_layout_reingold_tilford", graph,
-               as.igraph.vs(graph, params$root)-1,
-               as.double(params$mode), as.double(params$rootlevel),
-               as.logical(params$circular),
+  # Function call
+  res <- .Call("R_igraph_layout_gem", graph, coords, use.seed, maxiter,
+               temp.max, temp.min, temp.init,
                PACKAGE="igraph")
-  if (params$flip.y) {
-    res[,2] <- max(res[,2])-res[,2]
-  }
+
   res
 }
 
-layout.merge <- function(graphs, layouts, method="dla") {
 
-  if (!all(sapply(graphs, is.igraph))) {
+#' @rdname layout_with_gem
+#' @param ... Passed to \code{layout_with_gem}.
+#' @export
+
+with_gem <- function(...) layout_spec(layout_with_gem, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' The graphopt layout algorithm
+#'
+#' A force-directed layout algorithm, that scales relatively well to large
+#' graphs.
+#'
+#' \code{layout_with_graphopt} is a port of the graphopt layout algorithm by Michael
+#' Schmuhl. graphopt version 0.4.1 was rewritten in C and the support for
+#' layers was removed (might be added later) and a code was a bit reorganized
+#' to avoid some unneccessary steps is the node charge (see below) is zero.
+#'
+#' graphopt uses physical analogies for defining attracting and repelling
+#' forces among the vertices and then the physical system is simulated until it
+#' reaches an equilibrium. (There is no simulated annealing or anything like
+#' that, so a stable fixed point is not guaranteed.)
+#'
+#' See also \url{http://www.schmuhl.org/graphopt/} for the original graphopt.
+#'
+#' @aliases layout.graphopt
+#' @param graph The input graph.
+#' @param start If given, then it should be a matrix with two columns and one
+#' line for each vertex. This matrix will be used as starting positions for the
+#' algorithm. If not given, then a random starting matrix is used.
+#' @param niter Integer scalar, the number of iterations to perform.  Should be
+#' a couple of hundred in general. If you have a large graph then you might
+#' want to only do a few iterations and then check the result. If it is not
+#' good enough you can feed it in again in the \code{start} argument. The
+#' default value is 500.
+#' @param charge The charge of the vertices, used to calculate electric
+#' repulsion. The default is 0.001.
+#' @param mass The mass of the vertices, used for the spring forces. The
+#' default is 30.
+#' @param spring.length The length of the springs, an integer number. The
+#' default value is zero.
+#' @param spring.constant The spring constant, the default value is one.
+#' @param max.sa.movement Real constant, it gives the maximum amount of
+#' movement allowed in a single step along a single axis. The default value is
+#' 5.
+#' @return A numeric matrix with two columns, and a row for each vertex.
+#' @author Michael Schmuhl for the original graphopt code, rewritten and
+#' wrapped by Gabor Csardi \email{csardi.gabor@@gmail.com}.
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+
+layout_with_graphopt <- function(graph, start=NULL, niter=500, charge=0.001,
+                            mass=30, spring.length=0, spring.constant=1,
+                            max.sa.movement=5) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  if (method == "dla") {
-    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-    res <- .Call("R_igraph_layout_merge_dla",
-                 graphs, layouts,
-                 PACKAGE="igraph")
-  } else {
-    stop("Invalid `method'.")
+  if (!is.null(start)) {
+    start <- structure(as.numeric(start), dim=dim(start))
   }
-  res
+  niter <- as.double(niter)
+  charge <- as.double(charge)
+  mass <- as.double(mass)
+  spring.length <- as.double(spring.length)
+  spring.constant <- as.double(spring.constant)
+  max.sa.movement <- as.double(max.sa.movement)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  .Call("R_igraph_layout_graphopt", graph, niter, charge, mass,
+        spring.length, spring.constant, max.sa.movement, start,
+        PACKAGE="igraph")
 }
 
-# FROM SNA 0.5
-
-symmetrize.mat <- function(mats,rule=c("weak", "strong", "lower", "upper")){
-   rule <- igraph.match.arg(rule)
-   
-   #Build the input data structures
-   if(length(dim(mats))>2){
-      m<-dim(mats)[1]
-      n<-dim(mats)[2]
-      o<-dim(mats)[3]
-      d<-mats
-   }else{
-      m<-1
-      n<-dim(mats)[1]
-      o<-dim(mats)[2]
-      d<-array(dim=c(1,n,o))
-      d[1,,]<-mats
-   }
-   #Apply the symmetry rule
-   for(i in 1:m){
-      if(rule=="upper"){
-         temp<-d[i,,]
-         for(j in 1:n)
-            temp[j:n,j]<-temp[j,j:n]
-         d[i,,]<-temp
-      }else if(rule=="lower"){
-         temp<-d[i,,]
-         for(j in 1:n)
-            temp[j,j:n]<-temp[j:n,j]
-         d[i,,]<-temp
-      }else if(rule=="weak"){
-         d[i,,]<-matrix(as.numeric(d[i,,]|t(d[i,,])),nrow=n,ncol=o)
-      }else if(rule=="strong"){
-         d[i,,]<-matrix(as.numeric(d[i,,]&t(d[i,,])),nrow=n,ncol=o)
-      }
-   }
-   #Return the symmetrized matrix
-   if(m==1)
-      out<-d[1,,]
-   else
-      out<-d
-   out
-}
-
-# FROM SNA 0.5
-
-layout.spring<-function(graph, ..., params=list()) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  if (length(params)==0) {
-    params <- list(...)
-  }  
 
-  if (is.null(params$mass))     { params$mass     <- 0.1 }
-  if (is.null(params$equil))    { params$equil    <- 1 }
-  if (is.null(params$k))        { params$k        <- 0.001 }
-  if (is.null(params$repeqdis)) { params$repeqdis <- 0.1 }
-  if (is.null(params$kfr))      { params$kfr      <- 0.01 }
-  if (is.null(params$repulse))  { params$repulse  <- FALSE }
+#' @rdname layout_with_graphopt
+#' @param ... Passed to \code{layout_with_graphopt}.
+#' @export
+
+with_graphopt <- function(...) layout_spec(layout_with_graphopt, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' The Kamada-Kawai layout algorithm
+#'
+#' Place the vertices on the plane, or in the 3d space, based on a phyisical
+#' model of springs.
+#'
+#' See the referenced paper below for the details of the algorithm.
+#'
+#' This function was rewritten from scratch in igraph version 0.8.0 and it
+#' follows truthfully the original publication by Kamada and Kawai now.
+#'
+#' @param graph The input graph. Edge directions are ignored.
+#' @param coords If not \code{NULL}, then the starting coordinates should be
+#' given here, in a two or three column matrix, depending on the \code{dim}
+#' argument.
+#' @param dim Integer scalar, 2 or 3, the dimension of the layout.  Two
+#' dimensional layouts are places on a plane, three dimensional ones in the 3d
+#' space.
+#' @param maxiter The maximum number of iterations to perform. The algorithm
+#' might terminate earlier, see the \code{epsilon} argument.
+#' @param epsilon Numeric scalar, the algorithm terminates, if the maximal
+#' delta is less than this. (See the reference below for what delta means.) If
+#' you set this to zero, then the function always performs \code{maxiter}
+#' iterations.
+#' @param kkconst Numeric scalar, the Kamada-Kawai vertex attraction constant.
+#' Typical (and default) value is the number of vertices.
+#' @param weights Edge weights, larger values will result longer edges.
+#' @param minx If not \code{NULL}, then it must be a numeric vector that gives
+#' lower boundaries for the \sQuote{x} coordinates of the vertices. The length
+#' of the vector must match the number of vertices in the graph.
+#' @param maxx Similar to \code{minx}, but gives the upper boundaries.
+#' @param miny Similar to \code{minx}, but gives the lower boundaries of the
+#' \sQuote{y} coordinates.
+#' @param maxy Similar to \code{minx}, but gives the upper boundaries of the
+#' \sQuote{y} coordinates.
+#' @param minz Similar to \code{minx}, but gives the lower boundaries of the
+#' \sQuote{z} coordinates.
+#' @param maxz Similar to \code{minx}, but gives the upper boundaries of the
+#' \sQuote{z} coordinates.
+#' @param niter,sigma,initemp,coolexp These arguments are not supported from
+#' igraph version 0.8.0 and are ignored (with a warning).
+#' @param start Deprecated synonym for \code{coords}, for compatibility.
+#' @return A numeric matrix with two (dim=2) or three (dim=3) columns, and as
+#' many rows as the number of vertices, the x, y and potentially z coordinates
+#' of the vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout_with_drl}}, \code{\link{plot.igraph}},
+#' \code{\link{tkplot}}
+#' @references Kamada, T. and Kawai, S.: An Algorithm for Drawing General
+#' Undirected Graphs. \emph{Information Processing Letters}, 31/1, 7--15, 1989.
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+#' @examples
+#'
+#' g <- make_ring(10)
+#' E(g)$weight <- rep(1:2, length.out=ecount(g))
+#' plot(g, layout=layout_with_kk, edge.label=E(g)$weight)
+#'
+layout_with_kk <- function(graph, coords=NULL, dim=2,
+                                maxiter=50*vcount(graph),
+                                epsilon=0.0, kkconst=vcount(graph),
+                                weights=NULL, minx=NULL, maxx=NULL,
+                                miny=NULL, maxy=NULL, minz=NULL, maxz=NULL,
+                                niter, sigma, initemp, coolexp, start) {
+  # Argument checks
+  if (!missing(coords) && !missing(start)) {
+    stop("Both `coords' and `start' are given, give only one of them.")
+  }
+  if (!missing(start)) coords <- start
 
-  #Create initial condidions
-  vc <- vcount(graph)
-  f.x <- rep(0,vc)       #Set initial x/y forces to zero
-  f.y <- rep(0,vc)
-  v.x <- rep(0,vc)       #Set initial x/y velocities to zero
-  v.y <- rep(0,vc)
-  tempa <- sample((0:(vc-1))/vc) #Set initial positions randomly on the circle
-  x <- vc/(2*pi)*sin(2*pi*tempa)
-  y <- vc/(2*pi)*cos(2*pi*tempa)
-  ds <- symmetrize.mat(get.adjacency(graph, sparse=FALSE))#Symmetrize/dichotomize the graph
-  kfr <- params$kfr                     #Set initial friction level
-  niter <- 1                            #Set the iteration counter
-  #Simulate, with increasing friction, until motion stops    
-  repeat{
-    niter <- niter+1                    #Update the iteration counter
-    dis <- as.matrix(dist(cbind(x,y)))  #Get inter-point distances
-    #Get angles relative to the positive x direction
-    theta <- acos(t(outer(x,x,"-"))/dis)*sign(t(outer(y,y,"-"))) 
-    #Compute spring forces; note that we assume a base spring coefficient
-    #of params$k units ("pseudo-Newtons/quasi-meter"?), with an equilibrium
-    #extension of params$equil units for all springs
-    f.x <- apply(ds*cos(theta)*params$k*(dis-params$equil),1,sum,na.rm=TRUE)
-    f.y <- apply(ds*sin(theta)*params$k*(dis-params$equil),1,sum,na.rm=TRUE)
-    #If node repulsion is active, add a force component for this
-    #as well.  We employ an inverse cube law which is equal in power
-    #to the attractive spring force at distance params$repeqdis
-    if(params$repulse){
-      f.x <- f.x-apply(cos(theta)*params$k/(dis/params$repeqdis)^3,1,
-                       sum,na.rm=TRUE)
-      f.y <- f.y-apply(sin(theta)*params$k/(dis/params$repeqdis)^3,1,
-                       sum,na.rm=TRUE)
-    }
-    #Adjust the velocities (assume a mass of params$mass units); note that the
-    #motion is roughly modeled on the sliding of flat objects across
-    #a uniform surface (e.g., spring-connected cylinders across a table).
-    #We assume that the coefficients of static and kinetic friction are
-    #the same, which should only trouble you if you are under the 
-    #delusion that this is a simulation rather than a graph drawing
-    #exercise (in which case you should be upset that I'm not using
-    #Runge-Kutta or the like!).
-    v.x <- v.x+f.x/params$mass         #Add accumulated spring/repulsion forces
-    v.y <- v.y+f.y/params$mass
-    spd <- sqrt(v.x^2+v.y^2)     #Determine frictional forces
-    fmag <- pmin(spd,kfr)  #We can't let friction _create_ motion!
-    theta <- acos(v.x/spd)*sign(v.y)  #Calculate direction of motion
-    f.x <- fmag*cos(theta)        #Decompose frictional forces
-    f.y <- fmag*sin(theta)
-    f.x[is.nan(f.x)] <- 0         #Correct for any 0/0 problems
-    f.y[is.nan(f.y)] <- 0
-    v.x <- v.x-f.x                #Apply frictional forces (opposing motion -
-    v.y <- v.y-f.y                #note that mass falls out of equation)
-    #Adjust the positions (yep, it's primitive linear updating time!)
-    x <- x+v.x
-    y <- y+v.y
-    #Check for cessation of motion, and increase friction
-    mdist <- mean(dis)
-    if(all(v.x<mdist*1e-5)&&all(v.y<mdist*1e-5))
-      break
-    else
-      kfr <- params$kfr*exp(0.1*niter)
-  }
-  #Return the result
-  cbind(x,y)
-}
-
-layout.norm <- function(layout, xmin=NULL, xmax=NULL, ymin=NULL, ymax=NULL,
-                          zmin=NULL, zmax=NULL) {
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(coords)) {
+    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
+  }
+  dim <- as.integer(dim)
+  if (dim != 2L && dim != 3L) {
+    stop("Dimension must be two or three")
+  }
 
-  if (!is.matrix(layout)) {
-    stop("`layout' not a matrix")
+  maxiter <- as.integer(maxiter)
+  epsilon <- as.numeric(epsilon)
+  kkconst <- as.numeric(kkconst)
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
+    weights <- E(graph)$weight
   }
-  if (ncol(layout) != 2 && ncol(layout) != 3) {
-    stop("`layout' should have 2 or three columns")
+  if (!is.null(weights) && any(!is.na(weights))) {
+    weights <- as.numeric(weights)
+  } else {
+    weights <- NULL
   }
-  
-  if (!is.null(xmin) && !is.null(xmax)) {
-    layout[,1] <- .layout.norm.col(layout[,1], xmin, xmax)
+  if (!is.null(minx)) minx <- as.numeric(minx)
+  if (!is.null(maxx)) maxx <- as.numeric(maxx)
+  if (!is.null(miny)) miny <- as.numeric(miny)
+  if (!is.null(maxy)) maxy <- as.numeric(maxy)
+  if (!is.null(minz)) minz <- as.numeric(minz)
+  if (!is.null(maxz)) maxz <- as.numeric(maxz)
+
+  if (!missing(niter)) {
+    warning("Argument `niter' is deprecated and has no effect")
   }
-
-  if (!is.null(ymin) && !is.null(ymax)) {
-    layout[,2] <- .layout.norm.col(layout[,2], ymin, ymax)
+  if (!missing(sigma)) {
+    warning("Argument `sigma' is deprecated and has no effect")
   }
-  
-  if (ncol(layout)==3 && !is.null(zmin) && !is.null(zmax)) {
-    layout[,3] <- .layout.norm.col(layout[,3], zmin, zmax)
+  if (!missing(initemp)) {
+    warning("Argument `initemp' is deprecated and has no effect")
+  }
+  if (!missing(coolexp)) {
+    warning("Argument `coolexp' is deprecated and has no effect")
   }
 
-  layout
-}
-
-.layout.norm.col <- function(v, min, max) {
-
-  vr <- range(v)
-  if (vr[1]==vr[2]) {
-    fac <- 1
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  if (dim == 2) {
+    res <- .Call("R_igraph_layout_kamada_kawai", graph, coords, maxiter,
+                 epsilon, kkconst, weights, minx, maxx, miny, maxy,
+                 PACKAGE="igraph")
   } else {
-    fac <- (max-min)/(vr[2]-vr[1])
+    res <- .Call("R_igraph_layout_kamada_kawai_3d", graph, coords, maxiter,
+                 epsilon, kkconst, weights, minx, maxx, miny, maxy, minz,
+                 maxz, PACKAGE="igraph")
   }
 
-  (v-vr[1]) * fac + min
+  res
 }
 
-layout.svd <- function(graph, d=shortest.paths(graph), ...)
-  UseMethod("layout.svd", graph)
 
-layout.svd.igraph <- function(graph, d=shortest.paths(graph), ...) {
-    
-    if (!is.igraph(graph)) {
-      stop("Not a graph object")
-    }
+#' @rdname layout_with_kk
+#' @param ... Passed to \code{layout_with_kk}.
+#' @export
+#'
+with_kk <- function(...) layout_spec(layout_with_kk, ...)
 
-    clust <- clusters(graph)
-    llist <- list()
-    llen <- numeric()
-    glist <- list()
-    for(i in 1:length(clust$csize)){
-        ind <- clust$membership==i
-        
-        if(length(which(ind))>=3){
-            thisl <- svd(d[ind, ind], 2)[[2]]
-            thisl[, 1] <- thisl[, 1]/dist(range(thisl[, 1]))
-            thisl[, 2] <- thisl[, 2]/dist(range(thisl[, 2]))
-            llist[[i]] <- thisl
-        }else if(length(which(ind))==2){
-            llist[[i]] <- d[ind, ind]
-        } else {
-            llist[[i]] <- matrix(c(0, 0), nrow=1)
-        }
-        
-        llen[i] <- length(which(ind))
-        
-        glist[[i]] <- induced.subgraph(graph, V(graph)[ind])
-    }
-    
-    ## merge them all:
-    lmerged <- layout.merge(glist, llist)
-    
-    ## now reorder these rows to reflect original graph:
-    l <- matrix(rep(NA, 2*vcount(graph)), ncol=2)
-    l[order(clust$membership), ] <- lmerged
-    return(l)
-}
+#' @export
+#' @rdname layout.deprecated
 
-piecewise.layout <- function(graph, layout=layout.kamada.kawai, ...) {
+layout.kamada.kawai <- function(..., params = list()) {
+  do_call(layout_with_kk, .args = c(list(...), params))
+}
 
-  if (!is.igraph(graph)) {
+## ----------------------------------------------------------------
+
+
+#' Large Graph Layout
+#'
+#' A layout generator for larger graphs.
+#'
+#' \code{layout_with_lgl} is for large connected graphs, it is similar to the layout
+#' generator of the Large Graph Layout software
+#' (\url{http://lgl.sourceforge.net/}).
+#'
+#' @param graph The input graph
+#' @param maxiter The maximum number of iterations to perform (150).
+#' @param maxdelta The maximum change for a vertex during an iteration (the
+#' number of vertices).
+#' @param area The area of the surface on which the vertices are placed (square
+#' of the number of vertices).
+#' @param coolexp The cooling exponent of the simulated annealing (1.5).
+#' @param repulserad Cancellation radius for the repulsion (the \code{area}
+#' times the number of vertices).
+#' @param cellsize The size of the cells for the grid. When calculating the
+#' repulsion forces between vertices only vertices in the same or neighboring
+#' grid cells are taken into account (the fourth root of the number of
+#' \code{area}.
+#' @param root The id of the vertex to place at the middle of the layout. The
+#' default value is -1 which means that a random vertex is selected.
+#' @return A numeric matrix with two columns and as many rows as vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+#' @family graph layouts
+
+layout_with_lgl <- function(graph, maxiter=150, maxdelta=vcount(graph),
+                       area=vcount(graph)^2, coolexp=1.5,
+                       repulserad=area * vcount(graph),
+                       cellsize=sqrt(sqrt(area)), root=NULL) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
-  
-  V(graph)$id <- seq(vcount(graph))
-  gl <- decompose.graph(graph)
-  ll <- lapply(gl, layout, ...)
-  
-  l <- layout.merge(gl, ll)
-  l[ unlist(sapply(gl, get.vertex.attribute, "id")), ] <- l[]
-  l
+  if (is.null(root)) {
+    root <- -1
+  } else {
+    root <- as.igraph.vs(graph, root)-1
+  }
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  .Call("R_igraph_layout_lgl", graph, as.double(maxiter),
+        as.double(maxdelta), as.double(area), as.double(coolexp),
+        as.double(repulserad), as.double(cellsize), root,
+        PACKAGE="igraph")
 }
 
-layout.drl <- function(graph, use.seed = FALSE,
-                       seed=matrix(runif(vcount(graph)*2), ncol=2),
-                       options=igraph.drl.default,
-                       weights=E(graph)$weight,
-                       fixed=NULL,
-                       dim=2)
-{
-    if (!is.igraph(graph)) {
-        stop("Not a graph object")
-    }
-    if (dim != 2 && dim != 3) {
-      stop("`dim' must be 2 or 3")
-    }
-    use.seed <- as.logical(use.seed)
-    seed <- as.matrix(seed)
-    options.tmp <- igraph.drl.default
-    options.tmp[names(options)] <- options
-    options <- options.tmp
-    if (!is.null(weights)) {
-      weights <- as.numeric(weights)
-    }
-    if (!is.null(fixed)) {
-      fixed <- as.logical(fixed)
-    }
-    on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
-    if (dim==2) {
-      res <- .Call("R_igraph_layout_drl", graph, seed, use.seed, options, 
-                   weights, fixed, PACKAGE = "igraph")
-    } else {
-      res <- .Call("R_igraph_layout_drl_3d", graph, seed, use.seed, options, 
-                   weights, fixed, PACKAGE = "igraph")
-    }      
-    res
-}
-
-igraph.drl.default <- list(edge.cut=32/40,
-                           init.iterations=0,
-                           init.temperature=2000,
-                           init.attraction=10,
-                           init.damping.mult=1.0,
-                           liquid.iterations=200,
-                           liquid.temperature=2000,
-                           liquid.attraction=10,
-                           liquid.damping.mult=1.0,
-                           expansion.iterations=200,
-                           expansion.temperature=2000,
-                           expansion.attraction=2,
-                           expansion.damping.mult=1.0,
-                           cooldown.iterations=200,
-                           cooldown.temperature=2000,
-                           cooldown.attraction=1,
-                           cooldown.damping.mult=.1,
-                           crunch.iterations=50,
-                           crunch.temperature=250,
-                           crunch.attraction=1,
-                           crunch.damping.mult=0.25,
-                           simmer.iterations=100,
-                           simmer.temperature=250,
-                           simmer.attraction=.5,
-                           simmer.damping.mult=0)
-
-igraph.drl.coarsen <- list(edge.cut=32/40,
-                           init.iterations=0,
-                           init.temperature=2000,
-                           init.attraction=10,
-                           init.damping.mult=1.0,
-                           liquid.iterations=200,
-                           liquid.temperature=2000,
-                           liquid.attraction=2,
-                           liquid.damping.mult=1.0,
-                           expansion.iterations=200,
-                           expansion.temperature=2000,
-                           expansion.attraction=10,
-                           expansion.damping.mult=1.0,
-                           cooldown.iterations=200,
-                           cooldown.temperature=2000,
-                           cooldown.attraction=1,
-                           cooldown.damping.mult=.1,
-                           crunch.iterations=50,
-                           crunch.temperature=250,
-                           crunch.attraction=1,
-                           crunch.damping.mult=0.25,
-                           simmer.iterations=100,
-                           simmer.temperature=250,
-                           simmer.attraction=.5,
-                           simmer.damping.mult=0)
-
-igraph.drl.coarsest <- list(edge.cut=32/40,
-                            init.iterations=0,
-                            init.temperature=2000,
-                            init.attraction=10,
-                            init.damping.mult=1.0,
-                            liquid.iterations=200,
-                            liquid.temperature=2000,
-                            liquid.attraction=2,
-                            liquid.damping.mult=1.0,
-                            expansion.iterations=200,
-                            expansion.temperature=2000,
-                            expansion.attraction=10,
-                            expansion.damping.mult=1.0,
-                            cooldown.iterations=200,
-                            cooldown.temperature=2000,
-                            cooldown.attraction=1,
-                            cooldown.damping.mult=.1,
-                            crunch.iterations=200,
-                            crunch.temperature=250,
-                            crunch.attraction=1,
-                            crunch.damping.mult=0.25,
-                            simmer.iterations=100,
-                            simmer.temperature=250,
-                            simmer.attraction=.5,
-                            simmer.damping.mult=0)
-
-igraph.drl.refine <- list(edge.cut=32/40,
-                          init.iterations=0,
-                          init.temperature=50,
-                          init.attraction=.5,
-                          init.damping.mult=1.0,
-                          liquid.iterations=0,
-                          liquid.temperature=2000,
-                          liquid.attraction=2,
-                          liquid.damping.mult=1.0,
-                          expansion.iterations=50,
-                          expansion.temperature=500,
-                          expansion.attraction=.1,
-                          expansion.damping.mult=.25,
-                          cooldown.iterations=50,
-                          cooldown.temperature=250,
-                          cooldown.attraction=1,
-                          cooldown.damping.mult=.1,
-                          crunch.iterations=50,
-                          crunch.temperature=250,
-                          crunch.attraction=1,
-                          crunch.damping.mult=0.25,
-                          simmer.iterations=0,
-                          simmer.temperature=250,
-                          simmer.attraction=.5,
-                          simmer.damping.mult=0)
-
-igraph.drl.final <- list(edge.cut=32/40,
-                         init.iterations=0,
-                         init.temperature=50,
-                         init.attraction=.5,
-                         init.damping.mult=0,
-                         liquid.iterations=0,
-                         liquid.temperature=2000,
-                         liquid.attraction=2,
-                         liquid.damping.mult=1.0,
-                         expansion.iterations=50,
-                         expansion.temperature=2000,
-                         expansion.attraction=2,
-                         expansion.damping.mult=1.0,
-                         cooldown.iterations=50,
-                         cooldown.temperature=200,
-                         cooldown.attraction=1,
-                         cooldown.damping.mult=.1,
-                         crunch.iterations=50,
-                         crunch.temperature=250,
-                         crunch.attraction=1,
-                         crunch.damping.mult=0.25,
-                         simmer.iterations=25,
-                         simmer.temperature=250,
-                         simmer.attraction=.5,
-                         simmer.damping.mult=0)
-
-layout.auto <- function(graph, dim=2, ...) {
 
-  ## 1. If there is a 'layout' graph attribute, we just use that.
-  ## 2. Otherwise, if there are vertex attributes called 'x' and 'y',
-  ##    we use those (and the 'z' vertex attribute as well, if present).
-  ## 3. Otherwise, if the graph is connected and small (<100) we use
-  ##    the Kamada-Kawai layout.
-  ## 4. Otherwise if the graph is medium size (<1000) we use the
-  ##    Fruchterman-Reingold layout.
-  ## 5. Otherwise we use the DrL layout generator.
-  
-  if ("layout" %in% list.graph.attributes(graph)) {
-    lay <- get.graph.attribute(graph, "layout")
-    if (is.function(lay)) {
-      lay(graph, ...)
-    } else {
-      lay
-    }
+#' @rdname layout_with_lgl
+#' @param ... Passed to \code{layout_with_lgl}.
+#' @export
 
-  } else if ( all(c("x", "y") %in% list.vertex.attributes(graph)) ) {
-    if ("z" %in% list.vertex.attributes(graph)) {
-      cbind(V(graph)$x, V(graph)$y, V(graph)$z)
-    } else {
-      cbind(V(graph)$x, V(graph)$y)
-    }
+with_lgl <- function(...) layout_spec(layout_with_lgl, ...)
 
-  } else if (is.connected(graph) && vcount(graph) < 100) {
-    layout.kamada.kawai(graph, dim=dim, ...)
+#' @export
+#' @rdname layout.deprecated
 
-  } else if (vcount(graph) < 1000) {
-    layout.fruchterman.reingold(graph, dim=dim, ...)
+layout.lgl <- function(..., params = list()) {
+  do_call(layout_with_lgl, .args = c(list(...), params))
+}
 
-  } else {
-    layout.drl(graph, dim=dim, ...)
-  }
-  
+## ----------------------------------------------------------------
+
+
+
+#' Graph layout by multidimensional scaling
+#'
+#' Multidimensional scaling of some distance matrix defined on the vertices of
+#' a graph.
+#'
+#' \code{layout_with_mds} uses metric multidimensional scaling for generating the
+#' coordinates. Multidimensional scaling aims to place points from a higher
+#' dimensional space in a (typically) 2 dimensional plane, so that the distance
+#' between the points are kept as much as this is possible.
+#'
+#' By default igraph uses the shortest path matrix as the distances between the
+#' nodes, but the user can override this via the \code{dist} argument.
+#'
+#' This function generates the layout separately for each graph component and
+#' then merges them via \code{\link{merge_coords}}.
+#'
+#' @aliases layout.mds
+#' @param graph The input graph.
+#' @param dist The distance matrix for the multidimensional scaling.  If
+#' \code{NULL} (the default), then the unweighted shortest path matrix is used.
+#' @param dim \code{layout_with_mds} supports dimensions up to the number of nodes
+#' minus one, but only if the graph is connected; for unconnected graphs, the
+#' only possible values is 2. This is because \code{merge_coords} only works in
+#' 2D.
+#' @param options This is currently ignored, as ARPACK is not used any more for
+#' solving the eigenproblem
+#' @return A numeric matrix with \code{dim} columns.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout}}, \code{\link{plot.igraph}}
+#' @references Cox, T. F. and Cox, M. A. A. (2001) \emph{Multidimensional
+#' Scaling}.  Second edition. Chapman and Hall.
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+#' @examples
+#'
+#' g <- sample_gnp(100, 2/100)
+#' l <- layout_with_mds(g)
+#' plot(g, layout=l, vertex.label=NA, vertex.size=3)
+
+layout_with_mds <- function(graph, dist=NULL, dim=2,
+                       options=arpack_defaults) {
+
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (!is.null(dist)) dist <- structure(as.double(dist), dim=dim(dist))
+  dim <- as.integer(dim)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_layout_mds", graph, dist, dim,
+        PACKAGE="igraph")
+
+  res
 }
 
-layout.sugiyama <- function(graph, layers=NULL, hgap=1, vgap=1,
+
+#' @rdname layout_with_mds
+#' @param ... Passed to \code{layout_with_mds}.
+#' @export
+
+with_mds <- function(...) layout_spec(layout_with_mds, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' The Sugiyama graph layout generator
+#'
+#' Sugiyama layout algorithm for layered directed acyclic graphs. The algorithm
+#' minimized edge crossings.
+#'
+#' This layout algorithm is designed for directed acyclic graphs where each
+#' vertex is assigned to a layer. Layers are indexed from zero, and vertices of
+#' the same layer will be placed on the same horizontal line. The X coordinates
+#' of vertices within each layer are decided by the heuristic proposed by
+#' Sugiyama et al. to minimize edge crossings.
+#'
+#' You can also try to lay out undirected graphs, graphs containing cycles, or
+#' graphs without an a priori layered assignment with this algorithm. igraph
+#' will try to eliminate cycles and assign vertices to layers, but there is no
+#' guarantee on the quality of the layout in such cases.
+#'
+#' The Sugiyama layout may introduce \dQuote{bends} on the edges in order to
+#' obtain a visually more pleasing layout. This is achieved by adding dummy
+#' nodes to edges spanning more than one layer. The resulting layout assigns
+#' coordinates not only to the nodes of the original graph but also to the
+#' dummy nodes. The layout algorithm will also return the extended graph with
+#' the dummy nodes.
+#'
+#' For more details, see the reference below.
+#'
+#' @aliases layout.sugiyama
+#' @param graph The input graph.
+#' @param layers A numeric vector or \code{NULL}. If not \code{NULL}, then it
+#' should specify the layer index of the vertices. Layers are numbered from
+#' one. If \code{NULL}, then igraph calculates the layers automatically.
+#' @param hgap Real scalar, the minimum horizontal gap between vertices in the
+#' same layer.
+#' @param vgap Real scalar, the distance between layers.
+#' @param maxiter Integer scalar, the maximum number of iterations in the
+#' crossing minimization stage. 100 is a reasonable default; if you feel that
+#' you have too many edge crossings, increase this.
+#' @param weights Optional edge weight vector. If \code{NULL}, then the
+#' 'weight' edge attribute is used, if there is one. Supply \code{NA} here and
+#' igraph ignores the edge weights.
+#' @param attributes Which graph/vertex/edge attributes to keep in the extended
+#' graph. \sQuote{default} keeps the \sQuote{size}, \sQuote{size2},
+#' \sQuote{shape}, \sQuote{label} and \sQuote{color} vertex attributes and the
+#' \sQuote{arrow.mode} and \sQuote{arrow.size} edge attributes. \sQuote{all}
+#' keep all graph, vertex and edge attributes, \sQuote{none} keeps none of
+#' them.
+#' @return A list with the components: \item{layout}{The layout, a two-column
+#' matrix, for the original graph vertices.} \item{layout.dummy}{The layout for
+#' the dummy vertices, a two column matrix.} \item{extd_graph}{The original
+#' graph, extended with dummy vertices.  The \sQuote{dummy} vertex attribute is
+#' set on this graph, it is a logical attributes, and it tells you whether the
+#' vertex is a dummy vertex. The \sQuote{layout} graph attribute is also set,
+#' and it is the layout matrix for all (original and dummy) vertices.}
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @references K. Sugiyama, S. Tagawa and M. Toda, "Methods for Visual
+#' Understanding of Hierarchical Systems". IEEE Transactions on Systems, Man
+#' and Cybernetics 11(2):109-125, 1981.
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+#' @examples
+#'
+#' ## Data taken from http://tehnick-8.narod.ru/dc_clients/
+#' DC <- graph_from_literal("DC++" -+
+#'                 "LinuxDC++":"BCDC++":"EiskaltDC++":"StrongDC++":"DiCe!++",
+#'                 "LinuxDC++" -+ "FreeDC++", "BCDC++" -+ "StrongDC++",
+#'                 "FreeDC++" -+ "BMDC++":"EiskaltDC++",
+#'                 "StrongDC++" -+ "AirDC++":"zK++":"ApexDC++":"TkDC++",
+#'                 "StrongDC++" -+ "StrongDC++ SQLite":"RSX++",
+#'                 "ApexDC++" -+ "FlylinkDC++ ver <= 4xx",
+#'                 "ApexDC++" -+ "ApexDC++ Speed-Mod":"DiCe!++",
+#'                 "StrongDC++ SQLite" -+ "FlylinkDC++ ver >= 5xx",
+#'                 "ApexDC++ Speed-Mod" -+ "FlylinkDC++ ver <= 4xx",
+#'                 "ApexDC++ Speed-Mod" -+ "GreylinkDC++",
+#'                 "FlylinkDC++ ver <= 4xx" -+ "FlylinkDC++ ver >= 5xx",
+#'                 "FlylinkDC++ ver <= 4xx" -+ AvaLink,
+#'                 "GreylinkDC++" -+ AvaLink:"RayLinkDC++":"SparkDC++":PeLink)
+#'
+#' ## Use edge types
+#' E(DC)$lty <- 1
+#' E(DC)["BCDC++" %->% "StrongDC++"]$lty <- 2
+#' E(DC)["FreeDC++" %->% "EiskaltDC++"]$lty <- 2
+#' E(DC)["ApexDC++" %->% "FlylinkDC++ ver <= 4xx"]$lty <- 2
+#' E(DC)["ApexDC++" %->% "DiCe!++"]$lty <- 2
+#' E(DC)["StrongDC++ SQLite" %->% "FlylinkDC++ ver >= 5xx"]$lty <- 2
+#' E(DC)["GreylinkDC++" %->% "AvaLink"]$lty <- 2
+#'
+#' ## Layers, as on the plot
+#' layers <- list(c("DC++"),
+#'                c("LinuxDC++", "BCDC++"),
+#'                c("FreeDC++", "StrongDC++"),
+#'                c("BMDC++", "EiskaltDC++", "AirDC++", "zK++", "ApexDC++",
+#'                  "TkDC++", "RSX++"),
+#'                c("StrongDC++ SQLite", "ApexDC++ Speed-Mod", "DiCe!++"),
+#'                c("FlylinkDC++ ver <= 4xx", "GreylinkDC++"),
+#'                c("FlylinkDC++ ver >= 5xx", "AvaLink", "RayLinkDC++",
+#'                  "SparkDC++", "PeLink"))
+#'
+#' ## Check that we have all nodes
+#' all(sort(unlist(layers)) == sort(V(DC)$name))
+#'
+#' ## Add some graphical parameters
+#' V(DC)$color <- "white"
+#' V(DC)$shape <- "rectangle"
+#' V(DC)$size <- 20
+#' V(DC)$size2 <- 10
+#' V(DC)$label <- lapply(V(DC)$name, function(x)
+#'                       paste(strwrap(x, 12), collapse="\n"))
+#' E(DC)$arrow.size <- 0.5
+#'
+#' ## Create a similar layout using the predefined layers
+#' lay1 <-  layout_with_sugiyama(DC, layers=apply(sapply(layers,
+#'                         function(x) V(DC)$name %in% x), 1, which))
+#'
+#' ## Simple plot, not very nice
+#' par(mar=rep(.1, 4))
+#' plot(DC, layout=lay1$layout, vertex.label.cex=0.5)
+#'
+#' ## Sugiyama plot
+#' plot(lay1$extd_graph, vertex.label.cex=0.5)
+#'
+#' ## The same with automatic layer calculation
+#' ## Keep vertex/edge attributes in the extended graph
+#' lay2 <-  layout_with_sugiyama(DC, attributes="all")
+#' plot(lay2$extd_graph, vertex.label.cex=0.5)
+#'
+#' ## Another example, from the following paper:
+#' ## Markus Eiglsperger, Martin Siebenhaller, Michael Kaufmann:
+#' ## An Efficient Implementation of Sugiyama's Algorithm for
+#' ## Layered Graph Drawing, Journal of Graph Algorithms and
+#' ## Applications 9, 305--325 (2005).
+#'
+#' ex <- graph_from_literal( 0 -+ 29: 6: 5:20: 4,
+#'                  1 -+ 12,
+#'                  2 -+ 23: 8,
+#'                  3 -+  4,
+#'                  4,
+#'                  5 -+  2:10:14:26: 4: 3,
+#'                  6 -+  9:29:25:21:13,
+#'                  7,
+#'                  8 -+ 20:16,
+#'                  9 -+ 28: 4,
+#'                 10 -+ 27,
+#'                 11 -+  9:16,
+#'                 12 -+  9:19,
+#'                 13 -+ 20,
+#'                 14 -+ 10,
+#'                 15 -+ 16:27,
+#'                 16 -+ 27,
+#'                 17 -+  3,
+#'                 18 -+ 13,
+#'                 19 -+  9,
+#'                 20 -+  4,
+#'                 21 -+ 22,
+#'                 22 -+  8: 9,
+#'                 23 -+  9:24,
+#'                 24 -+ 12:15:28,
+#'                 25 -+ 11,
+#'                 26 -+ 18,
+#'                 27 -+ 13:19,
+#'                 28 -+  7,
+#'                 29 -+ 25                    )
+#'
+#' layers <- list( 0, c(5, 17), c(2, 14, 26, 3), c(23, 10, 18), c(1, 24),
+#'                 12, 6, c(29,21), c(25,22), c(11,8,15), 16, 27, c(13,19),
+#'                 c(9, 20), c(4, 28), 7 )
+#'
+#' layex <-  layout_with_sugiyama(ex, layers=apply(sapply(layers,
+#'                         function(x) V(ex)$name %in% as.character(x)),
+#'                         1, which))
+#'
+#' origvert <- c(rep(TRUE, vcount(ex)), rep(FALSE, nrow(layex$layout.dummy)))
+#' realedge <- as_edgelist(layex$extd_graph)[,2] <= vcount(ex)
+#' plot(layex$extd_graph, vertex.label.cex=0.5,
+#'      edge.arrow.size=.5,
+#'      vertex.size=ifelse(origvert, 5, 0),
+#'      vertex.shape=ifelse(origvert, "square", "none"),
+#'      vertex.label=ifelse(origvert, V(ex)$name, ""),
+#'      edge.arrow.mode=ifelse(realedge, 2, 0))
+#'
+ layout_with_sugiyama <- function(graph, layers=NULL, hgap=1, vgap=1,
                             maxiter=100, weights=NULL,
                             attributes=c("default", "all", "none")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   if (!is.null(layers)) layers <- as.numeric(layers)-1
   hgap <- as.numeric(hgap)
   vgap <- as.numeric(vgap)
   maxiter <- as.integer(maxiter)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
-    weights <- E(graph)$weight 
-  } 
-  if (!is.null(weights) && any(!is.na(weights))) { 
-    weights <- as.numeric(weights) 
-  } else { 
-    weights <- NULL 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
+    weights <- E(graph)$weight
+  }
+  if (!is.null(weights) && any(!is.na(weights))) {
+    weights <- as.numeric(weights)
+  } else {
+    weights <- NULL
   }
   attributes <- igraph.match.arg(attributes)
-  
+
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_layout_sugiyama", graph, layers, hgap,
@@ -782,89 +1752,275 @@ layout.sugiyama <- function(graph, layers=NULL, hgap=1, vgap=1,
   } else {
     res$layout.dummy <- res$res[(vc+1):nrow(res$res),]
   }
-  
+
   # Add some attributes to the extended graph
   E(res$extd_graph)$orig <- res$extd_to_orig_eids
   res$extd_to_orig_eids <- NULL
 
-  res$extd_graph <- set.vertex.attribute(res$extd_graph, "dummy",
+  res$extd_graph <- set_vertex_attr(res$extd_graph, "dummy",
                                          value=c(rep(FALSE, vc),
                                            rep(TRUE, nrow(res$res)-vc)))
 
   res$extd_graph$layout <- rbind(res$layout, res$layout.dummy)
 
   if (attributes=="default" || attributes=="all") {
-    if ("size" %in% list.vertex.attributes(graph)) {
+    if ("size" %in% vertex_attr_names(graph)) {
       V(res$extd_graph)$size <- 0
       V(res$extd_graph)$size[ !V(res$extd_graph)$dummy ] <- V(graph)$size
     }
-    if ("size2" %in% list.vertex.attributes(graph)) {
+    if ("size2" %in% vertex_attr_names(graph)) {
       V(res$extd_graph)$size2 <- 0
       V(res$extd_graph)$size2[ !V(res$extd_graph)$dummy ] <- V(graph)$size2
     }
-    if ("shape" %in% list.vertex.attributes(graph)) {
+    if ("shape" %in% vertex_attr_names(graph)) {
       V(res$extd_graph)$shape <- "none"
       V(res$extd_graph)$shape[ !V(res$extd_graph)$dummy ] <- V(graph)$shape
     }
-    if ("label" %in% list.vertex.attributes(graph)) {
+    if ("label" %in% vertex_attr_names(graph)) {
       V(res$extd_graph)$label <- ""
       V(res$extd_graph)$label[ !V(res$extd_graph)$dummy ] <- V(graph)$label
     }
-    if ("color" %in% list.vertex.attributes(graph)) {
+    if ("color" %in% vertex_attr_names(graph)) {
       V(res$extd_graph)$color <- head(V(graph)$color, 1)
       V(res$extd_graph)$color[ !V(res$extd_graph)$dummy ] <- V(graph)$color
     }
-    eetar <- get.edgelist(res$extd_graph, names=FALSE)[,2]
+    eetar <- as_edgelist(res$extd_graph, names=FALSE)[,2]
     E(res$extd_graph)$arrow.mode <- 0
-    if ("arrow.mode" %in% list.edge.attributes(graph)) {
+    if ("arrow.mode" %in% edge_attr_names(graph)) {
       E(res$extd_graph)$arrow.mode[ eetar <= vc ] <- E(graph)$arrow.mode
     } else {
-      E(res$extd_graph)$arrow.mode[ eetar <= vc ] <- is.directed(graph) * 2
+      E(res$extd_graph)$arrow.mode[ eetar <= vc ] <- is_directed(graph) * 2
     }
-    if ("arrow.size" %in% list.edge.attributes(graph)) {
+    if ("arrow.size" %in% edge_attr_names(graph)) {
       E(res$extd_graph)$arrow.size <- 0
       E(res$extd_graph)$arrow.size[ eetar <= vc ] <- E(graph)$arrow.size
     }
   }
 
   if (attributes=="all") {
-    gatt <- setdiff(list.graph.attributes(graph), "layout")
-    vatt <- setdiff(list.vertex.attributes(graph),
+    gatt <- setdiff(graph_attr_names(graph), "layout")
+    vatt <- setdiff(vertex_attr_names(graph),
                     c("size", "size2", "shape", "label", "color"))
-    eatt <- setdiff(list.edge.attributes(graph),
+    eatt <- setdiff(edge_attr_names(graph),
                     c("arrow.mode", "arrow.size"))
     for (ga in gatt) {
-      res$extd_graph <- set.graph.attribute(res$extd_graph, ga,
-                                            get.graph.attribute(graph, ga))
+      res$extd_graph <- set_graph_attr(res$extd_graph, ga,
+                                            graph_attr(graph, ga))
     }
     for (va in vatt) {
       notdummy <- which(!V(res$extd_graph)$dummy)
-      res$extd_graph <- set.vertex.attribute(res$extd_graph, va,
+      res$extd_graph <- set_vertex_attr(res$extd_graph, va,
                                              notdummy,
-                                             get.vertex.attribute(graph, va))
+                                             vertex_attr(graph, va))
     }
     for (ea in eatt) {
-      eanew <- get.edge.attribute(graph, ea)[E(res$extd_graph)$orig]
-      res$extd_graph <- set.edge.attribute(res$extd_graph, ea, value=eanew)
+      eanew <- edge_attr(graph, ea)[E(res$extd_graph)$orig]
+      res$extd_graph <- set_edge_attr(res$extd_graph, ea, value=eanew)
     }
   }
-  
+
   res$res <- NULL
   res
 }
 
-layout.mds <- function(graph, dist=NULL, dim=2,
-                       options=igraph.arpack.default) {
-  
-  # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (!is.null(dist)) dist <- structure(as.double(dist), dim=dim(dist))
-  dim <- as.integer(dim)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  # Function call
-  res <- .Call("R_igraph_layout_mds", graph, dist, dim,
-        PACKAGE="igraph")
 
+#' @rdname layout_with_sugiyama
+#' @param ... Passed to \code{layout_with_sugiyama}.
+#' @export
+
+with_sugiyama <- function(...) layout_spec(layout_with_sugiyama, ...)
+
+
+## ----------------------------------------------------------------
+
+
+#' Merging graph layouts
+#'
+#' Place several graphs on the same layout
+#'
+#' \code{merge_coords} takes a list of graphs and a list of coordinates and
+#' places the graphs in a common layout. The method to use is chosen via the
+#' \code{method} parameter, although right now only the \code{dla} method is
+#' implemented.
+#'
+#' The \code{dla} method covers the graph with circles.  Then it sorts the
+#' graphs based on the number of vertices first and places the largest graph at
+#' the center of the layout. Then the other graphs are placed in decreasing
+#' order via a DLA (diffision limited aggregation) algorithm: the graph is
+#' placed randomly on a circle far away from the center and a random walk is
+#' conducted until the graph walks into the larger graphs already placed or
+#' walks too far from the center of the layout.
+#'
+#' The \code{layout_components} function disassembles the graph first into
+#' maximal connected components and calls the supplied \code{layout} function
+#' for each component separately. Finally it merges the layouts via calling
+#' \code{merge_coords}.
+#'
+#' @aliases layout.merge piecewise.layout
+#' @param graphs A list of graph objects.
+#' @param layouts A list of two-column matrices.
+#' @param method Character constant giving the method to use. Right now only
+#' \code{dla} is implemented.
+#' @param layout A function object, the layout function to use.
+#' @param \dots Additional arguments to pass to the \code{layout} layout
+#' function.
+#' @return A matrix with two columns and as many lines as the total number of
+#' vertices in the graphs.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{plot.igraph}}, \code{\link{tkplot}},
+#' \code{\link{layout}}, \code{\link{disjoint_union}}
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+#' @examples
+#'
+#' # create 20 scale-free graphs and place them in a common layout
+#' graphs <- lapply(sample(5:20, 20, replace=TRUE),
+#'           barabasi.game, directed=FALSE)
+#' layouts <- lapply(graphs, layout_with_kk)
+#' lay <- merge_coords(graphs, layouts)
+#' g <- disjoint_union(graphs)
+#' \dontrun{plot(g, layout=lay, vertex.size=3, labels=NA, edge.color="black")}
+
+merge_coords <- function(graphs, layouts, method="dla") {
+
+  if (!all(sapply(graphs, is_igraph))) {
+    stop("Not a graph object")
+  }
+  if (method == "dla") {
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    res <- .Call("R_igraph_layout_merge_dla",
+                 graphs, layouts,
+                 PACKAGE="igraph")
+  } else {
+    stop("Invalid `method'.")
+  }
   res
 }
+
+
+
+#' Normalize coordinates for plotting graphs
+#'
+#' Rescale coordinates linearly to be within given bounds.
+#'
+#' \code{norm_coords} normalizes a layout, it linearly transforms each
+#' coordinate separately to fit into the given limits.
+#'
+#' @aliases layout.norm
+#' @param layout A matrix with two or three columns, the layout to normalize.
+#' @param xmin,xmax The limits for the first coordinate, if one of them or both
+#' are \code{NULL} then no normalization is performed along this direction.
+#' @param ymin,ymax The limits for the second coordinate, if one of them or
+#' both are \code{NULL} then no normalization is performed along this
+#' direction.
+#' @param zmin,zmax The limits for the third coordinate, if one of them or both
+#' are \code{NULL} then no normalization is performed along this direction.
+#' @return A numeric matrix with at the same dimension as \code{layout}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @family graph layouts
+#' @keywords graphs
+
+norm_coords <- function(layout, xmin=-1, xmax=1, ymin=-1, ymax=1,
+                          zmin=-1, zmax=1) {
+
+  if (!is.matrix(layout)) {
+    stop("`layout' not a matrix")
+  }
+  if (ncol(layout) != 2 && ncol(layout) != 3) {
+    stop("`layout' should have 2 or three columns")
+  }
+
+  if (!is.null(xmin) && !is.null(xmax)) {
+    layout[,1] <- .layout.norm.col(layout[,1], xmin, xmax)
+  }
+
+  if (!is.null(ymin) && !is.null(ymax)) {
+    layout[,2] <- .layout.norm.col(layout[,2], ymin, ymax)
+  }
+
+  if (ncol(layout)==3 && !is.null(zmin) && !is.null(zmax)) {
+    layout[,3] <- .layout.norm.col(layout[,3], zmin, zmax)
+  }
+
+  layout
+}
+
+.layout.norm.col <- function(v, min, max) {
+
+  vr <- range(v)
+  if (vr[1]==vr[2]) {
+    fac <- 1
+  } else {
+    fac <- (max-min)/(vr[2]-vr[1])
+  }
+
+  (v-vr[1]) * fac + min
+}
+
+#' @rdname merge_coords
+#' @aliases piecewise.layout
+#' @param graph The input graph.
+#' @export
+
+layout_components <- function(graph, layout=layout_with_kk, ...) {
+
+  if (!is_igraph(graph)) {
+    stop("Not a graph object")
+  }
+
+  V(graph)$id <- seq(vcount(graph))
+  gl <- decompose(graph)
+  ll <- lapply(gl, layout, ...)
+
+  l <- merge_coords(gl, ll)
+  l[ unlist(sapply(gl, vertex_attr, "id")), ] <- l[]
+  l
+}
+
+#' Spring layout, this was removed from igraph
+#'
+#' Now it calls the Fruchterman-Reingold layout, with a warning.
+#'
+#' @param graph Input graph.
+#' @param ... Extra arguments are ignored.
+#' @return Layout coordinates, a two column matrix.
+#'
+#' @export
+
+layout.spring <- function(graph, ...) {
+  warning("Spring layout was removed, we use Fruchterman-Reingold instead.")
+  layout_with_fr(graph)
+}
+
+#' SVD layout, this was removed from igraph
+#'
+#' Now it calls the Fruchterman-Reingold layout, with a warning.
+#'
+#' @param graph Input graph.
+#' @param ... Extra arguments are ignored.
+#' @return Layout coordinates, a two column matrix.
+#'
+#' @export
+
+layout.svd <- function(graph, ...) {
+  warning("SVD layout was removed, we use Fruchterman-Reingold instead.")
+  layout_with_fr(graph)
+}
+
+#' Grid Fruchterman-Reingold layout, this was removed from igraph
+#'
+#' Now it calls the Fruchterman-Reingold layout, with a warning.
+#'
+#' @param graph Input graph.
+#' @param ... Extra arguments are ignored.
+#' @return Layout coordinates, a two column matrix.
+#'
+#' @export
+
+layout.fruchterman.reingold.grid <- function(graph, ...) {
+  warning("Grid Fruchterman-Reingold layout was removed,\n",
+          "we use Fruchterman-Reingold instead.")
+  layout_with_fr(graph)
+}
diff --git a/R/layout_drl.R b/R/layout_drl.R
new file mode 100644
index 0000000..04680a9
--- /dev/null
+++ b/R/layout_drl.R
@@ -0,0 +1,275 @@
+
+#' The DrL graph layout generator
+#' 
+#' DrL is a force-directed graph layout toolbox focused on real-world
+#' large-scale graphs, developed by Shawn Martin and colleagues at Sandia
+#' National Laboratories.
+#' 
+#' This function implements the force-directed DrL layout generator.
+#' 
+#' The generator has the following parameters: \describe{ \item{edge.cut}{Edge
+#' cutting is done in the late stages of the algorithm in order to achieve less
+#' dense layouts.  Edges are cut if there is a lot of stress on them (a large
+#' value in the objective function sum). The edge cutting parameter is a value
+#' between 0 and 1 with 0 representing no edge cutting and 1 representing
+#' maximal edge cutting. } \item{init.iterations}{Number of iterations in the
+#' first phase.} \item{init.temperature}{Start temperature, first phase.}
+#' \item{init.attraction}{Attraction, first phase.}
+#' \item{init.damping.mult}{Damping, first phase.}
+#' \item{liquid.iterations}{Number of iterations, liquid phase.}
+#' \item{liquid.temperature}{Start temperature, liquid phase.}
+#' \item{liquid.attraction}{Attraction, liquid phase.}
+#' \item{liquid.damping.mult}{Damping, liquid phase.}
+#' \item{expansion.iterations}{Number of iterations, expansion phase.}
+#' \item{expansion.temperature}{Start temperature, expansion phase.}
+#' \item{expansion.attraction}{Attraction, expansion phase.}
+#' \item{expansion.damping.mult}{Damping, expansion phase.}
+#' \item{cooldown.iterations}{Number of iterations, cooldown phase.}
+#' \item{cooldown.temperature}{Start temperature, cooldown phase.}
+#' \item{cooldown.attraction}{Attraction, cooldown phase.}
+#' \item{cooldown.damping.mult}{Damping, cooldown phase.}
+#' \item{crunch.iterations}{Number of iterations, crunch phase.}
+#' \item{crunch.temperature}{Start temperature, crunch phase.}
+#' \item{crunch.attraction}{Attraction, crunch phase.}
+#' \item{crunch.damping.mult}{Damping, crunch phase.}
+#' \item{simmer.iterations}{Number of iterations, simmer phase.}
+#' \item{simmer.temperature}{Start temperature, simmer phase.}
+#' \item{simmer.attraction}{Attraction, simmer phase.}
+#' \item{simmer.damping.mult}{Damping, simmer phase.}
+#' 
+#' There are five pre-defined parameter settings as well, these are called
+#' \code{drl_defaults$default}, \code{drl_defaults$coarsen},
+#' \code{drl_defaults$coarsest}, \code{drl_defaults$refine} and
+#' \code{drl_defaults$final}.  }
+#' 
+#' @aliases layout.drl drl_defaults igraph.drl.coarsen
+#'  igraph.drl.coarsest igraph.drl.default igraph.drl.final
+#'  igraph.drl.refine
+#' @param graph The input graph, in can be directed or undirected.
+#' @param use.seed Logical scalar, whether to use the coordinates given in the
+#' \code{seed} argument as a starting point.
+#' @param seed A matrix with two columns, the starting coordinates for the
+#' vertices is \code{use.seed} is \code{TRUE}. It is ignored otherwise.
+#' @param options Options for the layout generator, a named list. See details
+#' below.
+#' @param weights Optional edge weights. Supply \code{NULL} here if you want to
+#' weight edges equally. By default the \code{weight} edge attribute is used if
+#' the graph has one.
+#' @param fixed Logical vector, it can be used to fix some vertices. All
+#' vertices for which it is \code{TRUE} are kept at the coordinates supplied in
+#' the \code{seed} matrix. It is ignored it \code{NULL} or if \code{use.seed}
+#' is \code{FALSE}.
+#' @param dim Either \sQuote{2} or \sQuote{3}, it specifies whether we want a
+#' two dimensional or a three dimensional layout. Note that because of the
+#' nature of the DrL algorithm, the three dimensional layout takes
+#' significantly longer to compute.
+#' @return A numeric matrix with two columns.
+#' @author Shawn Martin (\url{http://www.cs.otago.ac.nz/homepages/smartin/})
+#' and Gabor Csardi \email{csardi.gabor@@gmail.com} for the R/igraph interface
+#' and the three dimensional version.
+#' @seealso \code{\link{layout}} for other layout generators.
+#' @references See the following technical report: Martin, S., Brown, W.M.,
+#' Klavans, R., Boyack, K.W., DrL: Distributed Recursive (Graph) Layout. SAND
+#' Reports, 2008. 2936: p. 1-10.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- as.undirected(sample_pa(100, m=1))
+#' l <- layout_with_drl(g, options=list(simmer.attraction=0))
+#' \dontrun{
+#' plot(g, layout=l, vertex.size=3, vertex.label=NA)
+#' }
+#' 
+layout_with_drl <- function(graph, use.seed = FALSE,
+                       seed=matrix(runif(vcount(graph)*2), ncol=2),
+                       options=drl_defaults$default,
+                       weights=E(graph)$weight,
+                       fixed=NULL,
+                       dim=2)
+{
+    if (!is_igraph(graph)) {
+        stop("Not a graph object")
+    }
+    if (dim != 2 && dim != 3) {
+      stop("`dim' must be 2 or 3")
+    }
+    use.seed <- as.logical(use.seed)
+    seed <- as.matrix(seed)
+    options.tmp <- drl_defaults$default
+    options.tmp[names(options)] <- options
+    options <- options.tmp
+    if (!is.null(weights)) {
+      weights <- as.numeric(weights)
+    }
+    if (!is.null(fixed)) {
+      fixed <- as.logical(fixed)
+    }
+    on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+    if (dim==2) {
+      res <- .Call("R_igraph_layout_drl", graph, seed, use.seed, options, 
+                   weights, fixed, PACKAGE = "igraph")
+    } else {
+      res <- .Call("R_igraph_layout_drl_3d", graph, seed, use.seed, options, 
+                   weights, fixed, PACKAGE = "igraph")
+    }      
+    res
+}
+
+
+#' @rdname layout_with_drl
+#' @param ... Passed to \code{layout_with_drl}.
+#' @export
+
+with_drl <- function(...) layout_spec(layout_with_drl, ...)
+
+
+#' @export
+
+igraph.drl.default <- list(edge.cut=32/40,
+                           init.iterations=0,
+                           init.temperature=2000,
+                           init.attraction=10,
+                           init.damping.mult=1.0,
+                           liquid.iterations=200,
+                           liquid.temperature=2000,
+                           liquid.attraction=10,
+                           liquid.damping.mult=1.0,
+                           expansion.iterations=200,
+                           expansion.temperature=2000,
+                           expansion.attraction=2,
+                           expansion.damping.mult=1.0,
+                           cooldown.iterations=200,
+                           cooldown.temperature=2000,
+                           cooldown.attraction=1,
+                           cooldown.damping.mult=.1,
+                           crunch.iterations=50,
+                           crunch.temperature=250,
+                           crunch.attraction=1,
+                           crunch.damping.mult=0.25,
+                           simmer.iterations=100,
+                           simmer.temperature=250,
+                           simmer.attraction=.5,
+                           simmer.damping.mult=0)
+
+#' @export
+
+igraph.drl.coarsen <- list(edge.cut=32/40,
+                           init.iterations=0,
+                           init.temperature=2000,
+                           init.attraction=10,
+                           init.damping.mult=1.0,
+                           liquid.iterations=200,
+                           liquid.temperature=2000,
+                           liquid.attraction=2,
+                           liquid.damping.mult=1.0,
+                           expansion.iterations=200,
+                           expansion.temperature=2000,
+                           expansion.attraction=10,
+                           expansion.damping.mult=1.0,
+                           cooldown.iterations=200,
+                           cooldown.temperature=2000,
+                           cooldown.attraction=1,
+                           cooldown.damping.mult=.1,
+                           crunch.iterations=50,
+                           crunch.temperature=250,
+                           crunch.attraction=1,
+                           crunch.damping.mult=0.25,
+                           simmer.iterations=100,
+                           simmer.temperature=250,
+                           simmer.attraction=.5,
+                           simmer.damping.mult=0)
+
+#' @export
+
+igraph.drl.coarsest <- list(edge.cut=32/40,
+                            init.iterations=0,
+                            init.temperature=2000,
+                            init.attraction=10,
+                            init.damping.mult=1.0,
+                            liquid.iterations=200,
+                            liquid.temperature=2000,
+                            liquid.attraction=2,
+                            liquid.damping.mult=1.0,
+                            expansion.iterations=200,
+                            expansion.temperature=2000,
+                            expansion.attraction=10,
+                            expansion.damping.mult=1.0,
+                            cooldown.iterations=200,
+                            cooldown.temperature=2000,
+                            cooldown.attraction=1,
+                            cooldown.damping.mult=.1,
+                            crunch.iterations=200,
+                            crunch.temperature=250,
+                            crunch.attraction=1,
+                            crunch.damping.mult=0.25,
+                            simmer.iterations=100,
+                            simmer.temperature=250,
+                            simmer.attraction=.5,
+                            simmer.damping.mult=0)
+
+#' @export
+
+igraph.drl.refine <- list(edge.cut=32/40,
+                          init.iterations=0,
+                          init.temperature=50,
+                          init.attraction=.5,
+                          init.damping.mult=1.0,
+                          liquid.iterations=0,
+                          liquid.temperature=2000,
+                          liquid.attraction=2,
+                          liquid.damping.mult=1.0,
+                          expansion.iterations=50,
+                          expansion.temperature=500,
+                          expansion.attraction=.1,
+                          expansion.damping.mult=.25,
+                          cooldown.iterations=50,
+                          cooldown.temperature=250,
+                          cooldown.attraction=1,
+                          cooldown.damping.mult=.1,
+                          crunch.iterations=50,
+                          crunch.temperature=250,
+                          crunch.attraction=1,
+                          crunch.damping.mult=0.25,
+                          simmer.iterations=0,
+                          simmer.temperature=250,
+                          simmer.attraction=.5,
+                          simmer.damping.mult=0)
+
+#' @export
+
+igraph.drl.final <- list(edge.cut=32/40,
+                         init.iterations=0,
+                         init.temperature=50,
+                         init.attraction=.5,
+                         init.damping.mult=0,
+                         liquid.iterations=0,
+                         liquid.temperature=2000,
+                         liquid.attraction=2,
+                         liquid.damping.mult=1.0,
+                         expansion.iterations=50,
+                         expansion.temperature=2000,
+                         expansion.attraction=2,
+                         expansion.damping.mult=1.0,
+                         cooldown.iterations=50,
+                         cooldown.temperature=200,
+                         cooldown.attraction=1,
+                         cooldown.damping.mult=.1,
+                         crunch.iterations=50,
+                         crunch.temperature=250,
+                         crunch.attraction=1,
+                         crunch.damping.mult=0.25,
+                         simmer.iterations=25,
+                         simmer.temperature=250,
+                         simmer.attraction=.5,
+                         simmer.damping.mult=0)
+
+#' @export
+
+drl_defaults <- list(
+  coarsen = igraph.drl.coarsen,
+  coarsest = igraph.drl.coarsest,
+  default = igraph.drl.default,
+  final = igraph.drl.final,
+  refine = igraph.drl.refine
+)
diff --git a/R/lazyeval.R b/R/lazyeval.R
new file mode 100644
index 0000000..651b5c4
--- /dev/null
+++ b/R/lazyeval.R
@@ -0,0 +1,244 @@
+as.lazy <- function(x, env = baseenv()) UseMethod("as.lazy")
+as.lazy.lazy <- function(x, env = baseenv()) x
+as.lazy.formula <- function(x, env = baseenv()) lazy_(x[[2]], environment(x))
+as.lazy.character <- function(x, env = baseenv()) lazy_(parse(text = x)[[1]], env)
+as.lazy.call <- function(x, env = baseenv()) lazy_(x, env)
+as.lazy.name <- function(x, env = baseenv()) lazy_(x, env)
+as.lazy.numeric <- function(x, env = baseenv()) {
+  if (length(x) > 1) {
+    warning("Truncating vector to length 1", call. = FALSE)
+    x <- x[1]
+  }
+  lazy_(x, env)
+}
+as.lazy.logical <- as.lazy.numeric
+as.lazy_dots <- function(x, env) UseMethod("as.lazy_dots")
+as.lazy_dots.NULL <- function(x, env = baseenv()) {
+  structure(list(), class = "lazy_dots")
+}
+as.lazy_dots.list <- function(x, env = baseenv()) {
+  structure(lapply(x, as.lazy, env = env), class = "lazy_dots")
+}
+as.lazy_dots.name <- function(x, env = baseenv()) {
+  structure(list(as.lazy(x, env)), class = "lazy_dots")
+}
+as.lazy_dots.formula <- as.lazy_dots.name
+as.lazy_dots.call <- as.lazy_dots.name
+as.lazy_dots.lazy <- function(x, env = baseenv()) {
+  structure(list(x), class = "lazy_dots")
+}
+as.lazy_dots.character <- function(x, env = baseenv()) {
+  structure(lapply(x, as.lazy, env = env), class = "lazy_dots")
+}
+as.lazy_dots.lazy_dots <- function(x, env = baseenv()) {
+  x
+}
+all_dots <- function(.dots, ..., all_named = FALSE) {
+  dots <- as.lazy_dots(list(...))
+  if (!missing(.dots)) {
+    dots2 <- as.lazy_dots(.dots)
+    dots <- c(dots, dots2)
+  }
+
+  if (all_named) {
+    dots <- auto_name(dots)
+  }
+
+  dots
+
+}
+lazy_eval <- function(x, data = NULL) {
+  if (is.lazy_dots(x)) {
+    return(lapply(x, lazy_eval, data = data))
+  }
+
+  x <- as.lazy(x)
+
+  if (!is.null(data)) {
+    eval(x$expr, data, x$env)
+  } else {
+    eval(x$expr, x$env, emptyenv())
+  }
+}
+interp <- function(`_obj`, ..., .values) {
+  UseMethod("interp")
+}
+interp.call <- function(`_obj`, ..., .values) {
+  values <- all_values(.values, ...)
+
+  substitute_(`_obj`, values)
+}
+interp.name <- function(`_obj`, ..., .values) {
+  values <- all_values(.values, ...)
+
+  substitute_(`_obj`, values)
+}
+interp.formula <- function(`_obj`, ..., .values) {
+  values <- all_values(.values, ...)
+
+  `_obj`[[2]] <- substitute_(`_obj`[[2]], values)
+  `_obj`
+}
+interp.lazy <- function(`_obj`, ..., .values) {
+  values <- all_values(.values, ...)
+
+  `_obj`$expr <-  substitute_(`_obj`$expr, values)
+  `_obj`
+}
+interp.character <- function(`_obj`, ..., .values) {
+  values <- all_values(.values, ...)
+
+  expr1 <- parse(text = `_obj`)[[1]]
+  expr2 <- substitute_(expr1, values)
+  deparse(expr2)
+}
+substitute_ <- function(x, env) {
+  call <- substitute(substitute(x, env), list(x = x))
+  eval(call)
+}
+all_values <- function(.values, ...) {
+  if (missing(.values)) {
+    values <- list(...)
+  } else if (identical(.values, globalenv())) {
+    # substitute doesn't want to replace in globalenv
+    values <- as.list(globalenv())
+  } else {
+    values <- .values
+  }
+  # Replace lazy objects with their expressions
+  is_lazy <- vapply(values, is.lazy, logical(1))
+  values[is_lazy] <- lapply(values[is_lazy], `[[`, "expr")
+
+  values
+}
+missing_arg <- function() {
+  quote(expr = )
+}
+lazy_dots <- function(..., .follow_symbols = FALSE) {
+  if (nargs() == 0 || (nargs() == 1 &&  ! missing(.follow_symbols))) {
+    return(structure(list(), class = "lazy_dots"))
+  }
+
+  base::.Call("make_lazy_dots", environment(), .follow_symbols,
+              PACKAGE = "igraph")
+}
+is.lazy_dots <- function(x) inherits(x, "lazy_dots")
+`[.lazy_dots` <- function(x, i) {
+  structure(NextMethod(), class = "lazy_dots")
+}
+`$<-.lazy_dots` <- function(x, i, value) {
+  value <- as.lazy(value, parent.frame())
+  x[[i]] <- value
+  x
+}
+`[<-.lazy_dots` <- function(x, i, value) {
+  value <- lapply(value, as.lazy, env = parent.frame())
+  NextMethod()
+}
+c.lazy_dots <- function(..., recursive = FALSE) {
+  structure(NextMethod(), class = "lazy_dots")
+}
+lazy_ <- function(expr, env) {
+  stopifnot(is.call(expr) || is.name(expr) || is.atomic(expr))
+
+  structure(list(expr = expr, env = env), class = "lazy")
+}
+lazy <- function(expr, env = parent.frame(), .follow_symbols = TRUE) {
+  base::.Call("make_lazy", quote(expr), environment(), .follow_symbols,
+              PACKAGE = "igraph")
+}
+is.lazy <- function(x) inherits(x, "lazy")
+print.lazy <- function(x, ...) {
+  code <- deparse(x$expr)
+  if (length(code) > 1) {
+    code <- paste(code[[1]], "...")
+  }
+
+  cat("<lazy>\n")
+  cat("  expr: ", code, "\n", sep = "")
+  cat("  env:  ", format(x$env), "\n", sep = "")
+}
+make_call <- function(fun, args) {
+  stopifnot(is.call(fun) || is.name(fun))
+  args <- as.lazy_dots(args)
+  expr <- lapply(args, `[[`, "expr")
+
+  lazy_(
+    as.call(c(fun, expr)),
+    common_env(args)
+  )
+}
+common_env <- function(dots) {
+  if (!is.list(dots)) stop("dots must be a list", call. = FALSE)
+  if (length(dots) == 0) return(baseenv())
+
+  dots <- as.lazy_dots(dots)
+  env <- dots[[1]]$env
+  if (length(dots) == 1) return(env)
+
+  for (i in 2:length(dots)) {
+    if (!identical(env, dots[[i]]$env)) {
+      return(baseenv())
+    }
+  }
+  env
+}
+eval_call <- function(fun, dots, env = parent.frame()) {
+
+  vars <- paste0("x", seq_along(dots))
+  names(vars) <- names(dots)
+
+  # Create environment containing promises
+  env <- new.env(parent = env)
+  for(i in seq_along(dots)) {
+    dot <- dots[[i]]
+
+    assign_call <- substitute(
+      delayedAssign(vars[i], expr, dot$env, assign.env = env),
+      list(expr = dot$expr)
+    )
+    eval(assign_call)
+  }
+
+  args <- lapply(vars, as.symbol)
+  call <- as.call(c(fun, args))
+
+  eval(call, env)
+}
+auto_name <- function(x, max_width = 40) {
+  names(x) <- auto_names(x, max_width = max_width)
+  x
+}
+auto_names <- function(x, max_width = 40) {
+  x <- as.lazy_dots(x)
+
+  nms <- names(x) %||% rep("", length(x))
+
+  missing <- nms == ""
+  expr <- lapply(x[missing], `[[`, "expr")
+  nms[missing] <- vapply(expr, deparse_trunc, width = max_width,
+    FUN.VALUE = character(1), USE.NAMES = FALSE)
+
+  nms
+}
+deparse_trunc <- function(x, width = getOption("width")) {
+  if (is.symbol(x)) {
+    return(as.character(x))
+  }
+
+  text <- deparse(x, width.cutoff = width)
+  if (length(text) == 1 && nchar(text) < width) return(text)
+
+  paste0(substr(text[1], 1, width - 3), "...")
+}
+promise_expr <- function(prom) {
+  base::.Call("promise_expr_", prom, PACKAGE = "igraph")
+}
+
+promise_env <- function(prom) {
+  base::.Call("promise_env_", prom, PACKAGE = "igraph")
+}
+as.lazy.promise <- function(x, ...) {
+  lazy_(promise_expr(x), promise_env(x))
+}
+"%||%" <- function(x, y) if(is.null(x)) y else x
diff --git a/R/make.R b/R/make.R
new file mode 100644
index 0000000..faef6c2
--- /dev/null
+++ b/R/make.R
@@ -0,0 +1,1563 @@
+
+## ----------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2005-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------
+
+#' Make a new graph
+#'
+#' This is is generic function for creating graphs.
+#'
+#' @details
+#' \code{make_} is a generic function for creating graphs.
+#' For every graph constructor in igraph that has a \code{make_} prefix,
+#' there is a corresponding function without the prefix: e.g.
+#' for \code{\link{make_ring}} there is also \code{\link{ring}}, etc.
+#'
+#' The same is true for the random graph samplers, i.e. for each
+#' constructor with a \code{sample_} prefix, there is a corresponding
+#' function without that prefix.
+#'
+#' These shorter forms can be used together with \code{make_}.
+#' The advantage of this form is that the user can specify constructor
+#' modifiers which work with all constructors. E.g. the
+#' \code{link{with_vertex_}} modifier adds vertex attributes
+#' to the newly created graphs.
+#'
+#' See the examples and the various constructor modifiers below.
+#'
+#' @param ... Parameters, see details below.
+#'
+#' @seealso simplified with_edge_ with_graph_ with_vertex_
+#'   without_loops without_multiples
+#' @export
+#' @examples
+#' r <- make_(ring(10))
+#' l <- make_(lattice(c(3, 3, 3)))
+#'
+#' r2 <- make_(ring(10), with_vertex_(color = "red", name = LETTERS[1:10]))
+#' l2 <- make_(lattice(c(3, 3, 3)), with_edge_(weight = 2))
+#'
+#' ran <- sample_(degseq(c(3,3,3,3,3,3), method = "simple"), simplified())
+#' degree(ran)
+#' is_simple(ran)
+
+make_ <- function(...) {
+
+  me <- attr(sys.function(), "name") %||% "construct"
+  args <- list(...)
+  cidx <- vapply(args, inherits, TRUE, what = "igraph_constructor_spec")
+  if (sum(cidx) == 0) {
+    stop("Don't know how to ", me, ", nothing given")
+  }
+  if (sum(cidx) > 1) {
+    stop("Don't know how to ", me, ", multiple constructors given")
+  }
+  cons <- args[ cidx][[1]]
+  args <- args[!cidx]
+
+  ## Modifiers
+  wmods <- vapply(args, class, "") == "igraph_constructor_modifier"
+  mods <- args[wmods]
+  args <- args[!wmods]
+
+  args2 <- if (cons$lazy) lapply(cons$args, "[[", "expr") else lazy_eval(cons$args)
+
+  res <- do_call(cons$fun, args2, args)
+
+  for (m in mods) {
+    if (m$id == "without_attr") {
+      ## TODO: speed this up
+      ga <- graph_attr_names(res)
+      va <- vertex_attr_names(res)
+      ea <- edge_attr_names(res)
+      for (g in ga) res <- delete_graph_attr(res, g)
+      for (v in va) res <- delete_vertex_attr(res, v)
+      for (e in ea) res <- delete_edge_attr(res, e)
+
+    } else if (m$id == "without_loops") {
+      res <- simplify(res, remove.loops = TRUE, remove.multiple = FALSE)
+
+    } else if (m$id == "without_multiples") {
+      res <- simplify(res, remove.loops = FALSE, remove.multiple = TRUE)
+
+    } else if (m$id == "simplified") {
+      res <- simplify(res)
+
+    } else if (m$id == "with_vertex_") {
+      m$args <- lapply(m$args, eval)
+      ## TODO speed this up
+      for (a in seq_along(m$args)) {
+        n <- names(m$args)[a]
+        v <- m$args[[a]]
+        stopifnot(! is.null(n))
+        res <- set_vertex_attr(res, n, value = v)
+      }
+
+    } else if (m$id == "with_edge_") {
+      m$args <- lapply(m$args, eval)
+      ## TODO speed this up
+      for (a in seq_along(m$args)) {
+        n <- names(m$args)[a]
+        v <- m$args[[a]]
+        stopifnot(! is.null(n))
+        res <- set_edge_attr(res, n, value = v)
+      }
+
+    } else if (m$id == "with_graph_") {
+      m$args <- lapply(m$args, eval)
+      ## TODO speed this up
+      for (a in seq_along(m$args)) {
+        n <- names(m$args)[a]
+        v <- m$args[[a]]
+        stopifnot(! is.null(n))
+        res <- set_graph_attr(res, n, value = v)
+      }
+
+    }
+  }
+
+  res
+}
+
+#' Sample from a random graph model
+#'
+#' Generic function for sampling from network models.
+#'
+#' @details
+#' TODO
+#'
+#' @param ... Parameters, see details below.
+#'
+#' @export
+#' @examples
+#' pref_matrix <- cbind(c(0.8, 0.1), c(0.1, 0.7))
+#' blocky <- sample_(sbm(n = 20, pref.matrix = pref_matrix,
+#'   block.sizes = c(10, 10)))
+#'
+#' blocky2 <- pref_matrix %>%
+#'   sample_sbm(n = 20, block.sizes = c(10, 10))
+#'
+#' ## Arguments are passed on from sample_ to sample_sbm
+#' blocky3 <- pref_matrix %>%
+#'   sample_(sbm(), n = 20, block.sizes = c(10, 10))
+
+sample_ <- make_
+
+#' Convert object to a graph
+#'
+#' This is a generic function to convert R objects to igraph graphs.
+#'
+#' @details
+#' TODO
+#'
+#' @param ... Parameters, see details below.
+#'
+#' @export
+#' @examples
+#' ## These are equivalent
+#' graph_(cbind(1:5,2:6), from_edgelist(directed = FALSE))
+#' graph_(cbind(1:5,2:6), from_edgelist(), directed = FALSE)
+
+graph_ <- make_
+
+attr(make_, "name") <- "make_"
+attr(sample_, "name") <- "sample_"
+attr(graph_, "name") <- "graph_"
+
+constructor_spec <- function(fun, ..., .lazy = FALSE) {
+  structure(
+    list(
+      fun = fun,
+      args = lazy_dots(...),
+      lazy = .lazy
+    ),
+    class = "igraph_constructor_spec"
+  )
+}
+
+
+## -----------------------------------------------------------------
+## Constructor modifiers
+
+constructor_modifier <- function(...) {
+  structure(
+    list(...),
+    class = "igraph_constructor_modifier"
+  )
+}
+
+
+#' Construtor modifier to remove all attributes from a graph
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' g1 <- make_ring(10)
+#' g1
+#'
+#' g2 <- make_(ring(10), without_attr())
+#' g2
+
+without_attr <- function() {
+  constructor_modifier(
+    id = "without_attr"
+  )
+}
+
+
+#' Constructor modifier to drop loop edges
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' # An artificial example
+#' make_(full_graph(5, loops = TRUE))
+#' make_(full_graph(5, loops = TRUE), without_loops())
+
+without_loops <- function() {
+  constructor_modifier(
+    id = "without_loops"
+  )
+}
+
+
+#' Constructor modifier to drop multiple edges
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' sample_(pa(10, m = 3, algorithm = "bag"))
+#' sample_(pa(10, m = 3, algorithm = "bag"), without_multiples())
+
+without_multiples <- function() {
+  constructor_modifier(
+    id = "without_multiples"
+  )
+}
+
+
+#' Constructor modifier to drop multiple and loop edges
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' sample_(pa(10, m = 3, algorithm = "bag"))
+#' sample_(pa(10, m = 3, algorithm = "bag"), simplified())
+
+simplified <- function() {
+  constructor_modifier(
+    id = "simplified"
+  )
+}
+
+
+#' Constructor modifier to add vertex attributes
+#'
+#' @param ... The attributes to add. They must be named.
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' make_(ring(10),
+#'   with_vertex_(
+#'     color = "#7fcdbb",
+#'     frame.color = "#7fcdbb",
+#'     name = LETTERS[1:10])) %>%
+#'   plot()
+
+with_vertex_ <- function(...) {
+
+  args <- grab_args()
+
+  constructor_modifier(
+    id = "with_vertex_",
+    args = args
+  )
+}
+
+
+#' Constructor modifier to add edge attributes
+#'
+#' @param ... The attributes to add. They must be named.
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' make_(ring(10),
+#'   with_edge_(
+#'     color = "red",
+#'     weight = rep(1:2, 5))) %>%
+#'   plot()
+
+with_edge_ <- function(...) {
+
+  args <- grab_args()
+
+  constructor_modifier(
+    id = "with_edge_",
+    args = args
+  )
+}
+
+
+#' Constructor modifier to add graph attributes
+#'
+#' @param ... The attributes to add. They must be named.
+#'
+#' @family constructor modifiers
+#'
+#' @export
+#' @examples
+#' make_(ring(10), with_graph_(name = "10-ring"))
+
+with_graph_ <- function(...) {
+
+  args <- grab_args()
+
+  constructor_modifier(
+    id = "with_graph_",
+    args = args
+  )
+}
+
+
+
+## -----------------------------------------------------------------
+
+#' Create an igraph graph from a list of edges, or a notable graph
+#'
+#' @section Notable graphs:
+#'
+#' \code{make_graph} can create some notable graphs. The name of the
+#' graph (case insensitive), a character scalar must be suppliced as
+#' the \code{edges} argument, and other arguments are ignored. (A warning
+#' is given is they are specified.)
+#'
+#' \code{make_graph} knows the following graphs: \describe{
+#'   \item{Bull}{The bull graph, 5 vertices, 5 edges, resembles to the head
+#'     of a bull if drawn properly.}
+#'   \item{Chvatal}{This is the smallest triangle-free graph that is
+#'     both 4-chromatic and 4-regular. According to the Grunbaum conjecture there
+#'     exists an m-regular, m-chromatic graph with n vertices for every m>1 and
+#'     n>2. The Chvatal graph is an example for m=4 and n=12. It has 24 edges.}
+#'   \item{Coxeter}{A non-Hamiltonian cubic symmetric graph with 28 vertices and
+#'     42 edges.}
+#'   \item{Cubical}{The Platonic graph of the cube. A convex regular
+#'     polyhedron with 8 vertices and 12 edges.}
+#'   \item{Diamond}{A graph with 4 vertices and 5 edges, resembles to a
+#'     schematic diamond if drawn properly.}
+#'   \item{Dodecahedral, Dodecahedron}{Another Platonic solid with 20 vertices
+#'     and 30 edges.}
+#'   \item{Folkman}{The semisymmetric graph with minimum number of
+#'     vertices, 20 and 40 edges. A semisymmetric graph is regular, edge transitive
+#'     and not vertex transitive.}
+#'   \item{Franklin}{This is a graph whose embedding
+#'     to the Klein bottle can be colored with six colors, it is a counterexample
+#'     to the neccessity of the Heawood conjecture on a Klein bottle. It has 12
+#'     vertices and 18 edges.}
+#'   \item{Frucht}{The Frucht Graph is the smallest
+#'     cubical graph whose automorphism group consists only of the identity
+#'     element. It has 12 vertices and 18 edges.}
+#'   \item{Grotzsch}{The Groetzsch
+#'     graph is a triangle-free graph with 11 vertices, 20 edges, and chromatic
+#'     number 4. It is named after German mathematician Herbert Groetzsch, and its
+#'     existence demonstrates that the assumption of planarity is necessary in
+#'     Groetzsch's theorem that every triangle-free planar graph is 3-colorable.}
+#'   \item{Heawood}{The Heawood graph is an undirected graph with 14 vertices and
+#'     21 edges. The graph is cubic, and all cycles in the graph have six or more
+#'     edges. Every smaller cubic graph has shorter cycles, so this graph is the
+#'     6-cage, the smallest cubic graph of girth 6.}
+#'   \item{Herschel}{The Herschel
+#'     graph is the smallest nonhamiltonian polyhedral graph. It is the unique such
+#'     graph on 11 nodes, and has 18 edges.}
+#'   \item{House}{The house graph is a
+#'     5-vertex, 6-edge graph, the schematic draw of a house if drawn properly,
+#'     basicly a triangle of the top of a square.}
+#'   \item{HouseX}{The same as the
+#'     house graph with an X in the square. 5 vertices and 8 edges.}
+#'   \item{Icosahedral, Icosahedron}{A Platonic solid with 12 vertices and 30
+#'     edges.}
+#'   \item{Krackhardt kite}{A social network with 10 vertices and 18
+#'     edges.  Krackhardt, D. Assessing the Political Landscape: Structure,
+#'     Cognition, and Power in Organizations.  Admin. Sci. Quart. 35, 342-369,
+#'     1990.}
+#'   \item{Levi}{The graph is a 4-arc transitive cubic graph, it has 30
+#'     vertices and 45 edges.}
+#'   \item{McGee}{The McGee graph is the unique 3-regular
+#'     7-cage graph, it has 24 vertices and 36 edges.}
+#'   \item{Meredith}{The Meredith
+#'     graph is a quartic graph on 70 nodes and 140 edges that is a counterexample
+#'     to the conjecture that every 4-regular 4-connected graph is Hamiltonian.}
+#'   \item{Noperfectmatching}{A connected graph with 16 vertices and 27 edges
+#'     containing no perfect matching. A matching in a graph is a set of pairwise
+#'     non-adjacent edges; that is, no two edges share a common vertex. A perfect
+#'     matching is a matching which covers all vertices of the graph.}
+#'   \item{Nonline}{A graph whose connected components are the 9 graphs whose
+#'     presence as a vertex-induced subgraph in a graph makes a nonline graph. It
+#'     has 50 vertices and 72 edges.}
+#'   \item{Octahedral, Octahedron}{Platonic solid
+#'     with 6 vertices and 12 edges.}
+#'   \item{Petersen}{A 3-regular graph with 10
+#'     vertices and 15 edges. It is the smallest hypohamiltonian graph, ie. it is
+#'     non-hamiltonian but removing any single vertex from it makes it
+#'     Hamiltonian.}
+#'   \item{Robertson}{The unique (4,5)-cage graph, ie. a 4-regular
+#'    graph of girth 5. It has 19 vertices and 38 edges.}
+#'   \item{Smallestcyclicgroup}{A smallest nontrivial graph whose automorphism
+#'     group is cyclic. It has 9 vertices and 15 edges.}
+#'   \item{Tetrahedral,
+#'     Tetrahedron}{Platonic solid with 4 vertices and 6 edges.}
+#'   \item{Thomassen}{The smallest hypotraceable graph, on 34 vertices and 52
+#'     edges. A hypotracable graph does not contain a Hamiltonian path but after
+#'     removing any single vertex from it the remainder always contains a
+#'     Hamiltonian path. A graph containing a Hamiltonian path is called tracable.}
+#'   \item{Tutte}{Tait's Hamiltonian graph conjecture states that every
+#'     3-connected 3-regular planar graph is Hamiltonian.  This graph is a
+#'     counterexample. It has 46 vertices and 69 edges.}
+#'   \item{Uniquely3colorable}{Returns a 12-vertex, triangle-free graph with
+#'     chromatic number 3 that is uniquely 3-colorable.}
+#'   \item{Walther}{An identity
+#'     graph with 25 vertices and 31 edges. An identity graph has a single graph
+#'     automorphism, the trivial one.}
+#'   \item{Zachary}{Social network of friendships
+#'     between 34 members of a karate club at a US university in the 1970s. See W.
+#'     W. Zachary, An information flow model for conflict and fission in small
+#'     groups, Journal of Anthropological Research 33, 452-473 (1977).  } }
+#'
+#' @encoding UTF-8
+#' @aliases graph.famous graph
+#' @param edges A vector defining the edges, the first edge points
+#'   from the first element to the second, the second edge from the third
+#'   to the fourth, etc. For a numeric vector, these are interpreted
+#'   as internal vertex ids. For character vectors, they are interpreted
+#'   as vertex names.
+#'
+#'   Alternatively, this can be a character scalar, the name of a
+#'   notable graph. See Notable graphs below. The name is case
+#'   insensitive.
+#'
+#'   Starting from igraph 0.8.0, you can also include literals here,
+#'   via igraph's formula notation (see \code{\link{graph_from_literal}}).
+#'   In this case, the first term of the formula has to start with
+#'   a \sQuote{\code{~}} character, just like regular formulae in R.
+#'   See examples below.
+#' @param ... For \code{make_graph}: extra arguments for the case when the
+#'   graph is given via a literal, see \code{\link{graph_from_literal}}.
+#'   For \code{directed_graph} and \code{undirected_graph}:
+#'   Passed to \code{make_directed_graph} or \code{make_undirected_graph}.
+#' @param n The number of vertices in the graph. This argument is
+#'   ignored (with a warning) if \code{edges} are symbolic vertex names. It
+#'   is also ignored if there is a bigger vertex id in \code{edges}. This
+#'   means that for this function it is safe to supply zero here if the
+#'   vertex with the largest id is not an isolate.
+#' @param isolates Character vector, names of isolate vertices,
+#'   for symbolic edge lists. It is ignored for numeric edge lists.
+#' @param directed Whether to create a directed graph.
+#' @param dir It is the same as \code{directed}, for compatibility.
+#'   Do not give both of them.
+#' @param simplify For graph literals, whether to simplify the graph.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' make_graph(c(1, 2, 2, 3, 3, 4, 5, 6), directed = FALSE)
+#' make_graph(c("A", "B", "B", "C", "C", "D"), directed = FALSE)
+#'
+#' solids <- list(make_graph("Tetrahedron"),
+#'                make_graph("Cubical"),
+#'                make_graph("Octahedron"),
+#'                make_graph("Dodecahedron"),
+#'                make_graph("Icosahedron"))
+#'
+#' graph <- make_graph( ~ A-B-C-D-A, E-A:B:C:D,
+#'                       F-G-H-I-F, J-F:G:H:I,
+#'                       K-L-M-N-K, O-K:L:M:N,
+#'                       P-Q-R-S-P, T-P:Q:R:S,
+#'                       B-F, E-J, C-I, L-T, O-T, M-S,
+#'                       C-P, C-L, I-L, I-P)
+
+
+make_graph <- function(edges, ..., n = max(edges), isolates = NULL,
+                       directed = TRUE, dir = directed, simplify = TRUE) {
+
+  if (class(edges) == "formula") {
+    if (!missing(n)) stop("'n' should not be given for graph literals")
+    if (!missing(isolates)) {
+      stop("'isolates' should not be given for graph literals")
+    }
+    if (!missing(directed)) {
+      stop("'directed' should not be given for graph literals")
+    }
+
+    mf <- as.list(match.call())[-1]
+    mf[[1]] <- mf[[1]][[2]]
+    graph_from_literal_i(mf)
+
+  } else {
+
+    if (!missing(simplify)) {
+      stop("'simplify' should not be given for graph literals")
+    }
+
+    if (!missing(dir) && !missing(directed)) {
+      stop("Only give one of 'dir' and 'directed'")
+    }
+
+    if (!missing(dir) && missing(directed)) directed <- dir
+
+    if (is.character(edges) && length(edges) == 1) {
+      if (!missing(n)) warning("'n' is ignored for the '", edges, "' graph")
+      if (!missing(isolates)) {
+        warning("'isolates' is ignored for the '", edges, "' graph")
+      }
+      if (!missing(directed)) {
+        warning("'directed' is ignored for the '", edges, "' graph")
+      }
+      if (!missing(dir)) {
+        warning("'dir' is ignored for the '", edges, "' graph")
+      }
+      if (length(list(...))) stop("Extra arguments in make_graph")
+
+      make_famous_graph(edges)
+
+      ## NULL and empty logical vector is allowed for compatibility
+    } else if (is.numeric(edges) || is.null(edges) ||
+               (is.logical(edges) && length(edges) == 0)) {
+
+      if (is.null(edges) || is.logical(edges)) edges <- as.numeric(edges)
+      if (!is.null(isolates)) {
+        warning("'isolates' ignored for numeric edge list")
+      }
+
+      old_graph <- function(edges, n = max(edges), directed = TRUE) {
+        on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+        .Call("R_igraph_create", as.numeric(edges)-1, as.numeric(n),
+              as.logical(directed),
+              PACKAGE="igraph")
+      }
+
+      args <- list(edges, ...)
+      if (!missing(n)) args <- c(args, list(n = n))
+      if (!missing(directed)) args <- c(args, list(directed = directed))
+
+      do.call(old_graph, args)
+
+    } else if (is.character(edges)) {
+      if (!missing(n)) {
+        warning("'n' is ignored for edge list with vertex names")
+      }
+      if (length(list(...))) stop("Extra arguments in make_graph")
+
+      el <- matrix(edges, ncol = 2, byrow = TRUE)
+      res <- graph_from_edgelist(el, directed = directed)
+      if (!is.null(isolates)) {
+        isolates <- as.character(isolates)
+        res <- res + vertices(isolates)
+      }
+      res
+
+    } else {
+      stop("'edges' must be numeric or character")
+    }
+  }
+}
+
+make_famous_graph <- function(name) {
+
+  name <- gsub("\\s", "_", name)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_famous", as.character(name),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- capitalize(name)
+  }
+  res
+}
+
+#' @rdname make_graph
+#' @export
+
+make_directed_graph <- function(edges, n = max(edges)) {
+  if (missing(n)) {
+    make_graph(edges, directed = TRUE)
+  } else {
+    make_graph(edges, n = n, directed = TRUE)
+  }
+}
+
+#' @rdname make_graph
+#' @export
+
+make_undirected_graph <- function(edges, n = max(edges)) {
+  if (missing(n)) {
+    make_graph(edges, directed = FALSE)
+  } else {
+    make_graph(edges, n = n, directed = FALSE)
+  }
+}
+
+#' @rdname make_graph
+#' @export
+
+directed_graph <- function(...) constructor_spec(make_directed_graph, ...)
+
+#' @rdname make_graph
+#' @export
+
+undirected_graph <- function(...) constructor_spec(make_undirected_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' A graph with no edges
+#'
+#' @aliases graph.empty
+#' @concept Empty graph.
+#' @param n Number of vertices.
+#' @param directed Whether to create a directed graph.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' make_empty_graph(n = 10)
+#' make_empty_graph(n = 5, directed = FALSE)
+
+make_empty_graph <- function(n=0, directed=TRUE) {
+  # Argument checks
+  n <- as.integer(n)
+  directed <- as.logical(directed)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_empty", n, directed,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @rdname make_empty_graph
+#' @param ... Passed to \code{make_graph_empty}.
+#' @export
+
+empty_graph <- function(...) constructor_spec(make_empty_graph, ...)
+
+## -----------------------------------------------------------------
+
+
+#' Creating (small) graphs via a simple interface
+#'
+#' This function is useful if you want to create a small (named) graph
+#' quickly, it works for both directed and undirected graphs.
+#'
+#' @details
+#' \code{graph_from_literal} is very handy for creating small graphs quickly.
+#' You need to supply one or more R expressions giving the structure of
+#' the graph. The expressions consist of vertex names and edge
+#' operators. An edge operator is a sequence of \sQuote{\code{-}} and
+#' \sQuote{\code{+}} characters, the former is for the edges and the
+#' latter is used for arrow heads. The edges can be arbitrarily long,
+#' ie. you may use as many \sQuote{\code{-}} characters to \dQuote{draw}
+#' them as you like.
+#'
+#' If all edge operators consist of only \sQuote{\code{-}} characters
+#' then the graph will be undirected, whereas a single \sQuote{\code{+}}
+#' character implies a directed graph.
+#'
+#' Let us see some simple examples. Without arguments the function
+#' creates an empty graph:
+#' \preformatted{  graph_from_literal()
+#' }
+#'
+#' A simple undirected graph with two vertices called \sQuote{A} and
+#' \sQuote{B} and one edge only:
+#' \preformatted{  graph_from_literal(A-B)
+#' }
+#'
+#' Remember that the length of the edges does not matter, so we could
+#' have written the following, this creates the same graph:
+#' \preformatted{  graph_from_literal( A-----B )
+#' }
+#'
+#' If you have many disconnected components in the graph, separate them
+#' with commas. You can also give isolate vertices.
+#' \preformatted{  graph_from_literal( A--B, C--D, E--F, G--H, I, J, K )
+#' }
+#'
+#' The \sQuote{\code{:}} operator can be used to define vertex sets. If
+#' an edge operator connects two vertex sets then every vertex from the
+#' first set will be connected to every vertex in the second set. The
+#' following form creates a full graph, including loop edges:
+#' \preformatted{  graph_from_literal( A:B:C:D -- A:B:C:D )
+#' }
+#'
+#' In directed graphs, edges will be created only if the edge operator
+#' includes a arrow head (\sQuote{+}) \emph{at the end} of the edge:
+#' \preformatted{  graph_from_literal( A -+ B -+ C )
+#'   graph_from_literal( A +- B -+ C )
+#'   graph_from_literal( A +- B -- C )
+#' }
+#' Thus in the third example no edge is created between vertices \code{B}
+#' and \code{C}.
+#'
+#' Mutual edges can be also created with a simple edge operator:
+#' \preformatted{  graph_from_literal( A +-+ B +---+ C ++ D + E)
+#' }
+#' Note again that the length of the edge operators is arbitrary,
+#' \sQuote{\code{+}}, \sQuote{\code{++}} and \sQuote{\code{+-----+}} have
+#' exactly the same meaning.
+#'
+#' If the vertex names include spaces or other special characters then
+#' you need to quote them:
+#' \preformatted{  graph_from_literal( "this is" +- "a silly" -+ "graph here" )
+#' }
+#' You can include any character in the vertex names this way, even
+#' \sQuote{+} and \sQuote{-} characters.
+#'
+#' See more examples below.
+#'
+#' @aliases graph.formula
+#' @param ... For \code{graph_from_literal} the formulae giving the
+#'   structure of the graph, see details below. For \code{from_literal}
+#'   all arguments are passed to \code{graph_from_literal}.
+#' @param simplify Logical scalar, whether to call \code{\link{simplify}}
+#'   on the created graph. By default the graph is simplified, loop and
+#'   multiple edges are removed.
+#' @return An igraph graph
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' # A simple undirected graph
+#' g <- graph_from_literal( Alice-Bob-Cecil-Alice, Daniel-Cecil-Eugene,
+#'                      Cecil-Gordon )
+#' g
+#'
+#' # Another undirected graph, ":" notation
+#' g2 <- graph_from_literal( Alice-Bob:Cecil:Daniel, Cecil:Daniel-Eugene:Gordon )
+#' g2
+#'
+#' # A directed graph
+#' g3 <- graph_from_literal( Alice +-+ Bob --+ Cecil +-- Daniel,
+#'                      Eugene --+ Gordon:Helen )
+#' g3
+#'
+#' # A graph with isolate vertices
+#' g4 <- graph_from_literal( Alice -- Bob -- Daniel, Cecil:Gordon, Helen )
+#' g4
+#' V(g4)$name
+#'
+#' # "Arrows" can be arbitrarily long
+#' g5 <- graph_from_literal( Alice +---------+ Bob )
+#' g5
+#'
+#' # Special vertex names
+#' g6 <- graph_from_literal( "+" -- "-", "*" -- "/", "%%" -- "%/%" )
+#' g6
+#'
+
+graph_from_literal <- function(..., simplify=TRUE) {
+  mf <- as.list(match.call())[-1]
+  graph_from_literal_i(mf)
+}
+
+graph_from_literal_i <- function(mf) {
+
+  ## In case 'simplify' is given
+  simplify <- TRUE
+  if ('simplify' %in% names(mf)) {
+    w <- which(names(mf)=='simplify')
+    if (length(w) > 1) { stop("'simplify' specified multiple times") }
+    simplify <- eval(mf[[w]])
+    mf <- mf[-w]
+  }
+
+  ## Operators first
+  f <- function(x) {
+    if (is.call(x)) {
+      return (list(as.character(x[[1]]), lapply(x[-1], f)))
+    } else {
+      return (NULL)
+    }
+  }
+  ops <- unlist(lapply(mf, f))
+  if (all(ops %in% c("-", ":"))) {
+    directed <- FALSE
+  } else if (all(ops %in% c("-", "+", ":"))) {
+    directed <- TRUE
+  } else {
+    stop("Invalid operator in formula")
+  }
+
+  f <- function(x) {
+    if (is.call(x)) {
+      if (length(x)==3) {
+        return( list(f(x[[2]]), op=as.character(x[[1]]), f(x[[3]])) )
+      } else {
+        return( list(op=as.character(x[[1]]), f(x[[2]])) )
+      }
+    } else {
+      return( c(sym=as.character(x)) )
+    }
+  }
+
+  ret <- lapply(mf, function(x) unlist(f(x)))
+
+  v <- unique(unlist(lapply(ret, function(x) { x[ names(x)=="sym" ] })))
+
+  ## Merge symbols for ":"
+  ret <- lapply(ret, function(x) {
+    res <- list()
+    for (i in seq(along=x)) {
+      if (x[i]==":" && names(x)[i]=="op") {
+        ## SKIP
+      } else if (i>1 && x[i-1]==":" && names(x)[i-1]=="op") {
+        res[[length(res)]] <- c(res[[length(res)]], unname(x[i]))
+      } else {
+        res <- c(res, x[i])
+      }
+    }
+    res
+  })
+
+  ## Ok, create the edges
+  edges <- numeric()
+  for (i in seq(along=ret)) {
+    prev.sym <- character()
+    lhead <- rhead <- character()
+    for (j in seq(along=ret[[i]])) {
+      act <- ret[[i]][[j]]
+      if (names(ret[[i]])[j]=="op") {
+        if (length(lhead)==0) {
+          lhead <- rhead <- act
+        } else {
+          rhead <- act
+        }
+      } else if (names(ret[[i]])[j]=="sym") {
+        for (ps in prev.sym) {
+          for (ps2 in act) {
+            if (lhead=="+") {
+              edges <- c(edges, unname(c(ps2, ps)))
+            }
+            if (!directed || rhead=="+") {
+              edges <- c(edges, unname(c(ps, ps2)))
+            }
+          }
+        }
+        lhead <- rhead <- character()
+        prev.sym <- act
+      }
+    }
+  }
+
+  ids <- seq(along=v)
+  names(ids) <- v
+  res <- graph( unname(ids[edges]), n=length(v), directed=directed)
+  if (simplify) res <- simplify(res)
+  res <- set_vertex_attr(res, "name", value=v)
+  res
+}
+
+#' @rdname graph_from_literal
+#' @export
+
+from_literal <- function(...)
+  constructor_spec(graph_from_literal, ..., .lazy = TRUE)
+
+## -----------------------------------------------------------------
+
+#' Create a star graph, a tree with n vertices and n - 1 leaves
+#'
+#' \code{star} creates a star graph, in this every single vertex is
+#' connected to the center vertex and nobody else.
+#'
+#' @aliases graph.star
+#' @concept Star graph
+#' @param n Number of vertices.
+#' @param mode It defines the direction of the
+#'   edges, \code{in}: the edges point \emph{to} the center, \code{out}:
+#'   the edges point \emph{from} the center, \code{mutual}: a directed
+#'   star is created with mutual edges, \code{undirected}: the edges
+#'   are undirected.
+#' @param center ID of the center vertex.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' make_star(10, mode = "out")
+#' make_star(5, mode = "undirected")
+
+make_star <- function(n, mode=c("in", "out", "mutual", "undirected"),
+                   center=1 ) {
+
+  mode <- igraph.match.arg(mode)
+  mode1 <- switch(mode, "out"=0, "in"=1, "undirected"=2, "mutual"=3)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_star", as.numeric(n), as.numeric(mode1),
+               as.numeric(center)-1,
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- switch(mode, "in"="In-star", "out"="Out-star", "Star")
+    res$mode <- mode
+    res$center <- center
+  }
+  res
+}
+
+#' @rdname make_star
+#' @param ... Passed to \code{make_star}.
+#' @export
+
+star <- function(...) constructor_spec(make_star, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a full graph
+#'
+#' @aliases graph.full
+#' @concept Full graph
+#' @param n Number of vertices.
+#' @param directed Whether to create a directed graph.
+#' @param loops Whether to add self-loops to the graph.
+#' @return An igraph graph
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' make_full_graph(5)
+#' str(make_full_graph(4, directed = TRUE))
+
+make_full_graph <- function(n, directed=FALSE, loops=FALSE) {
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_full", as.numeric(n), as.logical(directed),
+               as.logical(loops),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- "Full graph"
+    res$loops <- loops
+  }
+  res
+}
+
+#' @rdname make_full_graph
+#' @param ... Passed to \code{make_full_graph}.
+#' @export
+
+full_graph <- function(...) constructor_spec(make_full_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a lattice graph
+#'
+#' \code{make_lattice} is a flexible function, it can create lattices of
+#' arbitrary dimensions, periodic or unperiodic ones. It has two
+#' forms. In the first form you only supply \code{dimvector}, but not
+#' \code{length} and \code{dim}. In the second form you omit
+#' \code{dimvector} and supply \code{length} and \code{dim}.
+#'
+#' @aliases graph.lattice
+#' @concept Lattice
+#' @param dimvector A vector giving the size of the lattice in each
+#'   dimension.
+#' @param length Integer constant, for regular lattices, the size of the
+#'   lattice in each dimension.
+#' @param dim Integer constant, the dimension of the lattice.
+#' @param nei The distance within which (inclusive) the neighbors on the
+#'   lattice will be connected. This parameter is not used right now.
+#' @param directed Whether to create a directed lattice.
+#' @param mutual Logical, if \code{TRUE} directed lattices will be
+#'   mutually connected.
+#' @param circular Logical, if \code{TRUE} the lattice or ring will be
+#'   circular.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' make_lattice(c(5, 5, 5))
+#' make_lattice(length = 5, dim = 3)
+
+make_lattice <- function(dimvector = NULL, length = NULL, dim = NULL,
+                          nei = 1, directed = FALSE, mutual = FALSE,
+                          circular=FALSE) {
+
+  if (is.null(dimvector)) {
+    dimvector <- rep(length, dim)
+  }
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_lattice", as.numeric(dimvector), as.numeric(nei),
+               as.logical(directed), as.logical(mutual),
+               as.logical(circular),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- "Lattice graph"
+    res$dimvector <- dimvector
+    res$nei <- nei
+    res$mutual <- mutual
+    res$circular <- circular
+  }
+  res
+}
+
+#' @rdname make_lattice
+#' @param ... Passed to \code{make_lattice}.
+#' @export
+
+lattice <- function(...) constructor_spec(make_lattice, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a ring graph
+#'
+#' A ring is a one-dimensional lattice and this function is a special case
+#' of \code{\link{make_lattice}}.
+#'
+#' @aliases make_ring graph.ring
+#' @param n Number of vertices.
+#' @param directed Whether the graph is directed.
+#' @param mutual Whether directed edges are mutual. It is ignored in
+#'   undirected graphs.
+#' @param circular Whether to create a circular ring. A non-circular
+#'   ring is essentially a \dQuote{line}: a tree where every non-leaf
+#'   vertex has one child.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' str(make_ring(10))
+#' str(make_ring(10, directed = TRUE, mutual = TRUE))
+
+make_ring <- function(n, directed=FALSE, mutual=FALSE, circular=TRUE) {
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_ring", as.numeric(n), as.logical(directed),
+               as.logical(mutual), as.logical(circular),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- "Ring graph"
+    res$mutual <- mutual
+    res$circular <- circular
+  }
+  res
+}
+
+#' @rdname make_ring
+#' @param ... Passed to \code{make_ring}.
+#' @export
+
+ring <- function(...) constructor_spec(make_ring, ...)
+
+## -----------------------------------------------------------------
+
+#' Create tree graphs
+#'
+#' Create a regular tree graph.
+#'
+#' @aliases graph.tree
+#' @concept Trees.
+#' @param n Number of vertices.
+#' @param children Integer scalar, the number of children of a vertex
+#'   (except for leafs)
+#' @param mode Defines the direction of the
+#'   edges. \code{out} indicates that the edges point from the parent to
+#'   the children, \code{in} indicates that they point from the children
+#'   to their parents, while \code{undirected} creates an undirected
+#'   graph.
+#' @return An igraph graph
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' make_tree(10, 2)
+#' make_tree(10, 3, mode = "undirected")
+
+make_tree <- function(n, children=2, mode=c("out", "in", "undirected")) {
+
+  mode <- igraph.match.arg(mode)
+  mode1 <- switch(mode, "out"=0, "in"=1, "undirected"=2);
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_tree", as.numeric(n), as.numeric(children),
+               as.numeric(mode1),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- "Tree"
+    res$children <- children
+    res$mode <- mode
+  }
+  res
+}
+
+#' @rdname make_tree
+#' @param ... Passed to \code{make_tree}.
+#' @export
+
+tree <- function(...) constructor_spec(make_tree, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a graph from the Graph Atlas
+#'
+#' \code{graph_from_atlas} creates graphs from the book
+#' \sQuote{An Atlas of Graphs} by
+#' Roland C. Read and Robin J. Wilson. The atlas contains all undirected
+#' graphs with up to seven vertices, numbered from 0 up to 1252. The
+#' graphs are listed:
+#' \enumerate{
+#'    \item in increasing order of number of nodes;
+#'    \item for a fixed number of nodes, in increasing order of the number
+#'      of edges;
+#'    \item for fixed numbers of nodes and edges, in increasing order of
+#'      the degree sequence, for example 111223 < 112222;
+#'    \item for fixed degree sequence, in increasing number of
+#'      automorphisms.
+#' }
+#'
+#' @aliases graph.atlas
+#' @concept Graph Atlas.
+#' @param n The id of the graph to create.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' ## Some randomly picked graphs from the atlas
+#' graph_from_atlas(sample(0:1252, 1))
+#' graph_from_atlas(sample(0:1252, 1))
+
+
+graph_from_atlas <- function(n) {
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_atlas", as.numeric(n),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- sprintf("Graph from the Atlas #%i", n)
+    res$n <- n
+  }
+  res
+}
+
+#' @rdname graph_from_atlas
+#'  @param ... Passed to \code{graph_from_atlas}.
+#' @export
+
+atlas <- function(...) constructor_spec(graph_from_atlas, ...)
+
+## -----------------------------------------------------------------
+
+#' Create an extended chordal ring graph
+#'
+#' \code{make_chordal_ring} creates an extended chordal ring.
+#' An extended chordal ring is regular graph, each node has the same
+#' degree. It can be obtained from a simple ring by adding some extra
+#' edges specified by a matrix. Let p denote the number of columns in
+#' the \sQuote{\code{W}} matrix. The extra edges of vertex \code{i}
+#' are added according to column \code{i mod p} in
+#' \sQuote{\code{W}}. The number of extra edges is the number
+#' of rows in \sQuote{\code{W}}: for each row \code{j} an edge
+#' \code{i->i+w[ij]} is added if \code{i+w[ij]} is less than the number
+#' of total nodes. See also Kotsis, G: Interconnection Topologies for
+#' Parallel Processing Systems, PARS Mitteilungen 11, 1-6, 1993.
+#'
+#' @aliases graph.extended.chordal.ring
+#' @param n The number of vertices.
+#' @param w A matrix which specifies the extended chordal ring. See
+#'   details below.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' chord <- make_chordal_ring(15,
+#'     matrix(c(3, 12, 4, 7, 8, 11), nr = 2))
+
+make_chordal_ring <- function(n, w) {
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_extended_chordal_ring", as.numeric(n),
+               as.matrix(w),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- "Extended chordal ring"
+    res$w <- w
+  }
+  res
+}
+
+#' @rdname make_chordal_ring
+#' @param ... Passed to \code{make_chordal_ring}.
+#' @export
+
+chordal_ring <- function(...) constructor_spec(make_chordal_ring, ...)
+
+## -----------------------------------------------------------------
+
+#' Line graph of a graph
+#'
+#' This function calculates the line graph of another graph.
+#'
+#' The line graph \code{L(G)} of a \code{G} undirected graph is defined as
+#' follows. \code{L(G)} has one vertex for each edge in \code{G} and two
+#' vertices in \code{L(G)} are connected by an edge if their corresponding
+#' edges share an end point.
+#'
+#' The line graph \code{L(G)} of a \code{G} directed graph is slightly
+#' different, \code{L(G)} has one vertex for each edge in \code{G} and two
+#' vertices in \code{L(G)} are connected by a directed edge if the target of
+#' the first vertex's corresponding edge is the same as the source of the
+#' second vertex's corresponding edge.
+#'
+#' @aliases line.graph
+#' @param graph The input graph, it can be directed or undirected.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}, the first version of
+#' the C code was written by Vincent Matossian.
+#' @keywords graphs
+#' @examples
+#'
+#' # generate the first De-Bruijn graphs
+#' g <- make_full_graph(2, directed=TRUE, loops=TRUE)
+#' make_line_graph(g)
+#' make_line_graph(make_line_graph(g))
+#' make_line_graph(make_line_graph(make_line_graph(g)))
+#'
+make_line_graph <- function(graph) {
+
+  if (!is_igraph(graph)) {
+    stop("Not a graph object")
+  }
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_line_graph", graph,
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- "Line graph"
+  }
+  res
+}
+
+#' @rdname make_line_graph
+#' @param ... Passed to \code{make_line_graph}.
+#' @export
+
+line_graph <- function(...) constructor_spec(make_line_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' De Bruijn graphs
+#'
+#' De Bruijn graphs are labeled graphs representing the overlap of strings.
+#'
+#' A de Bruijn graph represents relationships between strings. An alphabet of
+#' \code{m} letters are used and strings of length \code{n} are considered.  A
+#' vertex corresponds to every possible string and there is a directed edge
+#' from vertex \code{v} to vertex \code{w} if the string of \code{v} can be
+#' transformed into the string of \code{w} by removing its first letter and
+#' appending a letter to it.
+#'
+#' Please note that the graph will have \code{m} to the power \code{n} vertices
+#' and even more edges, so probably you don't want to supply too big numbers
+#' for \code{m} and \code{n}.
+#'
+#' De Bruijn graphs have some interesting properties, please see another
+#' source, eg. Wikipedia for details.
+#'
+#' @aliases graph.de.bruijn
+#' @param m Integer scalar, the size of the alphabet. See details below.
+#' @param n Integer scalar, the length of the labels. See details below.
+#' @return A graph object.
+#' @author Gabor Csardi <csardi.gabor@@gmail.com>
+#' @seealso \code{\link{make_kautz_graph}}, \code{\link{make_line_graph}}
+#' @keywords graphs
+#' @export
+#' @examples
+#'
+#' # de Bruijn graphs can be created recursively by line graphs as well
+#' g <- make_de_bruijn_graph(2,1)
+#' make_de_bruijn_graph(2,2)
+#' make_line_graph(g)
+
+make_de_bruijn_graph <- function(m, n) {
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_de_bruijn", as.numeric(m), as.numeric(n),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- sprintf("De-Bruijn graph %i-%i", m, n)
+    res$m <- m
+    res$n <- n
+  }
+  res
+}
+
+#' @rdname make_de_bruijn_graph
+#' @param ... Passed to \code{make_de_bruijn_graph}.
+#' @export
+
+de_bruijn_graph <- function(...) constructor_spec(make_de_bruijn_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' Kautz graphs
+#'
+#' Kautz graphs are labeled graphs representing the overlap of strings.
+#'
+#' A Kautz graph is a labeled graph, vertices are labeled by strings of length
+#' \code{n+1} above an alphabet with \code{m+1} letters, with the restriction
+#' that every two consecutive letters in the string must be different. There is
+#' a directed edge from a vertex \code{v} to another vertex \code{w} if it is
+#' possible to transform the string of \code{v} into the string of \code{w} by
+#' removing the first letter and appending a letter to it.
+#'
+#' Kautz graphs have some interesting properties, see eg. Wikipedia for
+#' details.
+#'
+#' @aliases graph.kautz
+#' @param m Integer scalar, the size of the alphabet. See details below.
+#' @param n Integer scalar, the length of the labels. See details below.
+#' @return A graph object.
+#' @author Gabor Csardi <csardi.gabor@@gmail.com>, the first version in R was
+#' written by Vincent Matossian.
+#' @seealso \code{\link{make_de_bruijn_graph}}, \code{\link{make_line_graph}}
+#' @keywords graphs
+#' @export
+#' @examples
+#'
+#' make_line_graph(make_kautz_graph(2,1))
+#' make_kautz_graph(2,2)
+#'
+make_kautz_graph <- function(m, n) {
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_kautz", as.numeric(m), as.numeric(n),
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$name <- sprintf("Kautz graph %i-%i", m, n)
+    res$m <- m
+    res$n <- n
+  }
+  res
+}
+
+#' @rdname make_kautz_graph
+#' @param ... Passed to \code{make_kautz_graph}.
+#' @export
+
+kautz_graph <- function(...) constructor_spec(make_kautz_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a full bipartite graph
+#'
+#' Bipartite graphs are also called two-mode by some. This function creates a
+#' bipartite graph in which every possible edge is present.
+#'
+#' Bipartite graphs have a \sQuote{\code{type}} vertex attribute in igraph,
+#' this is boolean and \code{FALSE} for the vertices of the first kind and
+#' \code{TRUE} for vertices of the second kind.
+#'
+#' @aliases graph.full.bipartite
+#' @param n1 The number of vertices of the first kind.
+#' @param n2 The number of vertices of the second kind.
+#' @param directed Logical scalar, whether the graphs is directed.
+#' @param mode Scalar giving the kind of edges to create for directed graphs.
+#' If this is \sQuote{\code{out}} then all vertices of the first kind are
+#' connected to the others; \sQuote{\code{in}} specifies the opposite
+#' direction; \sQuote{\code{all}} creates mutual edges. This argument is
+#' ignored for undirected graphs.x
+#' @return An igraph graph, with the \sQuote{\code{type}} vertex attribute set.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{make_full_graph}} for creating one-mode full graphs
+#' @keywords graphs
+#' @examples
+#'
+#' g <- make_full_bipartite_graph(2, 3)
+#' g2 <- make_full_bipartite_graph(2, 3, dir=TRUE)
+#' g3 <- make_full_bipartite_graph(2, 3, dir=TRUE, mode="in")
+#' g4 <- make_full_bipartite_graph(2, 3, dir=TRUE, mode="all")
+#'
+make_full_bipartite_graph <- function(n1, n2, directed=FALSE,
+                       mode=c("all", "out", "in")) {
+
+  n1 <- as.integer(n1)
+  n2 <- as.integer(n2)
+  directed <- as.logical(directed)
+  mode1 <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_full_bipartite", n1, n2, as.logical(directed), mode1,
+               PACKAGE="igraph")
+  if (igraph_opt("add.params")) {
+    res$graph$name <- "Full bipartite graph"
+    res$n1 <- n1
+    res$n2 <- n2
+    res$mode <- mode
+  }
+  set_vertex_attr(res$graph, "type", value=res$types)
+}
+
+#' @rdname make_full_bipartite_graph
+#' @param ... Passed to \code{make_full_bipartite_graph}.
+#' @export
+
+full_bipartite_graph <- function(...) constructor_spec(make_full_bipartite_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a bipartite graph
+#'
+#' A bipartite graph has two kinds of vertices and connections are only allowed
+#' between different kinds.
+#'
+#' Bipartite graphs have a \code{type} vertex attribute in igraph, this is
+#' boolean and \code{FALSE} for the vertices of the first kind and \code{TRUE}
+#' for vertices of the second kind.
+#'
+#' \code{make_bipartite_graph} basically does three things. First it checks tha
+#' \code{edges} vector against the vertex \code{types}. Then it creates a graph
+#' using the \code{edges} vector and finally it adds the \code{types} vector as
+#' a vertex attribute called \code{type}.
+#'
+#' \code{is_bipartite} checks whether the graph is bipartite or not. It just
+#' checks whether the graph has a vertex attribute called \code{type}.
+#'
+#' @aliases make_bipartite_graph graph.bipartite is.bipartite is_bipartite
+#' @param types A vector giving the vertex types. It will be coerced into
+#' boolean. The length of the vector gives the number of vertices in the graph.
+#' @param edges A vector giving the edges of the graph, the same way as for the
+#' regular \code{\link{graph}} function. It is checked that the edges indeed
+#' connect vertices of different kind, accoding to the supplied \code{types}
+#' vector.
+#' @param directed Whether to create a directed graph, boolean constant. Note
+#' that by default undirected graphs are created, as this is more common for
+#' bipartite graphs.
+#' @param graph The input graph.
+#' @return \code{make_bipartite_graph} returns a bipartite igraph graph. In other
+#' words, an igraph graph that has a vertex attribute named \code{type}.
+#'
+#' \code{is_bipartite} returns a logical scalar.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{graph}} to create one-mode networks
+#' @keywords graphs
+#' @examples
+#'
+#' g <- make_bipartite_graph( rep(0:1,length=10), c(1:10))
+#' print(g, v=TRUE)
+#'
+make_bipartite_graph <- function(types, edges, directed=FALSE) {
+
+  types <- as.logical(types)
+  edges <- as.numeric(edges)-1
+  directed <- as.logical(directed)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  res <- .Call("R_igraph_create_bipartite", types, edges, directed,
+               PACKAGE="igraph")
+  set_vertex_attr(res, "type", value=types)
+}
+
+#' @rdname make_bipartite_graph
+#' @param ... Passed to \code{make_bipartite_graph}.
+#' @export
+
+bipartite_graph <- function(...) constructor_spec(make_bipartite_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' Create a complete (full) citation graph
+#'
+#' \code{make_full_citation_graph} creates a full citation graph. This is a
+#' directed graph, where every \code{i->j} edge is present if and only if
+#' \eqn{j<i}. If \code{directed=FALSE} then the graph is just a full graph.
+#'
+#' @aliases graph.full.citation
+#' @param n The number of vertices.
+#' @param directed Whether to create a directed graph.
+#' @return An igraph graph.
+#'
+#' @family determimistic constructors
+#' @export
+#' @examples
+#' str(make_full_citation_graph(10))
+
+make_full_citation_graph <- function(n, directed=TRUE) {
+  # Argument checks
+  n <- as.integer(n)
+  directed <- as.logical(directed)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_full_citation", n, directed,
+        PACKAGE="igraph")
+
+  res <- set_graph_attr(res, 'name', 'Full citation graph')
+  res
+}
+
+#' @rdname make_full_citation_graph
+#' @param ... Passed to \code{make_full_citation_graph}.
+#' @export
+
+full_citation_graph <- function(...) constructor_spec(make_full_citation_graph, ...)
+
+## -----------------------------------------------------------------
+
+#' Creating a graph from LCF notation
+#' 
+#' LCF is short for Lederberg-Coxeter-Frucht, it is a concise notation for
+#' 3-regular Hamiltonian graphs. It constists of three parameters, the number
+#' of vertices in the graph, a list of shifts giving additional edges to a
+#' cycle backbone and another integer giving how many times the shifts should
+#' be performed. See \url{http://mathworld.wolfram.com/LCFNotation.html} for
+#' details.
+#' 
+#' 
+#' @aliases graph.lcf graph_from_lcf
+#' @param n Integer, the number of vertices in the graph.
+#' @param shifts Integer vector, the shifts.
+#' @param repeats Integer constant, how many times to repeat the shifts.
+#' @return A graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{graph}} can create arbitrary graphs, see also the other
+#' functions on the its manual page for creating special graphs.
+#' @keywords graphs
+#' @examples
+#' 
+#' # This is the Franklin graph:
+#' g1 <- graph_from_lcf(12, c(5,-5), 6)
+#' g2 <- make_graph("Franklin")
+#' isomorphic(g1, g2)
+#' @export
+#' @include auto.R
+
+graph_from_lcf <- graph_from_lcf
diff --git a/R/mgclust.R b/R/mgclust.R
new file mode 100644
index 0000000..03458e4
--- /dev/null
+++ b/R/mgclust.R
@@ -0,0 +1,168 @@
+
+#' @export
+
+gclust.rsvt <- function(glist,r=1,maxsvt=10,nmfout=FALSE,maxit=10000,nmfmethod='lee') 
+{
+    # rsvt -- repeated singular value thresholding 
+    # input could be a list of graphs (igraph model) 
+    # or a matrix, where each column corresponds to 
+    # a vectorized version of a graph 
+
+	if (is.list(glist)) {
+	    Time <- length(glist)
+	    if (class(glist[[1]])=="igraph") {
+	        glist <- lapply(glist,get.adjacency)
+	    }
+	    Xorigin <- sapply(glist,as.vector)
+	} else {
+	    Xorigin = glist
+	}
+	
+	Xraw = Xorigin 
+	Xorigin = Xorigin %*% solve(diag(colSums(Xorigin)))
+
+	mysvd = tryCatch(irlba::irlba(Xorigin,r,r,maxit=maxit), error=function(e) svd(Xorigin,r,r))
+	U = mysvd$u[,1:r,drop=FALSE]
+	V = mysvd$v[,1:r,drop=FALSE]
+	if(r == 1) {
+	    S = matrix(mysvd$d[1:r],1,1)
+	} else {
+	    S = diag(mysvd$d[1:r])
+	}
+	
+	maxsvt = ifelse(maxsvt > 0,maxsvt, 1)
+	for(itr in 1:maxsvt) {
+	    X = U %*% S %*% t(V)
+	    X[X<0]=0
+	    mysvd = tryCatch(irlba::irlba(X,r,r,maxit=maxit), error=function(e) svd(X,r,r))
+	    UU = mysvd$u[,1:r,drop=FALSE]
+	    VV = mysvd$v[,1:r,drop=FALSE]
+	    if(r == 1) {
+	        SS = matrix(mysvd$d[1:r],1,1)
+	    } else {
+	        SS = diag(mysvd$d[1:r])
+	    }
+	    if(norm(UU-U) + norm(VV-V) + norm(SS-S) < 1e-12) {
+	        break
+	    }
+	    U = UU;
+	    V = VV;
+	    S = SS;
+	}
+	
+	XX = X %*% solve(diag(colSums(X)))
+	stash = which(rowSums(XX)==0)
+	if(length(stash)>0){
+	    XX =  XX[-stash,]
+	}
+
+	mynmf = NMF::nmf(XX,rank=r,method=nmfmethod)
+	WW = matrix(0,nrow=nrow(X),ncol=r)
+	if(length(stash)>0){
+	    WW[-stash,] = NMF::basis(mynmf)
+	} else {
+	    WW = NMF::basis(mynmf)
+	}
+	
+	HH = coef(mynmf)
+	if(r > 1) {
+	    HH = diag(colSums(WW)) %*% HH
+	    WW = round(WW %*% solve(diag(colSums(WW))),12)
+	    HH = round(HH %*% solve(diag(colSums(HH))),12)   
+	} else {
+	    HH = colSums(WW) %*% HH
+	    WW = round(WW/colSums(WW),12)
+	    HH = round(HH %*% solve(diag(colSums(HH))),12)   
+	}
+	
+	if(nmfout)
+	    return(list(nmf=mynmf, W=WW, H=HH, Xorigin=Xraw))
+	else 
+	    return(list(nmf=NULL,  W=WW, H=HH, Xorigin=Xraw))
+}
+
+#' @export
+
+gclust.app <- function(glist, r=1, nmfout=FALSE, maxit=10000, nmfmethod='lee') 
+{
+    # app -- apparent (clustering), i.e. no rsvt
+    # input could be a list of graphs (igraph model) 
+    # or a matrix, where each column corresponds to 
+    # a vectorized version of a graph 
+
+	if (is.list(glist)) {
+	    Time <- length(glist)
+	    if (class(glist[[1]])=="igraph") {
+	        glist <- lapply(glist,get.adjacency)
+	    }
+	    Xorigin <- sapply(glist,as.vector)
+	} else {
+	    Xorigin = glist
+	}
+	
+	Xraw = Xorigin 
+	XX = Xorigin %*% solve(diag(colSums(Xorigin)))
+	
+	stash = which(rowSums(XX)==0)
+	if(length(stash)>0){
+	    XX =  XX[-stash,]
+	}
+
+	mynmf = NMF::nmf(XX,rank=r,method=nmfmethod)
+	WW = matrix(0,nrow=nrow(Xraw),ncol=r)
+	if(length(stash)>0){
+	    WW[-stash,] = cbind(NMF::basis(mynmf))
+	} else {
+	    WW = NMF::basis(mynmf)
+	}
+	HH = coef(mynmf)
+	if(r > 1) {
+	    HH = diag(colSums(WW)) %*% HH
+	    WW = round(WW %*% solve(diag(colSums(WW))),12)
+	    HH = round(HH %*% solve(diag(colSums(HH))),12)   
+	} else {
+	    HH = colSums(WW) %*% HH
+	    WW = round(WW /colSums(WW),12)
+	    HH = round(HH %*% solve(diag(colSums(HH))),12)   
+	}
+	
+	if(nmfout)
+	    return(list(nmf=mynmf,W=WW,H=HH, Xorigin=Xraw))
+	else 
+	    return(list(nmf=NULL,W=WW,H=HH, Xorigin=Xraw))
+}
+
+#' @export
+
+getAICc <- function(gfit) {
+
+    # input is the output from a call to gclust.rsvt or gclust.app
+    
+	Xorigin = gfit$Xorigin
+	Xmean = gfit$W %*% gfit$H %*% diag(colSums(Xorigin))
+	Xmean[Xmean<1e-12] = 0
+	
+	Phat = gfit$W %*% gfit$H
+	Phat[Phat < 1e-12] = 0
+	if(ncol(gfit$W) > 1) { 
+	    nparams = colSums((1.0*(gfit$W > 0) ))
+	    nparams = nparams %*% diag(1/colSums(Xorigin %*% t(gfit$H)))
+	    nparams = sum(nparams)
+	} else {
+	    nparams = colSums((1.0*(gfit$W > 0) ))
+	    nparams = nparams/colSums(Xorigin %*% t(gfit$H))
+	    nparams = sum(nparams)
+	}
+	
+	zeroprob = which(Phat<1e-12)
+	if(any(Xorigin[zeroprob]> 1e-12)) {
+	    retval = Inf
+	} else {
+	    if(length(zeroprob) > 0) {
+	        Phat = Phat[-zeroprob]
+	    } 
+	    retval = 2*(nparams) - 2*sum(Phat*log(Phat))
+	}
+	
+	data.frame(nclust=ncol(gfit$W),  negloglikpart=-2*sum(Phat*log(Phat)),  parampart=2*nparams, AIC=retval) 
+}
diff --git a/R/minimum.spanning.tree.R b/R/minimum.spanning.tree.R
index 497a60e..62d56f3 100644
--- a/R/minimum.spanning.tree.R
+++ b/R/minimum.spanning.tree.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,15 +19,53 @@
 #
 ###################################################################
 
-minimum.spanning.tree <- function(graph, weights=NULL,
+
+
+#' Minimum spanning tree
+#' 
+#' A subgraph of a connected graph is a \emph{minimum spanning tree} if it is
+#' tree, and the sum of its edge weights are the minimal among all tree
+#' subgraphs of the graph. A minimum spanning forest of a graph is the graph
+#' consisting of the minimum spanning trees of its components.
+#' 
+#' If the graph is unconnected a minimum spanning forest is returned.
+#'
+#' @aliases minimum.spanning.tree
+#' @param graph The graph object to analyze.
+#' @param weights Numeric algorithm giving the weights of the edges in the
+#' graph. The order is determined by the edge ids. This is ignored if the
+#' \code{unweighted} algorithm is chosen
+#' @param algorithm The algorithm to use for calculation. \code{unweighted} can
+#' be used for unwieghted graphs, and \code{prim} runs Prim's algorithm for
+#' weighted graphs.  If this is \code{NULL} then igraph tries to select the
+#' algorithm automatically: if the graph has an edge attribute called
+#' \code{weight} of the \code{weights} argument is not \code{NULL} then Prim's
+#' algorithm is chosen, otherwise the unwweighted algorithm is performed.
+#' @param \dots Additional arguments, unused.
+#' @return A graph object with the minimum spanning forest. (To check that it
+#' is a tree check that the number of its edges is \code{vcount(graph)-1}.)
+#' The edge and vertex attributes of the original graph are preserved in the
+#' result.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{components}}
+#' @references Prim, R.C. 1957. Shortest connection networks and some
+#' generalizations \emph{Bell System Technical Journal}, 37 1389--1401.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(100, 3/100)
+#' g_mst <- mst(g)
+#' 
+mst <- function(graph, weights=NULL,
                                   algorithm=NULL, ...) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
   if (is.null(algorithm)) {
-    if (!is.null(weights) || "weight" %in% list.edge.attributes(graph)) {
+    if (!is.null(weights) || "weight" %in% edge_attr_names(graph)) {
       algorithm <- "prim"
     } else {
       algorithm <- "unweighted"
@@ -40,7 +77,7 @@ minimum.spanning.tree <- function(graph, weights=NULL,
     .Call("R_igraph_minimum_spanning_tree_unweighted", graph,
           PACKAGE="igraph")
   } else if (algorithm=="prim") {
-    if (is.null(weights) && ! "weight" %in% list.edge.attributes(graph)) {
+    if (is.null(weights) && ! "weight" %in% edge_attr_names(graph)) {
       stop("edges weights must be supplied for Prim's algorithm")
     } else if (is.null(weights)) {
       weights <- E(graph)$weight
diff --git a/R/motifs.R b/R/motifs.R
index 4ece532..4cf3850 100644
--- a/R/motifs.R
+++ b/R/motifs.R
@@ -20,9 +20,40 @@
 #
 ###################################################################
 
-graph.motifs <- function(graph, size=3, cut.prob=rep(0, size)) {
+#' Graph motifs
+#' 
+#' Graph motifs are small connected subgraphs with a well-defined
+#' structure.  These functions search a graph for various motifs.
+#' 
+#' \code{motifs} searches a graph for motifs of a given size and returns a
+#' numeric vector containing the number of different motifs. The order of
+#' the motifs is defined by their isomorphism class, see
+#' \code{\link{isomorphism_class}}.
+#' 
+#' @aliases graph.motifs
+#' @param graph Graph object, the input graph.
+#' @param size The size of the motif, currently 3 and 4 are supported only.
+#' @param cut.prob Numeric vector giving the probabilities that the search
+#' graph is cut at a certain level. Its length should be the same as the size
+#' of the motif (the \code{size} argument). By default no cuts are made.
+#' @return \code{motifs} returns a numeric vector, the number of occurences of
+#' each motif in the graph. The motifs are ordered by their isomorphism
+#' classes. Note that for unconnected subgraphs, which are not considered to be
+#' motifs, the result will be \code{NA}.
+#' @seealso \code{\link{isomorphism_class}}
+#'
+#' @export
+#' @family graph motifs
+#'
+#' @examples
+#' g <- barabasi.game(100)
+#' motifs(g, 3)
+#' count_motifs(g, 3)
+#' sample_motifs(g, 3)
 
-  if (!is.igraph(graph)) {
+motifs <- function(graph, size=3, cut.prob=rep(0, size)) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   cut.prob <- as.numeric(cut.prob)
@@ -39,9 +70,35 @@ graph.motifs <- function(graph, size=3, cut.prob=rep(0, size)) {
   res
 }
 
-graph.motifs.no <- function(graph, size=3, cut.prob=rep(0, size)) {
+#' Graph motifs
+#' 
+#' Graph motifs are small connected subgraphs with a well-defined
+#' structure.  These functions search a graph for various motifs.
+#' 
+#' \code{count_motifs} calculates the total number of motifs of a given
+#' size in graph.
+#' 
+#' @aliases graph.motifs.no
+#' @param graph Graph object, the input graph.
+#' @param size The size of the motif, currently 3 and 4 are supported only.
+#' @param cut.prob Numeric vector giving the probabilities that the search
+#' graph is cut at a certain level. Its length should be the same as the size
+#' of the motif (the \code{size} argument). By default no cuts are made.
+#' @return \code{count_motifs} returns  a numeric scalar.
+#' @seealso \code{\link{isomorphism_class}}
+#'
+#' @export
+#' @family graph motifs
+#'
+#' @examples
+#' g <- barabasi.game(100)
+#' motifs(g, 3)
+#' count_motifs(g, 3)
+#' sample_motifs(g, 3)
+
+count_motifs <- function(graph, size=3, cut.prob=rep(0, size)) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   cut.prob <- as.numeric(cut.prob)
@@ -56,10 +113,41 @@ graph.motifs.no <- function(graph, size=3, cut.prob=rep(0, size)) {
         PACKAGE="igraph")
 }
 
-graph.motifs.est <- function(graph, size=3, cut.prob=rep(0, size),
+#' Graph motifs
+#' 
+#' Graph motifs are small connected subgraphs with a well-defined
+#' structure.  These functions search a graph for various motifs.
+#' 
+#' \code{sample_motifs} estimates the total number of motifs of a given
+#' size in a graph based on a sample.
+#' 
+#' @aliases graph.motifs.est
+#' @param graph Graph object, the input graph.
+#' @param size The size of the motif, currently 3 and 4 are supported only.
+#' @param cut.prob Numeric vector giving the probabilities that the search
+#' graph is cut at a certain level. Its length should be the same as the size
+#' of the motif (the \code{size} argument). By default no cuts are made.
+#' @param sample.size The number of vertices to use as a starting point for
+#' finding motifs. Only used if the \code{sample} argument is \code{NULL}.
+#' @param sample If not \code{NULL} then it specifies the vertices to use as a
+#' starting point for finding motifs.
+#' @return A numeric scalar, an estimate for the total number of motifs in
+#'   the graph.
+#' @seealso \code{\link{isomorphism_class}}
+#'
+#' @export
+#' @family graph motifs
+#'
+#' @examples
+#' g <- barabasi.game(100)
+#' motifs(g, 3)
+#' count_motifs(g, 3)
+#' sample_motifs(g, 3)
+
+sample_motifs <- function(graph, size=3, cut.prob=rep(0, size),
                              sample.size=vcount(graph)/10, sample=NULL) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   cut.prob <- as.numeric(cut.prob)
@@ -74,3 +162,75 @@ graph.motifs.est <- function(graph, size=3, cut.prob=rep(0, size),
         PACKAGE="igraph")
 }
   
+
+#' Dyad census of a graph
+#' 
+#' Classify dyads in a directed graphs. The relationship between each pair of
+#' vertices is measured. It can be in three states: mutual, asymmetric or
+#' non-existent.
+#' 
+#' 
+#' @aliases dyad.census dyad_census
+#' @param graph The input graph. A warning is given if it is not directed.
+#' @return A named numeric vector with three elements: \item{mut}{The number of
+#' pairs with mutual connections.} \item{asym}{The number of pairs with
+#' non-mutual connections.} \item{null}{The number of pairs with no connection
+#' between them.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{triad_census}} for the same classification, but with
+#' triples.
+#' @references Holland, P.W. and Leinhardt, S. A Method for Detecting Structure
+#' in Sociometric Data. \emph{American Journal of Sociology}, 76, 492--513.
+#' 1970.
+#' 
+#' Wasserman, S., and Faust, K. \emph{Social Network Analysis: Methods and
+#' Applications.} Cambridge: Cambridge University Press. 1994.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_pa(100)
+#' dyad_census(g)
+#' @export
+
+dyad_census <- dyad_census
+
+
+#' Triad census, subgraphs with three vertices
+#' 
+#' This function counts the different subgraphs of three vertices in a graph.
+#' 
+#' Triad census was defined by David and Leinhardt (see References below).
+#' Every triple of vertices (A, B, C) are classified into the 16 possible
+#' states: \describe{ \item{003}{A,B,C, the empty graph.} \item{012}{A->B, C,
+#' the graph with a single directed edge.} \item{102}{A<->B, C, the graph with
+#' a mutual connection between two vertices.} \item{021D}{A<-B->C, the
+#' out-star.} \item{021U}{A->B<-C, the in-star.} \item{021C}{A->B->C, directed
+#' line.} \item{111D}{A<->B<-C.} \item{111U}{A<->B->C.} \item{030T}{A->B<-C,
+#' A->C.} \item{030C}{A<-B<-C, A->C.} \item{201}{A<->B<->C.}
+#' \item{120D}{A<-B->C, A<->C.} \item{120U}{A->B<-C, A<->C.}
+#' \item{120C}{A->B->C, A<->C.} \item{210}{A->B<->C, A<->C.}
+#' \item{300}{A<->B<->C, A<->C, the complete graph.} }
+#' 
+#' This functions uses the RANDESU motif finder algorithm to find and count the
+#' subgraphs, see \code{\link{motifs}}.
+#' 
+#' @aliases triad.census triad_census
+#' @param graph The input graph, it should be directed. An undirected graph
+#' results a warning, and undefined results.
+#' @return A numeric vector, the subgraph counts, in the order given in the
+#' above description.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{dyad_census}} for classifying binary relationships,
+#' \code{\link{motifs}} for the underlying implementation.
+#' @references See also Davis, J.A. and Leinhardt, S.  (1972).  The Structure
+#' of Positive Interpersonal Relations in Small Groups.  In J. Berger (Ed.),
+#' Sociological Theories in Progress, Volume 2, 218-251.  Boston: Houghton
+#' Mifflin.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnm(15, 45, directed = TRUE)
+#' triad_census(g)
+#' @export
+
+triad_census <- triad_census
diff --git a/R/nexus.R b/R/nexus.R
index 5a64506..8c85e7a 100644
--- a/R/nexus.R
+++ b/R/nexus.R
@@ -48,6 +48,9 @@ makeNexusDatasetInfo <- function(entries) {
   dsi
 }
 
+#' @method print nexusDatasetInfo
+#' @rdname nexus
+
 print.nexusDatasetInfo <- function(x, ...) {
   ve <- strsplit(parseVE(x$`vertices/edges`), "/")[[1]]
   nc <- c("U", "-", "-", "-")
@@ -116,6 +119,9 @@ print.nexusDatasetInfo <- function(x, ...) {
   invisible(x)
 }
 
+#' @method summary nexusDatasetInfoList
+#' @rdname nexus
+
 summary.nexusDatasetInfoList <- function(object, ...) {
   o <- as.numeric(attr(object, "offset"))
   s <- as.numeric(attr(object, "size"))
@@ -143,6 +149,9 @@ parseVE <- function(ve) {
   paste(v, sep="/", e)
 }
 
+#' @method print nexusDatasetInfoList
+#' @rdname nexus
+
 print.nexusDatasetInfoList <- function(x, ...) {
   summary(x)
   
@@ -194,10 +203,172 @@ nexus.format.result <- function(l, name="") {
   res
 }
 
-nexus.list <- function(tags=NULL, offset=0, limit=10,
+#' Query and download from the Nexus network repository
+#' 
+#' The Nexus network repository is an online collection of network data sets.
+#' These functions can be used to query it and download data from it, directly
+#' as an igraph graph.
+#' 
+#' Nexus is an online repository of networks, with an API that allow
+#' programatic queries against it, and programatic data download as well.
+#' 
+#' The \code{nexus_list} and \code{nexus_info} functions query the online
+#' database. They both return \code{nexusDatasetInfo} objects.
+#' \code{nexus_info} returns more information than \code{nexus_list}.
+#' 
+#' \code{nexus_search} searches Nexus, and returns a list of data sets, as
+#' \code{nexusDatasetInfo} objects. See below for some search examples.
+#' 
+#' \code{nexus_get} downloads a data set from Nexus, based on its numeric id,
+#' or based on a Nexus search string. For search strings, only the first search
+#' hit is downloaded, but see also the \code{offset} argument. (If there are
+#' not data sets found, then the function returns an error.)
+#' 
+#' The \code{nexusDatasetInfo} objects returned by \code{nexus_list} have the
+#' following fields: \describe{
+#'   \item{id}{The numeric id of the dataset.}
+#'   \item{sid}{The character id of the dataset.}
+#'   \item{name}{Character scalar, the name of the dataset.}
+#'   \item{vertices/edges}{Character, the number of vertices and edges in
+#'     the graph(s). Vertices and edges are separated by a  slash, and if
+#'     the data set consists of multiple networks, then they are separated
+#'     by spaces.}
+#'   \item{tags}{Character vector, the tags of the dataset. Directed graph
+#'     have the tags \sQuote{directed}. Undirected graphs are tagged 
+#'     as \sQuote{undirected}. Other common tags are: \sQuote{weighted},
+#'     \sQuote{bipartite}, \sQuote{social network}, etc.}
+#'   \item{networks}{The ids and names of the networks in the data set. The
+#'     numeric and character id are separated by a slash, and multiple networks
+#'     are separated by spaces.}
+#' } 
+#' 
+#' \code{nexusDatasetInfo} objects returned by \code{nexus_info} have the
+#' following additional fields: \describe{
+#'   \item{date}{Character scalar, e.g. \sQuote{2011-01-09}, the date when
+#'     the dataset was added to the database.} 
+#'   \item{formats}{Character vector, the data formats in which the data set is
+#'     available. The various formats are separated by semicolons.}
+#'   \item{licence}{Character scalar, the licence of the dataset.}
+#'   \item{licence url}{Character scalar, the URL of the licence of the
+#'     dataset. Pleaase make sure you consult this before using a dataset.}
+#'   \item{summary}{Character scalar, the short description of the dataset,
+#'     this is usually a single sentence.}
+#'   \item{description}{Character scalar, the full description of the
+#'     dataset.}
+#'   \item{citation}{Character scalar, the paper(s) describing the
+#'     dataset. Please cite these papers if you are using the dataset in your
+#'     research, the licence of most datasets requires this.}
+#'   \item{attributes}{A list of lists, each list entry is a graph, vertex
+#'     or edge attribute and has the following entries: \describe{
+#'       \item{type}{Type of the attribute, either \sQuote{graph},
+#'         \sQuote{vertex} or \sQuote{edge}.}
+#'       \item{datatype}{Data type of the attribute, currently it can be
+#'         \sQuote{numeric} and \sQuote{string}.} 
+#'       \item{name}{Character scalar, the name of the attribute.}
+#'       \item{description}{Character scalar, the description of the
+#'         attribute.}
+#'     }
+#'   } 
+#' }
+#' 
+#' The results of the Nexus queries are printed to the screen in a consise
+#' format, similar to the format of igraph graphs. A data set list (typically
+#' the result of \code{nexus_list} and \code{nexus_search}) looks like this:
+#' \preformatted{NEXUS 1-5/18 -- data set list
+#' [1] kaptail.4         39/109-223   #18 Kapferer tailor shop
+#' [2] condmatcollab2003 31163/120029 #17 Condensed matter collaborations+
+#' [3] condmatcollab     16726/47594  #16 Condensed matter collaborations+
+#' [4] powergrid         4941/6594    #15 Western US power grid
+#' [5] celegansneural    297/2359     #14 C. Elegans neural network }
+#' Each line here represents a data set, and the following information is
+#' given about them: the character id of the data set (e.g. \code{kaptail}
+#' or \code{powergrid}), the number of vertices and number of edges in the
+#' graph of the data sets.  For data sets with multiple graphs, intervals
+#' are given here. Then the numeric id of the data set and the reamining
+#' space is filled with the name of the data set.
+#' 
+#' Summary information about an individual Nexus data set is printed as
+#' \preformatted{NEXUS B--- 39 109-223 #18 kaptail -- Kapferer tailor shop
+#' + tags: directed; social network; undirected
+#' + nets: 1/KAPFTI2; 2/KAPFTS2; 3/KAPFTI1; 4/KAPFTS1}
+#' This is very similar to the header that is used for printing igraph
+#' graphs, but there are some differences as well. The four characters
+#' after the \code{NEXUS} word give the most important properties of the
+#' graph(s): the first is \sQuote{\code{U}} for undirected and
+#' \sQuote{\code{D}} for directed graphs, and \sQuote{\code{B}} if the data
+#' set contains both directed and undirected graphs. The second is
+#' \sQuote{\code{N}} named graphs. The third character is \sQuote{\code{W}}
+#' for weighted graphs, the fourth is \sQuote{\code{B}} if the data set
+#' contains bipartite graphs. Then the number of vertices and number of
+#' edges are printed, for data sets with multiple graphs, the smallest and
+#' the largest values are given. Then comes the numeric id, and the string
+#' id of the data set. The end of the first line contains the name of the
+#' data set. The second row lists the data set tags, and the third row the
+#' networks that are included in the data set.
+#' 
+#' Detailed data set information is printed similarly, but it contains more
+#' fields.
+#'
+#' @rdname nexus
+#' @aliases nexus nexus.list nexus.info nexus.get nexus.search nexus_list
+#' nexus_info nexus_get nexus_search nexusDatasetInfo print.nexusDatasetInfo
+#' print.nexusDatasetInfoList summary.nexusDatasetInfoList
+#' @param tags A character vector, the tags that are searched. If not given (or
+#' \code{NULL}), then all datasets are listed.
+#' @param offset An offset to select part of the results. Results are listed
+#' from \code{offset}+1.
+#' @param limit The maximum number of results to return.
+#' @param operator A character scalar. If \sQuote{or} (the default), then all
+#' datasets that have at least one of the given tags, are returned. If it if
+#' \sQuote{and}, then only datasets that have all the given tags, are returned.
+#' @param order The ordering of the results, possible values are:
+#' \sQuote{date}, \sQuote{name}, \sQuote{popularity}.
+#' @param id The numeric or character id of the data set to query or download.
+#' Instead of the data set ids, it is possible to supply a
+#' \code{nexusDatasetInfo} or \code{nexusDatasetInfoList} object here directly
+#' and then the query is done on the corresponding data set(s).
+#' @param q Nexus search string. See examples below. For the complete
+#' documentation please see the Nexus homepage at
+#' \url{http://nexus.igraph.org}.
+#' @param nexus.url The URL of the Nexus server. Don't change this from the
+#' default, unless you set up your own Nexus server.
+#' @param x,object The \code{nexusDatasetInfo} object to print.
+#' @param \dots Currently ignored.
+#' @return \code{nexus_list} and \code{nexus_search} return a list of
+#' \code{nexusDatasetInfo} objects. The list also has these attributes:
+#' \describe{ \item{size}{The number of data sets returned by the query.}
+#' \item{totalsize}{The total number of data sets found for the query.}
+#' \item{offset}{The offset parameter of the query.} \item{limit}{The limit
+#' parameter of the query.} }
+#' 
+#' \code{nexus_info} returns a single \code{nexusDatasetInfo} object.
+#' 
+#' \code{nexus_get} returns an igraph graph object, or a list of graph objects,
+#' if the data set consists of multiple networks.
+#' @seealso \url{http://nexus.igraph.org}
+#' @examples
+#' \dontrun{nexus_list(tag="weighted")
+#' nexus_list(limit=3, order="name")
+#' nexus_list(limit=3, order="name")[[1]]
+#' nexus_info(2)
+#' g <- nexus_get(2)
+#' summary(g)
+#' 
+#' ## Data sets related to 'US':
+#' nexus_search("US")
+#' 
+#' ## Search for data sets that have 'network' in their name:
+#' nexus_search("name:network")
+#' 
+#' ## Any word can match
+#' nexus_search("blog or US or karate")
+#' }
+#' @export
+
+nexus_list <- function(tags=NULL, offset=0, limit=10,
                        operator=c("or", "and"),
                        order=c("date", "name", "popularity"),
-                       nexus.url=getIgraphOpt("nexus.url")) {
+                       nexus.url=igraph_opt("nexus.url")) {
 
   operator=igraph.match.arg(operator)
   order=igraph.match.arg(order)
@@ -220,13 +391,16 @@ nexus.list <- function(tags=NULL, offset=0, limit=10,
   nexus.format.result(l, name)
 }
 
-nexus.info <- function(id, nexus.url=getIgraphOpt("nexus.url")) {
+#' @export
+#' @rdname nexus
+ 
+nexus_info <- function(id, nexus.url=igraph_opt("nexus.url")) {
 
   if (inherits(id, "nexusDatasetInfo")) {
     id <- id$id
   } else if (inherits(id, "nexusDatasetInfoList")) {
     rid <- sapply(id, "[[", "id")
-    res <- lapply(rid, nexus.info, nexus.url=nexus.url)
+    res <- lapply(rid, nexus_info, nexus.url=nexus.url)
     class(res) <- class(id)
     attributes(res) <- attributes(id)
     return(res)
@@ -252,9 +426,12 @@ nexus.info <- function(id, nexus.url=getIgraphOpt("nexus.url")) {
   return(res)
 }  
 
-nexus.get <- function(id, offset=0,
+#' @export
+#' @rdname nexus
+
+nexus_get <- function(id, offset=0,
                       order=c("date", "name", "popularity"),
-                      nexus.url=getIgraphOpt("nexus.url")) {
+                      nexus.url=igraph_opt("nexus.url")) {
 
   order=igraph.match.arg(order)
 
@@ -262,7 +439,7 @@ nexus.get <- function(id, offset=0,
     id <- id$id
   } else if (inherits(id, "nexusDatasetInfoList")) {
     id <- sapply(id, "[[", "id")
-    return(lapply(id, nexus.get, nexus.url=nexus.url))
+    return(lapply(id, nexus_get, nexus.url=nexus.url))
   }
   
   u <- paste(sep="", nexus.url, "/api/dataset?id=", id, "&format=R-igraph")
@@ -270,12 +447,25 @@ nexus.get <- function(id, offset=0,
   rdata <- url(URLencode(u))
   load(rdata, envir=env)
   close(rdata)
-  return(get(ls(env)[1], env))
+  res <- get(ls(env)[1], env)
+
+  upgrade_if_igraph <- function(x) if (is_igraph(x)) upgrade_graph(x) else x
+
+  if (is_igraph(res)) {
+    upgrade_if_igraph(res)
+  } else if (is.list(res)) {
+    res2 <- lapply(res, upgrade_if_igraph)
+    attributes(res2) <- attributes(res)
+    res2
+  }
 }
 
-nexus.search <- function(q, offset=0, limit=10,
+#' @export
+#' @rdname nexus
+
+nexus_search <- function(q, offset=0, limit=10,
                          order=c("date", "name", "popularity"),
-                         nexus.url=getIgraphOpt("nexus.url")) {
+                         nexus.url=igraph_opt("nexus.url")) {
 
   order=igraph.match.arg(order)
 
@@ -295,6 +485,10 @@ nexus.search <- function(q, offset=0, limit=10,
   nexus.format.result(l, name=paste("q:", q))
 }
 
+#' @param i Index.
+#' @method [ nexusDatasetInfoList
+#' @rdname nexus
+
 `[.nexusDatasetInfoList` <- function(x, i) {
   res <- unclass(x)[i]
   class(res) <- class(x)
diff --git a/R/operators.R b/R/operators.R
index 9b3688b..4d8edee 100644
--- a/R/operators.R
+++ b/R/operators.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -22,11 +21,11 @@
 
 rename.attr.if.needed <- function(type, graphs, newsize=NULL, maps=NULL,
                                   maps2=NULL, ignore=character()) {
-  listfun <- switch(type, "g"=list.graph.attributes,
-                    "v"=list.vertex.attributes, "e"=list.edge.attributes,
+  listfun <- switch(type, "g"=graph_attr_names,
+                    "v"=vertex_attr_names, "e"=edge_attr_names,
                     stop("Internal igraph error"))
-  getfun <- switch(type, "g"=get.graph.attribute, "v"=get.vertex.attribute,
-                   "e"=get.edge.attribute, stop("Internal igraph error"))
+  getfun <- switch(type, "g"=graph_attr, "v"=vertex_attr,
+                   "e"=edge_attr, stop("Internal igraph error"))
   alist <- lapply(graphs, listfun)
   an <- unique(unlist(alist))
   an <- setdiff(an, ignore)
@@ -62,12 +61,55 @@ rename.attr.if.needed <- function(type, graphs, newsize=NULL, maps=NULL,
   attr
 }
 
-graph.disjoint.union <- function(...) {
+
+
+#' Disjoint union of graphs
+#' 
+#' The union of two or more graphs are created. The graphs are assumed to have
+#' disjoint vertex sets.
+#' 
+#' \code{disjoint_union} creates a union of two or more disjoint graphs.
+#' Thus first the vertices in the second, third, etc. graphs are relabeled to
+#' have completely disjoint graphs. Then a simple union is created. This
+#' function can also be used via the \%du\% operator.
+#' 
+#' \code{graph.disjont.union} handles graph, vertex and edge attributes.  In
+#' particular, it merges vertex and edge attributes using the basic \code{c()}
+#' function. For graphs that lack some vertex/edge attribute, the corresponding
+#' values in the new graph are set to \code{NA}. Graph attributes are simply
+#' copied to the result. If this would result a name clash, then they are
+#' renamed by adding suffixes: _1, _2, etc.
+#' 
+#' Note that if both graphs have vertex names (ie. a \code{name} vertex
+#' attribute), then the concatenated vertex names might be non-unique in the
+#' result. A warning is given if this happens.
+#' 
+#' An error is generated if some input graphs are directed and others are
+#' undirected.
+#' 
+#' @aliases graph.disjoint.union %du%
+#' @param \dots Graph objects or lists of graph objects.
+#' @param x,y Graph objects.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A star and a ring
+#' g1 <- make_star(10, mode="undirected")
+#' V(g1)$name <- letters[1:10]
+#' g2 <- make_ring(10)
+#' V(g2)$name <- letters[11:20]
+#' str(g1 %du% g2)
+#' @export
+
+disjoint_union <- function(...) {
   
   graphs <- unlist(recursive=FALSE, lapply(list(...), function(l) {
-    if (is.igraph(l)) list(l) else l
+    if (is_igraph(l)) list(l) else l
   } ))
-  if (!all(sapply(graphs, is.igraph))) {
+  if (!all(sapply(graphs, is_igraph))) {
     stop("Not a graph object")
   }
   
@@ -127,25 +169,28 @@ graph.disjoint.union <- function(...) {
   res
 }
 
+#' @export
+#' @rdname disjoint_union
+
 "%du%" <- function(x,y) {
-  graph.disjoint.union(x,y)
+  disjoint_union(x,y)
 }
 
 .igraph.graph.union.or.intersection <- function(call, ..., byname,
                                                 keep.all.vertices) {
 
   graphs <- unlist(recursive=FALSE, lapply(list(...), function(l) {
-    if (is.igraph(l)) list(l) else l
+    if (is_igraph(l)) list(l) else l
   } ))
-  if (!all(sapply(graphs, is.igraph))) {
+  if (!all(sapply(graphs, is_igraph))) {
     stop("Not a graph object")
   }
   if (byname != "auto" && !is.logical(byname)) {
     stop("`bynam' must be \"auto\", or logical")
   }
-  nonamed <- sum(sapply(graphs, is.named))
+  nonamed <- sum(sapply(graphs, is_named))
   if (byname == "auto") {
-    byname <- all(sapply(graphs, is.named))
+    byname <- all(sapply(graphs, is_named))
     if (nonamed != 0 && nonamed != length(graphs)) {
       warning("Some, but not all graphs are named, not using vertex names")
     }
@@ -153,21 +198,21 @@ graph.disjoint.union <- function(...) {
     stop("Some graphs are not named")
   }
 
-  edgemaps <- length(unlist(lapply(graphs, list.edge.attributes))) != 0
+  edgemaps <- length(unlist(lapply(graphs, edge_attr_names))) != 0
   
   if (byname) {
-    allnames <- lapply(graphs, get.vertex.attribute, "name")
+    allnames <- lapply(graphs, vertex_attr, "name")
     if (keep.all.vertices) {
       uninames <- unique(unlist(allnames))
       newgraphs <- lapply(graphs, function(g) {
         g <- g + setdiff(uninames, V(g)$name)
-        permute.vertices(g, match(V(g)$name, uninames))
+        permute(g, match(V(g)$name, uninames))
       })
     } else {
       uninames <- Reduce(intersect, allnames)
       newgraphs <- lapply(graphs, function(g) {
         g <- g - setdiff(V(g)$name, uninames)
-        permute.vertices(g, match(V(g)$name, uninames))
+        permute(g, match(V(g)$name, uninames))
       })
     }
     
@@ -223,35 +268,241 @@ graph.disjoint.union <- function(...) {
   res
 }
 
-graph.union <- function(..., byname="auto") {
+#' Union of two or more sets
+#'
+#' This is an S3 generic function. See \code{methods("union")}
+#' for the actual implementations for various S3 classes. Initially
+#' it is implemented for igraph graphs and igraph vertex and edge
+#' sequences. See
+#' \code{\link{union.igraph}}, and
+#' \code{\link{union.igraph.vs}}.
+#'
+#' @param ... Arguments, their number and interpretation depends on
+#' the function that implements \code{union}.
+#' @return Depends on the function that implements this method.
+#'
+#' @export
+
+union <- function(...)
+  UseMethod("union")
+
+#' @method union default
+#' @export
+
+union.default <- function(...) {
+  base::union(...)
+}
+
+#' Union of graphs
+#' 
+#' The union of two or more graphs are created. The graphs may have identical
+#' or overlapping vertex sets.
+#' 
+#' \code{union} creates the union of two or more graphs.  Edges which are
+#' included in at least one graph will be part of the new graph. This function
+#' can be also used via the \%u\% operator.
+#' 
+#' If the \code{byname} argument is \code{TRUE} (or \code{auto} and all graphs
+#' are named), then the operation is performed on symbolic vertex names instead
+#' of the internal numeric vertex ids.
+#' 
+#' \code{union} keeps the attributes of all graphs. All graph, vertex and
+#' edge attributes are copied to the result. If an attribute is present in
+#' multiple graphs and would result a name clash, then this attribute is
+#' renamed by adding suffixes: _1, _2, etc.
+#' 
+#' The \code{name} vertex attribute is treated specially if the operation is
+#' performed based on symbolic vertex names. In this case \code{name} must be
+#' present in all graphs, and it is not renamed in the result graph.
+#' 
+#' An error is generated if some input graphs are directed and others are
+#' undirected.
+#' 
+#' @aliases graph.union %u%
+#' @param \dots Graph objects or lists of graph objects.
+#' @param byname A logical scalar, or the character scalar \code{auto}. Whether
+#' to perform the operation based on symbolic vertex names. If it is
+#' \code{auto}, that means \code{TRUE} if all graphs are named and \code{FALSE}
+#' otherwise. A warning is generated if \code{auto} and some (but not all)
+#' graphs are named.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @method union igraph
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Union of two social networks with overlapping sets of actors
+#' net1 <- graph_from_literal(D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G,
+#'                   H-F:G, H-I-J)
+#' net2 <- graph_from_literal(D-A:F:Y, B-A-X-F-H-Z, F-Y)
+#' str(net1 %u% net2)
+
+union.igraph <- function(..., byname="auto") {
   .igraph.graph.union.or.intersection("R_igraph_union", ..., byname=byname,
                                       keep.all.vertices=TRUE)
 }
 
+#' @export
+
 "%u%" <- function(x,y) {
-  graph.union(x,y)
+  union(x,y)
 }
 
-graph.intersection <- function(..., byname="auto",
-                               keep.all.vertices=TRUE) {
+#' Intersection of two or more sets
+#'
+#' This is an S3 generic function. See \code{methods("intersection")}
+#' for the actual implementations for various S3 classes. Initially
+#' it is implemented for igraph graphs and igraph vertex and edge
+#' sequences. See
+#' \code{\link{intersection.igraph}}, and
+#' \code{\link{intersection.igraph.vs}}.
+#'
+#' @param ... Arguments, their number and interpretation depends on
+#' the function that implements \code{intersection}.
+#' @return Depends on the function that implements this method.
+#'
+#' @export
+
+intersection <- function(...)
+  UseMethod("intersection")
+
+#' Intersection of graphs
+#' 
+#' The intersection of two or more graphs are created.  The graphs may have
+#' identical or overlapping vertex sets.
+#' 
+#' \code{intersection} creates the intersection of two or more graphs:
+#' only edges present in all graphs will be included.  The corresponding
+#' operator is \%s\%.
+#' 
+#' If the \code{byname} argument is \code{TRUE} (or \code{auto} and all graphs
+#' are named), then the operation is performed on symbolic vertex names instead
+#' of the internal numeric vertex ids.
+#' 
+#' \code{intersection} keeps the attributes of all graphs. All graph,
+#' vertex and edge attributes are copied to the result. If an attribute is
+#' present in multiple graphs and would result a name clash, then this
+#' attribute is renamed by adding suffixes: _1, _2, etc.
+#' 
+#' The \code{name} vertex attribute is treated specially if the operation is
+#' performed based on symbolic vertex names. In this case \code{name} must be
+#' present in all graphs, and it is not renamed in the result graph.
+#' 
+#' An error is generated if some input graphs are directed and others are
+#' undirected.
+#' 
+#' @aliases graph.intersection %s%
+#' @param \dots Graph objects or lists of graph objects.
+#' @param byname A logical scalar, or the character scalar \code{auto}. Whether
+#' to perform the operation based on symbolic vertex names. If it is
+#' \code{auto}, that means \code{TRUE} if all graphs are named and \code{FALSE}
+#' otherwise. A warning is generated if \code{auto} and some (but not all)
+#' graphs are named.
+#' @param keep.all.vertices Logical scalar, whether to keep vertices that only
+#' appear in a subset of the input graphs.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @method intersection igraph
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Common part of two social networks
+#' net1 <- graph_from_literal(D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G,
+#'                   H-F:G, H-I-J)
+#' net2 <- graph_from_literal(D-A:F:Y, B-A-X-F-H-Z, F-Y)
+#' str(net1 %s% net2)
+
+intersection.igraph <- function(..., byname="auto",
+                                keep.all.vertices=TRUE) {
   .igraph.graph.union.or.intersection("R_igraph_intersection", ...,
                                       byname=byname,
                                       keep.all.vertices=keep.all.vertices)
 }
 
+#' @export
+
 "%s%" <- function(x,y) {
-  graph.intersection(x,y)
+  intersection(x,y)
 }
 
-graph.difference <- function(big, small, byname="auto") {
+#' Difference of two sets
+#'
+#' This is an S3 generic function. See \code{methods("difference")}
+#' for the actual implementations for various S3 classes. Initially
+#' it is implemented for igraph graphs (difference of edges in two graphs),
+#' and igraph vertex and edge sequences. See
+#' \code{\link{difference.igraph}}, and
+#' \code{\link{difference.igraph.vs}}.
+#'
+#' @param ... Arguments, their number and interpretation depends on
+#' the function that implements \code{difference}.
+#' @return Depends on the function that implements this method.
+#'
+#' @export
+
+difference <- function(...)
+  UseMethod("difference")
+
+
+#' Difference of graphs
+#' 
+#' The difference of two graphs are created.
+#' 
+#' \code{difference} creates the difference of two graphs. Only edges
+#' present in the first graph but not in the second will be be included in the
+#' new graph. The corresponding operator is \%m\%.
+#' 
+#' If the \code{byname} argument is \code{TRUE} (or \code{auto} and the graphs
+#' are all named), then the operation is performed based on symbolic vertex
+#' names. Otherwise numeric vertex ids are used.
+#' 
+#' \code{difference} keeps all attributes (graph, vertex and edge) of the
+#' first graph.
+#' 
+#' Note that \code{big} and \code{small} must both be directed or both be
+#' undirected, otherwise an error message is given.
+#' 
+#' @aliases graph.difference %m%
+#' @param big The left hand side argument of the minus operator. A directed or
+#' undirected graph.
+#' @param small The right hand side argument of the minus operator. A directed
+#' ot undirected graph.
+#' @param byname A logical scalar, or the character scalar \code{auto}. Whether
+#' to perform the operation based on symbolic vertex names. If it is
+#' \code{auto}, that means \code{TRUE} if both graphs are named and
+#' \code{FALSE} otherwise. A warning is generated if \code{auto} and one graph,
+#' but not both graphs are named.
+#' @param ... Ignored, included for S3 compatibility.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @method difference igraph
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Create a wheel graph
+#' wheel <- union(make_ring(10),
+#'                      make_star(11, center=11, mode="undirected"))
+#' V(wheel)$name <- letters[seq_len(vcount(wheel))]
+#' 
+#' ## Subtract a star graph from it
+#' sstar <- make_star(6, center=6, mode="undirected")
+#' V(sstar)$name <- letters[c(1,3,5,7,9,11)]
+#' G <- wheel %m% sstar
+#' str(G)
+#' plot(G, layout=layout_nicely(wheel))
+
+difference.igraph <- function(big, small, byname="auto", ...) {
 
-  if (!is.igraph(big) || !is.igraph(small)) {
+  if (!is_igraph(big) || !is_igraph(small)) {
     stop("argument is not a graph")
   }
   if (byname != "auto" && !is.logical(byname)) {
     stop("`bynam' must be \"auto\", or logical")
   }
-  nonamed <- is.named(big) + is.named(small)
+  nonamed <- is_named(big) + is_named(small)
   if (byname == "auto") {
     byname <- nonamed == 2
     if (nonamed == 1) {
@@ -272,12 +523,12 @@ graph.difference <- function(big, small, byname="auto") {
     if (any(is.na(perm))) {
       perm[is.na(perm)] <- seq(from=vcount(small)+1, to=vcount(big))
     }
-    big <- permute.vertices(big, perm)
+    big <- permute(big, perm)
 
     on.exit(.Call("R_igraph_finalizer", PACKAGE="igraph"))
     res <- .Call("R_igraph_difference", big, small,
                  PACKAGE="igraph")
-    permute.vertices(res, match(V(res)$name, bnames))
+    permute(res, match(V(res)$name, bnames))
 
   } else {
     on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -285,14 +536,50 @@ graph.difference <- function(big, small, byname="auto") {
           PACKAGE="igraph")
   }
 }
-    
+
+#' @export
+
 "%m%" <- function(x,y) {
-  graph.difference(x,y)
+  difference(x,y)
 }
 
-graph.complementer <- function(graph, loops=FALSE) {
 
-  if (!is.igraph(graph)) {
+
+#' Complementer of a graph
+#' 
+#' A complementer graph contains all edges that were not present in the input
+#' graph.
+#' 
+#' \code{complementer} creates the complementer of a graph. Only edges
+#' which are \emph{not} present in the original graph will be included in the
+#' new graph.
+#' 
+#' \code{complementer} keeps graph and vertex attriubutes, edge
+#' attributes are lost.
+#'
+#' @aliases graph.complementer
+#' @param graph The input graph, can be directed or undirected.
+#' @param loops Logical constant, whether to generate loop edges.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Complementer of a ring
+#' g <- make_ring(10)
+#' complementer(g)
+#' 
+#' ## A graph and its complementer give together the full graph
+#' g <- make_ring(10)
+#' gc <- complementer(g)
+#' gu <- union(g, gc)
+#' gu
+#' graph.isomorphic(gu, make_full_graph(vcount(g)))
+#' 
+complementer <- function(graph, loops=FALSE) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -300,16 +587,78 @@ graph.complementer <- function(graph, loops=FALSE) {
         PACKAGE="igraph")
 }
 
-graph.compose <- function(g1, g2, byname="auto") {
 
-  if (!is.igraph(g1) || !is.igraph(g2)) {
+
+#' Compose two graphs as binary relations
+#' 
+#' Relational composition of two graph.
+#' 
+#' \code{compose} creates the relational composition of two graphs. The
+#' new graph will contain an (a,b) edge only if there is a vertex c, such that
+#' edge (a,c) is included in the first graph and (c,b) is included in the
+#' second graph. The corresponding operator is \%c\%.
+#' 
+#' The function gives an error if one of the input graphs is directed and the
+#' other is undirected.
+#' 
+#' If the \code{byname} argument is \code{TRUE} (or \code{auto} and the graphs
+#' are all named), then the operation is performed based on symbolic vertex
+#' names. Otherwise numeric vertex ids are used.
+#' 
+#' \code{compose} keeps the attributes of both graphs. All graph, vertex
+#' and edge attributes are copied to the result. If an attribute is present in
+#' multiple graphs and would result a name clash, then this attribute is
+#' renamed by adding suffixes: _1, _2, etc.
+#' 
+#' The \code{name} vertex attribute is treated specially if the operation is
+#' performed based on symbolic vertex names. In this case \code{name} must be
+#' present in both graphs, and it is not renamed in the result graph.
+#' 
+#' Note that an edge in the result graph corresponds to two edges in the input,
+#' one in the first graph, one in the second. This mapping is not injective and
+#' several edges in the result might correspond to the same edge in the first
+#' (and/or the second) graph. The edge attributes in the result graph are
+#' updated accordingly.
+#' 
+#' Also note that the function may generate multigraphs, if there are more than
+#' one way to find edges (a,b) in g1 and (b,c) in g2 for an edge (a,c) in the
+#' result. See \code{\link{simplify}} if you want to get rid of the multiple
+#' edges.
+#' 
+#' The function may create loop edges, if edges (a,b) and (b,a) are present in
+#' g1 and g2, respectively, then (a,a) is included in the result. See
+#' \code{\link{simplify}} if you want to get rid of the self-loops.
+#' 
+#' @aliases graph.compose %c%
+#' @param g1 The first input graph.
+#' @param g2 The second input graph.
+#' @param byname A logical scalar, or the character scalar \code{auto}. Whether
+#' to perform the operation based on symbolic vertex names. If it is
+#' \code{auto}, that means \code{TRUE} if both graphs are named and
+#' \code{FALSE} otherwise. A warning is generated if \code{auto} and one graph,
+#' but not both graphs are named.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g1 <- make_ring(10)
+#' g2 <- make_star(10, mode="undirected")
+#' gc <- compose(g1, g2)
+#' str(gc)
+#' str(simplify(gc))
+#' 
+compose <- function(g1, g2, byname="auto") {
+
+  if (!is_igraph(g1) || !is_igraph(g2)) {
     stop("Not a graph object")
   }
 
   if (byname != "auto" && !is.logical(byname)) {
     stop("`byname' must be \"auto\", or logical")
   }
-  nonamed <- is.named(g1) + is.named(g2)
+  nonamed <- is_named(g1) + is_named(g2)
   if (byname == "auto") {
     byname <- nonamed == 2
     if (nonamed == 1) {
@@ -328,15 +677,15 @@ graph.compose <- function(g1, g2, byname="auto") {
       g2 <- g2 + setdiff(uninames, V(g2)$name)
     }
     if (any(uninames != V(g1)$name)) {
-      g1 <- permute.vertices(g1, match(V(g1)$name, uninames))
+      g1 <- permute(g1, match(V(g1)$name, uninames))
     }
     if (any(uninames != V(g2)$name)) {
-      g2 <- permute.vertices(g2, match(V(g2)$name, uninames))
+      g2 <- permute(g2, match(V(g2)$name, uninames))
     }
   }
 
-  edgemaps <- (length(list.edge.attributes(g1)) != 0 ||
-               length(list.edge.attributes(g2)) != 0)
+  edgemaps <- (length(edge_attr_names(g1)) != 0 ||
+               length(edge_attr_names(g2)) != 0)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_compose", g1, g2, edgemaps,
@@ -365,38 +714,254 @@ graph.compose <- function(g1, g2, byname="auto") {
   res
 }
 
+#' @export
+
 "%c%" <- function(x,y) {
-  graph.compose(x,y)
+  compose(x,y)
 }
 
+#' Helper function for adding and deleting edges
+#'
+#' This is a helper function that simplifies adding and deleting
+#' edges to/from graphs.
+#'
+#' \code{edges} is an alias for \code{edge}.
+#' 
+#' @details
+#' When adding edges via \code{+}, all unnamed arguments of
+#' \code{edge} (or \code{edges}) are concatenated, and then passed to
+#' \code{\link{add_edges}}. They are interpreted as pairs of vertex ids,
+#' and an edge will added between each pair. Named arguments will be
+#' used as edge attributes for the new edges.
+#'
+#' When deleting edges via \code{-}, all arguments of \code{edge} (or
+#' \code{edges}) are concatenated via \code{c()} and passed to
+#' \code{\link{delete_edges}}.
+#'
+#' @param ... See details below.
+#' @return A special object that can be used with together with
+#'   igraph graphs and the plus and minus operators.
+#'
+#' @family functions for manipulating graph structure
+#'
+#' @export
+#' @examples
+#' g <- make_ring(10) %>%
+#'   set_edge_attr("color", value = "red")
+#'
+#' g <- g + edge(1, 5, color = "green") +
+#'   edge(2, 6, color = "blue") -
+#'   edge("8|9")
+#'
+#' E(g)[[]]
+#'
+#' g %>%
+#'   add_layout_(in_circle()) %>%
+#'   plot()
+#'
+#' g <- make_ring(10) + edges(1:10)
+#' plot(g)
+
 edge <- function(...) {
   structure(list(...), class="igraph.edge")
 }
 
+#' @export
+#' @rdname edge
+
 edges <- edge
 
+#' Helper function for adding and deleting vertices
+#'
+#' This is a helper function that simplifies adding and deleting
+#' vertices to/from graphs.
+#'
+#' \code{vertices} is an alias for \code{vertex}.
+#' 
+#' @details
+#' When adding vertices via \code{+}, all unnamed arguments are interpreted
+#' as vertex names of the new vertices. Named arguments are interpreted as
+#' vertex attributes for the new vertices. 
+#'
+#' When deleting vertices via \code{-}, all arguments of \code{vertex} (or
+#' \code{vertices}) are concatenated via \code{c()} and passed to
+#' \code{\link{delete_vertices}}. 
+#'
+#' @param ... See details below.
+#' @return A special object that can be used with together with
+#'   igraph graphs and the plus and minus operators.
+#'
+#' @family functions for manipulating graph structure
+#' 
+#' @export
+#' @examples
+#' g <- make_(ring(10), with_vertex_(name = LETTERS[1:10])) +
+#'   vertices('X', 'Y')
+#' g
+#' plot(g)
+
 vertex <- function(...) {
   structure(list(...), class="igraph.vertex")
 }
 
+#' @export
+#' @rdname vertex
+
 vertices <- vertex
 
+#' Helper function to add or delete edges along a path
+#'
+#' This function can be used to add or delete edges that form a path.
+#'
+#' @details
+#' When adding edges via \code{+}, all unnamed arguments are
+#' concatenated, and each element of a final vector is interpreted
+#' as a vertex in the graph. For a vector of length \eqn{n+1}, \eqn{n}
+#' edges are then added, from vertex 1 to vertex 2, from vertex 2 to vertex
+#' 3, etc. Named arguments will be used as edge attributes for the new
+#' edges.
+#'
+#' When deleting edges, all attributes are concatenated and then passed
+#' to \code{\link{delete_edges}}.
+#'
+#' @param ... See details below.
+#' @return A special object that can be used together with igraph
+#'   graphs and the plus and minus operators.
+#'
+#' @family functions for manipulating graph structure
+#' 
+#' @export
+#' @examples
+#' # Create a (directed) wheel
+#' g <- make_star(11, center = 1) + path(2:11, 2)
+#' plot(g)
+#'
+#' g <- make_empty_graph(directed = FALSE, n = 10) %>%
+#'   set_vertex_attr("name", value = letters[1:10])
+#'
+#' g2 <- g + path("a", "b", "c", "d")
+#' plot(g2)
+#' 
+#' g3 <- g2 + path("e", "f", "g", weight=1:2, color="red")
+#' E(g3)[[]]
+#' 
+#' g4 <- g3 + path(c("f", "c", "j", "d"), width=1:3, color="green")
+#' E(g4)[[]]
+
 path <- function(...) {
   structure(list(...), class="igraph.path")
 }
 
+#' Add vertices, edges or another graph to a graph
+#'
+#' @details
+#'   The plus operator can be used to add vertices or edges to graph.
+#'   The actual operation that is performed depends on the type of the
+#'   right hand side argument.
+#'   \itemize{
+#'   \item If is is another igraph graph object and they are both
+#'     named graphs, then the union of the two graphs are calculated,
+#'     see \code{\link{union}}.
+#'   \item If it is another igraph graph object, but either of the two
+#'     are not named, then the disjoint union of
+#'     the two graphs is calculated, see \code{\link{disjoint_union}}.
+#'   \item If it is a numeric scalar, then the specified number of vertices
+#'     are added to the graph.
+#'   \item If it is a character scalar or vector, then it is interpreted as
+#'     the names of the vertices to add to the graph.
+#'   \item If it is an object created with the \code{\link{vertex}} or
+#'     \code{\link{vertices}} function, then new vertices are added to the
+#'     graph. This form is appropriate when one wants to add some vertex
+#'     attributes as well. The operands of the \code{vertices} function
+#'     specifies the number of vertices to add and their attributes as
+#'     well.
+#' 
+#'     The unnamed arguments of \code{vertices} are concatenated and
+#'     used as the \sQuote{\code{name}} vertex attribute (i.e. vertex
+#'     names), the named arguments will be added as additional vertex
+#'     attributes. Examples: \preformatted{  g <- g +
+#'         vertex(shape="circle", color= "red")
+#'   g <- g + vertex("foo", color="blue")
+#'   g <- g + vertex("bar", "foobar")
+#'   g <- g + vertices("bar2", "foobar2", color=1:2, shape="rectangle")}
+#' 
+#'     \code{vertex} is just an alias to \code{vertices}, and it is
+#'     provided for readability. The user should use it if a single vertex
+#'     is added to the graph.
+#' 
+#'   \item If it is an object created with the \code{\link{edge}} or
+#'     \code{\link{edges}} function, then new edges will be added to the
+#'     graph. The new edges and possibly their attributes can be specified as
+#'     the arguments of the \code{edges} function.
+#' 
+#'     The unnamed arguments of \code{edges} are concatenated and used
+#'     as vertex ids of the end points of the new edges. The named
+#'     arguments will be added as edge attributes.
+#' 
+#'     Examples: \preformatted{  g <- make_empty_graph() +
+#'          vertices(letters[1:10]) +
+#'          vertices("foo", "bar", "bar2", "foobar2")
+#'   g <- g + edge("a", "b")
+#'   g <- g + edges("foo", "bar", "bar2", "foobar2")
+#'   g <- g + edges(c("bar", "foo", "foobar2", "bar2"), color="red", weight=1:2)}
+#'     See more examples below.
+#'
+#'     \code{edge} is just an alias to \code{edges} and it is provided
+#'     for readability. The user should use it if a single edge is added to
+#'     the graph.
+#' 
+#'   \item If it is an object created with the \code{\link{path}} function, then
+#'     new edges that form a path are added. The edges and possibly their
+#'     attributes are specified as the arguments to the \code{path}
+#'     function. The non-named arguments are concatenated and interpreted
+#'     as the vertex ids along the path. The remaining arguments are added
+#'     as edge attributes.
+#' 
+#'     Examples: \preformatted{  g <- make_empty_graph() + vertices(letters[1:10])
+#'   g <- g + path("a", "b", "c", "d")
+#'   g <- g + path("e", "f", "g", weight=1:2, color="red")
+#'   g <- g + path(c("f", "c", "j", "d"), width=1:3, color="green")}
+#'   }
+#' 
+#'   It is important to note that, although the plus operator is
+#'   commutative, i.e. is possible to write \preformatted{  graph <- "foo" + make_empty_graph()}
+#'   it is not associative, e.g. \preformatted{  graph <- "foo" + "bar" + make_empty_graph()}
+#'   results a syntax error, unless parentheses are used: \preformatted{  graph <- "foo" + ( "bar" + make_empty_graph() )}
+#'   For clarity, we suggest to always put the graph object on the left
+#'   hand side of the operator: \preformatted{  graph <- make_empty_graph() + "foo" + "bar"}
+#' 
+#' @param e1 First argument, probably an igraph graph, but see details
+#'    below.
+#' @param e2 Second argument, see details below.
+#'
+#' @family functions for manipulating graph structure
+#'
+#' @method + igraph
+#' @export
+#' @examples
+#' # 10 vertices named a,b,c,... and no edges
+#' g <- make_empty_graph() + vertices(letters[1:10])
+#' 
+#' # Add edges to make it a ring
+#' g <- g + path(letters[1:10], letters[1], color = "grey")
+#' 
+#' # Add some extra random edges
+#' g <- g + edges(sample(V(g), 10, replace = TRUE), color = "red")
+#' g$layout <- layout_in_circle
+#' plot(g)
+
 `+.igraph` <- function(e1, e2) {
-  if (!is.igraph(e1) && is.igraph(e2)) {
+  if (!is_igraph(e1) && is_igraph(e2)) {
     tmp <- e1
     e1 <- e2
     e2 <- tmp
   }
-  if (is.igraph(e2) && is.named(e1) && is.named(e2)) {
+  if (is_igraph(e2) && is_named(e1) && is_named(e2)) {
     ## Union of graphs
-    res <- graph.union(e1, e2)
-  } else if (is.igraph(e2)) {
+    res <- union(e1, e2)
+  } else if (is_igraph(e2)) {
     ## Disjoint union of graphs
-    res <- graph.disjoint.union(e1,e2)
+    res <- disjoint_union(e1,e2)
 
   } else if ("igraph.edge" %in% class(e2)) {
     ## Adding edges, possibly with attributes
@@ -408,7 +973,7 @@ path <- function(...) {
       toadd <- unlist(e2[names(e2)==""])
       attr <- e2[names(e2)!=""]
     }
-    res <- add.edges(e1, as.igraph.vs(e1, toadd), attr=attr)
+    res <- add_edges(e1, as.igraph.vs(e1, toadd), attr=attr)
 
   } else if ("igraph.vertex" %in% class(e2)) {
     ## Adding vertices, possibly with attributes
@@ -428,7 +993,7 @@ path <- function(...) {
       e2 <- c(list(name=nn), e2[names(e2)!=""])
     }
     la <- unique(sapply(e2, length))
-    res <- add.vertices(e1, la, attr=e2)
+    res <- add_vertices(e1, la, attr=e2)
 
   } else if ("igraph.path" %in% class(e2)) {
     ## Adding edges along a path, possibly with attributes
@@ -444,18 +1009,18 @@ path <- function(...) {
     lt <- length(toadd)
     if (lt >= 2) {
       toadd <- c(toadd[1], rep(toadd[2:(lt-1)], each=2), toadd[lt])
-      res <- add.edges(e1, toadd, attr=attr)
+      res <- add_edges(e1, toadd, attr=attr)
     } else {
       res <- e1
     }
     
   } else if (is.numeric(e2) && length(e2)==1) {
     ## Adding some isolate vertices
-    res <- add.vertices(e1, e2)
+    res <- add_vertices(e1, e2)
 
   } else if (is.character(e2)) {
     ## Adding named vertices
-    res <- add.vertices(e1, length(e2), name=e2)
+    res <- add_vertices(e1, length(e2), name=e2)
     
   } else {
     stop("Cannot add unknown type to igraph graph")
@@ -463,33 +1028,134 @@ path <- function(...) {
   res
 }
 
+#' Delete vertices or edges from a graph
+#'
+#' @details
+#' The minus operator (\sQuote{\code{-}}) can be used to remove vertices
+#' or edges from the graph. The operation performed is selected based on
+#' the type of the right hand side argument:
+#' \itemize{
+#' \item If it is an igraph graph object, then the difference of the
+#'   two graphs is calculated, see \code{\link{difference}}.
+#' \item If it is a numeric or character vector, then it is interpreted
+#'   as a vector of vertex ids and the specified vertices will be
+#'   deleted from the graph. Example: \preformatted{  g <- make_ring(10)
+#' V(g)$name <- letters[1:10]
+#' g <- g - c("a", "b")}
+#' \item If \code{e2} is a vertex sequence (e.g. created by the
+#'   \code{\link{V}} function), then these vertices will be deleted from
+#'   the graph.
+#' \item If it is an edge sequence (e.g. created by the \code{\link{E}}
+#'   function), then these edges will be deleted from the graph.
+#' \item If it is an object created with the \code{\link{vertex}} (or the
+#'   \code{\link{vertices}}) function, then all arguments of \code{\link{vertices}} are
+#'   concatenated and the result is interpreted as a vector of vertex
+#'   ids. These vertices will be removed from the graph.
+#' \item If it is an object created with the \code{\link{edge}} (or the
+#'   \code{\link{edges}}) function, then all arguments of \code{\link{edges}} are
+#'   concatenated and then interpreted as edges to be removed from the
+#'   graph.
+#'   Example: \preformatted{  g <- make_ring(10)
+#' V(g)$name <- letters[1:10]
+#' E(g)$name <- LETTERS[1:10]
+#' g <- g - edge("e|f")
+#' g <- g - edge("H")}
+#' \item If it is an object created with the \code{\link{path}} function,
+#'   then all \code{\link{path}} arguments are concatenated and then interpreted
+#'   as a path along which edges will be removed from the graph.
+#'   Example: \preformatted{  g <- make_ring(10)
+#' V(g)$name <- letters[1:10]
+#' g <- g - path("a", "b", "c", "d")}
+#' }
+#'
+#' @param e1 Left argument, see details below.
+#' @param e2 Right argument, see details below.
+#' @return An igraph graph.
+#'
+#' @family functions for manipulating graph structure
+#' @name igraph-minus
+#'
+#' @method - igraph
+#' @export
+ 
 `-.igraph` <- function(e1, e2) {
   if (missing(e2)) {
     stop("Non-numeric argument to negation operator")
   }
-  if (is.igraph(e2)) {
-    res <- graph.difference(e1, e2)
+  if (is_igraph(e2)) {
+    res <- difference(e1, e2)
   } else if ("igraph.vertex" %in% class(e2)) {
-    res <- delete.vertices(e1, unlist(e2, recursive=FALSE))
+    res <- delete_vertices(e1, unlist(e2, recursive=FALSE))
   } else if ("igraph.edge" %in% class(e2)) {
-    res <- delete.edges(e1, unlist(e2, recursive=FALSE))
+    res <- delete_edges(e1, unlist(e2, recursive=FALSE))
   } else if ("igraph.path" %in% class(e2)) {
     todel <- unlist(e2, recursive=FALSE)
     lt <- length(todel)
     if (lt >= 2) {
       todel <- paste(todel[-lt], todel[-1], sep="|")
-      res <- delete.edges(e1, todel)
+      res <- delete_edges(e1, todel)
     } else {
       res <- e1
     }
   } else if ("igraph.vs" %in% class(e2)) {
-    res <- delete.vertices(e1, e2)
+    res <- delete_vertices(e1, e2)
   } else if ("igraph.es" %in% class(e2)) {
-    res <- delete.edges(e1, e2)
+    res <- delete_edges(e1, e2)
   } else if (is.numeric(e2) || is.character(e2)) {
-    res <- delete.vertices(e1, e2)
+    res <- delete_vertices(e1, e2)
   } else {
     stop("Cannot substract unknown type from igraph graph")
   }
   res
 }
+
+#' Replicate a graph multiple times
+#'
+#' The new graph will contain the input graph the given number
+#' of times, as unconnected components.
+#'
+#' @param x The input graph.
+#' @param n Number of times to replicate it.
+#' @param mark Whether to mark the vertices with a \code{which} attribute,
+#'   an integer number denoting which replication the vertex is coming
+#'   from.
+#' @param ... Additional arguments to satisfy S3 requirements,
+#'   currently ignored.
+#'
+#' @method rep igraph
+#' @export
+#'
+#' @examples
+#' rings <- make_ring(5) * 5
+
+rep.igraph <- function(x, n, mark = TRUE, ...) {
+
+  if (n < 0) stop("Number of replications must be positive")
+
+  res <- do_call(disjoint_union, .args =
+                   replicate(n, x, simplify = FALSE))
+
+  if (mark) V(res)$which <- rep(seq_len(n), each = gorder(x))
+
+  res
+}
+
+#' @rdname rep.igraph
+#' @method * igraph
+#' @export
+
+`*.igraph` <- function(x, n) {
+
+  if (!is_igraph(x) && is_igraph(n)) {
+    tmp <- x
+    x <- n
+    n <- tmp
+  }
+
+  if (is.numeric(n) && length(n) == 1) {
+    rep.igraph(x, n)
+
+  } else {
+    stop("Cannot multiply igraph graph with this type")
+  }
+}
diff --git a/R/other.R b/R/other.R
index 26df510..fb2efab 100644
--- a/R/other.R
+++ b/R/other.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,7 +19,31 @@
 #
 ###################################################################
 
-running.mean <- function(v, binwidth) {
+
+
+#' Running mean of a time series
+#' 
+#' \code{running_mean} calculates the running mean in a vector with the given
+#' bin width.
+#' 
+#' The running mean of \code{v} is a \code{w} vector of length
+#' \code{length(v)-binwidth+1}. The first element of \code{w} id the average of
+#' the first \code{binwidth} elements of \code{v}, the second element of
+#' \code{w} is the average of elements \code{2:(binwidth+1)}, etc.
+#'
+#' @aliases running.mean
+#' @param v The numeric vector.
+#' @param binwidth Numeric constant, the size of the bin, should be meaningful,
+#' ie. smaller than the length of \code{v}.
+#' @return A numeric vector of length \code{length(v)-binwidth+1}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords manip
+#' @examples
+#' 
+#' running_mean(1:100, 10)
+#' 
+running_mean <- function(v, binwidth) {
 
   v <- as.numeric(v)
   binwidth <- as.numeric(binwidth)
@@ -33,7 +56,34 @@ running.mean <- function(v, binwidth) {
        PACKAGE="igraph");
 }
 
-igraph.sample <- function(low, high, length) {
+
+
+#' Sampling a random integer sequence
+#' 
+#' This function provides a very efficient way to pull an integer random sample
+#' sequence from an integer interval.
+#' 
+#' The algorithm runs in \code{O(length)} expected time, even if
+#' \code{high-low} is big. It is much faster (but of course less general) than
+#' the builtin \code{sample} function of R.
+#'
+#' @aliases igraph.sample
+#' @param low The lower limit of the interval (inclusive).
+#' @param high The higher limit of the interval (inclusive).
+#' @param length The length of the sample.
+#' @return An increasing numeric vector containing integers, the sample.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Jeffrey Scott Vitter: An Efficient Algorithm for Sequential
+#' Random Sampling, \emph{ACM Transactions on Mathematical Software}, 13/1,
+#' 58--67.
+#' @export
+#' @keywords datagen
+#' @examples
+#' 
+#' rs <- sample_seq(1, 100000000, 10)
+#' rs
+#' 
+sample_seq <- function(low, high, length) {
   if (length>high-low+1) {
     stop("length too big for this interval")
   }
@@ -65,10 +115,42 @@ igraph.i.spMatrix <- function(M) {
   }
 }
 
+
+
+#' Deprecated function, used to set random seed of the C library's RNG
+#' 
+#' @param seed Ignored.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+
 srand <- function(seed) {
-  seed <- as.numeric(seed)
-  if (length(seed) != 1) { stop("Length of `seed' must be 1") }
-  if (seed < 0) { stop("Seed must be non-negative") }
-  res <- .Call("R_igraph_srand", seed, PACKAGE="igraph")
-  invisible(res)
+  warning("This function does nothing, as calling srand from R packages\n",
+          "is now not allowed. If you want to reproduce your past\n",
+          "results, use an older version of igraph, e.g. 0.7.1")
 }
+
+
+#' Convex hull of a set of vertices
+#' 
+#' Calculate the convex hull of a set of points, i.e. the covering polygon that
+#' has the smallest area.
+#' 
+#' 
+#' @aliases convex.hull convex_hull
+#' @param data The data points, a numeric matrix with two columns.
+#' @return A named list with components: \item{resverts}{The indices of the
+#' input vertices that constritute the convex hull.} \item{rescoords}{The
+#' coordinates of the corners of the convex hull.}
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @references Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and
+#' Clifford Stein. Introduction to Algorithms, Second Edition. MIT Press and
+#' McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: Finding
+#' the convex hull.
+#' @keywords graphs
+#' @examples
+#' 
+#' M <- cbind( runif(100), runif(100) )
+#' convex_hull(M)
+#' @export
+
+convex_hull <- convex_hull
diff --git a/R/package.R b/R/package.R
index 47c43d1..0e207ac 100644
--- a/R/package.R
+++ b/R/package.R
@@ -27,15 +27,6 @@
     invisible()
 }
 
-.onLoad <- function(libname, pkgname) {
-  library.dynam("igraph", pkgname, libname, local=FALSE);
-  .Call("R_igraph_init", FALSE, FALSE, PACKAGE="igraph")
-}
-
-.onUnload <- function(libpath) {
-  library.dynam.unload("igraph", libpath)
-}
-
 .Call <- function(.NAME, ...) {
   if (.NAME != "R_igraph_finalizer") {
     base::.Call("R_igraph_check_finally_stack", PACKAGE="igraph")
diff --git a/R/palette.R b/R/palette.R
new file mode 100644
index 0000000..921217b
--- /dev/null
+++ b/R/palette.R
@@ -0,0 +1,210 @@
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+
+#' Palette for categories
+#'
+#' This is a color blind friendly palette from
+#' \url{http://jfly.iam.u-tokyo.ac.jp/color}. It has 8 colors.
+#'
+#' This is the suggested palette for visualizations where vertex colors
+#' mark categories, e.g. community membership.
+#'
+#' @param n The number of colors in the palette. We simply take the first
+#' \code{n} colors from the total 8.
+#' @return A character vector of RGB color codes.
+#'
+#' @family palettes
+#' @export
+#' @examples
+#' \dontrun{
+#' library(igraphdata)
+#' data(karate)
+#' karate <- karate %>%
+#'   add_layout_(with_fr()) %>%
+#'   set_vertex_attr("size", value = 10)
+#'
+#' cl_k <- cluster_optimal(karate)
+#'
+#' V(karate)$color <- membership(cl_k)
+#' karate$palette <- categorical_pal(length(cl_k))
+#' plot(karate)
+#' }
+
+categorical_pal <- function(n) {
+
+  stopifnot(n > 0)
+
+  x <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2",
+         "#D55E00", "#CC79A7", "#999999")
+
+  if (n > length(x)) warning("Cannot make ", n, " categorical colors")
+
+  n <- min(n, length(x))
+
+  x[seq_len(n)]
+}
+
+
+#' Sequential palette
+#'
+#' This is the \sQuote{OrRd} palette from \url{http://colorbrewer2.org}.
+#' It has at most nine colors.
+#'
+#' Use this palette, if vertex colors mark some ordinal quantity, e.g. some
+#' centrality measure, or some ordinal vertex covariate, like the age of
+#' people, or their seniority level.
+#'
+#' @param n The number of colors in the palette. The maximum is nine
+#' currently.
+#' @return A character vector of RGB color codes.
+#'
+#' @family palettes
+#' @export
+#' @examples
+#' \dontrun{
+#' library(igraphdata)
+#' data(karate)
+#' karate <- karate %>%
+#'   add_layout_(with_kk()) %>%
+#'   set_vertex_attr("size", value = 10)
+#'
+#' V(karate)$color <- scales::dscale(degree(karate) %>% cut(5), sequential_pal)
+#' plot(karate)
+#' }
+
+sequential_pal <- function(n) {
+
+  stopifnot(n >= 0)
+
+  x <- list(
+    "#FEE8C8",
+    c("#FEE8C8", "#FDBB84"),
+    c("#FEE8C8", "#FDBB84", "#E34A33"),
+    c("#FEF0D9", "#FDCC8A", "#FC8D59", "#D7301F"),
+    c("#FEF0D9", "#FDCC8A", "#FC8D59", "#E34A33", "#B30000"),
+    c("#FEF0D9", "#FDD49E", "#FDBB84", "#FC8D59", "#E34A33", "#B30000"),
+    c("#FEF0D9", "#FDD49E", "#FDBB84", "#FC8D59", "#EF6548", "#D7301F",
+      "#990000"),
+    c("#FFF7EC", "#FEE8C8", "#FDD49E", "#FDBB84", "#FC8D59", "#EF6548",
+      "#D7301F", "#990000"),
+    c("#FFF7EC", "#FEE8C8", "#FDD49E", "#FDBB84", "#FC8D59", "#EF6548",
+      "#D7301F", "#B30000", "#7F0000")
+  )
+
+  if (n > length(x)) warning("Cannot make ", n, " sequential colors")
+
+  n <- min(n, length(x))
+
+  if (n == 0) character() else x[[n]]
+}
+
+
+#' Diverging palette
+#'
+#' This is the \sQuote{PuOr} palette from \url{http://colorbrewer2.org}.
+#' It has at most eleven colors.
+#'
+#' This is similar to \code{\link{sequential_pal}}, but it also puts
+#' emphasis on the mid-range values, plus the the two extreme ends.
+#' Use this palette, if you have such a quantity to mark with vertex
+#' colors.
+#'
+#' @param n The number of colors in the palette. The maximum is eleven
+#' currently.
+#' @return A character vector of RGB color codes.
+#'
+#' @family palettes
+#' @export
+#' @examples
+#' \dontrun{
+#' library(igraphdata)
+#' data(foodwebs)
+#' fw <- foodwebs[[1]] %>%
+#'   induced_subgraph(V(.)[ECO == 1]) %>%
+#'   add_layout_(with_fr()) %>%
+#'   set_vertex_attr("label", value = seq_len(gorder(.))) %>%
+#'   set_vertex_attr("size", value = 10) %>%
+#'   set_edge_attr("arrow.size", value = 0.3)
+#'
+#' V(fw)$color <- scales::dscale(V(fw)$Biomass %>% cut(10), diverging_pal)
+#' plot(fw)
+#'
+#' data(karate)
+#' karate <- karate %>%
+#'   add_layout_(with_kk()) %>%
+#'   set_vertex_attr("size", value = 10)
+#'
+#' V(karate)$color <- scales::dscale(degree(karate) %>% cut(5), diverging_pal)
+#' plot(karate)
+#' }
+
+diverging_pal <- function(n) {
+
+  stopifnot(n > 0)
+
+  x <- list(
+    "#F1A340",
+    c("#F1A340", "#F7F7F7"),
+    c("#F1A340", "#F7F7F7", "#998EC3"),
+    c("#E66101", "#FDB863", "#B2ABD2", "#5E3C99"),
+    c("#E66101", "#FDB863", "#F7F7F7", "#B2ABD2", "#5E3C99"),
+    c("#B35806", "#F1A340", "#FEE0B6", "#D8DAEB", "#998EC3", "#542788"),
+    c("#B35806", "#F1A340", "#FEE0B6", "#F7F7F7", "#D8DAEB", "#998EC3",
+      "#542788"),
+    c("#B35806", "#E08214", "#FDB863", "#FEE0B6", "#D8DAEB", "#B2ABD2",
+      "#8073AC", "#542788"),
+    c("#B35806", "#E08214", "#FDB863", "#FEE0B6", "#F7F7F7", "#D8DAEB",
+      "#B2ABD2", "#8073AC", "#542788"),
+    c("#7F3B08", "#B35806", "#E08214", "#FDB863", "#FEE0B6", "#D8DAEB",
+      "#B2ABD2", "#8073AC", "#542788", "#2D004B"),
+    c("#7F3B08", "#B35806", "#E08214", "#FDB863", "#FEE0B6", "#F7F7F7",
+      "#D8DAEB", "#B2ABD2", "#8073AC", "#542788", "#2D004B")
+  )
+
+  if (n > length(x)) warning("Cannot make ", n, " divergent colors")
+
+  n <- min(n, length(x))
+
+  if (n == 0) character() else x[[n]]
+}
+
+
+#' The default R palette
+#'
+#' This is the default R palette, to be able to reproduce the
+#' colors of older igraph versions. Its colors are appropriate
+#' for categories, but they are not very attractive.
+#'
+#' @param n The number of colors to use, the maximum is eight.
+#' @return A character vector of color names.
+#'
+#' @family palettes
+#' @export
+
+r_pal <- function(n) {
+  x <- palette()
+  if (n > length(x)) warning("Cannot make ", n, " divergent colors")
+  n <- min(n, length(x))
+  if (n == 0) character() else x[[n]]
+}
diff --git a/R/par.R b/R/par.R
index f491d6c..96705fc 100644
--- a/R/par.R
+++ b/R/par.R
@@ -32,8 +32,10 @@
                      "add.params"=TRUE,
                      "add.vertex.names"=TRUE,
                      "dend.plot.type"="auto",
-                     "print.full"=FALSE,
-                     "annotate.plot"=FALSE
+                     "print.full"="auto",
+                     "annotate.plot"=FALSE,
+                     "auto.print.lines" = 10,
+                     "return.vs.es" = TRUE
                     )
 
 igraph.pars.set.verbose <- function(verbose) {
@@ -45,7 +47,9 @@ igraph.pars.set.verbose <- function(verbose) {
     }
     if (verbose %in% c("tk", "tkconsole")) {
       if (!capabilities()[["X11"]]) { stop("X11 not available")           }
-      if (!require("tcltk"))        { stop("tcltk package not available") }
+      if (!requireNamespace("tcltk", quietly = TRUE)) {
+        stop("tcltk package not available")
+      }
     }
     .Call("R_igraph_set_verbose", verbose, PACKAGE="igraph")
   } else {
@@ -58,7 +62,91 @@ igraph.pars.callbacks <- list("verbose"=igraph.pars.set.verbose)
 
 ## This is based on 'sm.options' in the 'sm' package
 
-igraph.options <- function(...) {
+#' Parameters for the igraph package
+#' 
+#' igraph has some parameters which (usually) affect the behavior of many
+#' functions. These can be set for the whole session via \code{igraph_options}.
+#' 
+#' The parameter values set via a call to the \code{igraph_options} function
+#' will remain in effect for the rest of the session, affecting the subsequent
+#' behaviour of the other functions of the \code{igraph} package for which the
+#' given parameters are relevant.
+#' 
+#' This offers the possibility of customizing the functioning of the
+#' \code{igraph} package, for instance by insertions of appropriate calls to
+#' \code{igraph_options} in a load hook for package \pkg{igraph}.
+#' 
+#' The currently used parameters in alphabetical order:
+#' \describe{
+#'   \item{add.params}{Logical scalar, whether to add model
+#'     parameter to the graphs that are created by the various
+#'     graph constructors. By default it is \code{TRUE}.}
+#'   \item{add.vertex.names}{Logical scalar, whether to add
+#'     vertex names to node level indices, like degree, betweenness
+#'     scores, etc. By default it is \code{TRUE}.}
+#'   \item{annotate.plot}{Logical scalar, whether to annotate igraph
+#'     plots with the graph's name (\code{name} graph attribute, if
+#'     present) as \code{main}, and with the number of vertices and edges
+#'     as \code{xlab}. Defaults to \code{FALSE}.}
+#'   \item{dend.plot.type}{The plotting function to use when plotting
+#'     community structure dendrograms via
+#'     \code{\link{plot_dendrogram}}}. Possible values are \sQuote{auto} (the
+#'     default), \sQuote{phylo}, \sQuote{hclust} and
+#'     \sQuote{dendrogram}. See \code{\link{plot_dendrogram}} for details.
+#'   \item{edge.attr.comb}{Specifies what to do with the edge
+#'     attributes if the graph is modified. The default value is
+#'     \code{list(weight="sum", name="concat", "ignore")}. See
+#'     \code{\link{attribute.combination}} for details on this.}
+#'   \item{nexus.url}{The base URL of the default Nexus server. See
+#'     \code{\link{nexus}} for details.}
+#'   \item{print.edge.attributes}{Logical constant, whether to print edge
+#'     attributes when printing graphs. Defaults to \code{FALSE}.}
+#'   \item{print.full}{Logical scalar, whether \code{\link{print.igraph}}
+#'     should show the graph structure as well, or only a summary of the
+#'     graph.}
+#'   \item{print.graph.attributes}{Logical constant, whether to print
+#'     graph attributes when printing graphs. Defaults to \code{FALSE}.}
+#'   \item{print.vertex.attributes}{Logical constant, whether to print
+#'     vertex attributes when printing graphs. Defaults to \code{FALSE}.}
+#'   \item{sparsematrices}{Whether to use the \code{Matrix} package for
+#'     (sparse) matrices. It is recommended, if the user works with
+#'     larger graphs.}
+#'   \item{verbose}{Logical constant, whether igraph functions should
+#'     talk more than minimal. Eg. if \code{TRUE} thne some functions
+#'     will use progress bars while computing. Defaults to \code{FALSE}.}
+#'   \item{vertex.attr.comb}{Specifies what to do with the vertex
+#'     attributes if the graph is modified. The default value is
+#'     \code{list(name="concat", "ignore")} See
+#'     \code{\link{attribute.combination}} for details on this.}
+#' }
+#' 
+#' @aliases igraph.options igraph_options getIgraphOpt igraph_opt
+#' @param \dots A list may be given as the only argument, or any number of
+#' arguments may be in the \code{name=value} form, or no argument at all may be
+#' given. See the Value and Details sections for explanation.
+#' @param x A character string holding an option name.
+#' @param default If the specified option is not set in the options list, this
+#' value is returned. This facilitates retrieving an option and checking
+#' whether it is set and setting it separately if not.
+#' @return \code{igraph_options} returns a list with the updated values of the
+#' parameters. If the argument list is not empty, the returned list is
+#' invisible.
+#' 
+#' For \code{igraph_opt}, the current value set for option \code{x}, or
+#' \code{NULL} if the option is unset.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{igraph_options} is similar to \code{\link{options}} and
+#' \code{igraph_opt} is similar to \code{\link{getOption}}.
+#' @keywords graphs
+#' @examples
+#' 
+#' oldval <- igraph_opt("verbose")
+#' igraph_options(verbose=TRUE)
+#' layout_with_kk(make_ring(10))
+#' igraph_options(verbose=oldval)
+#' #' @export
+
+igraph_options <- function(...) {
   if (nargs() == 0) return(.igraph.pars)
   current <- .igraph.pars
   temp <- list(...)
@@ -83,25 +171,13 @@ igraph.options <- function(...) {
   invisible(current)
 }
 
-getIgraphOpt <- function(x, default=NULL) {
+#' @rdname igraph_options
+#' @export
+
+igraph_opt <- function(x, default=NULL) {
   if (missing(default)) 
-    return(igraph.options(x)[[1L]])
-  if (x %in% names(igraph.options())) 
-    igraph.options(x)[[1L]]
+    return(igraph_options(x)[[1L]])
+  if (x %in% names(igraph_options())) 
+    igraph_options(x)[[1L]]
   else default
 }
-
-## This is deprecated from 0.6
-
-igraph.par <- function(parid, parvalue=NULL) {
-
-  .Deprecated("igraph.options", package="igraph")
-  
-  if (is.null(parvalue)) {
-    res <- .igraph.pars[[parid]]
-    res
-  } else {
-    .igraph.pars[[parid]] <- parvalue
-    invisible(parvalue)
-  }
-}
diff --git a/R/paths.R b/R/paths.R
new file mode 100644
index 0000000..e8461ca
--- /dev/null
+++ b/R/paths.R
@@ -0,0 +1,231 @@
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' List all simple paths from one source
+#' 
+#' This function lists are simple paths from one source vertex to another
+#' vertex or vertices. A path is simple if the vertices it visits are not
+#' visited more than once.
+#' 
+#' Note that potentially there are exponentially many paths between two
+#' vertices of a graph, and you may run out of memory when using this
+#' function, if your graph is lattice-like.
+#' 
+#' This function currently ignored multiple and loop edges.
+#' 
+#' @param graph The input graph.
+#' @param from The source vertex.
+#' @param to The target vertex of vertices. Defaults to all vertices.
+#' @param mode Character constant, gives whether the shortest paths to or
+#'   from the given vertices should be calculated for directed graphs. If
+#'   \code{out} then the shortest paths \emph{from} the vertex, if \code{in}
+#'   then \emph{to} it will be considered. If \code{all}, the default, then
+#'   the corresponding undirected graph will be used, ie. not directed paths
+#'   are searched. This argument is ignored for undirected graphs.
+#' @return A list of integer vectors, each integer vector is a path from
+#'   the source vertex to one of the target vertices. A path is given by its
+#'   vertex ids.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' all_simple_paths(g, 1, 5)
+#' all_simple_paths(g, 1, c(3,5))
+#' 
+#' @export
+
+all_simple_paths <- function(graph, from, to = V(graph),
+                             mode = c("out", "in", "all", "total")) {
+  ## Argument checks
+  if (!is_igraph(graph)) stop("Not a graph object")
+  from <- as.igraph.vs(graph, from)
+  to <- as.igraph.vs(graph, to)
+  mode <- switch(igraph.match.arg(mode), "out" = 1, "in" = 2, "all" = 3,
+                 "total" = 3)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+
+  ## Function call
+  res <- .Call("R_igraph_get_all_simple_paths", graph, from - 1, to - 1,
+                mode, PACKAGE = "igraph")
+  res <- get.all.simple.paths.pp(res)
+
+  if (igraph_opt("return.vs.es")) { 
+    res <- lapply(res, create_vs, graph = graph)
+  }
+  res
+}
+
+
+#' Directed acyclic graphs
+#' 
+#' This function tests whether the given graph is a DAG, a directed acyclic
+#' graph.
+#' 
+#' \code{is_dag} checks whether there is a directed cycle in the graph. If not,
+#' the graph is a DAG.
+#' 
+#' @aliases is.dag is_dag
+#' @param graph The input graph. It may be undirected, in which case
+#' \code{FALSE} is reported.
+#' @return A logical vector of length one.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} for the C code, Gabor Csardi
+#' \email{csardi.gabor@@gmail.com} for the R interface.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_tree(10)
+#' is_dag(g)
+#' g2 <- g + edge(5,1)
+#' is_dag(g2)
+#' @export
+#' @include auto.R
+
+is_dag <- is_dag
+
+
+#' Maximum cardinality search
+#' 
+#' Maximum cardinality search is a simple ordering a vertices that is useful in
+#' determining the chordality of a graph.
+#' 
+#' Maximum cardinality search visits the vertices in such an order that every
+#' time the vertex with the most already visited neighbors is visited. Ties are
+#' broken randomly.
+#' 
+#' The algorithm provides a simple basis for deciding whether a graph is
+#' chordal, see References below, and also \code{\link{is_chordal}}.
+#' 
+#' @aliases maximum.cardinality.search max_cardinality
+#' @param graph The input graph. It may be directed, but edge directions are
+#' ignored, as the algorithm is defined for undirected graphs.
+#' @return A list with two components: \item{alpha}{Numeric vector. The
+#' vertices ordered according to the maximum cardinality search.}
+#' \item{alpham1}{Numeric vector. The inverse of \code{alpha}.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{is_chordal}}
+#' @references Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
+#' linear-time algorithms to test chordality of graphs, test acyclicity of
+#' hypergraphs, and selectively reduce acyclic hypergraphs.  \emph{SIAM Journal
+#' of Computation} 13, 566--579.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## The examples from the Tarjan-Yannakakis paper
+#' g1 <- graph_from_literal(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
+#'                 E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
+#'                 I-A:H)
+#' max_cardinality(g1)
+#' is_chordal(g1, fillin=TRUE)
+#' 
+#' g2 <- graph_from_literal(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
+#'                 E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
+#'                 I-G:H:J, J-H:I)
+#' max_cardinality(g2)
+#' is_chordal(g2, fillin=TRUE)
+
+max_cardinality <- max_cardinality
+
+
+#' Eccentricity of the vertices in a graph
+#' 
+#' The eccentricity of a vertex is its shortest path distance from the farthest
+#' other node in the graph.
+#' 
+#' The eccentricity of a vertex is calculated by measuring the shortest
+#' distance from (or to) the vertex, to (or from) all vertices in the graph,
+#' and taking the maximum.
+#' 
+#' This implementation ignores vertex pairs that are in different components.
+#' Isolate vertices have eccentricity zero.
+#' 
+#' @param graph The input graph, it can be directed or undirected.
+#' @param vids The vertices for which the eccentricity is calculated.
+#' @param mode Character constant, gives whether the shortest paths to or from
+#' the given vertices should be calculated for directed graphs. If \code{out}
+#' then the shortest paths \emph{from} the vertex, if \code{in} then \emph{to}
+#' it will be considered. If \code{all}, the default, then the corresponding
+#' undirected graph will be used, edge directions will be ignored. This
+#' argument is ignored for undirected graphs.
+#' @return \code{eccentricity} returns a numeric vector, containing the
+#' eccentricity score of each given vertex.
+#' @seealso \code{\link{radius}} for a related concept,
+#'   \code{\link{distances}} for general shortest path calculations.
+#' @references Harary, F. Graph Theory. Reading, MA: Addison-Wesley, p. 35,
+#' 1994.
+#' @examples
+#' g <- make_star(10, mode="undirected")
+#' eccentricity(g)
+#' @export
+#' @include auto.R
+
+eccentricity <- eccentricity
+
+
+#' Radius of a graph
+#' 
+#' The eccentricity of a vertex is its shortest path distance from the
+#' farthest other node in the graph. The smallest eccentricity in a graph
+#' is called its radius
+#' 
+#' The eccentricity of a vertex is calculated by measuring the shortest
+#' distance from (or to) the vertex, to (or from) all vertices in the
+#' graph, and taking the maximum.
+#' 
+#' This implementation ignores vertex pairs that are in different
+#' components.  Isolate vertices have eccentricity zero.
+#' 
+#' @param graph The input graph, it can be directed or undirected.
+#' @param mode Character constant, gives whether the shortest paths to or from
+#' the given vertices should be calculated for directed graphs. If \code{out}
+#' then the shortest paths \emph{from} the vertex, if \code{in} then \emph{to}
+#' it will be considered. If \code{all}, the default, then the corresponding
+#' undirected graph will be used, edge directions will be ignored. This
+#' argument is ignored for undirected graphs.
+#' @return A numeric scalar, the radius of the graph.
+#' @seealso \code{\link{eccentricity}} for the underlying
+#'   calculations, code{\link{distances}} for general shortest path
+#'   calculations. 
+#' @references Harary, F. Graph Theory. Reading, MA: Addison-Wesley, p. 35,
+#' 1994.
+#' @examples
+#' g <- make_star(10, mode="undirected")
+#' eccentricity(g)
+#' radius(g)
+#' @export
+#' @include auto.R
+
+radius <- radius
+
+#' @rdname distances
+#' @param directed Whether to consider directed paths in directed graphs,
+#'   this argument is ignored for undirected graphs.
+#' @param unconnected What to do if the graph is unconnected (not
+#'   strongly connected if directed paths are considered). If TRUE only
+#'   the lengths of the existing paths are considered and averaged; if
+#'   FALSE the length of the missing paths are counted having length
+#'   \code{vcount(graph)}, one longer than the longest possible geodesic
+#'   in the network.
+#' @export
+
+distance_table <- distance_table
diff --git a/R/plot.R b/R/plot.R
index 17d9421..161bb18 100644
--- a/R/plot.R
+++ b/R/plot.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,6 +19,63 @@
 #
 ###################################################################
 
+
+
+#' Plotting of graphs
+#' 
+#' \code{plot.igraph} is able to plot graphs to any R device. It is the
+#' non-interactive companion of the \code{tkplot} function.
+#' 
+#' One convenient way to plot graphs is to plot with \code{\link{tkplot}}
+#' first, handtune the placement of the vertices, query the coordinates by the
+#' \code{\link{tk_coords}} function and use them with \code{plot} to
+#' plot the graph to any R device.
+#'
+#' @aliases plot.graph
+#' @param x The graph to plot.
+#' @param axes Logical, whether to plot axes, defaults to FALSE.
+#' @param add Logical scalar, whether to add the plot to the current device, or
+#' delete the device's current contents first.
+#' @param xlim The limits for the horizontal axis, it is unlikely that you want
+#' to modify this.
+#' @param ylim The limits for the vertical axis, it is unlikely that you want
+#' to modify this.
+#' @param mark.groups A list of vertex id vectors. It is interpreted as a set
+#' of vertex groups. Each vertex group is highlighted, by plotting a colored
+#' smoothed polygon around and \dQuote{under} it. See the arguments below to
+#' control the look of the polygons.
+#' @param mark.shape A numeric scalar or vector. Controls the smoothness of the
+#' vertex group marking polygons. This is basically the \sQuote{shape}
+#' parameter of the \code{\link[graphics]{xspline}} function, its possible
+#' values are between -1 and 1. If it is a vector, then a different value is
+#' used for the different vertex groups.
+#' @param mark.col A scalar or vector giving the colors of marking the
+#' polygons, in any format accepted by \code{\link[graphics]{xspline}}; e.g.
+#' numeric color ids, symbolic color names, or colors in RGB.
+#' @param mark.border A scalar or vector giving the colors of the borders of
+#' the vertex group marking polygons. If it is \code{NA}, then no border is
+#' drawn.
+#' @param mark.expand A numeric scalar or vector, the size of the border around
+#' the marked vertex groups. It is in the same units as the vertex sizes. If a
+#' vector is given, then different values are used for the different vertex
+#' groups.
+#' @param \dots Additional plotting parameters. See \link{igraph.plotting} for
+#' the complete list.
+#' @return Returns \code{NULL}, invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{layout}} for different layouts,
+#' \code{\link{igraph.plotting}} for the detailed description of the plotting
+#' parameters and \code{\link{tkplot}} and \code{\link{rglplot}} for other
+#' graph plotting functions.
+#' @method plot igraph
+#' @export
+#' @export plot.igraph
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- ring(10)
+#' \dontrun{plot(g, layout=layout_with_kk, vertex.color="green")}
+#' 
 plot.igraph <- function(x, 
                        # SPECIFIC: #####################################
                        axes=FALSE, add=FALSE,
@@ -31,7 +87,7 @@ plot.igraph <- function(x,
                        ...) {
 
   graph <- x
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -76,6 +132,12 @@ plot.igraph <- function(x,
   xlab               <- params("plot", "xlab")
   ylab               <- params("plot", "ylab")
 
+  palette            <- params("plot", "palette")
+  if (!is.null(palette)) {
+    old_palette <- palette(palette)
+    on.exit(palette(old_palette), add = TRUE)
+  }
+
   # the new style parameters can't do this yet
   arrow.mode         <- i.get.arrow.mode(graph, arrow.mode)
 
@@ -84,7 +146,7 @@ plot.igraph <- function(x,
   maxv <- max(vertex.size)
   if (rescale) {
     # norm layout to (-1, 1)
-    layout <- layout.norm(layout, -1, 1, -1, 1)
+    layout <- norm_coords(layout, -1, 1, -1, 1)
     xlim <- c(xlim[1]-margin[2]-maxv, xlim[2]+margin[4]+maxv)
     ylim <- c(ylim[1]-margin[1]-maxv, ylim[2]+margin[3]+maxv)
   }
@@ -105,7 +167,7 @@ plot.igraph <- function(x,
   mark.expand <- rep(mark.expand, length=length(mark.groups))
   
   for (g in seq_along(mark.groups)) {
-    v <- mark.groups[[g]]
+    v <- V(graph)[mark.groups[[g]]]
     if (length(vertex.size)==1) {
       vs <- vertex.size
     } else {
@@ -121,7 +183,7 @@ plot.igraph <- function(x,
 
   ################################################################
   ## calculate position of arrow-heads
-  el <- get.edgelist(graph, names=FALSE)
+  el <- as_edgelist(graph, names=FALSE)
   loops.e <- which(el[,1] == el[,2])
   nonloops.e <- which(el[,1] != el[,2])
   loops.v <- el[,1] [loops.e]
@@ -341,15 +403,47 @@ plot.igraph <- function(x,
   invisible(NULL)
 }
 
+
+
+#' 3D plotting of graphs with OpenGL
+#' 
+#' Using the \code{rgl} package, \code{rglplot} plots a graph in 3D. The plot
+#' can be zoomed, rotated, shifted, etc. but the coordinates of the vertices is
+#' fixed.
+#' 
+#' Note that \code{rglplot} is considered to be highly experimental. It is not
+#' very useful either. See \code{\link{igraph.plotting}} for the possible
+#' arguments.
+#' 
+#' @aliases rglplot rglplot.igraph
+#' @param x The graph to plot.
+#' @param \dots Additional arguments, see \code{\link{igraph.plotting}} for the
+#' details
+#' @return \code{NULL}, invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{igraph.plotting}}, \code{\link{plot.igraph}} for the 2D
+#' version, \code{\link{tkplot}} for interactive graph drawing in 2D.
+#' @export
+#' @keywords graphs
+#' @export
+#' @examples
+#' 
+#' \dontrun{
+#' g <- make_lattice( c(5,5,5) )
+#' coords <- layout_with_fr(g, dim=3)
+#' rglplot(g, layout=coords)
+#' }
+#' 
 rglplot        <- function(x, ...)
   UseMethod("rglplot", x)
 
+#' @method rglplot igraph
+#' @export
+
 rglplot.igraph <- function(x, ...) {
 
-  require(rgl)
-  
   graph <- x
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -361,12 +455,12 @@ rglplot.igraph <- function(x, ...) {
     dist <- sqrt(sum((v2-v1)^2))   # distance of the centers
 
     if (am==0) {
-      edge <- qmesh3d(c(-ew/2,-ew/2,dist,1, ew/2,-ew/2,dist,1, ew/2,ew/2,dist,1,
+      edge <- rgl::qmesh3d(c(-ew/2,-ew/2,dist,1, ew/2,-ew/2,dist,1, ew/2,ew/2,dist,1,
                         -ew/2,ew/2,dist,1,  -ew/2,-ew/2,0,1, ew/2,-ew/2,0,1,
                         ew/2,ew/2,0,1, -ew/2,ew/2,0,1),
                       c(1,2,3,4, 5,6,7,8, 1,2,6,5, 2,3,7,6, 3,4,8,7, 4,1,5,8))
     } else if (am==1) {
-      edge <- qmesh3d(c(-ew/2,-ew/2,dist,1, ew/2,-ew/2,dist,1,
+      edge <- rgl::qmesh3d(c(-ew/2,-ew/2,dist,1, ew/2,-ew/2,dist,1,
                         ew/2,ew/2,dist,1, -ew/2,ew/2,dist,1,
                         -ew/2,-ew/2,al+r1,1, ew/2,-ew/2,al+r1,1,
                         ew/2,ew/2,al+r1,1, -ew/2,ew/2,al+r1,1,
@@ -377,7 +471,7 @@ rglplot.igraph <- function(x, ...) {
                         11,12,13,13))
     } else if (am==2) {
       box <- dist-r2-al
-      edge <- qmesh3d(c(-ew/2,-ew/2,box,1, ew/2,-ew/2,box,1, ew/2,ew/2,box,1,
+      edge <- rgl::qmesh3d(c(-ew/2,-ew/2,box,1, ew/2,-ew/2,box,1, ew/2,ew/2,box,1,
                         -ew/2,ew/2,box,1,  -ew/2,-ew/2,0,1, ew/2,-ew/2,0,1,
                         ew/2,ew/2,0,1, -ew/2,ew/2,0,1,
                         -aw/2,-aw/2,box,1, aw/2,-aw/2,box,1, aw/2,aw/2,box,1,
@@ -386,7 +480,7 @@ rglplot.igraph <- function(x, ...) {
                         9,10,11,12, 9,12,13,13, 9,10,13,13, 10,11,13,13,
                         11,12,13,13))
     } else {
-      edge <- qmesh3d(c(-ew/2,-ew/2,dist-al-r2,1, ew/2,-ew/2,dist-al-r2,1,
+      edge <- rgl::qmesh3d(c(-ew/2,-ew/2,dist-al-r2,1, ew/2,-ew/2,dist-al-r2,1,
                         ew/2,ew/2,dist-al-r2,1, -ew/2,ew/2,dist-al-r2,1,
                         -ew/2,-ew/2,r1+al,1, ew/2,-ew/2,r1+al,1,
                         ew/2,ew/2,r1+al,1, -ew/2,ew/2,r1+al,1,
@@ -409,11 +503,11 @@ rglplot.igraph <- function(x, ...) {
     rot1 <- rbind(c(1,0,0),c(0,cos(psi),sin(psi)), c(0,-sin(psi),cos(psi)))
     rot2 <- rbind(c(cos(phi),sin(phi),0),c(-sin(phi),cos(phi),0), c(0,0,1))
     rot <- rot1 %*% rot2
-    edge <- transform3d(edge, rotationMatrix(matrix=rot))
-    edge <- transform3d(edge, translationMatrix(v1[1], v1[2], v1[3]))
+    edge <- rgl::transform3d(edge, rgl::rotationMatrix(matrix=rot))
+    edge <- rgl::transform3d(edge, rgl::translationMatrix(v1[1], v1[2], v1[3]))
 
     ## we are ready 
-    shade3d(edge, col=ec)
+    rgl::shade3d(edge, col=ec)
   }
   
   create.loop <- function(v, r, ec, ew, am, la, la2, as) {
@@ -425,7 +519,7 @@ rglplot.igraph <- function(x, ...) {
     gap <- wi-2*ew
 
     if (am==0) {
-      edge <- qmesh3d(c(-wi/2,-ew/2,0,1, -gap/2,-ew/2,0,1,
+      edge <- rgl::qmesh3d(c(-wi/2,-ew/2,0,1, -gap/2,-ew/2,0,1,
                         -gap/2,ew/2,0,1, -wi/2,ew/2,0,1,
                         -wi/2,-ew/2,hi-ew+r,1, -gap/2,-ew/2,hi-ew+r,1,
                         -gap/2,ew/2,hi-ew+r,1, -wi/2,ew/2,hi-ew+r,1,
@@ -443,7 +537,7 @@ rglplot.igraph <- function(x, ...) {
                         5,13,19,17, 17,18,20,19, 8,16,20,18, 6,7,15,14
                         ))
     } else if (am==1 || am==2) {
-      edge <- qmesh3d(c(-wi/2,-ew/2,r+al,1, -gap/2,-ew/2,r+al,1,
+      edge <- rgl::qmesh3d(c(-wi/2,-ew/2,r+al,1, -gap/2,-ew/2,r+al,1,
                         -gap/2,ew/2,r+al,1, -wi/2,ew/2,r+al,1,
                         -wi/2,-ew/2,hi-ew+r,1, -gap/2,-ew/2,hi-ew+r,1,
                         -gap/2,ew/2,hi-ew+r,1, -wi/2,ew/2,hi-ew+r,1,
@@ -468,7 +562,7 @@ rglplot.igraph <- function(x, ...) {
                         21,24,25,25
                         ))
     } else if (am==3) {
-      edge <- qmesh3d(c(-wi/2,-ew/2,r+al,1, -gap/2,-ew/2,r+al,1,
+      edge <- rgl::qmesh3d(c(-wi/2,-ew/2,r+al,1, -gap/2,-ew/2,r+al,1,
                         -gap/2,ew/2,r+al,1, -wi/2,ew/2,r+al,1,
                         -wi/2,-ew/2,hi-ew+r,1, -gap/2,-ew/2,hi-ew+r,1,
                         -gap/2,ew/2,hi-ew+r,1, -wi/2,ew/2,hi-ew+r,1,
@@ -503,11 +597,11 @@ rglplot.igraph <- function(x, ...) {
     rot1 <- rbind(c(1,0,0),c(0,cos(la2),sin(la2)), c(0,-sin(la2),cos(la2)))
     rot2 <- rbind(c(cos(la),sin(la),0),c(-sin(la),cos(la),0), c(0,0,1))
     rot <- rot1 %*% rot2
-    edge <- transform3d(edge, rotationMatrix(matrix=rot))
-    edge <- transform3d(edge, translationMatrix(v[1], v[2], v[3]))
+    edge <- rgl::transform3d(edge, rgl::rotationMatrix(matrix=rot))
+    edge <- rgl::transform3d(edge, rgl::translationMatrix(v[1], v[2], v[3]))
 
     ## we are ready
-    shade3d(edge, col=ec)
+    rgl::shade3d(edge, col=ec)
   }
   
   # Visual parameters
@@ -537,14 +631,14 @@ rglplot.igraph <- function(x, ...) {
   # norm layout to (-1, 1)
   if (ncol(layout)==2) { layout <- cbind(layout, 0) }
   if (rescale) {
-    layout <- layout.norm(layout, -1, 1, -1, 1, -1, 1)
+    layout <- norm_coords(layout, -1, 1, -1, 1, -1, 1)
   }
   
   # add the edges, the loops are handled separately
-  el <- get.edgelist(graph, names=FALSE)
+  el <- as_edgelist(graph, names=FALSE)
   
   # It is faster this way
-  par3d(skipRedraw=TRUE)
+  rgl::par3d(skipRedraw=TRUE)
 
   # edges first
   for (i in seq(length=nrow(el))) {
@@ -570,7 +664,7 @@ rglplot.igraph <- function(x, ...) {
       
   # add the vertices
   if (length(vertex.size)==1) { vertex.size <- rep(vertex.size, nrow(layout)) }
-  rgl.spheres(layout[,1], layout[,2], layout[,3], radius=vertex.size,
+  rgl::rgl.spheres(layout[,1], layout[,2], layout[,3], radius=vertex.size,
               col=vertex.color)
 
   # add the labels, 'l1' is a stupid workaround of a mysterious rgl bug
@@ -582,8 +676,8 @@ rglplot.igraph <- function(x, ...) {
   z <- layout[,3]
   l1 <- labels[1]
   labels[1] <- ""
-  rgl.texts(x,y,z, labels, col=label.color, adj=0)
-  rgl.texts(c(0,x[1]), c(0,y[1]), c(0,z[1]),
+  rgl::rgl.texts(x,y,z, labels, col=label.color, adj=0)
+  rgl::rgl.texts(c(0,x[1]), c(0,y[1]), c(0,z[1]),
             c("",l1), col=c(label.color[1],label.color[1]), adj=0)
 
   edge.labels[is.na(edge.labels)] <- ""
@@ -594,12 +688,12 @@ rglplot.igraph <- function(x, ...) {
     y1 <- layout[,2][el[,2]]
     z0 <- layout[,3][el[,1]]
     z1 <- layout[,4][el[,2]]
-    rgl.texts((x0+x1)/2, (y0+y1)/2, (z0+z1)/2, edge.labels,
+    rgl::rgl.texts((x0+x1)/2, (y0+y1)/2, (z0+z1)/2, edge.labels,
               col=label.color)
   }
 
   # draw everything
-  par3d(skipRedraw=FALSE)
+  rgl::par3d(skipRedraw=FALSE)
   
   invisible(NULL)
 }
@@ -751,7 +845,7 @@ igraph.polygon <- function(points, vertex.size=15/200, expand.by=15/200,
               cbind(points[,1], points[,2]-vertex.size-by),
               cbind(points[,1], points[,2]+vertex.size+by))
 
-  cl <- convex.hull(pp)
+  cl <- convex_hull(pp)
   xspline(cl$rescoords, shape=shape, open=FALSE, col=col, border=border)
 }
 
diff --git a/R/plot.common.R b/R/plot.common.R
index dadcaf3..f262556 100644
--- a/R/plot.common.R
+++ b/R/plot.common.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -44,21 +43,21 @@ i.parse.plot.params <- function(graph, params) {
 
   mis <- ! names(p[["vertex"]]) %in% names(i.default.values$vertex) &
          ! paste("vertex.", sep="", names(p[["vertex"]])) %in%
-           names(igraph.options())
+           names(igraph_options())
   if (any(mis)) {
     stop("Unknown vertex parameters: ",
          paste(sep=", ", collapse=", ", names(p[["vertex"]])[mis]))
   }
   mis <- ! names(p[["edge"]]) %in% names(i.default.values$edge) &
          ! paste("edge.", sep="", names(p[["edge"]])) %in%
-           names(igraph.options())
+           names(igraph_options())
   if (any(mis)) {
     stop("Unknown edge parameters: ",
          paste(sep=", ", collapse=", ", names(p[["edge"]])[mis]))
   }
   mis <- ! names(p[["plot"]]) %in% names(i.default.values$plot) &
          ! paste("plot.", sep="", names(p[["plot"]])) %in%
-           names(igraph.options())
+           names(igraph_options())
   if (any(mis)) {
     stop("Unknown plot parameters: ",
          paste(sep=", ", collapse=", ", names(p[["plot"]]) [ mis ]))
@@ -88,19 +87,19 @@ i.parse.plot.params <- function(graph, params) {
       return(ret())
     } else {
       ## we don't have the parameter, check attributes first
-      if (type=="vertex" && name %in% list.vertex.attributes(graph)) {
-        p[[type]][[name]] <- get.vertex.attribute(graph, name)
+      if (type=="vertex" && name %in% vertex_attr_names(graph)) {
+        p[[type]][[name]] <- vertex_attr(graph, name)
         return(ret())
-      } else if (type=="edge" && name %in% list.edge.attributes(graph)) {
-        p[[type]][[name]] <- get.edge.attribute(graph, name)
+      } else if (type=="edge" && name %in% edge_attr_names(graph)) {
+        p[[type]][[name]] <- edge_attr(graph, name)
         return(ret())
-      } else if (type=="plot" && name %in% list.graph.attributes(graph)) {
-        p[[type]][[name]] <- get.graph.attribute(graph, name)
+      } else if (type=="plot" && name %in% graph_attr_names(graph)) {
+        p[[type]][[name]] <- graph_attr(graph, name)
         return(ret())
       } else {
         ## no attributes either, check igraph parameters
         n <- paste(sep="", type, ".", name)
-        v <- getIgraphOpt(n)
+        v <- igraph_opt(n)
         if (!is.null(v)) {
           p[[type]][[name]] <- v
           return(ret())
@@ -128,8 +127,8 @@ i.get.edge.labels <- function(graph, edge.labels=NULL) {
 i.get.labels <- function(graph, labels=NULL) {
 
   if (is.null(labels)) {
-    if ("name" %in% list.vertex.attributes(graph)) {
-      labels <- get.vertex.attribute(graph, "name")
+    if ("name" %in% vertex_attr_names(graph)) {
+      labels <- vertex_attr(graph, "name")
     } else {
       labels <- seq_len(vcount(graph))
     }
@@ -141,7 +140,7 @@ i.get.arrow.mode <- function(graph, arrow.mode=NULL) {
 
   if (is.character(arrow.mode) &&
       length(arrow.mode)==1 && substr(arrow.mode, 1, 2)=="a:") {
-    arrow.mode <- get.vertex.attribute(graph, substring(arrow.mode,3))
+    arrow.mode <- vertex_attr(graph, substring(arrow.mode,3))
   }
 
   if (is.character(arrow.mode)) {
@@ -153,7 +152,7 @@ i.get.arrow.mode <- function(graph, arrow.mode=NULL) {
   }
 
   if (is.null(arrow.mode)) {
-    if (is.directed(graph)) {
+    if (is_directed(graph)) {
       arrow.mode <- 2
     } else {
       arrow.mode <- 0
@@ -164,7 +163,7 @@ i.get.arrow.mode <- function(graph, arrow.mode=NULL) {
 }
 
 i.get.main <- function(graph) {
-  if (getIgraphOpt("annotate.plot")) {
+  if (igraph_opt("annotate.plot")) {
     n <- graph$name[1]
     n
   } else {
@@ -173,7 +172,7 @@ i.get.main <- function(graph) {
 }
 
 i.get.xlab <- function(graph) {
-  if (getIgraphOpt("annotate.plot")) {
+  if (igraph_opt("annotate.plot")) {
     paste(vcount(graph), "vertices,", ecount(graph), "edges")
   } else {
     ""
@@ -190,9 +189,44 @@ igraph.check.shapes <- function(x) {
   x
 }
 
-autocurve.edges <- function(graph, start=0.5) {
-  cm <- count.multiple(graph)
-  el <- apply(get.edgelist(graph, names=FALSE), 1, paste, collapse=":")
+
+
+#' Optimal edge curvature when plotting graphs
+#' 
+#' If graphs have multiple edges, then drawing them as straight lines does not
+#' show them when plotting the graphs; they will be on top of each other. One
+#' solution is to bend the edges, with diffenent curvature, so that all of them
+#' are visible.
+#' 
+#' \code{curve_multiple} calculates the optimal \code{edge.curved} vector for
+#' plotting a graph with multiple edges, so that all edges are visible.
+#'
+#' @aliases autocurve.edges
+#' @param graph The input graph.
+#' @param start The curvature at the two extreme edges. All edges will have a
+#' curvature between \code{-start} and \code{start}, spaced equally.
+#' @return A numeric vector, its length is the number of edges in the graph.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{igraph.plotting}} for all plotting parameters,
+#' \code{\link{plot.igraph}}, \code{\link{tkplot}} and \code{\link{rglplot}}
+#' for plotting functions.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- graph( c(0,1,1,0,1,2,1,3,1,3,1,3,
+#'               2,3,2,3,2,3,2,3,0,1)+1 )
+#' 
+#' curve_multiple(g)
+#' 
+#' \dontrun{
+#' set.seed(42)
+#' plot(g)
+#' }
+#' 
+curve_multiple <- function(graph, start=0.5) {
+  cm <- count_multiple(graph)
+  el <- apply(as_edgelist(graph, names=FALSE), 1, paste, collapse=":")
   ord <- order(el)
   res <- numeric(length(ord))
 
@@ -902,7 +936,9 @@ structure(c(16777215L, 16777215L, 16777215L, 16777215L, 16777215L,
 16777215L, 16777215L, 16777215L, 16777215L, 16777215L, 16777215L, 
 16777215L, 16777215L, 16777215L), .Dim = c(64L, 64L), class = "nativeRaster", channels = 4L)
 
-i.vertex.default <- list(color="SkyBlue2",
+#' @include palette.R
+
+i.vertex.default <- list(color=1,
                          size=15,
                          size2=15,
                          label=i.get.labels,
@@ -938,10 +974,11 @@ i.edge.default <- list(color="darkgrey",
                        label.y=NULL,
                        arrow.size=1,
                        arrow.mode=i.get.arrow.mode,
-                       curved=autocurve.edges,
+                       curved=curve_multiple,
                        arrow.width=1)
 
-i.plot.default <- list(layout=layout.auto,
+i.plot.default <- list(palette=categorical_pal(8),
+                       layout=layout_nicely,
                        margin=c(0,0,0,0),
                        rescale=TRUE,
                        asp=1,
diff --git a/R/plot.shapes.R b/R/plot.shapes.R
index 5f0dd39..1269c70 100644
--- a/R/plot.shapes.R
+++ b/R/plot.shapes.R
@@ -53,28 +53,263 @@
 ##              vertices are drawn.
 ##    params    A function object to query plotting parameters.
 ## 
-## vertex.shapes()         - lists all vertex shapes
-## vertex.shapes(shape)    - returns the clipping and plotting functions
+## shapes()         - lists all vertex shapes
+## shapes(shape)    - returns the clipping and plotting functions
 ##                           for a given vertex shape
-## add.vertex.shape()      - adds a new vertex shape, the clipping and
+## add_shape()             - adds a new vertex shape, the clipping and
 ##                           plotting functions must be given, and
 ##                           optionally the newly introduced plotting
 ##                           parameters. This function can also be used
 ##                           to overwrite a given vertex shape.
 ##
 ## Examples:
-## add.vertex.shapes("image", clip=image.clip, plot=image.plot,
+## add_shape("image", clip=image.clip, plot=image.plot,
 ##                   parameters=list(filename=NA))
 ##
-## add.vertex.shapes("triangle", clip=vertex.shapes("circle")$clip,
+## add_shape("triangle", clip=shapes("circle")$clip,
 ##                   plot=triangle.plot)
 ##
-## add.vertex.shapes("polygon", clip=vertex.shapes("circle")$clip,
+## add_shape("polygon", clip=shapes("circle")$clip,
 ##                   plot=polygon.plot)
 ##
 ###################################################################
 
-vertex.shapes <- function(shape=NULL) {
+#' Various vertex shapes when plotting igraph graphs
+#'
+#' Starting from version 0.5.1 igraph supports different
+#' vertex shapes when plotting graphs.
+#'
+#' @details
+#' In igraph a vertex shape is defined by two functions: 1) provides
+#' information about the size of the shape for clipping the edges and 2)
+#' plots the shape if requested. These functions are called \dQuote{shape
+#'   functions} in the rest of this manual page. The first one is the
+#' clipping function and the second is the plotting function.
+#'
+#' The clipping function has the following arguments:
+#' \describe{
+#'   \item{coords}{A matrix with four columns, it contains the
+#'     coordinates of the vertices for the edge list supplied in the
+#'     \code{el} argument.}
+#'   \item{el}{A matrix with two columns, the edges of which some end
+#'     points will be clipped. It should have the same number of rows as
+#'     \code{coords}.}
+#'   \item{params}{This is a function object that can be called to query
+#'     vertex/edge/plot graphical parameters. The first argument of the
+#'     function is \dQuote{\code{vertex}}, \dQuote{\code{edge}} or
+#'     \dQuote{\code{plot}} to decide the type of the parameter, the
+#'     second is a character string giving the name of the
+#'     parameter. E.g.
+#'     \preformatted{
+#'	params("vertex", "size")
+#'     }
+#'   }
+#'   \item{end}{Character string, it gives which end points will be
+#'     used. Possible values are \dQuote{\code{both}},
+#'     \dQuote{\code{from}} and \dQuote{\code{to}}. If
+#'     \dQuote{\code{from}} the function is expected to clip the
+#'     first column in the \code{el} edge list, \dQuote{\code{to}}
+#'     selects the second column, \dQuote{\code{both}} selects both.}
+#' }
+#'
+#' The clipping function should return a matrix
+#' with the same number of rows as the \code{el} arguments.
+#' If \code{end} is \code{both} then the matrix must have four
+#' columns, otherwise two. The matrix contains the modified coordinates,
+#' with the clipping applied.
+#'
+#' The plotting function has the following arguments:
+#' \describe{
+#'   \item{coords}{The coordinates of the vertices, a matrix with two
+#'     columns.}
+#'   \item{v}{The ids of the vertices to plot. It should match the number
+#'     of rows in the \code{coords} argument.}
+#'   \item{params}{The same as for the clipping function, see above.}
+#' }
+#'
+#' The return value of the plotting function is not used.
+#'
+#' \code{shapes} can be used to list the names of all installed
+#' vertex shapes, by calling it without arguments, or setting the
+#' \code{shape} argument to \code{NULL}. If a shape name is given, then
+#' the clipping and plotting functions of that shape are returned in a
+#' named list.
+#'
+#' \code{add_shape} can be used to add new vertex shapes to
+#' igraph. For this one must give the clipping and plotting functions of
+#' the new shape. It is also possible to list the plot/vertex/edge
+#' parameters, in the \code{parameters} argument, that the clipping
+#' and/or plotting functions can make use of. An example would be a
+#' generic regular polygon shape, which can have a parameter for the
+#' number of sides.
+#'
+#' \code{shape_noclip} is a very simple clipping function that the
+#' user can use in their own shape definitions. It does no clipping, the
+#' edges will be drawn exactly until the listed vertex position
+#' coordinates.
+#'
+#' \code{shape_noplot} is a very simple (and probably not very
+#' useful) plotting function, that does not plot anything.
+#'
+#' @aliases add.vertex.shape igraph.shape.noclip igraph.shape.noplot
+#'   vertex.shapes igraph.vertex.shapes
+#'
+#' @param shape Character scalar, name of a vertex shape. If it is
+#'    \code{NULL} for \code{shapes}, then the names of all defined
+#'    vertex shapes are returned.
+#' @param clip An R function object, the clipping function.
+#' @param plot An R function object, the plotting function.
+#' @param parameters Named list, additional plot/vertex/edge
+#'    parameters. The element named define the new parameters, and the
+#'    elements themselves define their default values.
+#'    Vertex parameters should have a prefix
+#'    \sQuote{\code{vertex.}}, edge parameters a prefix
+#'    \sQuote{\code{edge.}}. Other general plotting parameters should have
+#'    a prefix \sQuote{\code{plot.}}. See Details below.
+#' @param coords,el,params,end,v See parameters of the clipping/plotting
+#'    functions below.
+#' @return \code{shapes} returns a character vector if the
+#'    \code{shape} argument is \code{NULL}. It returns a named list with
+#'    entries named \sQuote{clip} and \sQuote{plot}, both of them R
+#'    functions.
+#'
+#'    \code{add_shape} returns \code{TRUE}, invisibly.
+#'
+#'    \code{shape_noclip} returns the appropriate columns of its
+#'    \code{coords} argument.
+#' @export
+#'
+#' @examples
+#' # all vertex shapes, minus "raster", that might not be available
+#' shapes <- setdiff(shapes(), "")
+#' g <- make_ring(length(shapes))
+#' set.seed(42)
+#' plot(g, vertex.shape=shapes, vertex.label=shapes, vertex.label.dist=1,
+#'      vertex.size=15, vertex.size2=15,
+#'      vertex.pie=lapply(shapes, function(x) if (x=="pie") 2:6 else 0),
+#'      vertex.pie.color=list(heat.colors(5)))
+#'
+#' # add new vertex shape, plot nothing with no clipping
+#' add_shape("nil")
+#' plot(g, vertex.shape="nil")
+#'
+#' #################################################################
+#' # triangle vertex shape
+#' mytriangle <- function(coords, v=NULL, params) {
+#'   vertex.color <- params("vertex", "color")
+#'   if (length(vertex.color) != 1 && !is.null(v)) {
+#'     vertex.color <- vertex.color[v]
+#'   }
+#'   vertex.size <- 1/200 * params("vertex", "size")
+#'   if (length(vertex.size) != 1 && !is.null(v)) {
+#'     vertex.size <- vertex.size[v]
+#'   }
+#'
+#'   symbols(x=coords[,1], y=coords[,2], bg=vertex.color,
+#'           stars=cbind(vertex.size, vertex.size, vertex.size),
+#'           add=TRUE, inches=FALSE)
+#' }
+#' # clips as a circle
+#' add_shape("triangle", clip=shapes("circle")$clip,
+#'                  plot=mytriangle)
+#' plot(g, vertex.shape="triangle", vertex.color=rainbow(vcount(g)),
+#'      vertex.size=seq(10,20,length=vcount(g)))
+#'
+#' #################################################################
+#' # generic star vertex shape, with a parameter for number of rays
+#' mystar <- function(coords, v=NULL, params) {
+#'   vertex.color <- params("vertex", "color")
+#'   if (length(vertex.color) != 1 && !is.null(v)) {
+#'     vertex.color <- vertex.color[v]
+#'   }
+#'   vertex.size  <- 1/200 * params("vertex", "size")
+#'   if (length(vertex.size) != 1 && !is.null(v)) {
+#'     vertex.size <- vertex.size[v]
+#'   }
+#'   norays <- params("vertex", "norays")
+#'   if (length(norays) != 1 && !is.null(v)) {
+#'     norays <- norays[v]
+#'   }
+#'
+#'   mapply(coords[,1], coords[,2], vertex.color, vertex.size, norays,
+#'          FUN=function(x, y, bg, size, nor) {
+#'            symbols(x=x, y=y, bg=bg,
+#'                    stars=matrix(c(size,size/2), nrow=1, ncol=nor*2),
+#'                    add=TRUE, inches=FALSE)
+#'          })
+#' }
+#' # no clipping, edges will be below the vertices anyway
+#' add_shape("star", clip=shape_noclip,
+#'                  plot=mystar, parameters=list(vertex.norays=5))
+#' plot(g, vertex.shape="star", vertex.color=rainbow(vcount(g)),
+#'      vertex.size=seq(10,20,length=vcount(g)))
+#' plot(g, vertex.shape="star", vertex.color=rainbow(vcount(g)),
+#'      vertex.size=seq(10,20,length=vcount(g)),
+#'      vertex.norays=rep(4:8, length=vcount(g)))
+#'
+#' #################################################################
+#' # Pictures as vertices.
+#' # Similar musicians from last.fm, we start from an artist and
+#' # will query two levels. We will use the XML, png and jpeg packages
+#' # for this, so these must be available. Otherwise the example is
+#' # skipped
+#'
+#' loadIfYouCan <- function(pkg) suppressWarnings(do.call(require, list(pkg)))
+#'
+#' if (loadIfYouCan("XML") && loadIfYouCan("png") &&
+#'     loadIfYouCan("jpeg")) {
+#'   url <- paste(sep="",
+#'                'http://ws.audioscrobbler.com/',
+#'                '2.0/?method=artist.getinfo&artist=%s',
+#'                '&api_key=1784468ada3f544faf9172ee8b99fca3')
+#'   getartist <- function(artist) {
+#'     cat("Downloading from last.fm. ... ")
+#'     txt <- readLines(sprintf(url, URLencode(artist)))
+#'     xml <- xmlTreeParse(txt, useInternal=TRUE)
+#'     img <- xpathSApply(xml, "/lfm/artist/image[@@size='medium'][1]",
+#'                        xmlValue)
+#'     if (img != "") {
+#'       con <- url(img, open="rb")
+#'       bin <- readBin(con, what="raw", n=10^6)
+#'       close(con)
+#'       if (grepl("\\\\.png$", img)) {
+#'         rast <- readPNG(bin, native=TRUE)
+#'       } else if (grepl("\\\\.jpe?g$", img)) {
+#'         rast <- readJPEG(bin, native=TRUE)
+#'       } else {
+#'         rast <- as.raster(matrix())
+#'       }
+#'     } else {
+#'       rast <- as.raster(numeric())
+#'     }
+#'     sim <- xpathSApply(xml, "/lfm/artist/similar/artist/name", xmlValue)
+#'     cat("done.\\n")
+#'     list(name=artist, image=rast, similar=sim)
+#'   }
+#'
+#'   ego <- getartist("Placebo")
+#'   similar <- lapply(ego$similar, getartist)
+#'
+#'   edges1 <- cbind(ego$name, ego$similar)
+#'   edges2 <- lapply(similar, function(x) cbind(x$name, x$similar))
+#'   edges3 <- rbind(edges1, do.call(rbind, edges2))
+#'   edges <- edges3[ edges3[,1] %in% c(ego$name, ego$similar) &
+#'                    edges3[,2] %in% c(ego$name, ego$similar), ]
+#'
+#'   musnet <- simplify(graph_from_data_frame(edges, dir=FALSE,
+#'                      vertices=data.frame(name=c(ego$name, ego$similar))))
+#'   str(musnet)
+#'
+#'   V(musnet)$raster <- c(list(ego$image), lapply(similar, "[[", "image"))
+#'   plot(musnet, layout=layout_as_star, vertex.shape="raster",
+#'        vertex.label=V(musnet)$name, margin=.2,
+#'        vertex.size=50, vertex.size2=50,
+#'        vertex.label.dist=2, vertex.label.degree=0)
+#' } else {
+#'   message("You need the `XML', `png' and `jpeg' packages to run this")
+#' }
+
+shapes <- function(shape=NULL) {
   if (is.null(shape)) {
     ls(.igraph.shapes)
   } else {
@@ -83,7 +318,10 @@ vertex.shapes <- function(shape=NULL) {
   }
 }
 
-igraph.shape.noclip <- function(coords, el, params,
+#' @rdname shapes
+#' @export
+
+shape_noclip <- function(coords, el, params,
                                 end=c("both", "from", "to")) {
   end <- igraph.match.arg(end)
 
@@ -96,13 +334,19 @@ igraph.shape.noclip <- function(coords, el, params,
   }
 }
 
-igraph.shape.noplot <- function(coords, v=NULL, params) {
+#' @rdname shapes
+#' @export
+
+shape_noplot <- function(coords, v=NULL, params) {
   invisible(NULL)
 }
 
-add.vertex.shape <- function(shape, clip=igraph.shape.noclip,
-                             plot=igraph.shape.noplot,
-                             parameters=list()) {
+#' @rdname shapes
+#' @export
+
+add_shape <- function(shape, clip=shape_noclip,
+                      plot=shape_noplot,
+                      parameters=list()) {
 
   ## TODO
   ## checkScalarString(shape)
diff --git a/R/pp.R b/R/pp.R
new file mode 100644
index 0000000..20f5dd6
--- /dev/null
+++ b/R/pp.R
@@ -0,0 +1,25 @@
+
+#   IGraph R package
+#   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+#   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
+#
+###################################################################
+
+get.all.simple.paths.pp <- function(vect) {
+  .Call("R_igraph_get_all_simple_paths_pp", vect, PACKAGE="igraph")
+}
diff --git a/R/print.R b/R/print.R
index e460f34..9259769 100644
--- a/R/print.R
+++ b/R/print.R
@@ -1,24 +1,26 @@
 
-#   IGraph R package
-#   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
-#   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
-#
-###################################################################
+## ----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2005-2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## ----------------------------------------------------------------------
 
 ###################################################################
 # Convert graphs to human readable forms
@@ -26,21 +28,21 @@
 
 .get.attr.codes <- function(object) {
   ga <- va <- ea <- ""
-  gal <- list.graph.attributes(object)
+  gal <- graph_attr_names(object)
   if (length(gal) != 0) {
     ga <- paste(sep="", gal, " (g/",
                 .Call("R_igraph_get_attr_mode", object, 2L, PACKAGE="igraph"),
                 ")")
   }
-  val <- list.vertex.attributes(object)
+  val <- vertex_attr_names(object)
   if (length(val) != 0) {
     va <- paste(sep="", val, " (v/",
                 .Call("R_igraph_get_attr_mode", object, 3L, PACKAGE="igraph"),
                 ")")
   }
-  eal <- list.edge.attributes(object)
+  eal <- edge_attr_names(object)
   if (length(eal) != 0) {
-    ea <- paste(sep="", list.edge.attributes(object), " (e/",
+    ea <- paste(sep="", edge_attr_names(object), " (e/",
                 .Call("R_igraph_get_attr_mode", object, 4L, PACKAGE="igraph"),
                 ")")
   }
@@ -49,18 +51,18 @@
 
 .print.header <- function(object) {
 
-  if (!is.igraph(object)) {
+  if (!is_igraph(object)) {
     stop("Not a graph object")
   }
 
   title <- paste(sep="", "IGRAPH ",
-                 c("U","D")[is.directed(object)+1],
-                 c("-","N")[is.named(object)+1],
-                 c("-","W")[is.weighted(object)+1],
-                 c("-","B")[is.bipartite(object)+1], " ",
+                 c("U","D")[is_directed(object)+1],
+                 c("-","N")[is_named(object)+1],
+                 c("-","W")[is_weighted(object)+1],
+                 c("-","B")[is_bipartite(object)+1], " ",
                  vcount(object), " ", ecount(object), " -- ")
   w <- getOption("width")
-  if (nchar(title) < w && "name" %in% list.graph.attributes(object)) {
+  if (nchar(title) < w && "name" %in% graph_attr_names(object)) {
     title <- substring(paste(sep="", title,
                              as.character(object$name)[1]), 1, w-1)
   }
@@ -69,27 +71,68 @@
   atxt <- .get.attr.codes(object)
   atxt <- paste(atxt[atxt!=""], collapse=", ")
   if (atxt != "") {
-    atxt <- strwrap(paste(sep="", "+ attr: ", atxt), exdent=2)
+    atxt <- strwrap(paste(sep="", "+ attr: ", atxt), prefix = "| ",
+                    initial = "")
     cat(atxt, sep="\n")
   }
+  1 + if (length(atxt) == 1 && atxt == "") 0 else length(atxt)
 }
 
-.print.graph.attributes <- function(x) {
-  list <- list.graph.attributes(x)
+indent_print <- printr$indent_print
+
+.print.graph.attributes <- function(x, full, max.lines) {
+  list <- graph_attr_names(x)
   if (length(list)!=0) {
     cat("+ graph attributes:\n")
-    lapply(list, function(n) {
-      cat(sep="", "[[", n, "]]\n")
-      print(get.graph.attribute(x, n))
+    out <- capture.output({
+      lapply(list, function(n) {
+        cat(sep="", "+ ", n, ":\n")
+        indent_print(graph_attr(x, n), .indent = "  ")
+      })
+      invisible(NULL)
     })
+    indent_print(out, sep = "\n", .indent = "| ", .printer = cat)
+    length(out) + 1
+  } else {
+    0
   }
 }
 
-.print.vertex.attributes <- function(x) {
+## IGRAPH U--- 10 10 -- Ring graph
+## + attr: name (g/c), mutual (g/l), circular (g/l)
+## + graph attributes:
+## | + name:
+## |   [1] "Ring graph"
+## | + mutual:
+## |   [1] FALSE
+## | + circular=
+## |   [1] TRUE
+## | + layout =
+## |            [,1]          [,2]
+## |    [1,]  0.000000  0.000000e+00
+## |    [2,]  1.000000  0.000000e+00
+## |    [3,]  0.809017  5.877853e-01
+## |    [4,]  0.309017  9.510565e-01
+## |    [5,] -0.309017  9.510565e-01
+## |    [6,] -0.809017  5.877853e-01
+## |    [7,] -1.000000  1.224647e-16
+## |    [8,] -0.809017 -5.877853e-01
+## |    [9,] -0.309017 -9.510565e-01
+## |   [10,]  0.309017 -9.510565e-01
+## |   [11,]  0.809017 -5.877853e-01
+## + edges:
+##  [1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 6-- 7 7-- 8 8-- 9 9--10 1--10
+
+.print.vertex.attributes <- function(x, full, max.lines) {
+  pf <- function(x) .print.vertex.attributes.old(x, full, max.lines)
+  if (length(vertex_attr_names(x))) cat("+ vertex attributes:\n")
+  indent_print(x, .indent = "| ", .printer = pf)
+}
+
+.print.vertex.attributes.old <- function(x, full, max.lines) {
   vc <- vcount(x)
-  list <- list.vertex.attributes(x)
+  list <- vertex_attr_names(x)
   if (length(list) != 0) {
-    cat("+ vertex attributes:\n")
     mp <- getOption("max.print")
     options(max.print=1000000000)
     if (vc <= mp) {
@@ -101,13 +144,13 @@
     }
     if (vc==0 ||
         all(sapply(list, function(v)
-                   is.numeric(get.vertex.attribute(x, v)) ||
-                   is.character(get.vertex.attribute(x, v)) ||
-                   is.logical(get.vertex.attribute(x, v))))) {
+                   is.numeric(vertex_attr(x, v)) ||
+                   is.character(vertex_attr(x, v)) ||
+                   is.logical(vertex_attr(x, v))))) {
       ## create a table
       tab <- data.frame(v=paste(sep="", "[", ind, "]"), row.names="v")
       for (i in list) {
-        tab[i] <- get.vertex.attribute(x, i, ind)
+        tab[i] <- vertex_attr(x, i, ind)
       }
       print(tab)
     } else {
@@ -115,7 +158,7 @@
         cat(sep="", "[[", i, "]]\n")
         lapply(list, function(n) {
           cat(sep="", "[[", i, "]][[", n, "]]\n")
-          print(get.vertex.attribute(x, n, i))})
+          print(vertex_attr(x, n, i))})
       }
     }
     options(max.print=mp)
@@ -126,23 +169,23 @@
   }
 }
 
-.print.edges.edgelist <- function(x, names) {
-  ec <- ecount(x)
-  list <- list.edge.attributes(x)
+.print.edges.edgelist <- function(x, edges = E(x), names) {
+  ec <- length(edges)
+  list <- edge_attr_names(x)
   list <- list[list!="name"]
-  arrow <- ifelse(is.directed(x), "->", "--")
-  if (is.named(x)) {
+  arrow <- ifelse(is_directed(x), "->", "--")
+  if (is_named(x)) {
     cat("+ edges (vertex names) and their attributes:\n")
   } else {
     cat("+ edges and their attributes:\n")
   }
-  if (names && ! "name" %in% list.vertex.attributes(x)) {
+  if (names && ! "name" %in% vertex_attr_names(x)) {
     names <- FALSE
   }
-  if (names && "name" %in% list.vertex.attributes(x) &&
-      !is.numeric(get.vertex.attribute(x, "name")) &&
-      !is.character(get.vertex.attribute(x, "name")) &&
-      !is.logical(get.vertex.attribute(x, "name"))) {
+  if (names && "name" %in% vertex_attr_names(x) &&
+      !is.numeric(vertex_attr(x, "name")) &&
+      !is.character(vertex_attr(x, "name")) &&
+      !is.logical(vertex_attr(x, "name"))) {
     warning("Can't print vertex names, complex `name' vertex attribute")
     names <- FALSE
   }
@@ -150,28 +193,28 @@
   mp <- getOption("max.print")
   if (mp >= ec) {
     omitted.edges <- 0
-    el <- get.edgelist(x, names=names)
+    el <- ends(x, edges, names=names)
   } else {
     omitted.edges <- ec-mp
-    el <- get.edges(x, seq_len(mp))
+    el <- ends(x, ends[seq_len(mp)])
     if (names) { el[] <- V(x)$name[el] }
   }
-  ename <- if ("name" %in% list.edge.attributes(x)) {
+  ename <- if ("name" %in% edge_attr_names(x)) {
     paste(sep="", "'", E(x)$name, "'")
   } else {
     seq(length=nrow(el))
   }
   if (ec==0 || 
-      all(sapply(list, function(v) is.numeric(get.edge.attribute(x, v)) |
-                 is.character(get.edge.attribute(x,v)) |
-                 is.logical(get.edge.attribute(x, v))))) {
+      all(sapply(list, function(v) is.numeric(edge_attr(x, v)) |
+                 is.character(edge_attr(x,v)) |
+                 is.logical(edge_attr(x, v))))) {
     ## create a table
     tab <- data.frame(row.names=paste(sep="", "[", ename, "]"))
     if (is.numeric(el)) { w <- nchar(max(el)) } else { w <- max(nchar(el)) }
     tab["edge"] <- paste(sep="", format(el[,1], width=w),
                          arrow, format(el[,2], width=w))
     for (i in list) {
-      tab[i] <- get.edge.attribute(x, i)
+      tab[i] <- edge_attr(x, i)
     }
     print(tab)
   } else {
@@ -180,7 +223,7 @@
       cat(sep="", "[", ename[i], "] ", v[1], " ", arrow, " ", v[2]);
       lapply(list, function(n) {
         cat(sep="", "\n[[", i, "]][[", n, "]]\n")
-        print(get.edge.attribute(x, n, i))})
+        print(edge_attr(x, n, i))})
       cat("\n")
       i <<- i+1
     })
@@ -189,23 +232,129 @@
     cat(paste('[ reached getOption("max.print") -- omitted', omitted.edges,
               'edges ]\n\n'))
   }    
-} 
+}
 
-.print.edges.compressed <- function(x, names) {
-  ## TODO: getOption("max.print")
-  if (is.named(x)) cat("+ edges (vertex names):\n") else cat("+ edges:\n")
-  el <- get.edgelist(x, names=names)
-  arrow <- c("--", "->")[is.directed(x)+1]
-  edges <- paste(sep="", format(el[,1]), arrow, format(el[,2]))
-  print(edges, quote=FALSE)
+#' @include printr.R
+
+head_print <- printr$head_print
+printer_callback <- printr$printer_callback
+
+.print.edges.compressed <- function(x, edges = E(x), names, num = FALSE,
+                                      max.lines = igraph_opt("auto.print.lines")) {
+
+  len <- length(edges)
+
+  title <- "+" %+%
+    (if (num) " " %+% chr(len) %+% "/" %+%
+       (if (is.null(x)) "?" else chr(gsize(x))) else "") %+%
+    (if (len == 1) " edge" else " edges") %+%
+    (if (is.null(x)) ", unknown graph" else "") %+%
+    (if (is.null(attr(edges, "vnames"))) "" else " (vertex names)") %+%
+    ":\n"
+  cat(title)
+
+  if (!is.null(attr(edges, "single")) && attr(edges, "single") &&
+      !is.null(x)) {
+    ## Double bracket
+    ea <- edge_attr(x)
+    if (all(sapply(ea, is.atomic))) {
+      etail <- tail_of(x, edges)
+      ehead <- head_of(x, edges)
+      df <- data.frame(
+        stringsAsFactors = FALSE,
+        tail = as_ids(etail),
+        head = as_ids(ehead),
+        tid  = as.vector(etail),
+        hid  = as.vector(ehead)
+      )
+      if (length(ea)) {
+        ea <- do_call(data.frame, .args = ea, stringsAsFactors = FALSE)
+        df <- cbind(df, ea[as.vector(edges), , drop = FALSE])
+      }
+      print(df)
+
+    } else {
+      print(lapply(ea, "[", as.vector(edges)))
+    }
+
+  } else if (is.null(max.lines)) {
+    .print.edges.compressed.all(x, edges, names)
+
+  } else {
+    .print.edges.compressed.limit(x, edges, names, max.lines)
+  }
+}
+
+.print.edges.compressed.all <- function(x, edges, names) {
+
+  arrow <- c("--", "->")[is_directed(x)+1]
+
+  if (!is.null(x)) {
+    el <- ends(x, edges, names=names)
+    pr <- paste(sep="", format(el[,1]), arrow, format(el[,2]))
+    print(pr, quote=FALSE)
+  } else {
+    if (!is.null(attr(edges, "vnames"))) {
+      print(as.vector(attr(edges, "vnames")), quote = FALSE)
+    } else if (!is.null(names(edges))) {
+      print(names(edges), quote = FALSE)
+    } else {
+      print(as.vector(edges))
+    }
+  }
+
+}
+
+.print.edges.compressed.limit <- function(x, edges, names, max.lines) {
+
+  if (!is.null(x)) {
+
+    arrow <- c("--", "->")[is_directed(x)+1]
+
+    can_max <- NA
+    el <- NA
+
+    fun <- function(q, no) {
+      if (q == "length") {
+        length(edges)
+      } else if (q == "min_width") {
+        5
+      } else if (q == "width") {
+        el <<- ends(x, edges[seq_len(no)], names = names)
+        cummax(nchar(el[,1])) + nchar(arrow) + cummax(nchar(el[,2])) + 1
+      } else if (q == "print") {
+        el <<- el[seq_len(no), , drop = FALSE]
+        out <- paste(sep="", format(el[,1]), arrow, format(el[,2]))
+        capture.output(print(out, quote = FALSE))
+      } else if (q == "max") {
+        can_max <<- no
+      } else if (q == "done") {
+        if (no["tried_items"] < length(edges) ||
+            no["printed_lines"] < no["tried_lines"]) {
+          cat("+ ... omitted several edges\n")
+        }
+      }
+    }
+
+    fun <- printer_callback(fun)
+    head_print(fun, max_lines = max.lines)
+  } else {
+    if (!is.null(attr(edges, "vnames"))) {
+      head_print(as.vector(attr(edges, "vnames")), quote = FALSE)
+    } else if (!is.null(names(edges))) {
+      head_print(names(edges), quote = FALSE)
+    } else {
+      head_print(as.vector(edges))
+    }
+  }
 }
 
 .print.edges.adjlist <- function(x) {
   ## TODO: getOption("max.print")
   cat("+ edges:\n")
   vc <- vcount(x)
-  arrow <- c(" -- ", " -> ")[is.directed(x)+1]
-  al <- get.adjlist(x, mode="out")
+  arrow <- c(" -- ", " -> ")[is_directed(x)+1]
+  al <- as_adj_list(x, mode="out")
   w <- nchar(max(which(degree(x, mode="in") != 0)))
   mpl <- trunc((getOption("width")-nchar(arrow)-nchar(vc)) / (w+1))
   if (any(sapply(al, length) > mpl)) {
@@ -239,80 +388,143 @@
   }
 }
 
-.print.edges.adjlist.named <- function(x) {
+.print.edges.adjlist.named <- function(x, edges = E(x)) {
   ## TODO getOption("max.print")
   cat("+ edges (vertex names):\n")
 
-  arrow <- c(" -- ", " -> ")[is.directed(x)+1]
+  arrow <- c(" -- ", " -> ")[is_directed(x)+1]
   vn <- V(x)$name
 
-  al <- get.adjlist(x, mode="out")
+  al <- as_adj_list(x, mode="out")
   alstr <- sapply(al, function(x) { paste(collapse=", ", vn[x]) })
   alstr <- paste(sep="", format(vn), arrow, alstr)
   alstr <- strwrap(alstr, exdent=max(nchar(vn))+nchar(arrow))
   cat(alstr, sep="\n")
 }
 
+#' @method str igraph
+#' @export
+
 str.igraph <- function(object, ...) {
   print.igraph(object, full=TRUE, ...)
 }
 
-print.igraph <- function(x, full=getIgraphOpt("print.full"),
-                graph.attributes=getIgraphOpt("print.graph.attributes"),
-                vertex.attributes=getIgraphOpt("print.vertex.attributes"),
-                edge.attributes=getIgraphOpt("print.edge.attributes"),
-                names=TRUE, ...) {
+
+
+#' Print graphs to the terminal
+#' 
+#' These functions attempt to print a graph to the terminal in a human readable
+#' form.
+#' 
+#' \code{summary.igraph} prints the number of vertices, edges and whether the
+#' graph is directed.
+#' 
+#' \code{str.igraph} prints the same information, and also lists the edges, and
+#' optionally graph, vertex and/or edge attributes.
+#' 
+#' \code{print.igraph} behaves either as \code{summary.igraph} or
+#' \code{str.igraph} depending on the \code{full} argument. See also the
+#' \sQuote{print.full} igraph option and \code{\link{igraph_opt}}.
+#' 
+#' The graph summary printed by \code{summary.igraph} (and \code{print.igraph}
+#' and \code{str.igraph}) consists one or more lines. The first line contains
+#' the basic properties of the graph, and the rest contains its attributes.
+#' Here is an example, a small star graph with weighed directed edges and named
+#' vertices: \preformatted{    IGRAPH DNW- 10 9 -- In-star
+#'     + attr: name (g/c), mode (g/c), center (g/n), name (v/c),
+#'       weight (e/n) }
+#' The first line always
+#' starts with \code{IGRAPH}, showing you that the object is an igraph graph.
+#' Then a four letter long code string is printed. The first letter
+#' distinguishes between directed (\sQuote{\code{D}}) and undirected
+#' (\sQuote{\code{U}}) graphs. The second letter is \sQuote{\code{N}} for named
+#' graphs, i.e. graphs with the \code{name} vertex attribute set. The third
+#' letter is \sQuote{\code{W}} for weighted graphs, i.e. graphs with the
+#' \code{weight} edge attribute set. The fourth letter is \sQuote{\code{B}} for
+#' bipartite graphs, i.e. for graphs with the \code{type} vertex attribute set.
+#' 
+#' Then, after two dashes, the name of the graph is printed, if it has one,
+#' i.e. if the \code{name} graph attribute is set.
+#' 
+#' From the second line, the attributes of the graph are listed, separated by a
+#' comma. After the attribute names, the kind of the attribute -- graph
+#' (\sQuote{\code{g}}), vertex (\sQuote{\code{v}}) or edge (\sQuote{\code{e}})
+#' -- is denoted, and the type of the attribute as well, character
+#' (\sQuote{\code{c}}), numeric (\sQuote{\code{n}}), logical
+#' (\sQuote{\code{l}}), or other (\sQuote{\code{x}}).
+#' 
+#' As of igraph 0.4 \code{str.igraph} and \code{print.igraph} use the
+#' \code{max.print} option, see \code{\link[base]{options}} for details.
+#' 
+#' @aliases print.igraph str.igraph summary.igraph
+#' @param x The graph to print.
+#' @param full Logical scalar, whether to print the graph structure itself as
+#' well.
+#' @param graph.attributes Logical constant, whether to print graph attributes.
+#' @param vertex.attributes Logical constant, whether to print vertex
+#' attributes.
+#' @param edge.attributes Logical constant, whether to print edge attributes.
+#' @param names Logical constant, whether to print symbolic vertex names (ie.
+#' the \code{name} vertex attribute) or vertex ids.
+#' @param max.lines The maximum number of lines to use. The rest of the
+#' output will be truncated.
+#' @param object The graph of which the summary will be printed.
+#' @param \dots Additional agruments.
+#' @return All these functions return the graph invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @method print igraph
+#' @export
+#' @export print.igraph
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' g
+#' summary(g)
+#' 
+print.igraph <- function(x, full=igraph_opt("print.full"),
+                graph.attributes=igraph_opt("print.graph.attributes"),
+                vertex.attributes=igraph_opt("print.vertex.attributes"),
+                edge.attributes=igraph_opt("print.edge.attributes"),
+                names=TRUE, max.lines = igraph_opt("auto.print.lines"), ...) {
   
-  if (!is.igraph(x)) {
+  if (!is_igraph(x)) {
     stop("Not a graph object")
   }
 
-  .print.header(x)
-  if (full) { 
-    if (graph.attributes)  .print.graph.attributes(x)
-    if (vertex.attributes) .print.vertex.attributes(x)
+  head_lines <- .print.header(x)
+  if (is.logical(full) && full) {
+    if (graph.attributes) {
+      head_lines <- head_lines + .print.graph.attributes(x, full, max.lines)
+    }
+    if (vertex.attributes) {
+      head_lines <- head_lines + .print.vertex.attributes(x, full, max.lines)
+    }
     if (ecount(x)==0) {
       ## Do nothing
-    } else if (edge.attributes && length(list.edge.attributes(x)) !=0 ) {
-      .print.edges.edgelist(x, names)
+    } else if (edge.attributes && length(edge_attr_names(x)) != 0 ) {
+      .print.edges.edgelist(x, names = names)
     } else if (median(degree(x, mode="out")) < 3) {
-      .print.edges.compressed(x, names)
-    } else if (is.named(x)) {
+      .print.edges.compressed(x, names = names, max.lines = NULL)
+    } else if (is_named(x)) {
       .print.edges.adjlist.named(x)
     } else {
       .print.edges.adjlist(x)
     }
+  } else if (full == "auto") {
+    .print.edges.compressed(x, names = names, max.lines =
+                              max.lines - head_lines)
   }
   
   invisible(x)
 }
 
-summary.igraph <- function(object, ...) {
-
-  if (!is.igraph(object)) {
-    stop("Not a graph object")
-  }
-
-  title <- paste(sep="", "IGRAPH ",
-                 c("U","D")[is.directed(object)+1],
-                 c("-","N")[is.named(object)+1],
-                 c("-","W")[is.weighted(object)+1],
-                 c("-","B")[is.bipartite(object)+1], " ",
-                 vcount(object), " ", ecount(object), " -- ")
-  w <- getOption("width")
-  if (nchar(title) < w && "name" %in% list.graph.attributes(object)) {
-    title <- substring(paste(sep="", title,
-                             as.character(object$name)[1]), 1, w-1)
-  }
-  cat(title, "\n", sep="")
-
-  atxt <- .get.attr.codes(object)
-  atxt <- paste(atxt[atxt!=""], collapse=", ")
-  if (atxt != "") {
-    atxt <- strwrap(paste(sep="", "attr: ", atxt), exdent=2)
-    cat(atxt, sep="\n")
-  }
+#' @rdname print.igraph
+#' @method summary igraph
+#' @export
 
+summary.igraph <- function(object, ...) {
+  .print.header(object)
   invisible(object)
 }
 
diff --git a/R/printr.R b/R/printr.R
new file mode 100644
index 0000000..86319f9
--- /dev/null
+++ b/R/printr.R
@@ -0,0 +1,189 @@
+
+printr <- (function() {
+
+#' Create a printer callback function
+#'
+#' A printer callback fucntion is a function can performs the actual
+#' printing. It has a number of subcommands, that are called by
+#' the \code{printer} package, in a form \preformatted{
+#'     printer_callback("subcommand", argument1, argument2, ...)
+#' } See the examples below.
+#'
+#' The subcommands:
+#'
+#' \describe{
+#'   \item{\code{length}}{The length of the data to print, the number of
+#'     items, in natural units. E.g. for a list of objects, it is the
+#'     number of objects.}
+#'   \item{\code{min_width}}{TODO}
+#'   \item{\code{width}}{Width of one item, if \code{no} items will be
+#'     printed. TODO}
+#'   \item{\code{print}}{Argument: \code{no}. Do the actual printing,
+#'     print \code{no} items.}
+#'   \item{\code{done}}{TODO}
+#' }
+#'
+#' @param fun The function to use as a printer callback function.
+#' @family printer callbacks
+#' @export
+
+printer_callback <- function(fun) {
+
+  if (!is.function(fun)) warning("'fun' is not a function")
+  add_class(fun, "printer_callback")
+}
+
+#' Is this a printer callback?
+#'
+#' @param x An R object.
+#' @family printer callbacks
+#' @export
+
+is_printer_callback <- function(x) {
+  inherits(x, "printer_callback")
+}
+
+print_header <- function(header) {
+  print_head_foot(header)
+}
+
+
+print_footer <- function(footer) {
+  print_head_foot(footer)
+}
+
+print_head_foot <- function(head_foot) {
+  if (is.function(head_foot)) head_foot() else cat(head_foot)
+}
+
+#' Print the only the head of an R object
+#'
+#' @param x The object to print, or a callback function. See
+#'   \code{\link{printer_callback}} for details.
+#' @param max_lines Maximum number of lines to print, \emph{not}
+#'   including the header and the footer.
+#' @param header The header, if a function, then it will be called,
+#'   otherwise printed using \code{cat}.
+#' @param footer The footer, if a function, then it will be called,
+#'   otherwise printed using \code{cat}.
+#' @param omitted_footer Footer that is only printed if anything
+#'   is omitted from the printout. If a function, then it will be called,
+#'   otherwise printed using \code{cat}.
+#' @param ... Extra arguments to pass to \code{print()}.
+#' @return \code{x}, invisibly.
+#'
+#' @export
+
+head_print <- function(x, max_lines = 20, header = "", footer = "",
+                       omitted_footer = "", ...) {
+  if (is_printer_callback(x)) {
+    head_print_callback(x, max_lines, header, footer, omitted_footer, ...)
+  } else {
+    head_print_object(x, max_lines, header, footer, omitted_footer, ...)
+  }
+  invisible(x)
+}
+
+head_print_object <- function(x, max_lines, header, footer, omitted_footer,
+                              print_fun = print, ...) {
+
+  print_header(header)
+
+  cout <- capture.output(print_fun(x, ...))
+  cout_no <- min(length(cout), max_lines)
+  cat(cout[seq_len(cout_no)], sep = "\n")
+
+  print_footer(footer)
+
+  if (cout_no < length(cout)) print_footer(omitted_footer)
+
+  invisible(c(lines = length(cout), printed = cout_no))
+}
+
+head_print_callback <- function(x, max_lines, header, footer,
+                                omitted_footer, ...) {
+
+  ## Header
+  print_header(header)
+
+  len <- x("length")
+  minw <- x("min_width")
+  ow <- getOption("width", 80)
+
+  ## Max number of items we can print. This is an upper bound.
+  can_max <- min(floor(ow / minw) * max_lines, len)
+  if (can_max == 0) { return() }
+
+  ## Width of item if we print up to this
+  cm <- x("width", no = can_max)
+
+  ## How many rows we need if we print up to a certain point
+  no_rows <- ceiling(cm * seq_along(cm) /(ow - 4) )
+
+  ## So how many items should be print?
+  no <- tail(which(no_rows <= max_lines), 1)
+  if (is.na(no)) no <- len
+
+  cat_pern <- function(..., sep = "\n") cat(..., sep = sep)
+
+  ## Format them, and print
+  out_lines <- head_print_object(
+    x("print", no = no, ...), print_fun = cat_pern, max_lines = max_lines,
+    header = "", footer = "", omitted_footer = ""
+  )
+
+  done_stat <- c(tried_items = no, tried_lines = out_lines[["lines"]],
+                 printed_lines = out_lines[["printed"]])
+
+  if (done_stat["tried_items"] < len ||
+      done_stat["printed_lines"] < done_stat["tried_lines"]) {
+    print_footer(omitted_footer)
+  }
+
+  x("done", done_stat)
+
+  ## Footer
+  print_footer(footer)
+}
+
+#' Indent a printout
+#'
+#' @param ... Passed to the printing function.
+#' @param .indent Character scalar, indent the printout with this.
+#' @param .printer The printing function, defaults to \code{print}.
+#' @return The first element in \code{...}, invisibly.
+#'
+#' @export
+
+indent_print <- function(..., .indent = " ", .printer = print) {
+
+  if (length(.indent) != 1) stop(".indent must be a scalar")
+  
+  opt <- options(width = getOption("width") - nchar(.indent))
+  on.exit(options(opt), add = TRUE)
+
+  cout <- capture.output(.printer(...))
+  if (length(cout)) {
+    cout <- paste0(.indent, cout)
+    cat(cout, sep = "\n")
+  }
+
+  invisible(list(...)[[1]])
+}
+
+#' Better printing of R packages
+#'
+#' @docType package
+#' @name printr
+NULL
+
+add_class <- function(x, class) {
+
+  if (!inherits(x, class)) {
+    class(x) <- c(class(x), class)
+  }
+  x
+}
+environment()
+})()
+
diff --git a/R/random_walk.R b/R/random_walk.R
new file mode 100644
index 0000000..1125c65
--- /dev/null
+++ b/R/random_walk.R
@@ -0,0 +1,53 @@
+
+#' Random walk on a graph
+#'
+#' Do a random walk. From the given start vertex, take the given number of
+#' steps, choosing an edge from the actual vertex uniformly randomly. Edge
+#' directions are observed in directed graphs (see the \code{mode} argument
+#' as well). Multiple and loop edges are also observed.
+#'
+#' @param graph The input graph, might be undirected or directed.
+#' @param start The start vertex.
+#' @param steps The number of steps to make.
+#' @param mode How to follow directed edges. \code{"out"} steps along the
+#'   edge direction, \code{"in"} is opposite to that. \code{"all"} ignores
+#'   edge directions. This argument is ignored for directed graphs.
+#' @param stuck What to do if the random walk gets stuck. \code{"return"}
+#'   returns the partial walk, \code{"error"} raises an error.
+#' @return A vertex sequence containing the vertices along the walk.
+#' @export
+#' @examples
+#' ## Stationary distribution of a Markov chain
+#' g <- make_ring(10, directed = TRUE) %u%
+#'   make_star(11, center = 11) + edge(11, 1)
+#'
+#' ec <- eigen_centrality(g, directed = TRUE)$vector
+#' pg <- page_rank(g, damping = 0.999)$vector
+#' w <- random_walk(g, start = 1, steps = 10000)
+#'
+#' ## These are similar, but not exactly the same
+#' cor(table(w), ec)
+#'
+#' ## But these are (almost) the same
+#' cor(table(w), pg)
+
+random_walk <- function(graph, start, steps, mode = c("out", "in", "all"),
+                        stuck = c("return", "error")) {
+  ## Argument checks
+  if (!is_igraph(graph)) stop("Not a graph object")
+  start <- as.igraph.vs(graph, start)
+  mode <- switch(igraph.match.arg(mode), "out" = 1, "in" = 2, "all" = 3,
+                 "total" = 3)
+  steps <- as.integer(steps)
+  stuck <- switch(igraph.match.arg(stuck), "error" = 0L, "return" = 1L)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE = "igraph") )
+
+  ## Function call
+  res <- .Call("R_igraph_random_walk", graph, start - 1, mode, steps, stuck,
+               PACKAGE="igraph")
+  if (igraph_opt("return.vs.es")) {
+    res <- create_vs(graph, res)
+  }
+  res
+}
diff --git a/R/revolver.R b/R/revolver.R
deleted file mode 100644
index 8afb6a6..0000000
--- a/R/revolver.R
+++ /dev/null
@@ -1,493 +0,0 @@
-
-#   IGraph R package
-#   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-#   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
-#
-###################################################################
-
-evolver.d <- function(nodes, kernel, outseq=NULL, outdist=NULL,
-                      m=1, directed=TRUE) {
-
-  if (!is.null(outseq)) { outseq <- as.numeric(outseq) }
-  if (!is.null(outdist)) { outdist <- as.numeric(outdist) }
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_evolver_d", as.numeric(nodes), as.numeric(kernel),
-        outseq, outdist, m, as.logical(directed),
-        PACKAGE="igraph")
-}
-  
-revolver.d <- function(graph, niter=5, sd=FALSE, norm=FALSE,
-                      cites=FALSE, expected=FALSE, error=TRUE,
-                      debug=numeric()) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_d", graph, as.numeric(niter), as.logical(sd),
-        as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug),
-        PACKAGE="igraph")
-}
-
-revolver.error.d <- function(graph, kernel) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_d", graph, as.numeric(kernel),
-        PACKAGE="igraph")
-}
-
-revolver.ad <- function(graph, niter=5, agebins=max(vcount(graph)/7100, 10),
-                       sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE, error=TRUE,
-                       debug=matrix(ncol=2, nrow=0)) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_ad", graph, as.numeric(niter), as.numeric(agebins),
-        as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)),
-        PACKAGE="igraph")
-}
-
-revolver.error.ad <- function(graph, kernel) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_ad", graph, kernel,
-        PACKAGE="igraph")
-}
-
-revolver.ade <- function(graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-                        sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                        error=TRUE, debug=matrix(ncol=2, nrow=0)) {
-                        
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_ade", graph, as.numeric(cats), as.numeric(niter),
-        as.numeric(agebins), as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)), 
-        PACKAGE="igraph")
-}
-
-revolver.error.ade <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-  
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_ade", graph, kernel, as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.e <- function(graph, cats, niter=5, st=FALSE,
-                      sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                      error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_e", graph, as.numeric(cats), as.numeric(niter), as.logical(st),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-                                                     
-revolver.error.e <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_e", graph, as.numeric(kernel), as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.de <- function(graph, cats, niter=5,
-                      sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                      error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_de", graph, as.numeric(cats), as.numeric(niter),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-                       
-revolver.error.de <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_de", graph, kernel, as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.l <- function(graph, niter=5, agebins=max(vcount(graph)/7100, 10),
-                      sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                      error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_l", graph, as.numeric(niter), as.numeric(agebins),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.l <- function(graph, kernel) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_l", graph, as.numeric(kernel),
-        PACKAGE="igraph")
-}
-
-revolver.dl <- function(graph, niter=5, agebins=max(vcount(graph)/7100, 10),
-                       sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                       error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_dl", graph, as.numeric(niter), as.numeric(agebins),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.dl <- function(graph, kernel) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_dl", graph, kernel,
-        PACKAGE="igraph")
-}
-
-revolver.el <- function(graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-                       sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                       error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_el", graph, as.numeric(cats), as.numeric(niter),
-        as.numeric(agebins),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.el <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_el", graph, kernel, as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.r <- function(graph, window, niter=5, sd=FALSE, norm=FALSE,
-                       cites=FALSE, expected=FALSE, error=TRUE,
-                       debug=numeric()) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_r", graph, as.numeric(niter), as.numeric(window),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.r <- function(graph, kernel, window) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_r", graph, as.numeric(kernel), as.numeric(window),
-        PACKAGE="igraph")
-}
-
-revolver.ar <- function(graph, window, niter=5, agebins=max(vcount(graph)/7100, 10),
-                       sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE, error=TRUE,
-                       debug=matrix(ncol=2, nrow=0)) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_ar", graph, as.numeric(niter), as.numeric(agebins),
-        as.numeric(window),
-        as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)), 
-        PACKAGE="igraph")
-}
-
-revolver.error.ar <- function(graph, kernel, window) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_ar", graph, kernel, as.numeric(window),
-        PACKAGE="igraph")
-}
-
-revolver.di <- function(graph, cats, niter=5,
-                      sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                      error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_di", graph, as.numeric(cats), as.numeric(niter),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.di <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_di", graph, kernel, as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.adi <- function(graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-                        sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                        error=TRUE, debug=matrix(ncol=2, nrow=0)) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_adi", graph, as.numeric(cats), as.numeric(niter),
-        as.numeric(agebins), as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)), 
-        PACKAGE="igraph")
-}
-
-revolver.error.adi <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_adi", graph, kernel, as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.il <- function(graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-                      sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                      error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_il", graph, as.numeric(cats),
-        as.numeric(niter), as.numeric(agebins),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.il <- function(graph, kernel, cats) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_il", graph, kernel, as.numeric(cats),
-        PACKAGE="igraph")
-}
-
-revolver.ir <- function(graph, cats, window, niter=5,
-                      sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                      error=TRUE, debug=numeric()) {
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_ir", graph, as.numeric(cats), as.numeric(window),
-        as.numeric(niter),
-        as.logical(sd), as.logical(norm), as.logical(cites), as.logical(expected),
-        as.logical(error), as.numeric(debug), 
-        PACKAGE="igraph")
-}
-
-revolver.error.ir <- function(graph, kernel, cats, window) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_ir", graph, kernel, as.numeric(cats),
-        as.numeric(window),
-        PACKAGE="igraph")
-}
-
-revolver.air <- function(graph, cats, window,
-                        niter=5, agebins=max(vcount(graph)/7100, 10),
-                        sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                        error=TRUE, debug=matrix(ncol=2, nrow=0)) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_air", graph, as.numeric(cats), as.numeric(window),
-        as.numeric(niter),
-        as.numeric(agebins), as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)), 
-        PACKAGE="igraph")
-}
-
-revolver.error.air <- function(graph, kernel, cats, window) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  kernel <- structure(as.numeric(kernel), dim=dim(kernel))
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_error2_air", graph, kernel, as.numeric(cats),
-        as.numeric(window),
-        PACKAGE="igraph")
-}
-
-revolver.d.d <- function(graph, vtime=V(graph)$time, etime=E(graph)$time, niter=5,
-                         sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                         error=TRUE, debug=matrix(ncol=2, nrow=0)) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-
-  if (is.null(vtime)) {
-    stop("vtime missing")
-  }
-  if (is.null(etime)) {
-    stop("etime missing")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_d_d", graph, as.numeric(niter),
-        as.numeric(vtime), as.numeric(etime), 
-        as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)), 
-        PACKAGE="igraph")
-}
-
-revolver.p.p <- function(graph, events=get.graph.attribute(graph, "events"),
-                         vtime=V(graph)$time, etime=E(graph)$time,
-                         niter=5, sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-                         error=TRUE, debug=matrix(ncol=2, nrow=0)) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object!")
-  }
-  if (is.null(events) || !is.list(events)) {
-    stop("events missing or not a list")
-  }
-  if (is.null(vtime)) {
-    ## TODO: calculate from events
-    stop("vtime missing")
-  }
-  if (is.null(etime)) {
-    ## TODO: calculate from events
-    stop("etime missing")
-  }
-  
-  authors <- unlist(events)
-  eventsizes <- sapply(events, length)
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_revolver_p_p", graph, as.numeric(niter),
-        as.numeric(vtime), as.numeric(etime), as.numeric(authors),
-        as.numeric(eventsizes), as.logical(sd), as.logical(norm), as.logical(cites),
-        as.logical(expected), as.logical(error),
-        structure(as.numeric(debug), dim=dim(debug)), 
-        PACKAGE="igraph")
-}
diff --git a/R/rewire.R b/R/rewire.R
new file mode 100644
index 0000000..fe43af4
--- /dev/null
+++ b/R/rewire.R
@@ -0,0 +1,142 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+
+#' Rewiring edges of a graph
+#'
+#' See the links below for the implemented rewiring methods.
+#'
+#' @param graph The graph to rewire
+#' @param with A function call to one of the rewiring methods,
+#'   see details below.
+#' @return The rewired graph.
+#'
+#' @family rewiring functions
+#' @export rewire
+#' @examples
+#' g <- make_ring(10)
+#' g %>%
+#'   rewire(each_edge(p = .1, loops = FALSE)) %>%
+#'   plot(layout=layout_in_circle)
+#' str(rewire(g, with = keeping_degseq(niter = vcount(g) * 10)))
+
+rewire <- function(graph, with) {
+  if (! is(with, "igraph_rewiring_method")) {
+    stop("'with' is not an igraph rewiring method")
+  }
+  do_call(with$fun, list(graph), .args = with$args)
+}
+
+#' Graph rewiring while preserving the degree distribution
+#'
+#' This function can be used together with \code{\link{rewire}} to
+#' randomly rewire the edges while preserving the original graph's degree
+#' distribution.
+#'
+#' The rewiring algorithm chooses two arbitrary edges in each step ((a,b)
+#' and (c,d)) and substitutes them with (a,d) and (c,b), if they not
+#' already exists in the graph. The algorithm does not create multiple
+#' edges.
+#'
+#' @param loops Whether to allow destroying and creating loop edges.
+#' @param niter Number of rewiring trials to perform.
+#'
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @family rewiring functions
+#' @seealso \code{\link{sample_degseq}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' g <- make_ring(10)
+#' g %>%
+#'   rewire(keeping_degseq(niter = 20)) %>%
+#'   degree()
+#' str(rewire(g, with = keeping_degseq(niter = vcount(g) * 10)))
+
+keeping_degseq <- function(loops = FALSE, niter = 100) {
+  method <- list(
+    fun = rewire_keeping_degseq,
+    args = list(loops = loops, niter = niter)
+  )
+  add_class(method, "igraph_rewiring_method")
+}
+
+rewire_keeping_degseq <- function(graph, loops, niter) {
+
+  if (!is_igraph(graph)) {
+    stop("Not a graph object")
+  }
+
+  loops <- as.logical(loops)
+  mode <- if (loops) 1 else 0
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  .Call("R_igraph_rewire", graph, as.numeric(niter), as.numeric(mode),
+        PACKAGE="igraph")
+}
+
+#' Rewires the endpoints of the edges of a graph to a random vertex
+#'
+#' This function can be used together with \code{\link{rewire}}.
+#' This method rewires the endpoints of the edges with a constant probability
+#' uniformly randomly to a new vertex in a graph.
+#'
+#' Note that this method might create graphs with multiple and/or loop edges.
+#'
+#' @param prob The rewiring probability, a real number between zero and one.
+#' @param loops Logical scalar, whether loop edges are allowed in the rewired
+#'   graph.
+#' @param multiple Logical scalar, whether multiple edges are allowed int the
+#'   generated graph.
+#'
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @family rewiring functions
+#' @export
+#' @keywords graphs
+#' @examples
+#'
+#' # Some random shortcuts shorten the distances on a lattice
+#' g <- make_lattice(length = 100, dim = 1, nei = 5)
+#' mean_distance(g)
+#' g <- rewire(g, each_edge(prob = 0.05))
+#' mean_distance(g)
+
+each_edge <- function(prob, loops = FALSE, multiple = FALSE) {
+  method <- list(
+    fun = rewire_each_edge,
+    args = list(prob = prob, loops = loops, multiple = multiple)
+  )
+  add_class(method, "igraph_rewiring_method")
+}
+
+rewire_each_edge <- function(graph, prob, loops=FALSE, multiple=FALSE) {
+  if (!is_igraph(graph)) {
+    stop("Not a graph object")
+  }
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  .Call("R_igraph_rewire_edges", graph, as.numeric(prob), as.logical(loops),
+        as.logical(multiple),
+        PACKAGE="igraph")
+}
diff --git a/R/scan.R b/R/scan.R
new file mode 100644
index 0000000..eb121b3
--- /dev/null
+++ b/R/scan.R
@@ -0,0 +1,424 @@
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' Compute local scan statistics on graphs
+#'
+#' The scan statistic is a summary of the locality statistics that is
+#' computed from the local neighborhood of each vertex. The
+#' \code{local_scan} function computes the local statistics for each vertex
+#' for a given neighborhood size and the statistic function.
+#'
+#' See the given reference below for the details on the local scan
+#' statistics.
+#'
+#' \code{local_scan} calculates exact local scan statistics.
+#'
+#' If \code{graph.them} is \code{NULL}, then \code{local_scan} computes the
+#' \sQuote{us} variant of the scan statistics.  Otherwise,
+#' \code{graph.them} should be an igraph object and the \sQuote{them}
+#' variant is computed using \code{graph.us} to extract the neighborhood
+#' information, and applying \code{FUN} on these neighborhoods in
+#' \code{graph.them}.
+#'
+#' @param graph.us,graph An igraph object, the graph for which the scan
+#'   statistics will be computed
+#' @param graph.them An igraph object or \code{NULL}, if not \code{NULL},
+#'   then the \sQuote{them} statistics is computed, i.e. the neighborhoods
+#'   calculated from \code{graph.us} are evaluated on \code{graph.them}.
+#' @param k An integer scalar, the size of the local neighborhood for each
+#'   vertex. Should be non-negative.
+#' @param FUN Character, a function name, or a function object itself, for
+#'   computing the local statistic in each neighborhood. If \code{NULL}(the
+#'   default value), \code{ecount} is used for unweighted graphs (if
+#'   \code{weighted=FALSE}) and a function that computes the sum of edge
+#'   weights is used for weighted graphs (if \code{weighted=TRUE}). This
+#'   argument is ignored if \code{k} is zero.
+#' @param weighted Logical scalar, TRUE if the edge weights should be used
+#'   for computation of the scan statistic. If TRUE, the graph should be
+#'   weighted.  Note that this argument is ignored if \code{FUN} is not
+#'   \code{NULL}, \code{"ecount"} and \code{"sumweights"}.
+#' @param mode Character scalar, the kind of neighborhoods to use for the
+#'   calculation. One of \sQuote{\code{out}}, \sQuote{\code{in}},
+#'   \sQuote{\code{all}} or \sQuote{\code{total}}. This argument is ignored
+#'   for undirected graphs.
+#' @param neighborhoods A list of neighborhoods, one for each vertex, or
+#'   \code{NULL}. If it is not \code{NULL}, then the function is evaluated on
+#'   the induced subgraphs specified by these neighborhoods.
+#'
+#'   In theory this could be useful if the same \code{graph.us} graph is used
+#'   for multiple \code{graph.them} arguments. Then the neighborhoods can be
+#'   calculated on \code{graph.us} and used with multiple graphs. In
+#'   practice, this is currently slower than simply using \code{graph.them}
+#'   multiple times.
+#' @param \dots Arguments passed to \code{FUN}, the function that computes
+#'   the local statistics.
+#' @return For \code{local_scan} typically a numeric vector containing the
+#'   computed local statistics for each vertex. In general a list or vector
+#'   of objects, as returned by \code{FUN}.
+#'
+#' @references Priebe, C. E., Conroy, J. M., Marchette, D. J., Park,
+#'   Y. (2005).  Scan Statistics on Enron Graphs. \emph{Computational and
+#'   Mathematical Organization Theory}.
+#'
+#' @family scan statistics
+#' @export
+#' @examples
+#' pair <- sample_correlated_gnp_pair(n = 10^3, corr = 0.8, p = 0.1)
+#' local_0_us <- local_scan(graph.us = pair$graph1, k = 0)
+#' local_1_us <- local_scan(graph.us = pair$graph1, k = 1)
+#'
+#' local_0_them <- local_scan(graph.us = pair$graph1,
+#'                            graph.them = pair$graph2, k = 0)
+#' local_1_them <- local_scan(graph.us = pair$graph1,
+#'                            graph.them = pair$graph2, k = 1)
+#'
+#' Neigh_1 <- neighborhood(pair$graph1, order = 1)
+#' local_1_them_nhood <- local_scan(graph.us = pair$graph1,
+#'                                  graph.them = pair$graph2,
+#'                                  neighborhoods = Neigh_1)
+
+local_scan <- function(graph.us, graph.them=NULL, k=1, FUN=NULL,
+                       weighted=FALSE, mode=c("out", "in", "all"),
+                       neighborhoods=NULL, ...) {
+
+  ## Must be igraph object
+  stopifnot(is.igraph(graph.us))
+
+  ## Must be NULL or igraph object
+  stopifnot(is.null(graph.them) || is.igraph(graph.them))
+
+  ## If given, number of vertices must match
+  stopifnot(is.null(graph.them) || vcount(graph.them) == vcount(graph.us))
+
+  ## k must be non-negative integer
+  stopifnot(length(k)==1, k >= 0, as.integer(k) == k)
+
+  ## Must be NULL or a function
+  stopifnot(is.null(FUN) || is.function(FUN) ||
+            (is.character(FUN) && length(FUN) == 1))
+
+  ## Logical scalar
+  stopifnot(is.logical(weighted), length(weighted )== 1)
+
+  ## If weighted, then the graph(s) must be weighted
+  stopifnot(!weighted || (is.weighted(graph.us) && (is.null(graph.them) ||
+                                                    is.weighted(graph.them))))
+
+  ## Check if 'neighborhoods' makes sense
+  if (!is.null(neighborhoods)) {
+    stopifnot(is.list(neighborhoods))
+    stopifnot(length(neighborhoods) == vcount(graph.us))
+  }
+  if (!is.null(neighborhoods) && k==0) {
+    warning("`neighborhoods' ignored for k=0")
+    neighborhoods <- NULL
+  }
+
+  ## Check mode argument
+  mode <- igraph.match.arg(mode)
+  cmode <- switch(mode, out = 1, `in` = 2, all = 3, total = 3)
+
+  sumweights <- function(g) sum(E(g)$weight)
+
+  if (is.null(FUN)) { FUN <- if (weighted) "sumweights" else "ecount" }
+
+  res <- if (is.null(graph.them)) {
+
+    if (!is.null(neighborhoods)) {
+      if (is.character(FUN) && FUN %in% c("ecount", "sumweights")) {
+        neighborhoods <- lapply(neighborhoods, function(x) {
+          as.integer(x)-1L
+        })
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_neighborhood_ecount", graph.us,
+              if (weighted) as.numeric(E(graph.us)$weight) else NULL,
+              neighborhoods, PACKAGE="igraph")
+      } else {
+        sapply(lapply(neighborhoods, induced.subgraph, graph=graph.us),
+               FUN, ...)
+      }
+    } else {
+      ## scan-0
+      if (k == 0) {
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_0", graph.us,
+              if (weighted) as.numeric(E(graph.us)$weight) else NULL, cmode,
+              PACKAGE="igraph")
+
+        ## scan-1, ecount
+      } else if (k==1 && is.character(FUN) &&
+                 FUN %in% c("ecount", "sumweights")) {
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_1_ecount", graph.us,
+              if (weighted) as.numeric(E(graph.us)$weight) else NULL, cmode,
+              PACKAGE="igraph")
+
+        ## scan-k, ecount
+      } else if (is.character(FUN) && FUN %in% c("ecount", "sumweights")) {
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_k_ecount", graph.us, as.integer(k),
+              if (weighted) as.numeric(E(graph.us)$weight) else NULL, cmode,
+              PACKAGE="igraph")
+
+        ## General
+      } else {
+        sapply(graph.neighborhood(graph.us, order=k, V(graph.us), mode=mode),
+               FUN, ...)
+      }
+    }
+    
+  } else {
+
+    if (!is.null(neighborhoods)) {
+      neighborhoods <- lapply(neighborhoods, as.vector)
+      if (is.character(FUN) && FUN %in% c("ecount", "wumweights")) {
+        neighborhoods <- lapply(neighborhoods, function(x) {
+          as.integer(x)-1L
+        })
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_neighborhood_ecount", graph.them,
+              if (weighted) as.numeric(E(graph.them)$weight) else NULL,
+              neighborhoods, PACKAGE="igraph")
+      } else {
+        sapply(lapply(neighborhoods, induced.subgraph, graph=graph.them),
+               FUN, ...)
+      }
+    } else {
+
+      ## scan-0
+      if (k == 0) {
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_0_them", graph.us, graph.them,
+              if (weighted) as.numeric(E(graph.them)$weight) else NULL,
+              cmode, PACKAGE="igraph")
+
+        ## scan-1, ecount
+      } else if (k==1 && is.character(FUN) &&
+                 FUN %in% c("ecount", "sumweights")) {
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_1_ecount_them", graph.us, graph.them,
+              if (weighted) as.numeric(E(graph.them)$weight) else NULL,
+              cmode, PACKAGE="igraph")
+
+        ## scan-k, ecount
+      } else if (is.character(FUN) && FUN %in% c("ecount", "sumweights")) {
+        on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+        .Call("R_igraph_local_scan_k_ecount_them", graph.us, graph.them,
+              as.integer(k),
+              if (weighted) as.numeric(E(graph.them)$weight) else NULL,
+              cmode, PACKAGE="igraph")
+
+        ## general case
+      } else {
+        sapply(V(graph.us), function(x) {
+          vei <- neighborhood(graph.us, order=k, nodes=x, mode=mode)[[1]]
+          if (!is.function(FUN)) { FUN <- getFunction(FUN, where=environment()) }
+          FUN(induced.subgraph(graph.them, vei), ...)
+        })
+      }
+    }
+  }
+
+  res <- as.numeric(res)
+
+  if (igraph_opt("add.vertex.names") && is_named(graph.us)) {
+    names(res) <- V(graph.us)$name
+  }
+
+  res
+}
+
+
+#' Scan statistics on a time series of graphs
+#'
+#' Calculate scan statistics on a time series of graphs.
+#' This is done by calculating the local scan statistics for
+#' each graph and each vertex, and then normalizing across the
+#' vertices and across the time steps.
+#'
+#' @param graphs A list of igraph graph objects. They must be all directed
+#'   or all undirected and they must have the same number of vertices.
+#' @param tau The number of previous time steps to consider for the
+#'   time-dependent normalization for individual vertices.  In other words,
+#'   the current locality statistics of each vertex will be compared to this
+#'   many previous time steps of the same vertex to decide whether it is
+#'   significantly larger.
+#' @param ell The number of previous time steps to consider
+#'   for the aggregated scan statistics. This is essentially a smoothing
+#'   parameter.
+#' @param locality Whether to calculate the \sQuote{us} or \sQuote{them}
+#'   statistics.
+#' @param ... Extra arguments are passed to \code{\link{local_scan}}.
+#' @return A list with entries:
+#'   \item{stat}{The scan statistics in each time step. It is \code{NA}
+#'     for the initial \code{tau + ell} time steps.}
+#'   \item{arg_max_v}{The (numeric) vertex ids for the vertex with
+#'     the largest locality statistics, at each time step. It is \code{NA}
+#'     for the initial \code{tau + ell} time steps.}
+#'
+#' @family scan statistics
+#' @export
+#' @examples
+#' ## Generate a bunch of SBMs, with the last one being different
+#' num_t <- 20
+#' block_sizes <- c(10, 5, 5)
+#' p_ij <- list(p = 0.1, h = 0.9, q = 0.9)
+#'
+#' P0 <- matrix(p_ij$p, 3, 3)
+#' P0[2, 2] <- p_ij$h
+#' PA <- P0
+#' PA[3, 3] <- p_ij$q
+#' num_v <- sum(block_sizes)
+#'
+#' tsg <- replicate(num_t - 1, P0, simplify = FALSE) %>%
+#'   append(list(PA)) %>%
+#'   lapply(sample_sbm, n = num_v, block.sizes = block_sizes, directed = TRUE)
+#'
+#' scan_stat(graphs = tsg, k = 1, tau = 4, ell = 2)
+#' scan_stat(graphs = tsg, locality = "them", k = 1, tau = 4, ell = 2)
+
+scan_stat <- function(graphs, tau = 1, ell = 0,
+                      locality = c("us", "them"), ...) {
+
+  ## List of igraph graphs, all have same directedness and
+  ## weightedness
+  stopifnot(is.list(graphs),
+            length(graphs) > 0,
+            all(sapply(graphs, is_igraph)),
+            length(unique(sapply(graphs, is_directed))) == 1,
+            length(unique(sapply(graphs, gorder))) == 1)
+
+  ## tau must the a non-negative integer
+  stopifnot(length(tau) == 1, tau >= 0, as.integer(tau) == tau)
+
+  ## ell must the a non-negative integer
+  stopifnot(length(ell) == 1, ell >= 0, as.integer(ell) == ell)
+
+  locality <- igraph.match.arg(locality)
+
+  ## number of time steps and number of vertices
+  maxTime = length(graphs)
+  nVertex = vcount(graphs[[1]])
+
+  if (locality == 'us') {
+    ## Underlying locality stat is us
+    lstatPsi <- matrix(0, nrow = nVertex , ncol = maxTime)
+    for (i in 1:maxTime) {
+      ## locality statistics \Psi over all vertices at t=i
+      lstatPsi[,i] <- local_scan(graphs[[i]], ...)
+    }
+    lstat <- lstatPsi
+
+  } else if (locality == 'them') {
+    ## Underlying locality stat is \Phi
+
+    lstatPhi <- array(0, dim = c(nVertex, (tau + 1), maxTime))
+    for (i in 1:maxTime) {
+      if (i > tau) {
+        ## graph to trace k-th order neighborhood
+        g <- graphs[[i]]
+        for (j in 0:tau) {
+          ## locality statistics \Phi over all vertices with t=i and t'=i-tau+j
+          lstatPhi[, (j + 1), i] <- local_scan(
+            graph.us = graphs[[i]],
+            graph.them= graphs[[i - tau + j]],
+            ...
+          )
+        }
+      }
+    }
+    lstat <- lstatPhi
+  }
+
+  ## vertex-dependent and temporal normalization
+  scan_temp_norm(
+    scan_vertex_norm(lstat, tau),
+    tau,
+    ell
+  )
+}
+
+scan_vertex_norm <-function (input_stat, tau) {
+  if (is.matrix(input_stat)) {
+    n <- nrow(input_stat)
+    nbins <- ncol(input_stat)
+    nstat <- matrix(0, n, nbins)
+    for (i in 1:nbins) {
+      if (i > tau) {
+        if (tau == 0) {
+          nstat[,i] <- input_stat[, i]
+        } else {
+          muv <- apply(as.matrix(input_stat[, (i - tau):(i-1)]), 1, mean)
+          sdv <- apply(as.matrix(input_stat[, (i - tau):(i-1)]), 1, sd)
+          sdv[is.na(sdv)] <- 1
+          nstat[, i] <- (input_stat[, i] - muv) / pmax(sdv, 1)
+        }
+      }
+    }
+  } else {
+    dd <- dim(input_stat)
+    n <- dd[1]
+    nbins <- dd[3]
+    nstat <- matrix(0, n, nbins)
+    for (i in 1:nbins) {
+      if (i > tau) {
+        if (tau == 0) {
+          nstat[, i] <- input_stat[, (tau + 1), i]
+        } else {
+          muv <- apply(as.matrix(input_stat[, (1 : tau), i]), 1, mean)
+          sdv <- apply(as.matrix(input_stat[, (1 : tau), i]), 1, sd)
+          sdv[is.na(sdv)] <- 1
+          nstat[, i] <- (input_stat[, (tau + 1),i] - muv) / pmax(sdv, 1)
+        }
+      }
+    }
+  }
+  return(nstat)
+}
+
+scan_temp_norm <- function (stat, tau, ell) {
+  maxTime <- ncol(stat)
+  Mtilde <- apply(stat, 2, max)
+  argmaxV <- apply(stat, 2, which.max)
+
+  if (ell == 0) {
+    res <- list(stat = Mtilde, arg_max_v = argmaxV)
+
+  } else if(ell ==1 ) {
+    res <- list(stat = Mtilde - c(NA, Mtilde[-maxTime]), arg_max_v = argmaxV)
+
+  } else {
+    muMtilde <- rep(0, maxTime)
+    sdMtilde <- rep(1, maxTime)
+    for (i in (ell + 1):maxTime) {
+      muMtilde[i] <- mean(Mtilde[(i - ell):(i - 1)])
+      sdMtilde[i] <- sd(Mtilde[(i - ell):(i - 1)])
+    }
+    sstat <- (Mtilde - muMtilde) / pmax(sdMtilde, 1)
+    res <- list(stat = sstat, arg_max_v = argmaxV)
+  }
+
+  res$stat[seq_len(tau + ell)] <- NA
+  res$arg_max_v[seq_len(tau + ell)] <- NA
+  res
+}
diff --git a/R/scg.R b/R/scg.R
index 6fd2d7d..e8cac35 100644
--- a/R/scg.R
+++ b/R/scg.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,9 +19,92 @@
 #
 ###################################################################
 
-get.stochastic <- function(graph, column.wise=FALSE,
-                           sparse=getIgraphOpt("sparsematrices")) {
-  if (!is.igraph(graph)) {
+
+#' Spectral Coarse Graining
+#' 
+#' Functions to perform the Spectral Coarse Graining (SCG) of matrices and
+#' graphs.
+#'
+#' @name scg-method
+#' @section Introduction: The SCG functions provide a framework, called
+#' Spectral Coarse Graining (SCG), for reducing large graphs while preserving
+#' their \emph{spectral-related features}, that is features closely related
+#' with the eigenvalues and eigenvectors of a graph matrix (which for now can
+#' be the adjacency, the stochastic, or the Laplacian matrix).
+#' 
+#' Common examples of such features comprise the first-passage-time of random
+#' walkers on Markovian graphs, thermodynamic properties of lattice models in
+#' statistical physics (e.g. Ising model), and the epidemic threshold of
+#' epidemic network models (SIR and SIS models).
+#' 
+#' SCG differs from traditional clustering schemes by producing a
+#' \emph{coarse-grained graph} (not just a partition of the vertices),
+#' representative of the original one. As shown in [1], Principal Component
+#' Analysis can be viewed as a particular SCG, called \emph{exact SCG}, where
+#' the matrix to be coarse-grained is the covariance matrix of some data set.
+#' 
+#' SCG should be of interest to practitioners of various fields dealing with
+#' problems where matrix eigenpairs play an important role, as for instance is
+#' the case of dynamical processes on networks.
+#' @author David Morton de Lachapelle,
+#' \url{http://people.epfl.ch/david.morton}.
+#' @references D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+#' Shrinking Matrices while Preserving their Eigenpairs with Application to the
+#' Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+#' Matrix Analysis and Applications}, 2008.
+#' \url{http://people.epfl.ch/david.morton}
+#' 
+#' D. Gfeller, and P. De Los Rios, Spectral Coarse Graining and Synchronization
+#' in Oscillator Networks. \emph{Physical Review Letters}, \bold{100}(17),
+#' 2008.  \url{http://arxiv.org/abs/0708.2055}
+#' 
+#' D. Gfeller, and P. De Los Rios, Spectral Coarse Graining of Complex
+#' Networks, \emph{Physical Review Letters}, \bold{99}(3), 2007.
+#' \url{http://arxiv.org/abs/0706.0812}
+#' @keywords graphs
+
+NULL
+
+#' Stochastic matrix of a graph
+#' 
+#' Retrieves the stochastic matrix of a graph of class \code{igraph}.
+#' 
+#' Let \eqn{M} be an \eqn{n \times n}{n x n} adjacency matrix with real
+#' non-negative entries. Let us define \eqn{D = \textrm{diag}(\sum_{i}M_{1i},
+#' \dots, \sum_{i}M_{ni})}{D=diag( sum(M[1,i], i), ..., sum(M[n,i], i) )}
+#' 
+#' The (row) stochastic matrix is defined as \deqn{W = D^{-1}M,}{W = inv(D) M,}
+#' where it is assumed that \eqn{D} is non-singular.  Column stochastic
+#' matrices are defined in a symmetric way.
+#'
+#' @aliases get.stochastic
+#' @param graph The input graph. Must be of class \code{igraph}.
+#' @param column.wise If \code{FALSE}, then the rows of the stochastic matrix
+#' sum up to one; otherwise it is the columns.
+#' @param sparse Logical scalar, whether to return a sparse matrix. The
+#' \code{Matrix} package is needed for sparse matrices.
+#' @return A regular matrix or a matrix of class \code{Matrix} if a
+#' \code{sparse} argument was \code{TRUE}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{as_adj}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' library(Matrix)
+#' ## g is a large sparse graph
+#' g <- barabasi.game(n = 10^5, power = 2, directed = FALSE)
+#' W <- stochastic_matrix(g, sparse=TRUE)
+#' 
+#' ## a dense matrix here would probably not fit in the memory
+#' class(W)
+#' 
+#' ## may not be exactly 1, due to numerical errors
+#' max(abs(rowSums(W))-1)
+#' 
+stochastic_matrix <- function(graph, column.wise=FALSE,
+                           sparse=igraph_opt("sparsematrices")) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
  
@@ -46,14 +128,126 @@ get.stochastic <- function(graph, column.wise=FALSE,
                  PACKAGE="igraph")
   }
 
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     rownames(res) <- colnames(res) <- V(graph)$name
   }
 
   res
 } 
 
-scgGrouping <- function(V, nt,
+
+
+#' SCG Problem Solver
+#' 
+#' This function solves the Spectral Coarse Graining (SCG) problem; either
+#' exactly, or approximately but faster.
+#' 
+#' The algorithm \dQuote{optimum} solves exactly the SCG problem for each
+#' eigenvector in \code{V}. The running time of this algorithm is \eqn{O(\max
+#' nt \cdot m^2)}{O(max(nt) m^2)} for the symmetric and laplacian matrix
+#' problems (i.e. when \code{mtype} is \dQuote{symmetric} or
+#' \dQuote{laplacian}. It is \eqn{O(m^3)} for the stochastic problem. Here
+#' \eqn{m} is the number of rows in \code{V}.  In all three cases, the memory
+#' usage is \eqn{O(m^2)}.
+#' 
+#' The algorithms \dQuote{interv} and \dQuote{interv\_km} solve approximately
+#' the SCG problem by performing a (for now) constant binning of the components
+#' of the eigenvectors, that is \code{nt[i]} constant-size bins are used to
+#' partition \code{V[,i]}. When \code{algo} = \dQuote{interv\_km}, the (Lloyd)
+#' k-means algorithm is run on each partition obtained by \dQuote{interv} to
+#' improve accuracy.
+#' 
+#' Once a minimizing partition (either exact or approximate) has been found for
+#' each eigenvector, the final grouping is worked out as follows: two vertices
+#' are grouped together in the final partition if they are grouped together in
+#' each minimizing partition. In general the size of the final partition is not
+#' known in advance when \code{ncol(V)}>1.
+#' 
+#' Finally, the algorithm \dQuote{exact\_scg} groups the vertices with equal
+#' components in each eigenvector. The last three algorithms essentially have
+#' linear running time and memory load.
+#'
+#' @aliases scgGrouping
+#' @param V A numeric matrix of (eigen)vectors to be preserved by the coarse
+#' graining (the vectors are to be stored column-wise in \code{V}).
+#' @param nt A vector of positive integers of length one or equal to
+#' \code{length(ev)}. When \code{algo} = \dQuote{optimum}, \code{nt} contains
+#' the number of groups used to partition each eigenvector separately. When
+#' \code{algo} is equal to \dQuote{interv\_km} or \dQuote{interv}, \code{nt}
+#' contains the number of intervals used to partition each eigenvector. The
+#' same partition size or number of intervals is used for each eigenvector if
+#' \code{nt} is a single integer. When \code{algo} = \dQuote{exact\_cg} this
+#' parameter is ignored.
+#' @param mtype The type of semi-projectors used in the SCG. For now
+#' \dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic} are
+#' available.
+#' @param algo The algorithm used to solve the SCG problem. Possible values are
+#' \dQuote{optimum}, \dQuote{interv\_km}, \dQuote{interv} and
+#' \dQuote{exact\_scg}.
+#' @param p A probability vector of length equal to \code{nrow(V)}. \code{p} is
+#' the stationary probability distribution of a Markov chain when \code{mtype}
+#' = \dQuote{stochastic}. This parameter is ignored in all other cases.
+#' @param maxiter A positive integer giving the maximum number of iterations of
+#' the k-means algorithm when \code{algo} = \dQuote{interv\_km}. This parameter
+#' is ignored in all other cases.
+#' @return A vector of \code{nrow(V)} integers giving the group label of each
+#' object (vertex) in the partition.
+#' @author David Morton de Lachapelle \email{david.morton@@epfl.ch},
+#' \email{david.mortondelachapelle@@swissquote.ch}
+#' @seealso \link{scg-method} for a detailed introduction. \code{\link{scg}},
+#' \code{\link{scg_eps}}
+#' @references D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+#' Shrinking Matrices while Preserving their Eigenpairs with Application to the
+#' Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+#' Matrix Analysis and Applications}, 2008.
+#' \url{http://people.epfl.ch/david.morton}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' 
+#' ## We are not running these examples any more, because they
+#' ## take a long time to run and this is against the CRAN repository
+#' ## policy. Copy and paste them by hand to your R prompt if
+#' ## you want to run them.
+#' 
+#' \dontrun{
+#' # eigenvectors of a random symmetric matrix
+#' M <- matrix(rexp(10^6), 10^3, 10^3)
+#' M <- (M + t(M))/2
+#' V <- eigen(M, symmetric=TRUE)$vectors[,c(1,2)]
+#' 
+#' # displays size of the groups in the final partition
+#' gr <- scg_group(V, nt=c(2,3))
+#' col <- rainbow(max(gr))
+#' plot(table(gr), col=col, main="Group size", xlab="group", ylab="size")
+#' 
+#' ## comparison with the grouping obtained by kmeans
+#' ## for a partition of same size
+#' gr.km <- kmeans(V,centers=max(gr), iter.max=100, nstart=100)$cluster
+#' op <- par(mfrow=c(1,2))
+#' plot(V[,1], V[,2], col=col[gr],
+#' 	main = "SCG grouping",
+#' 	xlab = "1st eigenvector",
+#' 	ylab = "2nd eigenvector")
+#' plot(V[,1], V[,2], col=col[gr.km],
+#' 	main = "K-means grouping",
+#' 	xlab = "1st eigenvector",
+#' 	ylab = "2nd eigenvector")
+#' par(op)
+#' ## kmeans disregards the first eigenvector as it
+#' ## spreads a much smaller range of values than the second one
+#' 
+#' ### comparing optimal and k-means solutions
+#' ### in the one-dimensional case.
+#' x <- rexp(2000, 2)
+#' gr.true <- scg_group(cbind(x), 100)
+#' gr.km <- kmeans(x, 100, 100, 300)$cluster
+#' scg_eps(cbind(x), gr.true)
+#' scg_eps(cbind(x), gr.km)
+#' }
+#' 
+scg_group <- function(V, nt,
                          mtype=c("symmetric", "laplacian",
                            "stochastic"),
                          algo=c("optimum", "interv_km", "interv",
@@ -79,11 +273,91 @@ scgGrouping <- function(V, nt,
   res
 }
 
-scgSemiProjectors <- function(groups,
+
+
+#' Semi-Projectors
+#' 
+#' A function to compute the \eqn{L} and \eqn{R} semi-projectors for a given
+#' partition of the vertices.
+#' 
+#' The three types of semi-projectors are defined as follows.  Let
+#' \eqn{\gamma(j)}{gamma(j)} label the group of vertex \eqn{j} in a partition
+#' of all the vertices.
+#' 
+#' The symmetric semi-projectors are defined as \deqn{L_{\alpha j}=R_{\alpha
+#' j}= }{% L[alpha,j] = R[alpha,j] = 1/sqrt(|alpha|)
+#' delta[alpha,gamma(j)],}\deqn{
+#' \frac{1}{\sqrt{|\alpha|}}\delta_{\alpha\gamma(j)},}{% L[alpha,j] =
+#' R[alpha,j] = 1/sqrt(|alpha|) delta[alpha,gamma(j)],} the (row) Laplacian
+#' semi-projectors as \deqn{L_{\alpha
+#' j}=\frac{1}{|\alpha|}\delta_{\alpha\gamma(j)}\,\,\,\, }{% L[alpha,j] =
+#' 1/|alpha| delta[alpha,gamma(j)] and R[alpha,j] =
+#' delta[alpha,gamma(j)],}\deqn{ \textrm{and}\,\,\,\, R_{\alpha
+#' j}=\delta_{\alpha\gamma(j)},}{% L[alpha,j] = 1/|alpha| delta[alpha,gamma(j)]
+#' and R[alpha,j] = delta[alpha,gamma(j)],} and the (row) stochastic
+#' semi-projectors as \deqn{L_{\alpha
+#' j}=\frac{p_{1}(j)}{\sum_{k\in\gamma(j)}p_{1}(k)}\,\,\,\, }{% L[alpha,j] =
+#' p[1][j] / sum(p[1][k]; k in gamma(j)) delta[alpha,gamma(j)] and R[alpha,j] =
+#' delta[alpha,gamma(j)],}\deqn{ \textrm{and}\,\,\,\, R_{\alpha
+#' j}=\delta_{\alpha\gamma(j)\delta_{\alpha\gamma(j)}},}{% L[alpha,j] = p[1][j]
+#' / sum(p[1][k]; k in gamma(j)) delta[alpha,gamma(j)] and R[alpha,j] =
+#' delta[alpha,gamma(j)],} where \eqn{p_1}{p[1]} is the (left) eigenvector
+#' associated with the one-eigenvalue of the stochastic matrix. \eqn{L} and
+#' \eqn{R} are defined in a symmetric way when \code{norm = col}. All these
+#' semi-projectors verify various properties described in the reference.
+#'
+#' @aliases scgSemiProjectors
+#' @param groups A vector of \code{nrow(X)} or \code{vcount(X)} integers giving
+#' the group label of every vertex in the partition.
+#' @param mtype The type of semi-projectors. For now \dQuote{symmetric},
+#' \dQuote{laplacian} and \dQuote{stochastic} are available.
+#' @param p A probability vector of length \code{length(gr)}. \code{p} is the
+#' stationary probability distribution of a Markov chain when \code{mtype} =
+#' \dQuote{stochastic}. This parameter is ignored in all other cases.
+#' @param norm Either \dQuote{row} or \dQuote{col}. If set to \dQuote{row} the
+#' rows of the Laplacian matrix sum up to zero and the rows of the stochastic
+#' sum up to one; otherwise it is the columns.
+#' @param sparse Logical scalar, whether to return sparse matrices.
+#' @return \item{L}{The semi-projector \eqn{L}.} \item{R}{The semi-projector
+#' \eqn{R}.}
+#' @author David Morton de Lachapelle,
+#' \url{http://people.epfl.ch/david.morton}.
+#' @seealso \link{scg-method} for a detailed introduction. \code{\link{scg}},
+#' \code{\link{scg_eps}}, \code{\link{scg_group}}
+#' @references D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+#' Shrinking Matrices while Preserving their Eigenpairs with Application to the
+#' Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+#' Matrix Analysis and Applications}, 2008.
+#' \url{http://people.epfl.ch/david.morton}
+#' @export
+#' @examples
+#' 
+#' library(Matrix)
+#' # compute the semi-projectors and projector for the partition
+#' # provided by a community detection method
+#' g <- barabasi.game(20, m=1.5)
+#' eb <- cluster_edge_betweenness(g)
+#' memb <- membership(eb)
+#' lr <- scg_semi_proj(memb)
+#' #In the symmetric case L = R
+#' tcrossprod(lr$R)  # same as lr$R %*% t(lr$R)
+#' P <- crossprod(lr$R)  # same as t(lr$R) %*% lr$R
+#' #P is an orthogonal projector
+#' isSymmetric(P)
+#' sum( (P %*% P-P)^2 )
+#' 
+#' ## use L and R to coarse-grain the graph Laplacian
+#' lr <- scg_semi_proj(memb, mtype="laplacian")
+#' L <- laplacian_matrix(g)
+#' Lt <- lr$L %*% L %*% t(lr$R)
+#' ## or better lr$L %*% tcrossprod(L,lr$R)
+#' rowSums(Lt)
+#' 
+scg_semi_proj <- function(groups,
                                mtype=c("symmetric", "laplacian",
                                  "stochastic"), p=NULL,
                                norm=c("row", "col"),
-                               sparse=getIgraphOpt("sparsematrices")) {
+                               sparse=igraph_opt("sparsematrices")) {
   # Argument checks
   groups <- as.numeric(groups)-1
   mtype <- switch(igraph.match.arg(mtype), "symmetric"=1, 
@@ -106,24 +380,215 @@ scgSemiProjectors <- function(groups,
   res
 }
 
+
+
+#' All-in-one Function for the SCG of Matrices and Graphs
+#' 
+#' This function handles all the steps involved in the Spectral Coarse Graining
+#' (SCG) of some matrices and graphs as described in the reference below.
+#' 
+#' Please see \link{scg-method} for an introduction.
+#' 
+#' In the following \eqn{V} is the matrix of eigenvectors for which the SCG is
+#' solved. \eqn{V} is calculated from \code{X}, if it is not given in the
+#' \code{evec} argument.
+#' 
+#' The algorithm \dQuote{optimum} solves exactly the SCG problem for each
+#' eigenvector in \code{V}. The running time of this algorithm is \eqn{O(\max
+#' nt \cdot m^2)}{O(max(nt) m^2)} for the symmetric and laplacian matrix
+#' problems (i.e. when \code{mtype} is \dQuote{symmetric} or
+#' \dQuote{laplacian}. It is \eqn{O(m^3)} for the stochastic problem. Here
+#' \eqn{m} is the number of rows in \code{V}.  In all three cases, the memory
+#' usage is \eqn{O(m^2)}.
+#' 
+#' The algorithms \dQuote{interv} and \dQuote{interv\_km} solve approximately
+#' the SCG problem by performing a (for now) constant binning of the components
+#' of the eigenvectors, that is \code{nt[i]} constant-size bins are used to
+#' partition \code{V[,i]}. When \code{algo} = \dQuote{interv\_km}, the (Lloyd)
+#' k-means algorithm is run on each partition obtained by \dQuote{interv} to
+#' improve accuracy.
+#' 
+#' Once a minimizing partition (either exact or approximate) has been found for
+#' each eigenvector, the final grouping is worked out as follows: two vertices
+#' are grouped together in the final partition if they are grouped together in
+#' each minimizing partition. In general the size of the final partition is not
+#' known in advance when \code{ncol(V)}>1.
+#' 
+#' Finally, the algorithm \dQuote{exact\_scg} groups the vertices with equal
+#' components in each eigenvector. The last three algorithms essentially have
+#' linear running time and memory load.
+#' 
+#' @param X The input graph or square matrix. Can be of class \code{igraph},
+#' \code{matrix} or \code{Matrix}.
+#' @param ev A vector of positive integers giving the indexes of the eigenpairs
+#' to be preserved. For real eigenpairs, 1 designates the eigenvalue with
+#' largest algebraic value, 2 the one with second largest algebraic value, etc.
+#' In the complex case, it is the magnitude that matters.
+#' @param nt A vector of positive integers of length one or equal to
+#' \code{length(ev)}. When \code{algo} = \dQuote{optimum}, \code{nt} contains
+#' the number of groups used to partition each eigenvector separately. When
+#' \code{algo} is equal to \dQuote{interv\_km} or \dQuote{interv}, \code{nt}
+#' contains the number of intervals used to partition each eigenvector. The
+#' same partition size or number of intervals is used for each eigenvector if
+#' \code{nt} is a single integer. When \code{algo} = \dQuote{exact\_cg} this
+#' parameter is ignored.
+#' @param groups A vector of \code{nrow(X)} or \code{vcount(X)} integers
+#' labeling each group vertex in the partition. If this parameter is supplied
+#' most part of the function is bypassed.
+#' @param mtype Character scalar. The type of semi-projector to be used for the
+#' SCG. For now \dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic}
+#' are available.
+#' @param algo Character scalar. The algorithm used to solve the SCG problem.
+#' Possible values are \dQuote{optimum}, \dQuote{interv\_km}, \dQuote{interv}
+#' and \dQuote{exact\_scg}.
+#' @param norm Character scalar. Either \dQuote{row} or \dQuote{col}. If set to
+#' \dQuote{row} the rows of the Laplacian matrix sum up to zero and the rows of
+#' the stochastic matrix sum up to one; otherwise it is the columns.
+#' @param direction Character scalar. When set to \dQuote{right}, resp.
+#' \dQuote{left}, the parameters \code{ev} and \code{evec} refer to right,
+#' resp. left eigenvectors. When passed \dQuote{default} it is the SCG
+#' described in the reference below that is applied (common usage). This
+#' argument is currently not implemented, and right eigenvectors are always
+#' used.
+#' @param evec A numeric matrix of (eigen)vectors to be preserved by the coarse
+#' graining (the vectors are to be stored column-wise in \code{evec}). If
+#' supplied, the eigenvectors should correspond to the indexes in \code{ev} as
+#' no cross-check will be done.
+#' @param p A probability vector of length \code{nrow(X)} (or
+#' \code{vcount(X)}). \code{p} is the stationary probability distribution of a
+#' Markov chain when \code{mtype} = \dQuote{stochastic}. This parameter is
+#' ignored in all other cases.
+#' @param use.arpack Logical scalar. When set to \code{TRUE} uses the function
+#' \code{\link{arpack}} to compute eigenpairs. This parameter should be set to
+#' \code{TRUE} if one deals with large (over a few thousands) AND sparse graphs
+#' or matrices. This argument is not implemented currently and LAPACK is used
+#' for solving the eigenproblems.
+#' @param maxiter A positive integer giving the maximum number of iterations
+#' for the k-means algorithm when \code{algo} = \dQuote{interv\_km}. This
+#' parameter is ignored in all other cases.
+#' @param sparse Logical scalar. Whether to return sparse matrices in the
+#' result, if matrices are requested.
+#' @param output Character scalar. Set this parameter to \dQuote{default} to
+#' retrieve a coarse-grained object of the same class as \code{X}.
+#' @param semproj Logical scalar. Set this parameter to \code{TRUE} to retrieve
+#' the semi-projectors of the SCG.
+#' @param epairs Logical scalar. Set this to \code{TRUE} to collect the
+#' eigenpairs computed by \code{scg}.
+#' @param stat.prob Logical scalar. This is to collect the stationary
+#' probability \code{p} when dealing with stochastic matrices.
+#' @return \item{Xt}{The coarse-grained graph, or matrix, possibly a sparse
+#' matrix.} \item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)}
+#' integers giving the group label of each object (vertex) in the partition.}
+#' \item{L}{The semi-projector \eqn{L} if \code{semproj = TRUE}.} \item{R}{The
+#' semi-projector \eqn{R} if \code{semproj = TRUE}.} \item{values}{The computed
+#' eigenvalues if \code{epairs = TRUE}.} \item{vectors}{The computed or
+#' supplied eigenvectors if \code{epairs = TRUE}.} \item{p}{The stationary
+#' probability vector if \code{mtype = stochastic} and \code{stat.prob = TRUE}.
+#' For other matrix types this is missing.}
+#' @author David Morton de Lachapelle,
+#' \url{http://people.epfl.ch/david.morton}.
+#' @seealso \link{scg-method} for an introduction.  \code{\link{scg_eps}},
+#' \code{\link{scg_group}} and \code{\link{scg_semi_proj}}.
+#' @references D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+#' Shrinking Matrices while Preserving their Eigenpairs with Application to the
+#' Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+#' Matrix Analysis and Applications}, 2008.
+#' \url{http://people.epfl.ch/david.morton}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' 
+#' ## We are not running these examples any more, because they
+#' ## take a long time (~20 seconds) to run and this is against the CRAN
+#' ## repository policy. Copy and paste them by hand to your R prompt if
+#' ## you want to run them.
+#' 
+#' \dontrun{
+#' # SCG of a toy network
+#' g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+#' g <- add_edges(g, c(1,6, 1,11, 6, 11))
+#' cg <- scg(g, 1, 3, algo="exact_scg")
+#' 
+#' #plot the result
+#' layout <- layout_with_kk(g)
+#' nt <- vcount(cg$Xt)
+#' col <- rainbow(nt)
+#' vsize <- table(cg$groups)
+#' ewidth <- round(E(cg$Xt)$weight,2)
+#' 
+#' op <- par(mfrow=c(1,2))
+#' plot(g, vertex.color = col[cg$groups], vertex.size = 20,
+#' 		vertex.label = NA, layout = layout)
+#' plot(cg$Xt, edge.width = ewidth, edge.label = ewidth, 
+#' 	vertex.color = col, vertex.size = 20*vsize/max(vsize),
+#' 	vertex.label=NA, layout = layout_with_kk)
+#' par(op)
+#' 
+#' ## SCG of real-world network
+#' library(igraphdata)
+#' data(immuno)
+#' summary(immuno)
+#' n <- vcount(immuno)
+#' interv <- c(100,100,50,25,12,6,3,2,2)
+#' cg <- scg(immuno, ev= n-(1:9), nt=interv, mtype="laplacian",
+#'                         algo="interv", epairs=TRUE)
+#' 
+#' ## are the eigenvalues well-preserved?
+#' gt <- cg$Xt
+#' nt <- vcount(gt)
+#' Lt <- laplacian_matrix(gt)
+#' evalt <- eigen(Lt, only.values=TRUE)$values[nt-(1:9)]
+#' res <- cbind(interv, cg$values, evalt)
+#' res <- round(res,5)
+#' colnames(res) <- c("interv","lambda_i","lambda_tilde_i")
+#' rownames(res) <- c("N-1","N-2","N-3","N-4","N-5","N-6","N-7","N-8","N-9")
+#' print(res)
+#' 
+#' ## use SCG to get the communities
+#' com <- scg(laplacian_matrix(immuno), ev=n-c(1,2), nt=2)$groups
+#' col <- rainbow(max(com))
+#' layout <- layout_nicely(immuno)
+#' 
+#' plot(immuno, layout=layout, vertex.size=3, vertex.color=col[com],
+#'                 vertex.label=NA)
+#' 
+#' ## display the coarse-grained graph
+#' gt <- simplify(as.undirected(gt))
+#' layout.cg <- layout_with_kk(gt)
+#' com.cg <- scg(laplacian_matrix(gt), nt-c(1,2), 2)$groups
+#' vsize <- sqrt(as.vector(table(cg$groups)))
+#' 
+#' op <- par(mfrow=c(1,2))
+#' plot(immuno, layout=layout, vertex.size=3, vertex.color=col[com],
+#'                 vertex.label=NA)
+#' plot(gt, layout=layout.cg, vertex.size=15*vsize/max(vsize), 
+#'                 vertex.color=col[com.cg],vertex.label=NA)
+#' par(op)
+#' 
+#' }
+#' 
 scg <- function(X, ev, nt, groups=NULL, 
                 mtype=c("symmetric", "laplacian", "stochastic"),
                 algo=c("optimum", "interv_km", "interv",
                   "exact_scg"), norm=c("row", "col"),
                 direction=c("default", "left", "right"),
                 evec=NULL, p=NULL, use.arpack=FALSE, maxiter=300,
-                sparse=getIgraphOpt("sparsematrices"),
+                sparse=igraph_opt("sparsematrices"),
                 output=c("default", "matrix", "graph"), semproj=FALSE,
                 epairs=FALSE, stat.prob=FALSE)
   UseMethod("scg")
 
+#' @method scg igraph
+#' @export
+
 scg.igraph <- function(X, ev, nt, groups=NULL,
                        mtype=c("symmetric", "laplacian", "stochastic"),
                        algo=c("optimum", "interv_km", "interv",
                          "exact_scg"), norm=c("row", "col"),
                        direction=c("default", "left", "right"),
                        evec=NULL, p=NULL, use.arpack=FALSE, maxiter=300,
-                       sparse=getIgraphOpt("sparsematrices"),
+                       sparse=igraph_opt("sparsematrices"),
                        output=c("default", "matrix", "graph"), semproj=FALSE,
                        epairs=FALSE, stat.prob=FALSE) {
   
@@ -135,13 +600,16 @@ scg.igraph <- function(X, ev, nt, groups=NULL,
         stat.prob=stat.prob)
 }
 
+#' @method scg matrix
+#' @export
+
 scg.matrix <- function(X, ev, nt, groups=NULL,
                        mtype=c("symmetric", "laplacian", "stochastic"),
                        algo=c("optimum", "interv_km", "interv",
                          "exact_scg"), norm=c("row", "col"),
                        direction=c("default", "left", "right"),
                        evec=NULL, p=NULL, use.arpack=FALSE, maxiter=300,
-                       sparse=getIgraphOpt("sparsematrices"),
+                       sparse=igraph_opt("sparsematrices"),
                        output=c("default", "matrix", "graph"), semproj=FALSE,
                        epairs=FALSE, stat.prob=FALSE) {
   
@@ -153,13 +621,16 @@ scg.matrix <- function(X, ev, nt, groups=NULL,
         stat.prob=stat.prob)
 }
 
+#' @method scg Matrix
+#' @export
+
 scg.Matrix <- function(X, ev, nt, groups=NULL,
                        mtype=c("symmetric", "laplacian", "stochastic"),
                        algo=c("optimum", "interv_km", "interv",
                          "exact_scg"), norm=c("row", "col"),
                        direction=c("default", "left", "right"),
                        evec=NULL, p=NULL, use.arpack=FALSE, maxiter=300,
-                       sparse=getIgraphOpt("sparsematrices"),
+                       sparse=igraph_opt("sparsematrices"),
                        output=c("default", "matrix", "graph"), semproj=FALSE,
                        epairs=FALSE, stat.prob=FALSE) {
 
@@ -177,12 +648,12 @@ myscg <- function(graph, matrix, sparsemat, ev, nt, groups=NULL,
                     "exact_scg"), norm=c("row", "col"),
                   direction=c("default", "left", "right"),
                   evec=NULL, p=NULL, use.arpack=FALSE, maxiter=300,
-                  sparse=getIgraphOpt("sparsematrices"),
+                  sparse=igraph_opt("sparsematrices"),
                   output=c("default", "matrix", "graph"), semproj=FALSE,
                   epairs=FALSE, stat.prob=FALSE) {
 
   ## Argument checks
-  if (!is.null(graph))  { stopifnot(is.igraph(graph)) }
+  if (!is.null(graph))  { stopifnot(is_igraph(graph)) }
   if (!is.null(matrix)) { stopifnot(is.matrix(matrix)) }
   if (!is.null(sparsemat)) { stopifnot(inherits(sparsemat, "Matrix")) }
 
@@ -246,3 +717,43 @@ myscg <- function(graph, matrix, sparsemat, ev, nt, groups=NULL,
 
   res
 }
+
+
+#' Error of the spectral coarse graining (SCG) approximation
+#' 
+#' \code{scg_eps} computes \eqn{\Vert v_i-Pv_i\Vert}{|v[i]-Pv[i]|}, where
+#' \eqn{v_i}{v[i]} is the \eqn{i}th eigenvector in \code{V} and \eqn{P} is the
+#' projector corresponding to the \code{mtype} argument.
+#' 
+#' @aliases scg_eps scgNormEps
+#' @param V A numeric matrix of (eigen)vectors assumed normalized.  The vectors
+#' are to be stored column-wise in \code{V}).
+#' @param groups A vector of \code{nrow(V)} integers labeling each group vertex
+#' in the partition.
+#' @param mtype The type of semi-projector used for the SCG. For now
+#' \dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic} are
+#' available.
+#' @param p A probability vector of length \code{nrow(V)}.  \code{p} is the
+#' stationary probability distribution of a Markov chain when \code{mtype} =
+#' \dQuote{stochastic}. This parameter is ignored otherwise.
+#' @param norm Either \dQuote{row} or \dQuote{col}. If set to \dQuote{row} the
+#' rows of the Laplacian matrix sum to zero and the rows of the stochastic
+#' matrix sum to one; otherwise it is the columns.
+#' @return \code{scg_eps} returns with a numeric vector whose \eqn{i}th
+#' component is \eqn{\Vert v_i-Pv_i\Vert}{|v[i]-Pv[i]|} (see Details).
+#' @author David Morton de Lachapelle,
+#' \url{http://people.epfl.ch/david.morton}.
+#' @seealso \link{scg-method} and \code{\link{scg}}.
+#' @references D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+#' Shrinking Matrices while Preserving their Eigenpairs with Application to the
+#' Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+#' Matrix Analysis and Applications}, 2008.
+#' \url{http://people.epfl.ch/david.morton}
+#' @examples
+#' 
+#' v <- rexp(20)
+#' km <- kmeans(v,5)
+#' sum(km$withinss)
+#' scg_eps(cbind(v), km$cluster)^2
+
+scg_eps <- scg_eps
diff --git a/R/sgm.R b/R/sgm.R
new file mode 100644
index 0000000..ee11909
--- /dev/null
+++ b/R/sgm.R
@@ -0,0 +1,138 @@
+
+solve_LSAP <- function (x, maximum = FALSE) {
+  if (!is.matrix(x) || any(x < 0)) {
+    stop("x must be a matrix with nonnegative entries.")
+  }
+  nr <- nrow(x)
+  nc <- ncol(x)
+  if (nr > nc) stop("x must not have more rows than columns.")
+  if (nc > nr)  x <- rbind(x, matrix(2 * sum(x), nc - nr, nc))
+  if (maximum)  x <- max(x) - x
+  storage.mode(x) <- "double"
+  out <- .Call("R_igraph_solve_lsap", x, as.integer(nc),
+               PACKAGE = "igraph") + 1L
+  out[seq_len(nr)]
+}
+
+#' Match Graphs given a seeding of vertex correspondences
+#' 
+#' Given two adjacency matrices \code{A} and \code{B} of the same size, match
+#' the two graphs with the help of \code{m} seed vertex pairs which correspond
+#' to the first \code{m} rows (and columns) of the adjacency matrices.
+#' 
+#' The approximate graph matching problem is to find a bijection between the
+#' vertices of two graphs , such that the number of edge disagreements between
+#' the corresponding vertex pairs is minimized. For seeded graph matching, part
+#' of the bijection that consist of known correspondences (the seeds) is known
+#' and the problem task is to complete the bijection by estimating the
+#' permutation matrix that permutes the rows and columns of the adjacency
+#' matrix of the second graph.
+#' 
+#' It is assumed that for the two supplied adjacency matrices \code{A} and
+#' \code{B}, both of size \eqn{n\times n}{n*n}, the first \eqn{m} rows(and
+#' columns) of \code{A} and \code{B} correspond to the same vertices in both
+#' graphs. That is, the \eqn{n \times n}{n*n} permutation matrix that defines
+#' the bijection is \eqn{I_{m} \bigoplus P} for a \eqn{(n-m)\times
+#' (n-m)}{(n-m)*(n-m)} permutation matrix \eqn{P} and \eqn{m} times \eqn{m}
+#' identity matrix \eqn{I_{m}}. The function \code{match_vertices} estimates
+#' the permutation matrix \eqn{P} via an optimization algorithm based on the
+#' Frank-Wolfe algorithm.
+#' 
+#' See references for further details.
+#' 
+#' @aliases match_vertices seeded.graph.match
+#' @param A a numeric matrix, the adjacency matrix of the first graph
+#' @param B a numeric matrix, the adjacency matrix of the second graph
+#' @param m The number of seeds. The first \code{m} vertices of both graphs are
+#' matched.
+#' @param start a numeric matrix, the permutation matrix estimate is
+#' initialized with \code{start}
+#' @param iteration The number of iterations for the Frank-Wolfe algorithm
+#' @return A numeric matrix which is the permutation matrix that determines the
+#' bijection between the graphs of \code{A} and \code{B}
+#' @author Vince Lyzinski \url{http://www.ams.jhu.edu/~lyzinski/}
+#' @seealso
+#' \code{\link{sample_correlated_gnp}},\code{\link{sample_correlated_gnp_pair}}
+#' @references Vogelstein, J. T., Conroy, J. M., Podrazik, L. J., Kratzer, S.
+#' G., Harley, E. T., Fishkind, D. E.,Vogelstein, R. J., Priebe, C. E. (2011).
+#' Fast Approximate Quadratic Programming for Large (Brain) Graph Matching.
+#' Online: \url{http://arxiv.org/abs/1112.5507}
+#' 
+#' Fishkind, D. E., Adali, S., Priebe, C. E. (2012). Seeded Graph Matching
+#' Online: \url{http://arxiv.org/abs/1209.0367}
+#' @keywords graphs
+#' @examples
+#' 
+#'  #require(Matrix)
+#'  g1 <- erdos.renyi.game(10, .1)
+#'  randperm <- c(1:3, 3+sample(7))
+#'  g2 <- sample_correlated_gnp(g1, corr=1, p=g1$p, perm=randperm)
+#'  A  <- as.matrix(get.adjacency(g1))
+#'  B  <- as.matrix(get.adjacency(g2))
+#'  P  <-match_vertices (A, B, m=3, start=diag(rep(1, nrow(A)-3)), 20)
+#'  P
+#'  #' @export
+
+match_vertices <- function(A, B, m, start, iteration) {
+  ## Seeds are assumed to be vertices 1:m in both graphs
+  totv <- ncol(A)
+  n <- totv - m
+  if (m != 0) {
+    A12 <- A[1:m, (m+1):(m+n), drop=FALSE]
+    A21 <- A[(m+1):(m+n), 1:m, drop=FALSE]
+    B12 <- B[1:m, (m+1):(m+n), drop=FALSE]
+    B21 <- B[(m+1):(m+n), 1:m, drop=FALSE]
+  }
+  if ( m==0 ) {
+    A12 <- Matrix::Matrix(0, n, n)
+    A21 <- Matrix::Matrix(0, n, n)
+    B12 <- Matrix::Matrix(0, n, n)
+    B21 <- Matrix::Matrix(0, n, n)
+  }
+  A22 <- A[(m+1):(m+n), (m+1):(m+n)]
+  B22 <- B[(m+1):(m+n), (m+1):(m+n)]
+  patience <- iteration
+  tol <- 1
+  P <- start
+  toggle <- 1
+  iter <- 0
+  while (toggle == 1 & iter < patience)  {
+    iter <- iter+1
+    x <-  A21 %*% Matrix::t(B21)
+    y <-  Matrix::t(A12) %*% B12
+    z <-  A22 %*% P %*% Matrix::t(B22)
+    w <-  Matrix::t(A22) %*% P %*% B22
+    Grad <- x + y + z + w
+    ind <- unclass(solve_LSAP(as.matrix(Grad), maximum = TRUE))
+    ind2 <- cbind(1:n, ind)
+    T <- Matrix::Diagonal(n)
+    T <- T[ind, ]
+    wt <- Matrix::t(A22)[,order(ind)] %*% B22
+    c <- sum(w * P)
+    d <- sum(wt * P) + sum(w [ ind2 ])
+    e <- sum(wt[ind2])
+    u <- sum(P * (x + y))
+    v <- sum((x + y)[ind2])
+    if ( c-d+e == 0 && d-2*e+u-v == 0) {
+      alpha <- 0
+    } else {
+      alpha <- -(d-2*e+u-v) / (2*(c-d+e))}
+    f0 <- 0
+    f1 <-  c-e+u-v
+    falpha <- (c-d+e) * alpha^2 + (d-2*e+u-v) * alpha
+    if (alpha < tol && alpha > 0 && falpha > f0 && falpha > f1) {
+      P <-  alpha*P + (1-alpha) * T
+    } else if (f0 > f1) {
+      P <- T
+    } else {
+      toggle <- 0
+    }
+  }
+  D <- P
+  corr <- matrix(solve_LSAP(as.matrix(P),  maximum = TRUE))
+  P = Matrix::diag(n)
+  P = rbind(cbind(Matrix::diag(m), matrix(0, m, n)),
+    cbind(matrix(0, n, m), P[corr, ]))
+  corr <- cbind(matrix((m+1):totv,  n), matrix(m+corr, n))
+  list(corr=corr,  P=P,  D=D)
+}
diff --git a/R/similarity.R b/R/similarity.R
new file mode 100644
index 0000000..a348271
--- /dev/null
+++ b/R/similarity.R
@@ -0,0 +1,65 @@
+#' Similarity measures of two vertices
+#'
+#' These functions calculates similarity scores for vertices based on their
+#' connection patterns.
+#'
+#' @details
+#' The Jaccard similarity coefficient of two vertices is the number of common
+#' neighbors divided by the number of vertices that are neighbors of at least
+#' one of the two vertices being considered. The \code{jaccard} method
+#' calculates the pairwise Jaccard similarities for some (or all) of the
+#' vertices.
+#'
+#' The Dice similarity coefficient of two vertices is twice the number of
+#' common neighbors divided by the sum of the degrees of the vertices.
+#' Methof \code{dice} calculates the pairwise Dice similarities for some
+#' (or all) of the vertices.
+#'
+#' The inverse log-weighted similarity of two vertices is the number of their
+#' common neighbors, weighted by the inverse logarithm of their degrees.  It is
+#' based on the assumption that two vertices should be considered more similar
+#' if they share a low-degree common neighbor, since high-degree common
+#' neighbors are more likely to appear even by pure chance.  Isolated vertices
+#' will have zero similarity to any other vertex.  Self-similarities are not
+#' calculated.  See the following paper for more details: Lada A. Adamic and
+#' Eytan Adar: Friends and neighbors on the Web. Social Networks,
+#' 25(3):211-230, 2003.
+#'
+#' @aliases similarity.jaccard similarity.dice similarity.invlogweighted
+#' @param graph The input graph.
+#' @param vids The vertex ids for which the similarity is calculated.
+#' @param mode The type of neighboring vertices to use for the calculation,
+#'   possible values: \sQuote{\code{out}}, \sQuote{\code{in}},
+#'   \sQuote{\code{all}}.
+#' @param loops Whether to include vertices themselves in the neighbor
+#'   sets.
+#' @param method The method to use.
+#' @return A \code{length(vids)} by \code{length(vids)} numeric matrix
+#'   containing the similarity scores. This argument is ignored by the
+#'   \code{invlogweighted} method.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#'   \email{csardi.gabor@@gmail.com} for the manual page.
+#' @seealso \code{\link{cocitation}} and \code{\link{bibcoupling}}
+#' @references Lada A. Adamic and Eytan Adar: Friends and neighbors on the Web.
+#'   \emph{Social Networks}, 25(3):211-230, 2003.
+#' @keywords graphs
+#' @export
+#' @examples
+#'
+#' g <- make_ring(5)
+#' similarity(g, method = "dice")
+#' similarity(g, method = "jaccard")
+
+similarity <- function(graph, vids = V(graph), mode = c("all", "out", "in",
+                          "total"), loops = FALSE, method = c("jaccard",
+                          "dice", "invlogweighted")) {
+
+  method <- igraph.match.arg(method)
+  if (method == "jaccard") {
+    similarity.jaccard(graph, vids, mode, loops)
+  } else if (method == "dice") {
+    similarity.dice(graph, vids, mode, loops)
+  } else if (method == "invlogweighted") {
+    similarity.invlogweighted(graph, vids, mode)
+  }
+}
diff --git a/R/simple.R b/R/simple.R
new file mode 100644
index 0000000..489a420
--- /dev/null
+++ b/R/simple.R
@@ -0,0 +1,70 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' Simple graphs
+#' 
+#' Simple graphs are graphs which do not contain loop and multiple edges.
+#' 
+#' A loop edge is an edge for which the two endpoints are the same
+#' vertex. Two edges are multiple edges if they have exactly the same two
+#' endpoints (for directed graphs order does matter). A graph is simple is
+#' it does not contain loop edges and multiple edges.
+#' 
+#' \code{is_simple} checks whether a graph is simple.
+#' 
+#' \code{simplify} removes the loop and/or multiple edges from a graph.  If
+#' both \code{remove.loops} and \code{remove.multiple} are \code{TRUE} the
+#' function returns a simple graph.
+#' 
+#' @aliases simplify is.simple is_simple
+#' @param graph The graph to work on.
+#' @param remove.loops Logical, whether the loop edges are to be removed.
+#' @param remove.multiple Logical, whether the multiple edges are to be
+#' removed.
+#' @param edge.attr.comb Specifies what to do with edge attributes, if
+#' \code{remove.multiple=TRUE}. In this case many edges might be mapped to a
+#' single one in the new graph, and their attributes are combined. Please see
+#' \code{\link{attribute.combination}} for details on this.
+#' @return A new graph object with the edges deleted.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{which_loop}}, \code{\link{which_multiple}} and
+#' \code{\link{count_multiple}}, \code{\link{delete_edges}},
+#' \code{\link{delete_vertices}}
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- graph( c(1,2,1,2,3,3) )
+#' is_simple(g)
+#' is_simple(simplify(g, remove.loops=FALSE))
+#' is_simple(simplify(g, remove.multiple=FALSE))
+#' is_simple(simplify(g))
+#' @export
+#' @include auto.R
+
+simplify <- simplify
+
+#' @export
+#' @rdname simplify
+
+is_simple <- is_simple
diff --git a/R/sir.R b/R/sir.R
new file mode 100644
index 0000000..eaa4795
--- /dev/null
+++ b/R/sir.R
@@ -0,0 +1,103 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+#' SIR model on graphs
+#' 
+#' Run simulations for an SIR (susceptible-infected-recovered) model, on a
+#' graph
+#' 
+#' The SIR model is a simple model from epidemiology. The individuals of the
+#' population might be in three states: susceptible, infected and recovered.
+#' Recovered people are assumed to be immune to the disease. Susceptibles
+#' become infected with a rate that depends on their number of infected
+#' neigbors. Infected people become recovered with a constant rate.
+#' 
+#' The function \code{sir} simulates the model.
+#' 
+#' Function \code{time_bins} bins the simulation steps, using the
+#' Freedman-Diaconis heuristics to determine the bin width.
+#' 
+#' Function \code{median} and \code{quantile} calculate the median and
+#' quantiles of the results, respectively, in bins calculated with
+#' \code{time_bins}.
+#' 
+#' @aliases median.sir quantile.sir time_bins time_bins.sir sir
+#' @param graph The graph to run the model on. If directed, then edge
+#' directions are ignored and a warning is given.
+#' @param beta Non-negative scalar. The rate of infection of an individual that
+#' is susceptible and has a single infected neighbor. The infection rate of a
+#' susceptible individual with n infected neighbors is n times beta. Formally
+#' this is the rate parameter of an exponential distribution.
+#' @param gamma Positive scalar. The rate of recovery of an infected
+#' individual. Formally, this is the rate parameter of an exponential
+#' distribution.
+#' @param no.sim Integer scalar, the number simulation runs to perform.
+#' @param x A \code{sir} object, returned by the \code{sir} function.
+#' @param middle Logical scalar, whether to return the middle of the time bins,
+#' or the boundaries.
+#' @param na.rm Logical scalar, whether to ignore \code{NA} values.  \code{sir}
+#' objects do not contain any \code{NA} values currently, so this argument is
+#' effectively ignored.
+#' @param comp Character scalar. The component to calculate the quantile of.
+#' \code{NI} is infected agents, \code{NS} is susceptibles, \code{NR} stands
+#' for recovered.
+#' @param prob Numeric vector of probabilities, in [0,1], they specify the
+#' quantiles to calculate.
+#' @param \dots Additional arguments, ignored currently.
+#' @return For \code{sir} the results are returned in an object of class
+#' \sQuote{\code{sir}}, which is a list, with one element for each simulation.
+#' Each simulation is itself a list with the following elements. They are all
+#' numeric vectors, with equal length: \describe{
+#'   \item{times}{The times of the events.}
+#'   \item{NS}{The number of susceptibles in the population, over time.}
+#'   \item{NI}{The number of infected individuals in the population, over
+#'     time.}
+#'   \item{NR}{The number of recovered individuals in the population, over
+#'     time.}
+#' } 
+#' 
+#' Function \code{time_bins} returns a numeric vector, the middle or the
+#' boundaries of the time bins, depending on the \code{middle} argument.
+#' 
+#' \code{median} returns a list of three named numeric vectors, \code{NS},
+#' \code{NI} and \code{NR}. The names within the vectors are created from the
+#' time bins.
+#' 
+#' \code{quantile} returns the same vector as \code{median} (but only one, the
+#' one requested) if only one quantile is requested. If multiple quantiles are
+#' requested, then a list of these vectors is returned, one for each quantile.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}. Eric Kolaczyk
+#' (\url{http://math.bu.edu/people/kolaczyk/}) wrote the initial version in R.
+#' @seealso \code{\link{plot.sir}} to conveniently plot the results
+#' @references Bailey, Norman T. J. (1975). The mathematical theory of
+#' infectious diseases and its applications (2nd ed.). London: Griffin.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnm(100, 100)
+#' sm <- sir(g, beta=5, gamma=1)
+#' plot(sm)
+#' @export
+
+sir <- sir
diff --git a/R/socnet.R b/R/socnet.R
index d87c2eb..db7dc60 100644
--- a/R/socnet.R
+++ b/R/socnet.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -30,9 +29,26 @@
 
 .tkigraph.env <- new.env()
 
+
+
+#' Experimental basic igraph GUI
+#' 
+#' This functions starts an experimental GUI to some igraph functions. The GUI
+#' was written in Tcl/Tk, so it is cross platform.
+#' 
+#' \code{tkigraph} has its own online help system, please see that for the
+#' details about how to use it.
+#' 
+#' @return Returns \code{NULL}, invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{tkplot}} for interactive plotting of graphs.
+#' @keywords graphs
+#' @export
+
 tkigraph <- function() {
 
-  require(tcltk) || stop("tcl/tk library not available")
+  requireNamespace("tcltk", quietly = TRUE) ||
+    stop("tcl/tk library not available")
 
   options(scipen=10000)
   
@@ -46,12 +62,12 @@ tkigraph <- function() {
   }
   
   # Create top window
-  top <- tktoplevel(background="lightgrey", width=700, height=400)
-  tktitle(top) <- "iGraph GUI (Social Network Basics)"
-  topframe <- tkframe(top, relief="sunken", borderwidth=1)
-  scr <- tkscrollbar(top, repeatinterval=5,
-                     command=function(...) tkyview(topframe))
-  tkplace(topframe, x=0, y=0, relwidth=1.0)
+  top <- tcltk::tktoplevel(background="lightgrey", width=700, height=400)
+  tcltk::tktitle(top) <- "iGraph GUI (Social Network Basics)"
+  topframe <- tcltk::tkframe(top, relief="sunken", borderwidth=1)
+  scr <- tcltk::tkscrollbar(top, repeatinterval=5,
+                     command=function(...) tcltk::tkyview(topframe))
+  tcltk::tkplace(topframe, x=0, y=0, relwidth=1.0)
   
   # Store myself in the environment if needed
   if (!exists("top", envir=.tkigraph.env, inherits=FALSE)) {
@@ -60,319 +76,319 @@ tkigraph <- function() {
   }
   
   # kill myself if window was closed
-  tkbind(top, "<Destroy>", function() .tkigraph.close())
+  tcltk::tkbind(top, "<Destroy>", function() .tkigraph.close())
 
   # pull-down menu
-  main.menu <- tkmenu(top)
+  main.menu <- tcltk::tkmenu(top)
 
-  graph.menu <- tkmenu(main.menu)
+  graph.menu <- tcltk::tkmenu(main.menu)
   
-  create.menu <- tkmenu(main.menu)
-  tkadd(create.menu, "command", label="By hand", command=function() {
+  create.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(create.menu, "command", label="By hand", command=function() {
     .tkigraph.by.hand()
   })
-  tkadd(create.menu, "separator")
-  tkadd(create.menu, "command", label="Ring", command=function() {
+  tcltk::tkadd(create.menu, "separator")
+  tcltk::tkadd(create.menu, "command", label="Ring", command=function() {
     .tkigraph.ring()
   })
-  tkadd(create.menu, "command", label="Tree", command=function() {
+  tcltk::tkadd(create.menu, "command", label="Tree", command=function() {
     .tkigraph.tree()
   })
-  tkadd(create.menu, "command", label="Lattice", command=function() {
+  tcltk::tkadd(create.menu, "command", label="Lattice", command=function() {
     .tkigraph.lattice()
   })
-  tkadd(create.menu, "command", label="Star", command=function() {
+  tcltk::tkadd(create.menu, "command", label="Star", command=function() {
     .tkigraph.star()
   })
-  tkadd(create.menu, "command", label="Full", command=function() {
+  tcltk::tkadd(create.menu, "command", label="Full", command=function() {
     .tkigraph.full()
   })
-  tkadd(create.menu, "separator")
-  tkadd(create.menu, "command", label="Graph atlas...", command=function() {
+  tcltk::tkadd(create.menu, "separator")
+  tcltk::tkadd(create.menu, "command", label="Graph atlas...", command=function() {
     .tkigraph.atlas()
   })
-  tkadd(create.menu, "separator")
-  tkadd(create.menu, "command", label="Moody-White network", command=function() {
-    g <- graph.adjacency(.tkigraph.net.moody.white, mode="undirected")
-    g <- set.graph.attribute(g, "name", "Moody-White network")
+  tcltk::tkadd(create.menu, "separator")
+  tcltk::tkadd(create.menu, "command", label="Moody-White network", command=function() {
+    g <- graph_from_adjacency_matrix(.tkigraph.net.moody.white, mode="undirected")
+    g <- set_graph_attr(g, "name", "Moody-White network")
     .tkigraph.add.graph(g)
   })
   
-  tkadd(create.menu, "separator") 
-  tkadd(create.menu, "command", label="Random (Erdos-Renyi G(n,p))",
+  tcltk::tkadd(create.menu, "separator") 
+  tcltk::tkadd(create.menu, "command", label="Random (Erdos-Renyi G(n,p))",
         command=function() {
           .tkigraph.erdos.renyi.game()
         })
-  tkadd(create.menu, "command", label="Random (Erdos-Renyi G(n,m))",
+  tcltk::tkadd(create.menu, "command", label="Random (Erdos-Renyi G(n,m))",
         command=function() { .tkigraph.erdos.renyi.gnm.game() })
-  tkadd(create.menu, "command", label="Random (Barabasi-Albert)",
+  tcltk::tkadd(create.menu, "command", label="Random (Barabasi-Albert)",
         command=function() {
           .tkigraph.barabasi.game()
         })
-  tkadd(create.menu, "command", label="Random (Configuration model)",
+  tcltk::tkadd(create.menu, "command", label="Random (Configuration model)",
         command=function() {
           .tkigraph.degree.sequence.game()
         })
-  tkadd(create.menu, "command", label="Watts-Strogatz random graph",
+  tcltk::tkadd(create.menu, "command", label="Watts-Strogatz random graph",
         command=function() {
           .tkigraph.watts.strogatz()
         })
-  tkadd(create.menu, "separator")
-  tkadd(create.menu, "command", label="Simplify", command=function() {
+  tcltk::tkadd(create.menu, "separator")
+  tcltk::tkadd(create.menu, "command", label="Simplify", command=function() {
     .tkigraph.simplify()
   })
-  tkadd(graph.menu, "cascade", label="Create", menu=create.menu)
-  tkadd(graph.menu, "command", label="Delete", command=function() {
+  tcltk::tkadd(graph.menu, "cascade", label="Create", menu=create.menu)
+  tcltk::tkadd(graph.menu, "command", label="Delete", command=function() {
     .tkigraph.delete() })  
-  tkadd(graph.menu, "separator")
-  tkadd(graph.menu, "command", label="Show graph",
+  tcltk::tkadd(graph.menu, "separator")
+  tcltk::tkadd(graph.menu, "command", label="Show graph",
         command=function() { .tkigraph.show() })
-  tkadd(graph.menu, "command", label="Basic statistics",
+  tcltk::tkadd(graph.menu, "command", label="Basic statistics",
         command=function() { .tkigraph.stat() })
-  tkadd(graph.menu, "separator")
-  tkadd(graph.menu, "command", label="Import session", command=function() {
+  tcltk::tkadd(graph.menu, "separator")
+  tcltk::tkadd(graph.menu, "command", label="Import session", command=function() {
     .tkigraph.load()
   })
-#  tkadd(graph.menu, "command", label="Load from the Web", command=function() {
+#  tcltk::tkadd(graph.menu, "command", label="Load from the Web", command=function() {
 #    .tkigraph.load.online()
 #  })
-  tkadd(graph.menu, "command", label="Export session", command=function() {
+  tcltk::tkadd(graph.menu, "command", label="Export session", command=function() {
     .tkigraph.save()
   })
-  tkadd(graph.menu, "separator")
-  tkadd(graph.menu, "command", label="Import adjacency matrix",
+  tcltk::tkadd(graph.menu, "separator")
+  tcltk::tkadd(graph.menu, "command", label="Import adjacency matrix",
         command=function() .tkigraph.import.adjacency())
-  tkadd(graph.menu, "command", label="Import edge list",
+  tcltk::tkadd(graph.menu, "command", label="Import edge list",
         command=function() .tkigraph.import.edgelist())
-  tkadd(graph.menu, "command", label="Import Pajek file",
+  tcltk::tkadd(graph.menu, "command", label="Import Pajek file",
         command=function() .tkigraph.import.pajek())
-  tkadd(graph.menu, "command", label="Export adjacency matrix",
+  tcltk::tkadd(graph.menu, "command", label="Export adjacency matrix",
         command=function() .tkigraph.export.adjacency())
-  tkadd(graph.menu, "command", label="Export edge list",
+  tcltk::tkadd(graph.menu, "command", label="Export edge list",
         command=function() .tkigraph.export.edgelist())
-  tkadd(graph.menu, "command", label="Export Pajek file",
+  tcltk::tkadd(graph.menu, "command", label="Export Pajek file",
         command=function() .tkigraph.export.pajek())
-  tkadd(main.menu, "cascade", label="Graph", menu=graph.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Graph", menu=graph.menu)
 
-  plot.menu <- tkmenu(main.menu)
-  tkadd(plot.menu, "command", label="Simple", command=function() {
+  plot.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(plot.menu, "command", label="Simple", command=function() {
     .tkigraph.plot(simple=TRUE)
   })
-  tkadd(plot.menu, "command", label="Advanced", command=function() {
+  tcltk::tkadd(plot.menu, "command", label="Advanced", command=function() {
     .tkigraph.plot(simple=FALSE)
   })
-  tkadd(main.menu, "cascade", label="Draw", menu=plot.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Draw", menu=plot.menu)
   
-  centrality.menu <- tkmenu(main.menu)
-  tkadd(centrality.menu, "command", label="Degree (out)", command=function() {
+  centrality.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(centrality.menu, "command", label="Degree (out)", command=function() {
     .tkigraph.degree("out")
   })
-  tkadd(centrality.menu, "command", label="Degree (in)", command=function() {
+  tcltk::tkadd(centrality.menu, "command", label="Degree (in)", command=function() {
     .tkigraph.degree("in")
   })
-  tkadd(centrality.menu, "command", label="Degree (total)",
+  tcltk::tkadd(centrality.menu, "command", label="Degree (total)",
         command=function() {
           .tkigraph.degree("total")
         })
-  tkadd(centrality.menu, "command", label="Plot log-log degree distribution",
+  tcltk::tkadd(centrality.menu, "command", label="Plot log-log degree distribution",
         command=function() {
           .tkigraph.degree.dist(power=FALSE)
         })
-  tkadd(centrality.menu, "command", label="Fit a power-law to degree distribution",
+  tcltk::tkadd(centrality.menu, "command", label="Fit a power-law to degree distribution",
         command=function() {
           .tkigraph.degree.dist(power=TRUE)
         })
-  tkadd(centrality.menu, "separator")
-  tkadd(centrality.menu, "command", label="Closeness", command=function() {
+  tcltk::tkadd(centrality.menu, "separator")
+  tcltk::tkadd(centrality.menu, "command", label="Closeness", command=function() {
     .tkigraph.closeness()
   })
-  tkadd(centrality.menu, "command", label="Betweenness", command=function() {
+  tcltk::tkadd(centrality.menu, "command", label="Betweenness", command=function() {
     .tkigraph.betweenness()
   })
-  tkadd(centrality.menu, "command", label="Burt's constraint", command=function() {
+  tcltk::tkadd(centrality.menu, "command", label="Burt's constraint", command=function() {
     .tkigraph.constraints()
   })
-  tkadd(centrality.menu, "command", label="Page rank", command=function() {
+  tcltk::tkadd(centrality.menu, "command", label="Page rank", command=function() {
     .tkigraph.page.rank()
   })
-  tkadd(centrality.menu, "separator")  
-  tkadd(centrality.menu, "command", label="Edge betweenness",
+  tcltk::tkadd(centrality.menu, "separator")  
+  tcltk::tkadd(centrality.menu, "command", label="Edge betweenness",
         command=function() {
           .tkigraph.edge.betweenness()
         })
-  tkadd(main.menu, "cascade", label="Centrality", menu=centrality.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Centrality", menu=centrality.menu)
 
-  distances.menu <- tkmenu(main.menu)
-  tkadd(distances.menu, "command", label="Distance matrix",
+  distances.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(distances.menu, "command", label="Distance matrix",
         command=function() { .tkigraph.dist.matrix() })
-  tkadd(distances.menu, "command", label="Distances from/to vertex",
+  tcltk::tkadd(distances.menu, "command", label="Distances from/to vertex",
         command=function() { .tkigraph.distance.tofrom() })
-  tkadd(distances.menu, "command", label="Diameter (undirected)",
+  tcltk::tkadd(distances.menu, "command", label="Diameter (undirected)",
         command=function() { .tkigraph.diameter() })
-  tkadd(distances.menu, "command", label="Draw diameter",
+  tcltk::tkadd(distances.menu, "command", label="Draw diameter",
         command=function() { .tkigraph.plot.diameter(simple=FALSE) })
-  tkadd(distances.menu, "command", label="Average path length (undirected)",
+  tcltk::tkadd(distances.menu, "command", label="Average path length (undirected)",
         command=function() { .tkigraph.diameter(mode="path") })
-  tkadd(main.menu, "cascade", label="Distances", menu=distances.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Distances", menu=distances.menu)
 
-  component.menu <- tkmenu(main.menu)
-  tkadd(component.menu, "command", label="Show components",
+  component.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(component.menu, "command", label="Show components",
         command=function() { .tkigraph.clusters() })
-  tkadd(component.menu, "command", label="Show membership",
+  tcltk::tkadd(component.menu, "command", label="Show membership",
         command=function() { .tkigraph.clusters.membership() })
-  tkadd(component.menu, "command", label="Calculate component sizes",
+  tcltk::tkadd(component.menu, "command", label="Calculate component sizes",
         command=function() { .tkigraph.calculate.clusters() })
-  tkadd(component.menu, "command", label="Draw components",
+  tcltk::tkadd(component.menu, "command", label="Draw components",
         command=function() { .tkigraph.plot.comp(simple=FALSE) })
-  tkadd(component.menu, "command", label="Create graph from giant component",
+  tcltk::tkadd(component.menu, "command", label="Create graph from giant component",
         command=function() { .tkigraph.create.giantcomp() })
-  tkadd(component.menu, "command", label="Create graph from component of a vertex",
+  tcltk::tkadd(component.menu, "command", label="Create graph from component of a vertex",
         command=function() { .tkigraph.create.mycomp() })
-  tkadd(component.menu, "command", label="Create graph from a component",
+  tcltk::tkadd(component.menu, "command", label="Create graph from a component",
         command=function() { .tkigraph.create.comp() })
 
-  community.menu <- tkmenu(main.menu)
-  tkadd(community.menu, "command", label="Spinglass algorithm",
+  community.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(community.menu, "command", label="Spinglass algorithm",
         command=function() { .tkigraph.spinglass() })
-  tkadd(community.menu, "command", label="Spinglass algorithm, single vertex",
+  tcltk::tkadd(community.menu, "command", label="Spinglass algorithm, single vertex",
         command=function() { .tkigraph.my.spinglass() })
 
-  cohesion.menu <- tkmenu(main.menu)
-  tkadd(cohesion.menu, "command", label="Cohesion of all components",
+  cohesion.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(cohesion.menu, "command", label="Cohesion of all components",
         command=function() { .tkigraph.cohesion() })
   
-  subgraph.menu <- tkmenu(main.menu)
-  tkadd(subgraph.menu, "cascade", label="Components", menu=component.menu)
-  tkadd(subgraph.menu, "cascade", label="Communities", menu=community.menu)
-  tkadd(subgraph.menu, "cascade", label="Cohesion", menu=cohesion.menu)
+  subgraph.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(subgraph.menu, "cascade", label="Components", menu=component.menu)
+  tcltk::tkadd(subgraph.menu, "cascade", label="Communities", menu=community.menu)
+  tcltk::tkadd(subgraph.menu, "cascade", label="Cohesion", menu=cohesion.menu)
   
-  tkadd(main.menu, "cascade", label="Subgraphs", menu=subgraph.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Subgraphs", menu=subgraph.menu)
   
-  motif.menu <- tkmenu(main.menu)
-  tkadd(motif.menu, "command", label="Draw motifs", command=function() {
+  motif.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(motif.menu, "command", label="Draw motifs", command=function() {
     .tkigraph.motifs.draw()
   })
-  tkadd(motif.menu, "command", label="Find motifs", command=function() {
+  tcltk::tkadd(motif.menu, "command", label="Find motifs", command=function() {
     .tkigraph.motifs.find()
   })
-  tkadd(main.menu, "cascade", label="Motifs", menu=motif.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Motifs", menu=motif.menu)
 
-  help.menu <- tkmenu(main.menu)
-  tkadd(help.menu, "command", label="Contents", command=function() { .tkigraph.help() })
-  tkadd(help.menu, "command", label="In external browser",
+  help.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(help.menu, "command", label="Contents", command=function() { .tkigraph.help() })
+  tcltk::tkadd(help.menu, "command", label="In external browser",
         command=function() { .tkigraph.help.external() })
-  tkadd(help.menu, "separator")
-  tkadd(help.menu, "command", label="About", command=function() { .tkigraph.about() })
-  tkadd(main.menu, "cascade", label="Help", menu=help.menu)
+  tcltk::tkadd(help.menu, "separator")
+  tcltk::tkadd(help.menu, "command", label="About", command=function() { .tkigraph.about() })
+  tcltk::tkadd(main.menu, "cascade", label="Help", menu=help.menu)
   
-  tkadd(main.menu, "command", label="Quit", command=.tkigraph.close)
+  tcltk::tkadd(main.menu, "command", label="Quit", command=.tkigraph.close)
   
-  tkconfigure(top, "-menu", main.menu)
+  tcltk::tkconfigure(top, "-menu", main.menu)
 
   # Set up the main area
-  tkgrid(tklabel(top, text=""),
-         tklabel(top, text="#", justify="center", relief="raised"),
-         tklabel(top, text="Name", width=50, relief="raised",
+  tcltk::tkgrid(tcltk::tklabel(top, text=""),
+         tcltk::tklabel(top, text="#", justify="center", relief="raised"),
+         tcltk::tklabel(top, text="Name", width=50, relief="raised",
                  justify="left"),
-         tklabel(top, text="|V|", width=6, relief="raised",
+         tcltk::tklabel(top, text="|V|", width=6, relief="raised",
                  justify="left"),
-         tklabel(top, text="|E|", width=6, relief="raised",
+         tcltk::tklabel(top, text="|E|", width=6, relief="raised",
                  justify="left"),
-         tklabel(top, text="Dir.", width=6, relief="raised",
+         tcltk::tklabel(top, text="Dir.", width=6, relief="raised",
                  justify="left"),
          sticky="nsew", "in"=topframe)
-  tkgrid.columnconfigure(topframe, 2, weight=1)
+  tcltk::tkgrid.columnconfigure(topframe, 2, weight=1)
 
   invisible(NULL)
 }
 
 .tkigraph.close <- function() {
   message <- "Are you sure?"
-  yesno <- tkmessageBox(message=message, icon="question", type="yesno",
+  yesno <- tcltk::tkmessageBox(message=message, icon="question", type="yesno",
                         default="yes")
   if (as.character(yesno) == "no") { return() }
   top <- get("top", .tkigraph.env)
-  tkbind(top, "<Destroy>", "")
-  tkdestroy(top)
+  tcltk::tkbind(top, "<Destroy>", "")
+  tcltk::tkdestroy(top)
   rm(list=ls(envir=.tkigraph.env), envir=.tkigraph.env)
 }
 
 .tkigraph.get.selected <- function() {
   gnos <- get("selected", .tkigraph.env)
-  which(as.logical(sapply(gnos, tclvalue)))
+  which(as.logical(sapply(gnos, tcltk::tclvalue)))
 }
 
 .tkigraph.error <- function(message) {
-  tkmessageBox(message=message, icon="error", type="ok")
+  tcltk::tkmessageBox(message=message, icon="error", type="ok")
 }
 
 .tkigraph.warning <- function(message) {
-  tkmessageBox(message=message, icon="warning", type="ok")
+  tcltk::tkmessageBox(message=message, icon="warning", type="ok")
 }
 
 .tkigraph.dialogbox <- function(TITLE="Setup parameters", ...) {
   
   params <- list(...)
   answers <- lapply(params, "[[", "default")
-  dialog <- tktoplevel()
-  frame <- tkframe(dialog)
-  tkgrid(frame)
-  tktitle(dialog) <- TITLE
-  vars <- lapply(answers, tclVar)
+  dialog <- tcltk::tktoplevel()
+  frame <- tcltk::tkframe(dialog)
+  tcltk::tkgrid(frame)
+  tcltk::tktitle(dialog) <- TITLE
+  vars <- lapply(answers, tcltk::tclVar)
   retval <- list()
   widgets <- list()
 
   OnOK <- function() {
-    retval <<- lapply(vars, tclvalue)
+    retval <<- lapply(vars, tcltk::tclvalue)
     for (i in seq(along=params)) {
       if (params[[i]]$type == "listbox") {
-        retval[[i]] <<- as.numeric(tclvalue(tkcurselection(widgets[[i]])))
+        retval[[i]] <<- as.numeric(tcltk::tclvalue(tcltk::tkcurselection(widgets[[i]])))
       }
     }
-    tkdestroy(dialog)    
+    tcltk::tkdestroy(dialog)    
   }
 
-  tkgrid(tklabel(dialog, text=TITLE,
-                 font=tkfont.create(family="times", size="16", weight="bold")),
+  tcltk::tkgrid(tcltk::tklabel(dialog, text=TITLE,
+                 font=tcltk::tkfont.create(family="times", size="16", weight="bold")),
          columnspan=2, sticky="nsew", "in"=frame, padx=10, pady=10)
   
-  OK.but <- tkbutton(dialog, text="   OK    ", command=OnOK)
+  OK.but <- tcltk::tkbutton(dialog, text="   OK    ", command=OnOK)
   for (i in seq(along=params)) {
-    tkgrid(tklabel(dialog, text=params[[i]]$name),
+    tcltk::tkgrid(tcltk::tklabel(dialog, text=params[[i]]$name),
            column=0, row=i, sticky="nw", padx=10, "in"=frame)
     if (params[[i]]$type == "numeric" || params[[i]]$type == "text") {
-      tmp <- tkentry(dialog, width="10", textvariable=vars[[i]])
-      tkgrid(tmp, column=1, row=i, sticky="nsew", padx=10, "in"=frame)
-      tkbind(tmp, "<Return>", OnOK)
+      tmp <- tcltk::tkentry(dialog, width="10", textvariable=vars[[i]])
+      tcltk::tkgrid(tmp, column=1, row=i, sticky="nsew", padx=10, "in"=frame)
+      tcltk::tkbind(tmp, "<Return>", OnOK)
     } else if (params[[i]]$type == "boolean") {
-      b <- tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
+      b <- tcltk::tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
                            variable=vars[[i]])
-      if (params[[i]]$default == "TRUE") { tkselect(b) }
-      tkgrid(b, column=1, row=i, sticky="w", padx=10, "in"=frame)
+      if (params[[i]]$default == "TRUE") { tcltk::tkselect(b) }
+      tcltk::tkgrid(b, column=1, row=i, sticky="w", padx=10, "in"=frame)
     } else if (params[[i]]$type == "listbox") {
-      f <- tkframe(dialog)
-      tkgrid(f, "in"=frame, padx=10, sticky="nsew", column=1, row=i)
-      scr <- tkscrollbar(f, repeatinterval=5)
-      fun <- eval(eval(substitute(expression(function(...) tkset(scr,...)),
+      f <- tcltk::tkframe(dialog)
+      tcltk::tkgrid(f, "in"=frame, padx=10, sticky="nsew", column=1, row=i)
+      scr <- tcltk::tkscrollbar(f, repeatinterval=5)
+      fun <- eval(eval(substitute(expression(function(...) tcltk::tkset(scr,...)),
                                   list(scr=scr))))
-      lb <- tklistbox(f, selectmode="single", exportselection=FALSE,
+      lb <- tcltk::tklistbox(f, selectmode="single", exportselection=FALSE,
                       height=3, yscrollcommand=fun)
-      fun <- eval(eval(substitute(expression(function(...) tkyview(lb, ...)),
+      fun <- eval(eval(substitute(expression(function(...) tcltk::tkyview(lb, ...)),
           list(lb=lb))))
-      tkconfigure(scr, "-command", fun)
-      tkselection.set(lb, as.numeric(params[[i]]$default)+1)
-      lapply(params[[i]]$values, function(l) tkinsert(lb, "end", l))
-      tkselection.set(lb, as.numeric(params[[i]]$default))
-      tkgrid(lb, scr, sticky="nsew", "in"=f)
-      tkgrid.configure(scr, sticky="nsw")
-      tkgrid.columnconfigure(f, 0, weight=1)
+      tcltk::tkconfigure(scr, "-command", fun)
+      tcltk::tkselection.set(lb, as.numeric(params[[i]]$default)+1)
+      lapply(params[[i]]$values, function(l) tcltk::tkinsert(lb, "end", l))
+      tcltk::tkselection.set(lb, as.numeric(params[[i]]$default))
+      tcltk::tkgrid(lb, scr, sticky="nsew", "in"=f)
+      tcltk::tkgrid.configure(scr, sticky="nsw")
+      tcltk::tkgrid.columnconfigure(f, 0, weight=1)
       widgets[[i]] <- lb
     }
   }
-  tkgrid(OK.but, column=0, columnspan=2, sticky="nsew", "in"=frame, pady=10,
+  tcltk::tkgrid(OK.but, column=0, columnspan=2, sticky="nsew", "in"=frame, pady=10,
          padx=10)
-  tkgrid.columnconfigure(frame, 1, weight=1)
-  tkwait.window(dialog)
+  tcltk::tkgrid.columnconfigure(frame, 1, weight=1)
+  tcltk::tkwait.window(dialog)
 
   for (i in seq(retval)) {
     if (params[[i]]$type == "numeric") {
@@ -398,10 +414,10 @@ tkigraph <- function() {
   topframe <- get("topframe", .tkigraph.env)
 
   ## add 'name' attribute if not present
-  if (!"name" %in% list.vertex.attributes(g)) {
+  if (!"name" %in% vertex_attr_names(g)) {
     V(g)$name <- as.integer(seq(vcount(g)))
   }
-  if (!"name" %in% list.edge.attributes(g)) {
+  if (!"name" %in% edge_attr_names(g)) {
     E(g)$name <- as.integer(seq(ecount(g)))
   }
   
@@ -410,21 +426,21 @@ tkigraph <- function() {
   assign("graphs", append(graphs, list(g)), .tkigraph.env)
   no <- length(graphs)+1
 
-  selected[[no]] <- tclVar("FALSE")
+  selected[[no]] <- tcltk::tclVar("FALSE")
   assign("selected", selected, .tkigraph.env)
 
-  name <- get.graph.attribute(g, "name")
-  tmpvar <- tclVar(as.character(name))
-  but <- tkcheckbutton(top, onvalue="TRUE", offvalue="FALSE",
+  name <- graph_attr(g, "name")
+  tmpvar <- tcltk::tclVar(as.character(name))
+  but <- tcltk::tkcheckbutton(top, onvalue="TRUE", offvalue="FALSE",
                        variable=selected[[no]])
-  lab <- tklabel(top, text=as.character(no), width=2)
-  ent <- tkentry(top, width=30, textvariable=tmpvar)
-  lab2 <- tklabel(top, text=as.character(vcount(g)),
+  lab <- tcltk::tklabel(top, text=as.character(no), width=2)
+  ent <- tcltk::tkentry(top, width=30, textvariable=tmpvar)
+  lab2 <- tcltk::tklabel(top, text=as.character(vcount(g)),
                   justify="right", padx=2)
-  lab3 <- tklabel(top, text=as.character(ecount(g)), justify="right",
+  lab3 <- tcltk::tklabel(top, text=as.character(ecount(g)), justify="right",
                   padx=2)
-  lab4 <- tklabel(top, text=if (is.directed(g)) "YES" else "NO")
-  tkgrid(but, lab, ent, lab2, lab3, lab4, "in"=topframe, sticky="nsew")
+  lab4 <- tcltk::tklabel(top, text=if (is_directed(g)) "YES" else "NO")
+  tcltk::tkgrid(but, lab, ent, lab2, lab3, lab4, "in"=topframe, sticky="nsew")
 
   tklines <- get("tklines", .tkigraph.env)
   tklines[[no]] <- list(but, lab, ent, lab2, lab3, lab4)
@@ -440,7 +456,7 @@ tkigraph <- function() {
   } else {
     message <- paste("Are you sure to delete graph #", gnos, "?")
   }
-  yesno <- tkmessageBox(message=message, icon="question", type="yesno",
+  yesno <- tcltk::tkmessageBox(message=message, icon="question", type="yesno",
                         default="yes")
   if (as.character(yesno) == "no") { return() }
 
@@ -450,20 +466,20 @@ tkigraph <- function() {
   todel <- get("tklines", .tkigraph.env)[gnos]
   todel <- unlist(recursive=FALSE, todel)
   for (i in todel) {
-    tkgrid.remove(topframe, i)
+    tcltk::tkgrid.remove(topframe, i)
   }
   ## delete the graphs
   graphs[gnos] <- NA
   assign("graphs", graphs, .tkigraph.env)
   selected <- get("selected", .tkigraph.env)
   for (i in gnos) { 
-    selected[[i]] <- tclVar("FALSE")
+    selected[[i]] <- tcltk::tclVar("FALSE")
   }
   assign("selected", selected, .tkigraph.env)
 }
 
 .tkigraph.load <- function() {
-  filename <- tkgetOpenFile(defaultextension="Rdata",
+  filename <- tcltk::tkgetOpenFile(defaultextension="Rdata",
                             title="Load graphs")
   env <- new.env()
   load(paste(as.character(filename), collapse=" "), envir=env)
@@ -485,19 +501,19 @@ tkigraph <- function() {
   topframe <- get("topframe", .tkigraph.env)
   for (i in seq(graphs)) {
     if (is.na(graphs)[i]) { next }
-    entry <- tkgrid.slaves(topframe, row=i, col=2)
-    graphs[[i]] <- set.graph.attribute(graphs[[i]], "name",
-                                       as.character(tcl(entry, "get")))
+    entry <- tcltk::tkgrid.slaves(topframe, row=i, col=2)
+    graphs[[i]] <- set_graph_attr(graphs[[i]], "name",
+                                       as.character(tcltk::tcl(entry, "get")))
   }
   graphs <- graphs[ !is.na(graphs) ]
-  filename <- tkgetSaveFile(initialfile="graphs.Rdata",
+  filename <- tcltk::tkgetSaveFile(initialfile="graphs.Rdata",
                             defaultextension="Rdata",
                             title="Save graphs")
   save(graphs, file=paste(as.character(filename), collapse=" "))
 }
 
 .tkigraph.import.adjacency <- function() {
-  filename <- tkgetOpenFile(defaultextension="adj",
+  filename <- tcltk::tkgetOpenFile(defaultextension="adj",
                             title="Import adjacency matrix")
   filename <- paste(as.character(filename), collapse=" ")
   if (filename=="") { return() }
@@ -514,25 +530,25 @@ tkigraph <- function() {
     weighted <- "weight"
   }
   g <- .tkigraph.graph.adjacency(tab, mode=dir, weighted=weighted)
-  g <- set.graph.attribute(g, "name", "Imported adjacency matrix")
+  g <- set_graph_attr(g, "name", "Imported adjacency matrix")
   .tkigraph.add.graph(g)
 }
 
 .tkigraph.graph.adjacency <- function(adjmatrix, mode, weighted) {
   if (is.null(weighted)) {
-    g <- graph.adjacency(adjmatrix, mode=mode)
+    g <- graph_from_adjacency_matrix(adjmatrix, mode=mode)
   } else {
     ## there is bug in the currect igraph version, this is a workaround
     if (mode=="undirected") {
       adjmatrix[ lower.tri(adjmatrix) ] <- 0
     }
-    g <- graph.adjacency(adjmatrix, mode=mode, weighted=weighted)
+    g <- graph_from_adjacency_matrix(adjmatrix, mode=mode, weighted=weighted)
   }
   g
 }
 
 .tkigraph.import.edgelist <- function() {
-  filename <- tkgetOpenFile(defaultextension="el",
+  filename <- tcltk::tkgetOpenFile(defaultextension="el",
                             title="Import edge list")
   filename <- paste(as.character(filename), collapse=" ")
   if (filename=="") { return() }
@@ -544,21 +560,21 @@ tkigraph <- function() {
   read <- .tkigraph.dialogbox(TITLE="Importing an edge list",
                               directed=list(name="Directed", type="boolean",
                                 default="FALSE"))
-  g <- graph.data.frame(tab, directed=read$directed)
-  g <- set.graph.attribute(g, "name", "Imported edge list")
+  g <- graph_from_data_frame(tab, directed=read$directed)
+  g <- set_graph_attr(g, "name", "Imported edge list")
   .tkigraph.add.graph(g)
 }
 
 .tkigraph.import.pajek <- function() {
-  filename <- tkgetOpenFile(defaultextension="net",
+  filename <- tcltk::tkgetOpenFile(defaultextension="net",
                             title="Import Pajek file")
   filename <- paste(as.character(filename), collapse=" ")
   if (filename=="") { return() }
-  g <- read.graph(file=filename, format="pajek")
+  g <- read_graph(file=filename, format="pajek")
   color <- NULL # To eliminate a check NOTE
-  if ("color" %in% list.vertex.attributes(g)) { V(g)[ color=="" ]$color <- "black" }
-  if ("color" %in% list.edge.attributes(g)) { E(g)[ color=="" ]$color <- "black" }
-  g <- set.graph.attribute(g, "name", "Imported Pajek fie")
+  if ("color" %in% vertex_attr_names(g)) { V(g)[ color=="" ]$color <- "black" }
+  if ("color" %in% edge_attr_names(g)) { E(g)[ color=="" ]$color <- "black" }
+  g <- set_graph_attr(g, "name", "Imported Pajek fie")
   .tkigraph.add.graph(g)
 }
 
@@ -569,12 +585,12 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  if ("weight" %in% list.graph.attributes(graph)) {
-    tab <- get.adjacency(graph, attr="weight", names=FALSE, sparse=FALSE)
+  if ("weight" %in% graph_attr_names(graph)) {
+    tab <- as_adj(graph, attr="weight", names=FALSE, sparse=FALSE)
   } else {
-    tab <- get.adjacency(graph, names=FALSE, sparse=FALSE)
+    tab <- as_adj(graph, names=FALSE, sparse=FALSE)
   }
-  filename <- tkgetSaveFile(initialfile="graph.adj",
+  filename <- tcltk::tkgetSaveFile(initialfile="graph.adj",
                             defaultextension="adj",
                             title="Export adjacency matrix")
   filename <- paste(as.character(filename), collapse=" ")
@@ -589,11 +605,11 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  el <- get.edgelist(graph)
-  if ("weight" %in% list.edge.attributes(graph)) {
+  el <- as_edgelist(graph)
+  if ("weight" %in% edge_attr_names(graph)) {
     el <- cbind(el, E(graph)$weight)
   }
-  filename <- tkgetSaveFile(initialfile="graph.el",
+  filename <- tcltk::tkgetSaveFile(initialfile="graph.el",
                             defaultextension="el",
                             title="Export edge list")
   filename <- paste(as.character(filename), collapse=" ")
@@ -609,12 +625,12 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  filename <- tkgetSaveFile(initialfile="pajek.net",
+  filename <- tcltk::tkgetSaveFile(initialfile="pajek.net",
                             defaultextension="net",
                             title="Export Pajek file")
   filename <- paste(as.character(filename), collapse=" ")
   if (filename=="") { return() }
-  write.graph(graph, file=filename, format="pajek")
+  write_graph(graph, file=filename, format="pajek")
 }
 
 .tkigraph.show <- function() {
@@ -624,13 +640,13 @@ tkigraph <- function() {
     return()
   }
   graphs <- get("graphs", .tkigraph.env)
-  el <- get.edgelist(graphs[[gnos]])
+  el <- as_edgelist(graphs[[gnos]])
   el <- data.frame(from=el[,1], to=el[,2])
 #  if (any(V(graphs[[gnos]])$name != seq(length=vcount(graphs[[gnos]])))) {
-#    el2 <- get.edgelist(graphs[[gnos]], names=FALSE)
+#    el2 <- as_edgelist(graphs[[gnos]], names=FALSE)
 #    el <- cbind(el, el2)
 #  }
-  if ("weight" %in% list.edge.attributes(graphs[[gnos]])) {
+  if ("weight" %in% edge_attr_names(graphs[[gnos]])) {
     el <- cbind(el, value=E(graphs[[gnos]])$weight)
   }
 
@@ -690,7 +706,7 @@ tkigraph <- function() {
       recip[i] <- reciprocity( graphs[[ i ]] )
     }
     if (read$dens) {
-      dens[i] <- graph.density( graphs[[ i ]] )
+      dens[i] <- edge_density( graphs[[ i ]] )
     }
     if (read$trans) {
       trans[i] <- transitivity( graphs[[ i ]], type="global")
@@ -834,28 +850,28 @@ tkigraph <- function() {
   }
   
   layout.default <- function(graph, layout.par) {
-    if ("x" %in% list.vertex.attributes(graph) &&
-        "y" %in% list.vertex.attributes(graph)) {
+    if ("x" %in% vertex_attr_names(graph) &&
+        "y" %in% vertex_attr_names(graph)) {
       cbind( V(graph)$x , V(graph)$y )
-    } else if ("layout" %in% list.graph.attributes(graph)) {
-      l <- get.graph.attribute(graph, "layout")
+    } else if ("layout" %in% graph_attr_names(graph)) {
+      l <- graph_attr(graph, "layout")
       if (is.function(l)) {
         l(graph)
       } else {
         l
       }
-    } else if (vcount(graph) < 300 && is.connected(graph)) {
-      layout.kamada.kawai(graph)
+    } else if (vcount(graph) < 300 && is_connected(graph)) {
+      layout_with_kk(graph)
     } else if (vcount(graph) < 1000) {
-      layout.fruchterman.reingold(graph)
+      layout_with_fr(graph)
     } else {
-      layout.circle(graph)
+      layout_in_circle(graph)
     }
   }
   
-  layouts <- list(layout.default, layout.kamada.kawai,
-                  layout.fruchterman.reingold,
-                  layout.reingold.tilford, layout.circle, layout.random)
+  layouts <- list(layout.default, layout_with_kk,
+                  layout_with_fr,
+                  layout_as_tree, layout_in_circle, layout_randomly)
 
   if (read$vertex.size < 10) {
     label.dist <- 0.4
@@ -872,7 +888,7 @@ tkigraph <- function() {
     } else if (read$labels == "2") {
       labels <- V(graphs[[i]])$name
     } else if (read$labels == "3") {
-      if ("label" %in% list.vertex.attributes(graphs[[i]])) {
+      if ("label" %in% vertex_attr_names(graphs[[i]])) {
         labels <- V(graphs[[i]])$label
       } else {
         labels <- V(graphs[[i]])$name
@@ -886,7 +902,7 @@ tkigraph <- function() {
     } else if (read$labels == "2") {
       elabels <- E(graphs[[i]])$name
     } else if (read$labels == "3") {
-      if ("weight" %in% list.edge.attributes(graphs[[i]])) {
+      if ("weight" %in% edge_attr_names(graphs[[i]])) {
         elabels <- E(graphs[[i]])$weight
       } else {
         .tkigraph.warning("No edge weights, not a valued graph");
@@ -901,7 +917,7 @@ tkigraph <- function() {
     }
     
     g <- graphs[[i]]
-    g <- remove.vertex.attribute(g, "name")
+    g <- delete_vertex_attr(g, "name")
     fun(g, layout=layouts[[ read$layout+1 ]],
         vertex.size=read$vertex.size, ## vertex.color=read$vertex.color,
         vertex.label=labels, vertex.label.dist=label.dist,
@@ -925,14 +941,14 @@ tkigraph <- function() {
     read <- .tkigraph.dialogbox(TITLE="Creating a graph by hand",
                                 directed=list(name="Directed", type="boolean",
                                   default="FALSE"))
-    g <- graph.data.frame(newdf, directed=read$directed)
-    g <- set.graph.attribute(g, "name", "New graph")
+    g <- graph_from_data_frame(newdf, directed=read$directed)
+    g <- set_graph_attr(g, "name", "New graph")
     .tkigraph.add.graph(g)
   } else {
     graphs <- get("graphs", .tkigraph.env)
-    df <- get.edgelist(graphs[[gnos]])
+    df <- as_edgelist(graphs[[gnos]])
     colnames <- c("from", "to")    
-    if ("weight" %in% list.edge.attributes(graphs[[gnos]])) {
+    if ("weight" %in% edge_attr_names(graphs[[gnos]])) {
       df <- cbind(df, E(g)$weight)
       colnames <- c("from", "to", "weight")
     }
@@ -943,8 +959,7 @@ tkigraph <- function() {
     if (ncol(df) > 2) {
       colnames(df) <- c("from", "to", "weight")
     }
-    graphs[[gnos]] <- graph.data.frame(df,
-                                       directed=is.directed(graphs[[gnos]]))
+    graphs[[gnos]] <- graph_from_data_frame(df, directed=is_directed(graphs[[gnos]]))
     assign("graphs", graphs, .tkigraph.env)
   }
   invisible(NULL)
@@ -960,10 +975,10 @@ tkigraph <- function() {
                                 values=c("Directed (out)", "Directed (in)",
                                   "Undirected"), default="2"))
   read$mode <- c("out", "in", "undirected")[read$mode+1]
-  g <- graph.tree(n=read$n, children=read$b, mode=read$mode)
-  lay <- layout.reingold.tilford(g, root=1, mode="all")
-  g <- set.graph.attribute(g, "layout", lay)
-  g <- set.graph.attribute(g, "name", "Regular tree")
+  g <- make_tree(n=read$n, children=read$b, mode=read$mode)
+  lay <- layout_as_tree(g, root=1, mode="all")
+  g <- set_graph_attr(g, "layout", lay)
+  g <- set_graph_attr(g, "name", "Regular tree")
   .tkigraph.add.graph(g)
 }
 
@@ -971,9 +986,9 @@ tkigraph <- function() {
   read <- .tkigraph.dialogbox(TITLE="Regular ring",
                               n=list(name="Vertices", type="numeric",
                                 default=100, min=0))
-  g <- graph.ring(n=read$n)
-  g <- set.graph.attribute(g, "layout", layout.circle)
-  g <- set.graph.attribute(g, "name", "Regular ring")
+  g <- make_ring(n=read$n)
+  g <- set_graph_attr(g, "layout", layout_in_circle)
+  g <- set_graph_attr(g, "name", "Regular ring")
   .tkigraph.add.graph(g)
 }
 
@@ -993,8 +1008,8 @@ tkigraph <- function() {
                                 default=10, min=1))
   if (read$dim > 5) { read$dim <- 5 }
   dimv <- c(read$s1, read$s2, read$s3, read$s4, read$s5)[1:read$dim]
-  g <- graph.lattice(dimvector=dimv)
-  g <- set.graph.attribute(g, "name", "Regular Lattice")
+  g <- make_lattice(dimvector=dimv)
+  g <- set_graph_attr(g, "name", "Regular Lattice")
   .tkigraph.add.graph(g)
 }
 
@@ -1006,8 +1021,8 @@ tkigraph <- function() {
                                 values=c("Directed (out)", "Directed (in)",
                                   "Undirected"), default="2"))
   read$mode <- c("out", "in", "undirected")[read$mode+1]
-  g <- graph.star(read$n, mode=read$mode)
-  g <- set.graph.attribute(g, "name", "Star graph")
+  g <- make_star(read$n, mode=read$mode)
+  g <- set_graph_attr(g, "name", "Star graph")
   .tkigraph.add.graph(g)
 }
 
@@ -1019,8 +1034,8 @@ tkigraph <- function() {
                                 default="FALSE"),
                               loops=list(name="Loops", type="boolean",
                                 default="FALSE"))
-  g <- graph.full(read$n, read$directed, read$loops)
-  g <- set.graph.attribute(g, "name", "Full graph")
+  g <- make_full_graph(read$n, read$directed, read$loops)
+  g <- set_graph_attr(g, "name", "Full graph")
   .tkigraph.add.graph(g)
 }                             
 
@@ -1029,7 +1044,7 @@ tkigraph <- function() {
                               n=list(name="Number", type="numeric",
                                 default=sample(0:1252, 1), min=0, max=1252))
   g <- graph.atlas(read$n)
-  g <- set.graph.attribute(g, "name",
+  g <- set_graph_attr(g, "name",
                            paste("Graph Atlas #", read$n))
   .tkigraph.add.graph(g)
 }
@@ -1043,8 +1058,8 @@ tkigraph <- function() {
                               directed=list(name="Directed",
                                 type="boolean", default="FALSE"))
   
-  g <- erdos.renyi.game(read$n,read$p,directed=read$directed)
-  g <- set.graph.attribute(g, "name", "Random graph (Erdos-Renyi G(n,p))")
+  g <- sample_gnp(read$n,read$p,directed=read$directed)
+  g <- set_graph_attr(g, "name", "Random graph (Erdos-Renyi G(n,p))")
   .tkigraph.add.graph(g)
 }
 
@@ -1057,8 +1072,8 @@ tkigraph <- function() {
                               directed=list(name="Directed",
                                 type="boolean", default="FALSE"))
 
-  g <- erdos.renyi.game(read$n, read$m, type="gnm", directed=read$directed)
-  g <- set.graph.attribute(g, "name", "Random graph (Erdos-Renyi G(n,m))")
+  g <- sample_gnm(read$n, read$m, directed=read$directed)
+  g <- set_graph_attr(g, "name", "Random graph (Erdos-Renyi G(n,m))")
   .tkigraph.add.graph(g)
 }
 
@@ -1071,7 +1086,7 @@ tkigraph <- function() {
                               directed=list(name="Directed",
                                 type="boolean", default="TRUE"))
   g <- barabasi.game(n=read$n, m=read$m, directed=read$directed)
-  g <- set.graph.attribute(g, "name", "Scale-free random graph")
+  g <- set_graph_attr(g, "name", "Scale-free random graph")
   .tkigraph.add.graph(g)
 }
 
@@ -1084,15 +1099,15 @@ tkigraph <- function() {
   graphs <- get("graphs", .tkigraph.env)
 
   for (i in gnos) {
-    if (is.directed(graphs[[i]])) {
+    if (is_directed(graphs[[i]])) {
       indeg <- degree(graphs[[i]], mode="in")
       outdeg <- degree(graphs[[i]], mode="out")
-      g <- degree.sequence.game(out.deg=outdeg, in.deg=indeg)
+      g <- sample_degseq(out.deg=outdeg, in.deg=indeg)
     } else {
       deg <- degree(graphs[[i]])
-      g <- degree.sequence.game(deg)
+      g <- sample_degseq(deg)
     }
-    g <- set.graph.attribute(g, "name",
+    g <- set_graph_attr(g, "name",
                              paste(sep="", "Configuration model (#", i,")"))
     .tkigraph.add.graph(g)
   }
@@ -1108,11 +1123,11 @@ tkigraph <- function() {
                                 default=5, min=1),
                               p=list(name="Rewiring probability",
                                 type="numeric", default=0.01, min=0, max=1))
-  g <- watts.strogatz.game(dim=read$dim, size=read$size, nei=read$nei,
+  g <- sample_smallworld(dim=read$dim, size=read$size, nei=read$nei,
                            p=read$p)
-  g <- set.graph.attribute(g, "name", "Watts-Strogatz small-world graph")
+  g <- set_graph_attr(g, "name", "Watts-Strogatz small-world graph")
   if (read$dim == 1) { 
-    g <- set.graph.attribute(g, "layout", layout.circle)
+    g <- set_graph_attr(g, "layout", layout_in_circle)
   }
   .tkigraph.add.graph(g)
 }
@@ -1123,7 +1138,7 @@ tkigraph <- function() {
 
   for (i in gnos) {
     g <- simplify(graphs[[i]])
-    g <- set.graph.attribute(g, "name",
+    g <- set_graph_attr(g, "name",
                              paste(sep="", "Simplification of #", i))
     .tkigraph.add.graph(g)
   }
@@ -1195,7 +1210,7 @@ tkigraph <- function() {
       .tkigraph.error("Degrees are too small for a power-law fit")
       return()
     }
-    fit <- power.law.fit(deg, xmin=10)
+    fit <- fit_power_law(deg, xmin=10)
     lines(0:max(deg), (0:max(deg))^(-coef(fit)), col="red")
     legend("topright", c(paste("exponent:", round(coef(fit), 2)),
                          paste("standard error:", round(sqrt(vcov(fit)), 2))),
@@ -1263,7 +1278,7 @@ tkigraph <- function() {
     return()
   }
   graphs <- get("graphs", .tkigraph.env)
-  bp <- bonpow(graphs[[gnos]])
+  bp <- power_centrality(graphs[[gnos]])
   value <- data.frame(V(graphs[[gnos]])$name, bp)
   colnames(value) <- c("Vertex", "Power centrality")
   value <- value[ order(value[,2], decreasing=TRUE), ]
@@ -1280,7 +1295,7 @@ tkigraph <- function() {
     return()
   }
   graphs <- get("graphs", .tkigraph.env)
-  bp <- page.rank(graphs[[gnos]])$vector
+  bp <- page_rank(graphs[[gnos]])$vector
   value <- data.frame(V(graphs[[gnos]])$name, bp)
   colnames(value) <- c("Vertex", "Page rank")
   value <- value[ order(value[,2], decreasing=TRUE), ]
@@ -1297,8 +1312,8 @@ tkigraph <- function() {
     return()
   }
   graphs <- get("graphs", .tkigraph.env)
-  ebtw <- edge.betweenness(graphs[[gnos]])
-  el <- get.edgelist(graphs[[gnos]])
+  ebtw <- edge_betweenness(graphs[[gnos]])
+  el <- as_edgelist(graphs[[gnos]])
   value <- data.frame(E(graphs[[gnos]])$name, el[,1], el[,2], ebtw)
   colnames(value) <- c("Edge", "From", "To", "Betweenness")
   value <- value[ order(value[,4], decreasing=TRUE), ]
@@ -1323,7 +1338,7 @@ tkigraph <- function() {
     return()
   }
 
-  value <- shortest.paths(graph, mode="out")
+  value <- distances(graph, mode="out")
   rownames(value) <- colnames(value) <- V(graph)$name
   .tkigraph.showData(value, sort.button=FALSE, 
                      title=paste(sep="", "Distance matrix for graph #", gnos))
@@ -1345,7 +1360,7 @@ tkigraph <- function() {
     return()
   }
 
-  value <- shortest.paths(graph, read$v, mode="out")
+  value <- distances(graph, read$v, mode="out")
   dim(value) <- NULL
   value <- data.frame( V(graph)$name, value)
   colnames(value) <- c("Vertex", "Distance")
@@ -1369,9 +1384,9 @@ tkigraph <- function() {
     if (mode=="dia") {
       dia[i] <- diameter(graphs[[ gnos[i] ]], directed=FALSE)
     } else if (mode=="path") {
-      dia[i] <- average.path.length(graphs[[ gnos[i] ]], directed=FALSE)
+      dia[i] <- mean_distance(graphs[[ gnos[i] ]], directed=FALSE)
     }
-    isconn[i] <- is.connected(graphs[[ gnos[i] ]])
+    isconn[i] <- is_connected(graphs[[ gnos[i] ]])
   }
 
   value <- data.frame( gnos, isconn, dia)
@@ -1397,7 +1412,7 @@ tkigraph <- function() {
   }
 
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  edges <- E(graph, path=get.diameter(graph, directed=FALSE), directed=FALSE)
+  edges <- E(graph, path=get_diameter(graph, directed=FALSE), directed=FALSE)
   color <- rep("black", ecount(graph))
   color[edges] <- "red"
   width <- rep(1, ecount(graph))
@@ -1412,7 +1427,7 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  comm <- clusters(graph)
+  comm <- components(graph)
   members <- sapply(sapply(seq(along=comm$csize),
                            function(i) which(comm$membership==i)),
                     paste, collapse=", ")
@@ -1428,7 +1443,7 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  comm <- clusters(graph)
+  comm <- components(graph)
   value <- data.frame("Vertex"=seq(along=comm$membership),
                  "Component"=comm$membership)
   .tkigraph.showData(value, title=paste("Components of graph #", gnos))
@@ -1441,7 +1456,7 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  cs <- clusters(graph)$csize
+  cs <- components(graph)$csize
   value <- data.frame(seq(along=cs), cs)
   colnames(value) <- c("Cluster #", "Size")
 
@@ -1483,7 +1498,7 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  clu <- clusters(graph)
+  clu <- components(graph)
   colbar <- rainbow(length(clu$csize)*2)
   vertex.color <- colbar[ clu$membership ]
   .tkigraph.plot(gnos=gnos, simple=simple, vertex.color=vertex.color)
@@ -1496,9 +1511,9 @@ tkigraph <- function() {
     return()
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
-  clu <- clusters(graph)
+  clu <- components(graph)
   v <- which(clu$membership == which.max(clu$csize))
-  g <- induced.subgraph(graph, v)
+  g <- induced_subgraph(graph, v)
   .tkigraph.add.graph(g)
 }
 
@@ -1517,7 +1532,7 @@ tkigraph <- function() {
     return()
   }
 
-  g <- induced.subgraph(graph, subcomponent(graph, read$vertex))
+  g <- induced_subgraph(graph, subcomponent(graph, read$vertex))
   .tkigraph.add.graph(g)
 }
 
@@ -1531,14 +1546,14 @@ tkigraph <- function() {
   read <- .tkigraph.dialogbox(TITLE="Graph from component",
                               comp=list(name="Component id", type="numeric",
                                 default=1, min=1))
-  clu <- clusters(graph)
+  clu <- components(graph)
   if (read$comp<1 || read$comp > length(clu$csize)) {
     .tkigraph.error("Invalid component id")
     return()
   }
   
   v <- which(clu$membership==read$comp)
-  g <- induced.subgraph(graph, v)
+  g <- induced_subgraph(graph, v)
   .tkigraph.add.graph(g)  
 }
 
@@ -1579,7 +1594,7 @@ tkigraph <- function() {
   layout( matrix(1:(rows*cols), nrow=rows, byrow=TRUE) )
   layout.show(rows*cols)
   for (i in seq(no)) {
-    g <- graph.isocreate(read$size, i-1, directed=read$dir)
+    g <- graph_from_isomorphism_class(read$size, i-1, directed=read$dir)
     par(mai=c(0,0,0,0), mar=c(0,0,0,0))
     par(cex=2)
     plot(g, layout=co, vertex.color="red", vertex.label=NA, frame=TRUE,
@@ -1606,7 +1621,7 @@ tkigraph <- function() {
   }
   
   graphs <- get("graphs", .tkigraph.env)
-  motifs <- graph.motifs(graphs[[gnos]], size=read$size)
+  motifs <- motifs(graphs[[gnos]], size=read$size)
 
   if (read$size == 3) {
     co <- matrix( c(1,1, 0,0, 2,0), ncol=2, byrow=TRUE)
@@ -1614,16 +1629,16 @@ tkigraph <- function() {
     co <- matrix( c(0,1, 1,1, 0,0, 1,0), ncol=2, byrow=TRUE)
   }
 
-  if (read$size == 3 && is.directed(graphs[[gnos]])) {
+  if (read$size == 3 && is_directed(graphs[[gnos]])) {
     no <- 16
     rows <- cols <- 4
-  } else if (read$size == 3 && !is.directed(graphs[[gnos]])) {
+  } else if (read$size == 3 && !is_directed(graphs[[gnos]])) {
     no <- 4
     rows <- cols <- 2
-  } else if (read$size == 4 && is.directed(graphs[[gnos]])) {
+  } else if (read$size == 4 && is_directed(graphs[[gnos]])) {
     no <- 216
     rows <- cols <- 15
-  } else if (read$size == 4 && !is.directed(graphs[[gnos]])) {
+  } else if (read$size == 4 && !is_directed(graphs[[gnos]])) {
     no <- 11
     rows <- 4
     cols <- 3
@@ -1637,8 +1652,8 @@ tkigraph <- function() {
   layout( matrix(1:(rows*cols), nrow=rows, byrow=TRUE) )
   layout.show(rows*cols)
   for (i in seq(no)) {
-    g <- graph.isocreate(read$size, i-1,
-                         directed=is.directed(graphs[[gnos]]))
+    g <- graph_from_isomorphism_class(read$size, i-1,
+                         directed=is_directed(graphs[[gnos]]))
     par(mai=c(0,0,0,0), mar=c(0,0,0,0))
     par(cex=2)
     plot(g, layout=co, vertex.color="red", vertex.label=NA, frame=TRUE,
@@ -1656,12 +1671,12 @@ tkigraph <- function() {
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
 
-  if (!is.connected(graph)) {
+  if (!is_connected(graph)) {
     .tkigraph.error("Graph is not connected")
     return()
   }
 
-  weights <- if ("weight" %in% list.edge.attributes(graph)) "TRUE" else "FALSE"
+  weights <- if ("weight" %in% edge_attr_names(graph)) "TRUE" else "FALSE"
   read <- .tkigraph.dialogbox(TITLE="Spinglass community structure",
                               gamma=list(name="Gamma parameter",
                                 type="numeric", default=1),
@@ -1683,7 +1698,7 @@ tkigraph <- function() {
 
   read$update.rule <- c("simple", "config")[read$update.rule+1]
   if (read$weights) {
-    if (!"weight" %in% list.edge.attributes(graph)) {
+    if (!"weight" %in% edge_attr_names(graph)) {
       .tkigraph.warning("This graphs is not weighted")
       read$weights <- NULL
     } else {
@@ -1692,7 +1707,7 @@ tkigraph <- function() {
   } else {
     read$weights <- NULL
   }
-  comm <- spinglass.community(graph, weights=read$weights, spins=read$spins,
+  comm <- cluster_spinglass(graph, weights=read$weights, spins=read$spins,
                               parupdate=read$parupdate, start.temp=read$start.temp,
                               stop.temp=read$stop.temp, cool.fact=read$cool.fact,
                               update.rule=read$update.rule, gamma=read$gamma)
@@ -1701,36 +1716,36 @@ tkigraph <- function() {
 }
 
 .tkigraph.spinglass.community.dialog <- function(comm, read, gnos) {
-  dialog <- tktoplevel()
-  frame <- tkframe(dialog)
-  tkgrid(frame)
-  tktitle(dialog) <- "Spinglass community structure algorithm results"
+  dialog <- tcltk::tktoplevel()
+  frame <- tcltk::tkframe(dialog)
+  tcltk::tkgrid(frame)
+  tcltk::tktitle(dialog) <- "Spinglass community structure algorithm results"
 
   read$update.rule <- if (read$update.rule=="simple") "Simple" else "Configuration model"
-  tkgrid(tklabel(dialog, text="Spinglass community structure algorithm results",
-                 font=tkfont.create(family="times", size=16, weight="bold")),
+  tcltk::tkgrid(tcltk::tklabel(dialog, text="Spinglass community structure algorithm results",
+                 font=tcltk::tkfont.create(family="times", size=16, weight="bold")),
          columnspan=3, sticky="nsew", "in"=frame, padx=10, pady=10)
-  tkgrid(txt <- tktext(dialog), columnspan=1, rowspan=5, sticky="nsew",
+  tcltk::tkgrid(txt <- tcltk::tktext(dialog), columnspan=1, rowspan=5, sticky="nsew",
          "in"=frame, padx=10, pady=10)
-  tkconfigure(txt, height=15)
-  tkinsert(txt, "end", "Parameters were:\n")
-  tkinsert(txt, "end", paste("  Gamma=", read$gamma, "\n"))
-  tkinsert(txt, "end", if (is.null(read$weights)) "  Weights were not used.\n" else
+  tcltk::tkconfigure(txt, height=15)
+  tcltk::tkinsert(txt, "end", "Parameters were:\n")
+  tcltk::tkinsert(txt, "end", paste("  Gamma=", read$gamma, "\n"))
+  tcltk::tkinsert(txt, "end", if (is.null(read$weights)) "  Weights were not used.\n" else
            "  Weights were used.\n")
-  tkinsert(txt, "end", paste("  Number of spins=", read$spins, "\n"))
-  tkinsert(txt, "end", if (read$parupdate) "  Parallel updating.\n" else
+  tcltk::tkinsert(txt, "end", paste("  Number of spins=", read$spins, "\n"))
+  tcltk::tkinsert(txt, "end", if (read$parupdate) "  Parallel updating.\n" else
            "  Sequential updating.\n")
-  tkinsert(txt, "end", paste("  Update rule:", read$update.rule, "\n"))
-  tkinsert(txt, "end", paste("  Start temperature was", read$start.temp, "\n"))
-  tkinsert(txt, "end", paste("  Stop temperaure was", read$stop.temp, "\n"))
-  tkinsert(txt, "end", paste("  Cooling factor was", read$cool.fact, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Update rule:", read$update.rule, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Start temperature was", read$start.temp, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Stop temperaure was", read$stop.temp, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Cooling factor was", read$cool.fact, "\n"))
 
-  tkinsert(txt, "end", "\nResults:\n")
-  tkinsert(txt, "end", paste("  Number of communities found:", length(comm$csize),
+  tcltk::tkinsert(txt, "end", "\nResults:\n")
+  tcltk::tkinsert(txt, "end", paste("  Number of communities found:", length(comm$csize),
                              "\n"))
-  tkinsert(txt, "end", paste("  Modularity of the result:", comm$modularity, "\n"))
-  tkinsert(txt, "end", paste("  Stopped at temperature:", comm$temperature, "\n"))
-  tkconfigure(txt, state="disabled")
+  tcltk::tkinsert(txt, "end", paste("  Modularity of the result:", comm$modularity, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Stopped at temperature:", comm$temperature, "\n"))
+  tcltk::tkconfigure(txt, state="disabled")
 
   show.communities <- function() {
     members <- sapply(sapply(seq(along=comm$csize),
@@ -1764,19 +1779,19 @@ tkigraph <- function() {
     ## TODO
   }
   
-  tkgrid(tkbutton(dialog, text="Show communities", command=show.communities),
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Show communities", command=show.communities),
          "in"=frame, sticky="ew", column=1, row=1, padx=10, pady=10)
-  tkgrid(tkbutton(dialog, text="Show membership", command=show.membership),
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Show membership", command=show.membership),
          "in"=frame, sticky="ew", column=1, row=2, padx=10, pady=10)
-  tkgrid(tkbutton(dialog, text="Show community sizes", command=show.csize),
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Show community sizes", command=show.csize),
          "in"=frame, sticky="ew", column=1, row=3, padx=10, pady=10)
-  tkgrid(tkbutton(dialog, text="Draw communities",
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Draw communities",
                   command=function() plot.communities(simple=FALSE)),
          "in"=frame, sticky="ew", column=1, row=4, padx=10, pady=10)
-##   tkgrid(tkbutton(dialog, text="Create subgraph", command=create.subgraph),
+##   tcltk::tkgrid(tcltk::tkbutton(dialog, text="Create subgraph", command=create.subgraph),
 ##          "in"=frame, sticky="nsew", column=1, row=6, padx=10, pady=10)
   
-  tkgrid(tkbutton(dialog, text="Close", command=function() tkdestroy(dialog)),
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Close", command=function() tcltk::tkdestroy(dialog)),
          "in"=frame, sticky="nsew", columnspan=2, padx=10, pady=10)
 }
 
@@ -1788,12 +1803,12 @@ tkigraph <- function() {
   }
   graph <- get("graphs", .tkigraph.env)[[gnos]]
 
-  if (!is.connected(graph)) {
+  if (!is_connected(graph)) {
     .tkigraph.error("Graph is not connected")
     return()
   }
 
-  weights <- if ("weight" %in% list.edge.attributes(graph)) "TRUE" else "FALSE"
+  weights <- if ("weight" %in% edge_attr_names(graph)) "TRUE" else "FALSE"
   read <- .tkigraph.dialogbox(TITLE="Spinglass community of a vertex",
                               vertex=list(name="Vertex", type="numeric",
                                 default=1, min=1, max=vcount(graph)),
@@ -1814,7 +1829,7 @@ tkigraph <- function() {
   
   read$update.rule <- c("simple", "config")[read$update.rule+1]
   if (read$weights) {
-    if (!"weight" %in% list.edge.attributes(graph)) {
+    if (!"weight" %in% edge_attr_names(graph)) {
       .tkigraph.warning("This graphs is not weighted")
       read$weights <- NULL
     } else {
@@ -1823,51 +1838,51 @@ tkigraph <- function() {
   } else {
     read$weights <- NULL
   }
-  comm <- spinglass.community(graph, vertex=read$vertex,
+  comm <- cluster_spinglass(graph, vertex=read$vertex,
                               weights=read$weights, spins=read$spins,
                               update.rule=read$update.rule, gamma=read$gamma)
   .tkigraph.spinglass.mycommunity.dialog(comm, read, gnos)
 }
 
 .tkigraph.spinglass.mycommunity.dialog <- function(comm, read, gnos) {
-  dialog <- tktoplevel()
-  frame <- tkframe(dialog)
-  tkgrid(frame)
-  tktitle(dialog) <- "Spinglass community of a single vertex"
+  dialog <- tcltk::tktoplevel()
+  frame <- tcltk::tkframe(dialog)
+  tcltk::tkgrid(frame)
+  tcltk::tktitle(dialog) <- "Spinglass community of a single vertex"
 
-  scr <- tkscrollbar(dialog, repeatinterval=5,
-                     command=function(...) tkyview(txt,...))
+  scr <- tcltk::tkscrollbar(dialog, repeatinterval=5,
+                     command=function(...) tcltk::tkyview(txt,...))
   
   read$update.rule <- if (read$update.rule=="simple") "Simple" else "Configuration model"
-  tkgrid(tklabel(dialog, text="Spinglass community of a single vertex",
-                 font=tkfont.create(family="times", size=16, weight="bold")),
+  tcltk::tkgrid(tcltk::tklabel(dialog, text="Spinglass community of a single vertex",
+                 font=tcltk::tkfont.create(family="times", size=16, weight="bold")),
          columnspan=3, sticky="nsew", "in"=frame, padx=10, pady=10)
-  tkgrid(txt <- tktext(dialog, yscrollcommand=function(...) tkset(scr,...)),
+  tcltk::tkgrid(txt <- tcltk::tktext(dialog, yscrollcommand=function(...) tcltk::tkset(scr,...)),
          columnspan=1, rowspan=3, sticky="nsew", "in"=frame, padx=10, pady=10)
-  tkconfigure(txt, height=17)
-  tkgrid(scr, row=1, column=1, rowspan=3, sticky="ns", "in"=frame, pady=10)
-  tkinsert(txt, "end", "Parameters were:\n")
-  tkinsert(txt, "end", paste("  Vertex:", read$vertex, "\n"));
-  tkinsert(txt, "end", paste("  Gamma=", read$gamma, "\n"))
-  tkinsert(txt, "end", if (is.null(read$weights)) "  Weights were not used.\n" else
+  tcltk::tkconfigure(txt, height=17)
+  tcltk::tkgrid(scr, row=1, column=1, rowspan=3, sticky="ns", "in"=frame, pady=10)
+  tcltk::tkinsert(txt, "end", "Parameters were:\n")
+  tcltk::tkinsert(txt, "end", paste("  Vertex:", read$vertex, "\n"));
+  tcltk::tkinsert(txt, "end", paste("  Gamma=", read$gamma, "\n"))
+  tcltk::tkinsert(txt, "end", if (is.null(read$weights)) "  Weights were not used.\n" else
            "  Weights were used.\n")
-  tkinsert(txt, "end", paste("  Number of spins=", read$spins, "\n"))
-  tkinsert(txt, "end", paste("  Update rule:", read$update.rule, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Number of spins=", read$spins, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Update rule:", read$update.rule, "\n"))
 
-  tkinsert(txt, "end", "\nResults:\n")
-  tkinsert(txt, "end", paste("  Size of the community:", length(comm$community),
+  tcltk::tkinsert(txt, "end", "\nResults:\n")
+  tcltk::tkinsert(txt, "end", paste("  Size of the community:", length(comm$community),
                              "\n"))
-  tkinsert(txt, "end", paste("  Cohesion:", comm$cohesion, "\n"))
-  tkinsert(txt, "end", paste("  Adhesion:", comm$adhesion, "\n"))
-  tkinsert(txt, "end", paste("  Inner links:", comm$inner.links, "\n"))
-  tkinsert(txt, "end", paste("  Outer links:", comm$outer.links, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Cohesion:", comm$cohesion, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Adhesion:", comm$adhesion, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Inner links:", comm$inner.links, "\n"))
+  tcltk::tkinsert(txt, "end", paste("  Outer links:", comm$outer.links, "\n"))
 
-  tkinsert(txt, "end", "\nThe community:\n")
+  tcltk::tkinsert(txt, "end", "\nThe community:\n")
   con <- textConnection(NULL, open="w", local=TRUE)
   cat(sort(comm$community), file=con, fill=TRUE, sep=", ")
-  tkinsert(txt, "end", textConnectionValue(con))
+  tcltk::tkinsert(txt, "end", textConnectionValue(con))
   close(con)
-  tkconfigure(txt, state="disabled")
+  tcltk::tkconfigure(txt, state="disabled")
 
   plot.communities <- function(simple=FALSE) {
     graph <- get("graphs", .tkigraph.env)[[gnos]]
@@ -1878,18 +1893,18 @@ tkigraph <- function() {
   
   create.graph <- function() {
     graph <- get("graphs", .tkigraph.env)[[gnos]]
-    g <- induced.subgraph(graph, comm$community)
+    g <- induced_subgraph(graph, comm$community)
     .tkigraph.add.graph(g)
   }
   
-  tkgrid(tkbutton(dialog, text="Draw community",
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Draw community",
                   command=function() plot.communities(simple=FALSE)),
          "in"=frame, sticky="ew", column=2, row=1, padx=10, pady=10)  
-  tkgrid(tkbutton(dialog, text="Create graph from community",
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Create graph from community",
                   command=create.graph),
          "in"=frame, sticky="ew", column=2, row=2, padx=10, pady=10)         
   
-  tkgrid(tkbutton(dialog, text="Close", command=function() tkdestroy(dialog)),
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Close", command=function() tcltk::tkdestroy(dialog)),
          "in"=frame, sticky="nsew", columnspan=3, padx=10, pady=10)  
 }
 
@@ -1899,61 +1914,61 @@ tkigraph <- function() {
     .tkigraph.error("Please select exactly one graph")
     return()
   }
-  graphs <- decompose.graph(get("graphs", .tkigraph.env)[[gnos]])
-  coh <- sapply(graphs, graph.cohesion)
+  graphs <- decompose(get("graphs", .tkigraph.env)[[gnos]])
+  coh <- sapply(graphs, cohesion)
   value <- data.frame("Component"=seq(length=length(graphs)), "Cohesion"=coh)
   .tkigraph.showData(value, title=paste("Cohesion of components in graph #",
                               gnos), right=FALSE)
 }  
 
 .tkigraph.help <- function(page="index.html") {
-  dialog <- tktoplevel()
-  tktitle(dialog) <- "Help (main page)"
+  dialog <- tcltk::tktoplevel()
+  tcltk::tktitle(dialog) <- "Help (main page)"
 
   close <- function() {
-    tkdestroy(dialog)
+    tcltk::tkdestroy(dialog)
   }
 
-  scr <- tkscrollbar(dialog, repeatinterval=5,
-                     command=function(...) tkyview(txt,...))
-  txt <- tktext(dialog, yscrollcommand=function(...) tkset(scr, ...),
+  scr <- tcltk::tkscrollbar(dialog, repeatinterval=5,
+                     command=function(...) tcltk::tkyview(txt,...))
+  txt <- tcltk::tktext(dialog, yscrollcommand=function(...) tcltk::tkset(scr, ...),
                 width=80, height=40)
 
-  main.menu <- tkmenu(dialog)
-  tkadd(main.menu, "command", label="Back", command=function() {
-    tcl("render_back", txt)
+  main.menu <- tcltk::tkmenu(dialog)
+  tcltk::tkadd(main.menu, "command", label="Back", command=function() {
+    tcltk::tcl("render_back", txt)
   })
-  tkadd(main.menu, "command", label="Forw", command=function() {
-    tcl("render_forw", txt)
+  tcltk::tkadd(main.menu, "command", label="Forw", command=function() {
+    tcltk::tcl("render_forw", txt)
   })
-  tkadd(main.menu, "command", label="Home", command=function() {
-    tcl("render", txt, "index.html"); return()
+  tcltk::tkadd(main.menu, "command", label="Home", command=function() {
+    tcltk::tcl("render", txt, "index.html"); return()
   })
-  tkadd(main.menu, "command", label="Close", command=function() {
-    tkdestroy(dialog); return()
+  tcltk::tkadd(main.menu, "command", label="Close", command=function() {
+    tcltk::tkdestroy(dialog); return()
   })
-  tkconfigure(dialog, "-menu", main.menu)
+  tcltk::tkconfigure(dialog, "-menu", main.menu)
   
-  tkpack(scr, side="right", fill="y", expand=0)
-  tkpack(txt, side="left", fill="both", expand=1)
+  tcltk::tkpack(scr, side="right", fill="y", expand=0)
+  tcltk::tkpack(txt, side="left", fill="both", expand=1)
 
-  browser.button <- tkbutton(dialog, command=function() {
-    browseURL(tclvalue("browser_url"))
+  browser.button <- tcltk::tkbutton(dialog, command=function() {
+    browseURL(tcltk::tclvalue("browser_url"))
   })
   
-  tcl("global", "tkigraph_help_root", "tkigraph_help_history",
+  tcltk::tcl("global", "tkigraph_help_root", "tkigraph_help_history",
       "tkigraph_help_history_pos", "browser_button", "browser_url")  
-  tcl("set", "tkigraph_help_root",
+  tcltk::tcl("set", "tkigraph_help_root",
       system.file("tkigraph_help", package="igraph"))
-  tcl("set", "browser_button", browser.button)
+  tcltk::tcl("set", "browser_button", browser.button)
   
-  tcl("source", system.file("html_library.tcl", package="igraph"))
-  tcl("source", system.file("my_html_library.tcl", package="igraph"))
-  tcl("HMinit_win", txt)
-  tcl("start_history", txt)
-  tcl("render", txt, "index.html")
+  tcltk::tcl("source", system.file("html_library.tcl", package="igraph"))
+  tcltk::tcl("source", system.file("my_html_library.tcl", package="igraph"))
+  tcltk::tcl("HMinit_win", txt)
+  tcltk::tcl("start_history", txt)
+  tcltk::tcl("render", txt, "index.html")
   
-  tkconfigure(txt, state="disabled")
+  tcltk::tkconfigure(txt, state="disabled")
 }
 
 .tkigraph.help.external <- function(page="index.html") {
@@ -1962,24 +1977,24 @@ tkigraph <- function() {
 }
 
 .tkigraph.about <- function() {
-  dialog <- tktoplevel()
-  tktitle(dialog) <- "About tkigraph"
-  image <-tkimage.create("photo", "img", format="gif",
+  dialog <- tcltk::tktoplevel()
+  tcltk::tktitle(dialog) <- "About tkigraph"
+  image <- tcltk::tkimage.create("photo", "img", format="gif",
                          file=system.file("igraph.gif", package="igraph"))
-  logo <- tklabel(dialog, relief="flat", padx=10, pady=10, image=image)
-  label <- tklabel(dialog, padx=30, pady=10,
+  logo <- tcltk::tklabel(dialog, relief="flat", padx=10, pady=10, image=image)
+  label <- tcltk::tklabel(dialog, padx=30, pady=10,
                    text=paste(sep="", "tkigraph (c) 2009 Gabor Csardi\n",
                      "igraph (c) 2003-2009 Gabor Csardi and Tamas Nepusz\n\n",
                      "This is igraph version ",
                      packageDescription("igraph")$Version, " and\n",
                      R.version$version.string))
-  close <- tkbutton(dialog, text="Close", command=function() {
-    tkdestroy(dialog); return()
+  close <- tcltk::tkbutton(dialog, text="Close", command=function() {
+    tcltk::tkdestroy(dialog); return()
   })
 
-  tkpack(logo, side="top", anchor="c", expand=0)
-  tkpack(label, side="top", anchor="c", expand=0)
-  tkpack(close, side="bottom", anchor="c", expand=0)
+  tcltk::tkpack(logo, side="top", anchor="c", expand=0)
+  tcltk::tkpack(label, side="top", anchor="c", expand=0)
+  tcltk::tkpack(close, side="bottom", anchor="c", expand=0)
 }
 
 #####################################################
@@ -2043,9 +2058,9 @@ tkigraph <- function() {
        "data frame too wide")
     options(width = oldwidth)
     if (is.null(inthis)) {
-      base <- tktoplevel()
-      tkwm.geometry(base, placement)
-      tkwm.title(base, {
+      base <- tcltk::tktoplevel()
+      tcltk::tkwm.geometry(base, placement)
+      tcltk::tkwm.title(base, {
         if (is.null(title))
           object.name
         else title
@@ -2061,14 +2076,14 @@ tkigraph <- function() {
     yy <- substring(zz, 2 + max(nchar(row.names(dataframe))))
     datawidth <- max(nchar(yy))
     winwidth <- min(1 + datawidth, maxwidth)
-    hdr <- tktext(base,
+    hdr <- tcltk::tktext(base,
                   bg = colname.bgcolor,
                   fg = colname.textcolor,
                   font = font,
                   height = 1,
                   width = winwidth,
                   takefocus = TRUE)
-    ftr <- tktext(base,
+    ftr <- tcltk::tktext(base,
                   bg = colname.bgcolor,
                   fg = colname.textcolor,
                   font = font,
@@ -2076,7 +2091,7 @@ tkigraph <- function() {
                   width = winwidth,
                   takefocus = TRUE)
     textheight <- min(maxheight, nrows)
-    txt <- tktext(base,
+    txt <- tcltk::tktext(base,
                   bg = body.bgcolor,
                   fg = body.textcolor,
                   font = font,
@@ -2084,216 +2099,216 @@ tkigraph <- function() {
                   width = winwidth,
                   setgrid = 1,
                   takefocus = TRUE)
-     lnames <- tktext(base,
+     lnames <- tcltk::tktext(base,
                      bg = rowname.bgcolor,
                      fg = rowname.textcolor,
                      font = font,
                      height = textheight,
                      width = namewidth,
                      takefocus = TRUE)
-    rnames <- tktext(base,
+    rnames <- tcltk::tktext(base,
                      bg = rowname.bgcolor,
                      fg = rowname.textcolor,
                      font = font,
                      height = textheight,
                      width = namewidth,
                      takefocus = TRUE)
-    xscroll <- tkscrollbar(base,
+    xscroll <- tcltk::tkscrollbar(base,
                            orient = "horizontal",
                            repeatinterval = 1,
                            command = function(...) {
-                               tkxview(txt, ...)
-                               tkxview(hdr, ...)
-                               tkxview(ftr, ...)
+                               tcltk::tkxview(txt, ...)
+                               tcltk::tkxview(hdr, ...)
+                               tcltk::tkxview(ftr, ...)
                            })
     string.to.vector <- function(string.of.indices) {
-        string.of.indices <- tclvalue(string.of.indices)
+        string.of.indices <- tcltk::tclvalue(string.of.indices)
         as.numeric(strsplit(string.of.indices, split = " ")[[1]])
     }
-    tkconfigure(txt, xscrollcommand = function(...) {
-        tkset(xscroll, ...)
-        xy <- string.to.vector(tkget(xscroll))
-        tkxview.moveto(hdr, xy[1])
-        tkxview.moveto(ftr, xy[1])
+    tcltk::tkconfigure(txt, xscrollcommand = function(...) {
+        tcltk::tkset(xscroll, ...)
+        xy <- string.to.vector(tcltk::tkget(xscroll))
+        tcltk::tkxview.moveto(hdr, xy[1])
+        tcltk::tkxview.moveto(ftr, xy[1])
     })
-    tkconfigure(hdr, xscrollcommand = function(...) {
-        tkset(xscroll, ...)
-        xy <- string.to.vector(tkget(xscroll))
-        tkxview.moveto(txt, xy[1])
-        tkxview.moveto(ftr, xy[1])
+    tcltk::tkconfigure(hdr, xscrollcommand = function(...) {
+        tcltk::tkset(xscroll, ...)
+        xy <- string.to.vector(tcltk::tkget(xscroll))
+        tcltk::tkxview.moveto(txt, xy[1])
+        tcltk::tkxview.moveto(ftr, xy[1])
     })
-    tkconfigure(ftr, xscrollcommand = function(...) {
-        tkset(xscroll, ...)
-        xy <- string.to.vector(tkget(xscroll))
-        tkxview.moveto(hdr, xy[1])
-        tkxview.moveto(txt, xy[1])
+    tcltk::tkconfigure(ftr, xscrollcommand = function(...) {
+        tcltk::tkset(xscroll, ...)
+        xy <- string.to.vector(tcltk::tkget(xscroll))
+        tcltk::tkxview.moveto(hdr, xy[1])
+        tcltk::tkxview.moveto(txt, xy[1])
     })
-    yscroll <- tkscrollbar(base,
+    yscroll <- tcltk::tkscrollbar(base,
                            orient = "vertical",
                            repeatinterval = 1,
                            command = function(...) {
-                               tkyview(txt, ...)
-                               tkyview(lnames, ...)
-                               tkyview(rnames, ...)
+                               tcltk::tkyview(txt, ...)
+                               tcltk::tkyview(lnames, ...)
+                               tcltk::tkyview(rnames, ...)
                            })
-    tkconfigure(txt, yscrollcommand = function(...) {
-        tkset(yscroll, ...)
-        xy <- string.to.vector(tkget(yscroll))
-        tkyview.moveto(lnames, xy[1])
-        tkyview.moveto(rnames, xy[1])
+    tcltk::tkconfigure(txt, yscrollcommand = function(...) {
+        tcltk::tkset(yscroll, ...)
+        xy <- string.to.vector(tcltk::tkget(yscroll))
+        tcltk::tkyview.moveto(lnames, xy[1])
+        tcltk::tkyview.moveto(rnames, xy[1])
     })
-    tkconfigure(lnames, yscrollcommand = function(...) {
-        tkset(yscroll, ...)
-        xy <- string.to.vector(tkget(yscroll))
-        tkyview.moveto(txt, xy[1])
-        tkyview.moveto(rnames, xy[1])
+    tcltk::tkconfigure(lnames, yscrollcommand = function(...) {
+        tcltk::tkset(yscroll, ...)
+        xy <- string.to.vector(tcltk::tkget(yscroll))
+        tcltk::tkyview.moveto(txt, xy[1])
+        tcltk::tkyview.moveto(rnames, xy[1])
     })
-    tkconfigure(rnames, yscrollcommand = function(...) {
-        tkset(yscroll, ...)
-        xy <- string.to.vector(tkget(yscroll))
-        tkyview.moveto(txt, xy[1])
-        tkyview.moveto(lnames, xy[1])
+    tcltk::tkconfigure(rnames, yscrollcommand = function(...) {
+        tcltk::tkset(yscroll, ...)
+        xy <- string.to.vector(tcltk::tkget(yscroll))
+        tcltk::tkyview.moveto(txt, xy[1])
+        tcltk::tkyview.moveto(lnames, xy[1])
     })
-    tkbind(txt, "<B2-Motion>", function(x, y) {
-        tkscan.dragto(txt, x, y)
+    tcltk::tkbind(txt, "<B2-Motion>", function(x, y) {
+        tcltk::tkscan.dragto(txt, x, y)
     })
 ## The next block just enables copying from the text boxes
 {
     copyText.hdr <- function(){
-        tcl("event", "generate",
-              .Tk.ID(hdr),
+        tcltk::tcl("event", "generate",
+                   tcltk::.Tk.ID(hdr),
               "<<Copy>>")}
-    tkbind(hdr, "<Button-1>", function() tkfocus(hdr))
-    editPopupMenu.hdr <- tkmenu(hdr, tearoff = FALSE)
-    tkadd(editPopupMenu.hdr, "command", label = "Copy <Ctrl-C>",
+    tcltk::tkbind(hdr, "<Button-1>", function() tcltk::tkfocus(hdr))
+    editPopupMenu.hdr <- tcltk::tkmenu(hdr, tearoff = FALSE)
+    tcltk::tkadd(editPopupMenu.hdr, "command", label = "Copy <Ctrl-C>",
               command = copyText.hdr)
     RightClick.hdr <- function(x,y) # x and y are the mouse coordinates
     {
-        rootx <- as.integer(tkwinfo("rootx", hdr))
-        rooty <- as.integer(tkwinfo("rooty", hdr))
+        rootx <- as.integer(tcltk::tkwinfo("rootx", hdr))
+        rooty <- as.integer(tcltk::tkwinfo("rooty", hdr))
         xTxt <- as.integer(x) + rootx
         yTxt <- as.integer(y) + rooty
-        tcl("tk_popup", editPopupMenu.hdr, xTxt, yTxt)
+        tcltk::tcl("tk_popup", editPopupMenu.hdr, xTxt, yTxt)
     }
-    tkbind(hdr, "<Button-3>", RightClick.hdr)
-    tkbind(hdr, "<Control-KeyPress-c>", copyText.hdr)
+    tcltk::tkbind(hdr, "<Button-3>", RightClick.hdr)
+    tcltk::tkbind(hdr, "<Control-KeyPress-c>", copyText.hdr)
     ##
     copyText.ftr <- function(){
-        tcl("event", "generate",
-              .Tk.ID(ftr),
+        tcltk::tcl("event", "generate",
+              tcltk::.Tk.ID(ftr),
               "<<Copy>>")}
-    tkbind(ftr, "<Button-1>", function() tkfocus(ftr))
-    editPopupMenu.ftr <- tkmenu(ftr, tearoff = FALSE)
-    tkadd(editPopupMenu.ftr, "command", label = "Copy <Ctrl-C>",
+    tcltk::tkbind(ftr, "<Button-1>", function() tcltk::tkfocus(ftr))
+    editPopupMenu.ftr <- tcltk::tkmenu(ftr, tearoff = FALSE)
+    tcltk::tkadd(editPopupMenu.ftr, "command", label = "Copy <Ctrl-C>",
               command = copyText.ftr)
     RightClick.ftr <- function(x,y) # x and y are the mouse coordinates
     {
-        rootx <- as.integer(tkwinfo("rootx", ftr))
-        rooty <- as.integer(tkwinfo("rooty", ftr))
+        rootx <- as.integer(tcltk::tkwinfo("rootx", ftr))
+        rooty <- as.integer(tcltk::tkwinfo("rooty", ftr))
         xTxt <- as.integer(x) + rootx
         yTxt <- as.integer(y) + rooty
-        tcl("tk_popup", editPopupMenu.ftr, xTxt, yTxt)
+        tcltk::tcl("tk_popup", editPopupMenu.ftr, xTxt, yTxt)
     }
-    tkbind(ftr, "<Button-3>", RightClick.ftr)
-    tkbind(ftr, "<Control-KeyPress-c>", copyText.ftr)
+    tcltk::tkbind(ftr, "<Button-3>", RightClick.ftr)
+    tcltk::tkbind(ftr, "<Control-KeyPress-c>", copyText.ftr)
     ##
     copyText.txt <- function(){
-        tcl("event", "generate",
-              .Tk.ID(txt),
+        tcltk::tcl("event", "generate",
+              tcltk::.Tk.ID(txt),
               "<<Copy>>")}
-    tkbind(txt, "<Button-1>", function() tkfocus(txt))
-    editPopupMenu.txt <- tkmenu(txt, tearoff = FALSE)
-    tkadd(editPopupMenu.txt, "command", label = "Copy <Ctrl-C>",
+    tcltk::tkbind(txt, "<Button-1>", function() tcltk::tkfocus(txt))
+    editPopupMenu.txt <- tcltk::tkmenu(txt, tearoff = FALSE)
+    tcltk::tkadd(editPopupMenu.txt, "command", label = "Copy <Ctrl-C>",
               command = copyText.txt)
     RightClick.txt <- function(x,y) # x and y are the mouse coordinates
     {
-        rootx <- as.integer(tkwinfo("rootx", txt))
-        rooty <- as.integer(tkwinfo("rooty", txt))
+        rootx <- as.integer(tcltk::tkwinfo("rootx", txt))
+        rooty <- as.integer(tcltk::tkwinfo("rooty", txt))
         xTxt <- as.integer(x) + rootx
         yTxt <- as.integer(y) + rooty
-        tcl("tk_popup", editPopupMenu.txt, xTxt, yTxt)
+        tcltk::tcl("tk_popup", editPopupMenu.txt, xTxt, yTxt)
     }
-    tkbind(txt, "<Button-3>", RightClick.txt)
-    tkbind(txt, "<Control-KeyPress-c>", copyText.txt)
+    tcltk::tkbind(txt, "<Button-3>", RightClick.txt)
+    tcltk::tkbind(txt, "<Control-KeyPress-c>", copyText.txt)
     ##
     copyText.lnames <- function(){
-        tcl("event", "generate",
-              .Tk.ID(lnames),
+        tcltk::tcl("event", "generate",
+              tcltk::.Tk.ID(lnames),
               "<<Copy>>")}
-    tkbind(lnames, "<Button-1>", function() tkfocus(lnames))
-    editPopupMenu.lnames <- tkmenu(lnames, tearoff = FALSE)
-    tkadd(editPopupMenu.lnames, "command", label = "Copy <Ctrl-C>",
+    tcltk::tkbind(lnames, "<Button-1>", function() tcltk::tkfocus(lnames))
+    editPopupMenu.lnames <- tcltk::tkmenu(lnames, tearoff = FALSE)
+    tcltk::tkadd(editPopupMenu.lnames, "command", label = "Copy <Ctrl-C>",
               command = copyText.lnames)
     RightClick.lnames <- function(x,y) # x and y are the mouse coordinates
     {
-        rootx <- as.integer(tkwinfo("rootx", lnames))
-        rooty <- as.integer(tkwinfo("rooty", lnames))
+        rootx <- as.integer(tcltk::tkwinfo("rootx", lnames))
+        rooty <- as.integer(tcltk::tkwinfo("rooty", lnames))
         xTxt <- as.integer(x) + rootx
         yTxt <- as.integer(y) + rooty
-        tcl("tk_popup", editPopupMenu.lnames, xTxt, yTxt)
+        tcltk::tcl("tk_popup", editPopupMenu.lnames, xTxt, yTxt)
     }
-    tkbind(lnames, "<Button-3>", RightClick.lnames)
-    tkbind(lnames, "<Control-KeyPress-c>", copyText.lnames)
+    tcltk::tkbind(lnames, "<Button-3>", RightClick.lnames)
+    tcltk::tkbind(lnames, "<Control-KeyPress-c>", copyText.lnames)
     ##
         copyText.rnames <- function(){
-        tcl("event", "generate",
-              .Tk.ID(rnames),
+        tcltk::tcl("event", "generate",
+              tcltk::.Tk.ID(rnames),
               "<<Copy>>")}
-    tkbind(rnames, "<Button-1>", function() tkfocus(rnames))
-    editPopupMenu.rnames <- tkmenu(rnames, tearoff = FALSE)
-    tkadd(editPopupMenu.rnames, "command", label = "Copy <Ctrl-C>",
+    tcltk::tkbind(rnames, "<Button-1>", function() tcltk::tkfocus(rnames))
+    editPopupMenu.rnames <- tcltk::tkmenu(rnames, tearoff = FALSE)
+    tcltk::tkadd(editPopupMenu.rnames, "command", label = "Copy <Ctrl-C>",
               command = copyText.rnames)
     RightClick.rnames <- function(x,y) # x and y are the mouse coordinates
     {
-        rootx <- as.integer(tkwinfo("rootx", rnames))
-        rooty <- as.integer(tkwinfo("rooty", rnames))
+        rootx <- as.integer(tcltk::tkwinfo("rootx", rnames))
+        rooty <- as.integer(tcltk::tkwinfo("rooty", rnames))
         xTxt <- as.integer(x) + rootx
         yTxt <- as.integer(y) + rooty
-        tcl("tk_popup", editPopupMenu.rnames, xTxt, yTxt)
+        tcltk::tcl("tk_popup", editPopupMenu.rnames, xTxt, yTxt)
     }
-    tkbind(rnames, "<Button-3>", RightClick.rnames)
-    tkbind(rnames, "<Control-KeyPress-c>", copyText.rnames)
+    tcltk::tkbind(rnames, "<Button-3>", RightClick.rnames)
+    tcltk::tkbind(rnames, "<Control-KeyPress-c>", copyText.rnames)
 }
 
-    tktag.configure(hdr, "notwrapped", wrap = "none")
-    tktag.configure(ftr, "notwrapped", wrap = "none")
-    tktag.configure(txt, "notwrapped", wrap = "none")
-    tktag.configure(lnames, "notwrapped", wrap = "none")
-    tktag.configure(rnames, "notwrapped", wrap = "none")
-    tkinsert(txt, "end", paste(paste(yy[-1], collapse = "\n"),
+    tcltk::tktag.configure(hdr, "notwrapped", wrap = "none")
+    tcltk::tktag.configure(ftr, "notwrapped", wrap = "none")
+    tcltk::tktag.configure(txt, "notwrapped", wrap = "none")
+    tcltk::tktag.configure(lnames, "notwrapped", wrap = "none")
+    tcltk::tktag.configure(rnames, "notwrapped", wrap = "none")
+    tcltk::tkinsert(txt, "end", paste(paste(yy[-1], collapse = "\n"),
                                sep = ""), "notwrapped")
 
-    tkgrid(txt, row = 1, column = 1, sticky = "nsew")
+    tcltk::tkgrid(txt, row = 1, column = 1, sticky = "nsew")
     if ("top" %in% colname.bar) {
-        tkinsert(hdr, "end", paste(yy[1], sep = ""), "notwrapped")
-        tkgrid(hdr, row = 0, column = 1, sticky = "ew")
+        tcltk::tkinsert(hdr, "end", paste(yy[1], sep = ""), "notwrapped")
+        tcltk::tkgrid(hdr, row = 0, column = 1, sticky = "ew")
     }
     if ("bottom" %in% colname.bar) {
-        tkinsert(ftr, "end", paste(yy[1], sep = ""), "notwrapped")
-        tkgrid(ftr, row = 2, column = 1, sticky = "ew")
+        tcltk::tkinsert(ftr, "end", paste(yy[1], sep = ""), "notwrapped")
+        tcltk::tkgrid(ftr, row = 2, column = 1, sticky = "ew")
     }
     if ("left" %in% rowname.bar) {
-        tkinsert(lnames, "end",
+        tcltk::tkinsert(lnames, "end",
                  paste(rowname.text, collapse = "\n"),
                  "notwrapped")
-        tkgrid(lnames, row = 1, column = 0, sticky = "ns")
+        tcltk::tkgrid(lnames, row = 1, column = 0, sticky = "ns")
     }
     if ("right" %in% rowname.bar) {
-        tkinsert(rnames, "end",
+        tcltk::tkinsert(rnames, "end",
                  paste(rowname.text, collapse = "\n"),
                  "notwrapped")
-        tkgrid(rnames, row = 1, column = 2, sticky = "ns")
+        tcltk::tkgrid(rnames, row = 1, column = 2, sticky = "ns")
     }
-    tkconfigure(hdr, state = "disabled")
-    tkconfigure(ftr, state = "disabled")
-    tkconfigure(txt, state = "disabled")
-    tkconfigure(lnames, state = "disabled")
-    tkconfigure(rnames, state = "disabled")
+    tcltk::tkconfigure(hdr, state = "disabled")
+    tcltk::tkconfigure(ftr, state = "disabled")
+    tcltk::tkconfigure(txt, state = "disabled")
+    tcltk::tkconfigure(lnames, state = "disabled")
+    tcltk::tkconfigure(rnames, state = "disabled")
     if (maxheight < nrows) {
-        tkgrid(yscroll, row = 1, column = 3, sticky = "ns")
+        tcltk::tkgrid(yscroll, row = 1, column = 3, sticky = "ns")
     }
     if (maxwidth < datawidth) {
-        tkgrid(xscroll, row = 3, column = 1, sticky = "ew")
+        tcltk::tkgrid(xscroll, row = 3, column = 1, sticky = "ew")
     }
 
     sortColumn <- function(n, decreasing=FALSE) {
@@ -2323,60 +2338,60 @@ tkigraph <- function() {
                          inthis=base)
     }
 
-    pf <- tkframe(base)
-    if (is.null(inthis)) { tkgrid(pf, column=5, row=0, rowspan=10, sticky="new") }
+    pf <- tcltk::tkframe(base)
+    if (is.null(inthis)) { tcltk::tkgrid(pf, column=5, row=0, rowspan=10, sticky="new") }
 
     if (!is.null(showmean) && is.null(inthis)) {
       for (i in seq(along=showmean)) {
-        tkgrid(tklabel(base, text=showmean[1]), sticky="nsew",
+        tcltk::tkgrid(tcltk::tklabel(base, text=showmean[1]), sticky="nsew",
                column=0, padx=1, pady=1, columnspan=4)
       }
     }
 
-    sortBut <- tkbutton(base, text="Sort otherwise", command=function() {})
+    sortBut <- tcltk::tkbutton(base, text="Sort otherwise", command=function() {})
 
     sortPopup <- function() {
-      sortMenu <- tkmenu(base, tearoff=FALSE)
+      sortMenu <- tcltk::tkmenu(base, tearoff=FALSE)
       sapply(seq(along=colnames(dataframe)),
              function(n) {
-               tkadd(sortMenu, "command", label=colnames(dataframe)[n],
+               tcltk::tkadd(sortMenu, "command", label=colnames(dataframe)[n],
                      command=function() sortColumn(colnames(dataframe)[n]))
                label <- paste(colnames(dataframe)[n], "decreasing", sep=", ")
-               tkadd(sortMenu, "command", label=label,
+               tcltk::tkadd(sortMenu, "command", label=label,
                      command=function() sortColumn(colnames(dataframe)[n],
                        decreasing=TRUE))
              })
-      rootx <- as.integer(tkwinfo("rootx", sortBut))
-      rooty <- as.integer(tkwinfo("rooty", sortBut))
-      tkpopup(sortMenu, rootx, rooty)
+      rootx <- as.integer(tcltk::tkwinfo("rootx", sortBut))
+      rooty <- as.integer(tcltk::tkwinfo("rooty", sortBut))
+      tcltk::tkpopup(sortMenu, rootx, rooty)
     }
 
     if (!is.null(plot.command)) {
-      but <- tkbutton(base, text=plot.text, command=plot.command)
-      tkgrid(but, "in"=pf, sticky="ew", column=10, row=1, padx=1, pady=1)
+      but <- tcltk::tkbutton(base, text=plot.text, command=plot.command)
+      tcltk::tkgrid(but, "in"=pf, sticky="ew", column=10, row=1, padx=1, pady=1)
     }
 
-    if (sort.button) { tkgrid(sortBut, "in"=pf, sticky="ew", column=10, row=2,
+    if (sort.button) { tcltk::tkgrid(sortBut, "in"=pf, sticky="ew", column=10, row=2,
                               padx=1, pady=1) }
-    tkconfigure(sortBut, command=sortPopup)
+    tcltk::tkconfigure(sortBut, command=sortPopup)
 
-    savebut <- tkbutton(base, text="Export table to file", command=function() {
-      filename <- tkgetSaveFile(initialfile="data.txt",
+    savebut <- tcltk::tkbutton(base, text="Export table to file", command=function() {
+      filename <- tcltk::tkgetSaveFile(initialfile="data.txt",
                                 defaultextension="txt",
                                 title="Export as table")
       filename <- paste(as.character(filename), collapse=" ")
       write.table(dataframe, file=filename, row.names=FALSE, col.names=FALSE)
     })
-    tkgrid(savebut, "in"=pf, sticky="ew", column=10, row=3, padx=1, pady=1)
+    tcltk::tkgrid(savebut, "in"=pf, sticky="ew", column=10, row=3, padx=1, pady=1)
 
-    but <- tkbutton(base, text="Close", command=function() tkdestroy(base))
-    tkgrid(but, "in"=pf, sticky="ew", column=10, row=4, padx=1, pady=1) 
-    tkgrid.columnconfigure(pf, 0, weight=1)
+    but <- tcltk::tkbutton(base, text="Close", command=function() tcltk::tkdestroy(base))
+    tcltk::tkgrid(but, "in"=pf, sticky="ew", column=10, row=4, padx=1, pady=1) 
+    tcltk::tkgrid.columnconfigure(pf, 0, weight=1)
 
-    tkgrid.rowconfigure(base, 1, weight = 1)
-    tkgrid.columnconfigure(base, 1, weight = 1)
-    tkwm.maxsize(base, 2 + datawidth, nrows)
-    tkwm.minsize(base, 2 + nchar(names(dataframe)[1]), 1)
+    tcltk::tkgrid.rowconfigure(base, 1, weight = 1)
+    tcltk::tkgrid.columnconfigure(base, 1, weight = 1)
+    tcltk::tkwm.maxsize(base, 2 + datawidth, nrows)
+    tcltk::tkwm.minsize(base, 2 + nchar(names(dataframe)[1]), 1)
 invisible(NULL)
 }
 
diff --git a/R/sparsedf.R b/R/sparsedf.R
index 17e5981..af0db74 100644
--- a/R/sparsedf.R
+++ b/R/sparsedf.R
@@ -58,10 +58,14 @@ sdf <- function(..., row.names = NULL, NROW = NULL) {
   cols
 }
 
+#' @method as.data.frame igraphSDF
+
 as.data.frame.igraphSDF <- function(x, row.names, optional, ...) {
   as.data.frame(lapply(x, rep, length.out=attr(x, "NROW")))
 }
 
+#' @method "[" igraphSDF
+
 `[.igraphSDF` <- function(x, i, j, ..., drop=TRUE) {
   if (!is.character(j)) {
     stop("The column index must be character")
@@ -80,6 +84,8 @@ as.data.frame.igraphSDF <- function(x, row.names, optional, ...) {
   }
 }
 
+#' @method "[<-" igraphSDF
+ 
 `[<-.igraphSDF` <- function(x, i, j, value) {
   if (!is.character(j)) {
     stop("The column index must be character")
diff --git a/R/structural.properties.R b/R/structural.properties.R
index a155d75..c8986ba 100644
--- a/R/structural.properties.R
+++ b/R/structural.properties.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -24,13 +23,66 @@
 # Structural properties
 ###################################################################
 
+
+
+#' Diameter of a graph
+#' 
+#' The diameter of a graph is the length of the longest geodesic.
+#' 
+#' The diameter is calculated by using a breadth-first search like method.
+#' 
+#' \code{get_diameter} returns a path with the actual diameter. If there are
+#' many shortest paths of the length of the diameter, then it returns the first
+#' one found.
+#' 
+#' \code{farthest_vertices} returns two vertex ids, the vertices which are
+#' connected by the diameter path.
+#' 
+#' @aliases diameter get.diameter farthest.nodes farthest_vertices get_diameter
+#' @param graph The graph to analyze.
+#' @param directed Logical, whether directed or undirected paths are to be
+#' considered. This is ignored for undirected graphs.
+#' @param unconnected Logical, what to do if the graph is unconnected. If
+#' FALSE, the function will return a number that is one larger the largest
+#' possible diameter, which is always the number of vertices. If TRUE, the
+#' diameters of the connected components will be calculated and the largest one
+#' will be returned.
+#' @param weights Optional positive weight vector for calculating weighted
+#' distances. If the graph has a \code{weight} edge attribute, then this is
+#' used by default.
+#' @return A numeric constant for \code{diameter}, a numeric vector for
+#' \code{get_diameter}. \code{farthest_vertices} returns a list with two
+#' entries: \itemize{
+#'   \item \code{vertices} The two vertices that are the farthest.
+#'   \item \code{distnace} Their distance.
+#' }
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{distances}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' g2 <- delete_edges(g, c(1,2,1,10))
+#' diameter(g2, unconnected=TRUE)
+#' diameter(g2, unconnected=FALSE)
+#' 
+#' ## Weighted diameter
+#' set.seed(1)
+#' g <- make_ring(10)
+#' E(g)$weight <- sample(seq_len(ecount(g)))
+#' diameter(g)
+#' get_diameter(g)
+#' diameter(g, weights=NA)
+#' get_diameter(g, weights=NA)
+#' 
 diameter <- function(graph, directed=TRUE, unconnected=TRUE, weights=NULL) {
   
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -45,14 +97,16 @@ diameter <- function(graph, directed=TRUE, unconnected=TRUE, weights=NULL) {
         PACKAGE="igraph")
 }
 
-get.diameter <- function(graph, directed=TRUE, unconnected=TRUE,
+#' @export
+
+get_diameter <- function(graph, directed=TRUE, unconnected=TRUE,
                          weights=NULL) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -64,18 +118,25 @@ get.diameter <- function(graph, directed=TRUE, unconnected=TRUE,
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_get_diameter", graph, as.logical(directed),
                as.logical(unconnected), weights,
-               PACKAGE="igraph")
-  res + 1
+               PACKAGE="igraph") + 1L
+
+  if (igraph_opt("return.vs.es")) {
+    res <- create_vs(graph, res)
+  }
+
+  res
 }
 
-farthest.nodes <- function(graph, directed=TRUE, unconnected=TRUE,
+#' @export
+
+farthest_vertices <- function(graph, directed=TRUE, unconnected=TRUE,
                            weights=NULL) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -88,13 +149,21 @@ farthest.nodes <- function(graph, directed=TRUE, unconnected=TRUE,
   res <- .Call("R_igraph_farthest_points", graph, as.logical(directed),
                as.logical(unconnected), weights,
                PACKAGE="igraph")
-  res[1:2] <- res[1:2] + 1
+  res <- list(vertices = res[1:2] + 1L, distance = res[3])
+
+  if (igraph_opt("return.vs.es")) {
+    res$vertices <- create_vs(graph, res$vertices)
+  }
+
   res
 }       
 
-average.path.length <- function(graph, directed=TRUE, unconnected=TRUE) {
+#' @export
+#' @rdname distances
+
+mean_distance <- function(graph, directed=TRUE, unconnected=TRUE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -103,11 +172,47 @@ average.path.length <- function(graph, directed=TRUE, unconnected=TRUE) {
         PACKAGE="igraph")
 }
 
+
+
+#' Degree and degree distribution of the vertices
+#' 
+#' The degree of a vertex is its most basic structural property, the number of
+#' its adjacent edges.
+#' 
+#' 
+#' @aliases degree degree.distribution degree_distribution
+#' @param graph The graph to analyze.
+#' @param v The ids of vertices of which the degree will be calculated.
+#' @param mode Character string, \dQuote{out} for out-degree, \dQuote{in} for
+#' in-degree or \dQuote{total} for the sum of the two. For undirected graphs
+#' this argument is ignored. \dQuote{all} is a synonym of \dQuote{total}.
+#' @param loops Logical; whether the loop edges are also counted.
+#' @param normalized Logical scalar, whether to normalize the degree.  If
+#' \code{TRUE} then the result is divided by \eqn{n-1}, where \eqn{n} is the
+#' number of vertices in the graph.
+#' @param \dots Additional arguments to pass to \code{degree}, eg. \code{mode}
+#' is useful but also \code{v} and \code{loops} make sense.
+#' @return For \code{degree} a numeric vector of the same length as argument
+#' \code{v}.
+#' 
+#' For \code{degree_distribution} a numeric vector of the same length as the
+#' maximum degree plus one. The first element is the relative frequency zero
+#' degree vertices, the second vertices with degree one, etc.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' degree(g)
+#' g2 <- sample_gnp(1000, 10/1000)
+#' degree_distribution(g2)
+#' 
 degree <- function(graph, v=V(graph),
                    mode=c("all", "out", "in", "total"), loops=TRUE,
                    normalized=FALSE){
   
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   v <- as.igraph.vs(graph, v)
@@ -118,15 +223,20 @@ degree <- function(graph, v=V(graph),
   res <- .Call("R_igraph_degree", graph, v-1,
                as.numeric(mode), as.logical(loops), PACKAGE="igraph")
   if (normalized) { res <- res / (vcount(graph)-1) }
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     names(res) <- V(graph)$name[v]
   }
   res
 }
+
+#' @rdname degree
+#' @param cumulative Logical; whether the cumulative degree distribution is to
+#' be calculated.
+#' @export
+
+degree_distribution <- function(graph, cumulative=FALSE, ...) {
   
-degree.distribution <- function(graph, cumulative=FALSE, ...) {
-  
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   cs <- degree(graph, ...)
@@ -140,13 +250,148 @@ degree.distribution <- function(graph, cumulative=FALSE, ...) {
   res
 }
 
-shortest.paths <- function(graph, v=V(graph), to=V(graph),
+
+
+#' Shortest (directed or undirected) paths between vertices
+#' 
+#' \code{distances} calculates the length of all the shortest paths from
+#' or to the vertices in the network. \code{shortest_paths} calculates one
+#' shortest path (the path itself, and not just its length) from or to the
+#' given vertex.
+#' 
+#' The shortest path, or geodesic between two pair of vertices is a path with
+#' the minimal number of vertices. The functions documented in this manual page
+#' all calculate shortest paths between vertex pairs.
+#' 
+#' \code{distances} calculates the lengths of pairwise shortest paths from
+#' a set of vertices (\code{from}) to another set of vertices (\code{to}). It
+#' uses different algorithms, depending on the \code{argorithm} argument and
+#' the \code{weight} edge attribute of the graph. The implemented algorithms
+#' are breadth-first search (\sQuote{\code{unweighted}}), this only works for
+#' unweighted graphs; the Dijkstra algorithm (\sQuote{\code{dijkstra}}), this
+#' works for graphs with non-negative edge weights; the Bellman-Ford algorithm
+#' (\sQuote{\code{bellman-ford}}), and Johnson's algorithm
+#' (\sQuote{\code{"johnson"}}). The latter two algorithms work with arbitrary
+#' edge weights, but (naturally) only for graphs that don't have a negative
+#' cycle.
+#' 
+#' igraph can choose automatically between algorithms, and chooses the most
+#' efficient one that is appropriate for the supplied weights (if any). For
+#' automatic algorithm selection, supply \sQuote{\code{automatic}} as the
+#' \code{algorithm} argument. (This is also the default.)
+#' 
+#' \code{shortest_paths} calculates a single shortest path (i.e. the path
+#' itself, not just its length) between the source vertex given in \code{from},
+#' to the target vertices given in \code{to}. \code{shortest_paths} uses
+#' breadth-first search for unweighted graphs and Dijkstra's algorithm for
+#' weighted graphs. The latter only works if the edge weights are non-negative.
+#' 
+#' \code{all_shortest_paths} calculates \emph{all} shortest paths between
+#' pairs of vertices. More precisely, between the \code{from} vertex to the
+#' vertices given in \code{to}. It uses a breadth-first search for unweighted
+#' graphs and Dijkstra's algorithm for weighted ones. The latter only supports
+#' non-negative edge weights.
+#' 
+#' \code{mean_distance} calculates the average path length in a graph, by
+#' calculating the shortest paths between all pairs of vertices (both ways for
+#' directed graphs). This function does not consider edge weights currently and
+#' uses a breadth-first search.
+#' 
+#' \code{distance_table} calculates a histogram, by calculating the shortest
+#' path length between each pair of vertices. For directed graphs both
+#' directions are considered, so every pair of vertices appears twice in the
+#' histogram.
+#' 
+#' @aliases shortest.paths get.shortest.paths get.all.shortest.paths distances
+#' mean_distance distance_table average.path.length path.length.hist
+#' all_shortest_paths shortest_paths
+#' @param graph The graph to work on.
+#' @param v Numeric vector, the vertices from which the shortest paths will be
+#' calculated.
+#' @param to Numeric vector, the vertices to which the shortest paths will be
+#' calculated. By default it includes all vertices. Note that for
+#' \code{distances} every vertex must be included here at most once. (This
+#' is not required for \code{shortest_paths}.
+#' @param mode Character constant, gives whether the shortest paths to or from
+#' the given vertices should be calculated for directed graphs. If \code{out}
+#' then the shortest paths \emph{from} the vertex, if \code{in} then \emph{to}
+#' it will be considered. If \code{all}, the default, then the corresponding
+#' undirected graph will be used, ie. not directed paths are searched. This
+#' argument is ignored for undirected graphs.
+#' @param weights Possibly a numeric vector giving edge weights. If this is
+#' \code{NULL} and the graph has a \code{weight} edge attribute, then the
+#' attribute is used. If this is \code{NA} then no weights are used (even if
+#' the graph has a \code{weight} attribute).
+#' @param algorithm Which algorithm to use for the calculation. By default
+#' igraph tries to select the fastest suitable algorithm. If there are no
+#' weights, then an unweighted breadth-first search is used, otherwise if all
+#' weights are positive, then Dijkstra's algorithm is used. If there are
+#' negative weights and we do the calculation for more than 100 sources, then
+#' Johnson's algorithm is used. Otherwise the Bellman-Ford algorithm is used.
+#' You can override igraph's choice by explicitly giving this parameter. Note
+#' that the igraph C core might still override your choice in obvious cases,
+#' i.e. if there are no edge weights, then the unweighted algorithm will be
+#' used, regardless of this argument.
+#' @return For \code{distances} a numeric matrix with \code{length(to)}
+#' columns and \code{length(v)} rows. The shortest path length from a vertex to
+#' itself is always zero. For unreachable vertices \code{Inf} is included.
+#' 
+#' For \code{shortest_paths} a named list with four entries is returned:
+#' \item{vpath}{This itself is a list, of length \code{length(to)}; list
+#' element \code{i} contains the vertex ids on the path from vertex \code{from}
+#' to vertex \code{to[i]} (or the other way for directed graphs depending on
+#' the \code{mode} argument). The vector also contains \code{from} and \code{i}
+#' as the first and last elements. If \code{from} is the same as \code{i} then
+#' it is only included once. If there is no path between two vertices then a
+#' numeric vector of length zero is returned as the list element. If this
+#' output is not requested in the \code{output} argument, then it will be
+#' \code{NULL}.} \item{epath}{This is a list similar to \code{vpath}, but the
+#' vectors of the list contain the edge ids along the shortest paths, instead
+#' of the vertex ids. This entry is set to \code{NULL} if it is not requested
+#' in the \code{output} argument.} \item{predecessors}{Numeric vector, the
+#' predecessor of each vertex in the \code{to} argument, or \code{NULL} if it
+#' was not requested.} \item{inbound_edges}{Numeric vector, the inbound edge
+#' for each vertex, or \code{NULL}, if it was not requested.}
+#' 
+#' For \code{all_shortest_paths} a list is returned, each list element
+#' contains a shortest path from \code{from} to a vertex in \code{to}. The
+#' shortest paths to the same vertex are collected into consecutive elements of
+#' the list.
+#' 
+#' For \code{mean_distance} a single number is returned.
+#' 
+#' \code{distance_table} returns a named list with two entries: \code{res} is
+#' a numeric vector, the histogram of distances, \code{unconnected} is a
+#' numeric scalar, the number of pairs for which the first vertex is not
+#' reachable from the second. The sum of the two entries is always \eqn{n(n-1)}
+#' for directed graphs and \eqn{n(n-1)/2} for undirected graphs.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references West, D.B. (1996). \emph{Introduction to Graph Theory.} Upper
+#' Saddle River, N.J.: Prentice Hall.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' distances(g)
+#' shortest_paths(g, 5)
+#' all_shortest_paths(g, 1, 6:8)
+#' mean_distance(g)
+#' ## Weighted shortest paths
+#' el <- matrix(nc=3, byrow=TRUE,
+#'              c(1,2,0, 1,3,2, 1,4,1, 2,3,0, 2,5,5, 2,6,2, 3,2,1, 3,4,1,
+#'                3,7,1, 4,3,0, 4,7,2, 5,6,2, 5,8,8, 6,3,2, 6,7,1, 6,9,1,
+#'                6,10,3, 8,6,1, 8,9,1, 9,10,4) )
+#' g2 <- add_edges(make_empty_graph(10), t(el[,1:2]), weight=el[,3])
+#' distances(g2, mode="out")
+#' 
+distances <- function(graph, v=V(graph), to=V(graph),
                            mode=c("all", "out", "in"),
                            weights=NULL,
                            algorithm=c("automatic", "unweighted", "dijkstra",
                              "bellman-ford", "johnson")) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   v <- as.igraph.vs(graph, v)
@@ -158,7 +403,7 @@ shortest.paths <- function(graph, v=V(graph), to=V(graph),
                       "dijkstra"=2, "bellman-ford"=3, "johnson"=4)
   
   if (is.null(weights)) {
-    if ("weight" %in% list.edge.attributes(graph)) {
+    if ("weight" %in% edge_attr_names(graph)) {
       weights <- as.numeric(E(graph)$weight)
     }
   } else {
@@ -178,20 +423,44 @@ shortest.paths <- function(graph, v=V(graph), to=V(graph),
   res <- .Call("R_igraph_shortest_paths", graph, v-1, to-1,
                as.numeric(mode), weights, as.numeric(algorithm),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     rownames(res) <- V(graph)$name[v]
     colnames(res) <- V(graph)$name[to]
   }
   res
 }
 
-get.shortest.paths <- function(graph, from, to=V(graph),
+#' @rdname distances
+#' @param from Numeric constant, the vertex from or to the shortest paths will
+#' be calculated. Note that right now this is not a vector of vertex ids, but
+#' only a single vertex.
+#' @param output Character scalar, defines how to report the shortest paths.
+#' \dQuote{vpath} means that the vertices along the paths are reported, this
+#' form was used prior to igraph version 0.6. \dQuote{epath} means that the
+#' edges along the paths are reported. \dQuote{both} means that both forms are
+#' returned, in a named list with components \dQuote{vpath} and \dQuote{epath}.
+#' @param predecessors Logical scalar, whether to return the predecessor vertex
+#' for each vertex. The predecessor of vertex \code{i} in the tree is the
+#' vertex from which vertex \code{i} was reached. The predecessor of the start
+#' vertex (in the \code{from} argument) is itself by definition. If the
+#' predecessor is zero, it means that the given vertex was not reached from the
+#' source during the search. Note that the search terminates if all the
+#' vertices in \code{to} are reached.
+#' @param inbound.edges Logical scalar, whether to return the inbound edge for
+#' each vertex. The inbound edge of vertex \code{i} in the tree is the edge via
+#' which vertex \code{i} was reached. The start vertex and vertices that were
+#' not reached during the search will have zero in the corresponding entry of
+#' the vector. Note that the search terminates if all the vertices in \code{to}
+#' are reached.
+#' @export
+
+shortest_paths <- function(graph, from, to=V(graph),
                                mode=c("out", "all", "in"),
                                weights=NULL,
                                output=c("vpath", "epath", "both"),
                                predecessors=FALSE, inbound.edges=FALSE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -200,7 +469,7 @@ get.shortest.paths <- function(graph, from, to=V(graph),
   output <- switch(output, "vpath"=0, "epath"=1, "both"=2)
 
   if (is.null(weights)) {
-    if ("weight" %in% list.edge.attributes(graph)) {
+    if ("weight" %in% edge_attr_names(graph)) {
       weights <- as.numeric(E(graph)$weight)
     }
   } else {
@@ -232,22 +501,42 @@ get.shortest.paths <- function(graph, from, to=V(graph),
     res$inbound_edges <- res$inbound_edges + 1
   }
 
+  if (igraph_opt("return.vs.es")) {
+    if (!is.null(res$vpath)) {
+      res$vpath <- lapply(res$vpath, create_vs, graph = graph)
+    }
+    if (!is.null(res$epath)) {
+      res$epath <- lapply(res$epath, create_es, graph = graph)
+    }
+    if (!is.null(res$predecessors)) {
+      res$predecessors <- create_vs(res$predecessors, graph = graph,
+                                    na_ok = TRUE)
+    }
+    if (!is.null(res$inbound_edges)) {
+      res$inbound_edges <- create_es(res$inbound_edges, graph = graph,
+                                     na_ok = TRUE)
+    }
+  }
+
   res
 }
 
-get.all.shortest.paths <- function(graph, from,
+#' @export
+#' @rdname distances
+
+all_shortest_paths <- function(graph, from,
                                    to=V(graph),
                                    mode=c("out", "all", "in"),
 				   weights=NULL) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
   mode <- switch(mode, "out"=1, "in"=2, "all"=3)
 
   if (is.null(weights)) {
-    if ("weight" %in% list.edge.attributes(graph)) {
+    if ("weight" %in% edge_attr_names(graph)) {
       weights <- as.numeric(E(graph)$weight)
     }
   } else {
@@ -268,12 +557,45 @@ get.all.shortest.paths <- function(graph, from,
                  as.igraph.vs(graph, from)-1, as.igraph.vs(graph, to)-1,
                  weights, as.numeric(mode), PACKAGE="igraph")
   }       
+
+  if (igraph_opt("return.vs.es")) {
+    res$res <- lapply(res$res, create_vs, graph = graph)
+  }
+
   res
 }
 
+#' In- or out- component of a vertex
+#' 
+#' Finds all vertices reachable from a given vertex, or the opposite: all
+#' vertices from which a given vertex is reachable via a directed path.
+#' 
+#' A breadh-first search is conducted starting from vertex \code{v}.
+#' 
+#' @aliases subcomponent
+#' @param graph The graph to analyze.
+#' @param v The vertex to start the search from.
+#' @param mode Character string, either \dQuote{in}, \dQuote{out} or
+#' \dQuote{all}. If \dQuote{in} all vertices from which \code{v} is reachable
+#' are listed. If \dQuote{out} all vertices reachable from \code{v} are
+#' returned. If \dQuote{all} returns the union of these. It is ignored for
+#' undirected graphs.
+#' @return Numeric vector, the ids of the vertices in the same component as
+#' \code{v}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{components}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(100, 1/200)
+#' subcomponent(g, 1, "in")
+#' subcomponent(g, 1, "out")
+#' subcomponent(g, 1, "all")
+
 subcomponent <- function(graph, v, mode=c("all", "out", "in")) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -282,13 +604,49 @@ subcomponent <- function(graph, v, mode=c("all", "out", "in")) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_subcomponent", graph, as.igraph.vs(graph, v)-1,
                as.numeric(mode),
-               PACKAGE="igraph")
-  res+1
+               PACKAGE="igraph") + 1L
+
+  if (igraph_opt("return.vs.es")) res <- create_vs(graph, res)
+
+  res
 }
 
+
+
+#' Subgraph of a graph
+#' 
+#' \code{subgraph} creates a subgraph of a graph, containing only the specified
+#' vertices and all the edges among them.
+#' 
+#' \code{induced_subgraph} calculates the induced subgraph of a set of vertices
+#' in a graph. This means that exactly the specified vertices and all the edges
+#' between then will be kept in the result graph.
+#' 
+#' \code{subgraph.edges} calculates the subgraph of a graph. For this function
+#' one can specify the vertices and edges to keep. This function will be
+#' renamed to \code{subgraph} in the next major version of igraph.
+#' 
+#' The \code{subgraph} function does the same as \code{induced.graph} currently
+#' (assuming \sQuote{\code{auto}} as the \code{impl} argument), but it is
+#' deprecated and will be removed in the next major version of igraph.
+#' 
+#' @aliases subgraph induced.subgraph subgraph.edges induced_subgraph
+#' @param graph The original graph.
+#' @param v Numeric vector, the vertices of the original graph which will
+#' form the subgraph.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' g2 <- induced_subgraph(g, 1:7)
+#' g3 <- subgraph.edges(g, 1:5, 1:5)
+#' 
 subgraph <- function(graph, v) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -296,14 +654,168 @@ subgraph <- function(graph, v) {
         PACKAGE="igraph")
 }
 
+#' @rdname subgraph
+#' @param vids Numeric vector, the vertices of the original graph which will
+#' form the subgraph.
+#' @param impl Character scalar, to choose between two implementation of the
+#' subgraph calculation. \sQuote{\code{copy_and_delete}} copies the graph
+#' first, and then deletes the vertices and edges that are not included in the
+#' result graph. \sQuote{\code{create_from_scratch}} searches for all vertices
+#' and edges that must be kept and then uses them to create the graph from
+#' scratch. \sQuote{\code{auto}} chooses between the two implementations
+#' automatically, using heuristics based on the size of the original and the
+#' result graph.
+#' @export
+
+induced_subgraph <- function(graph, vids, impl=c("auto", "copy_and_delete", "create_from_scratch")) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  vids <- as.igraph.vs(graph, vids)
+  impl <- switch(igraph.match.arg(impl), "auto"=0, "copy_and_delete"=1, "create_from_scratch"=2)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_induced_subgraph", graph, vids-1, impl,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @rdname subgraph
+#' @param eids The edge ids of the edges that will be kept in the result graph.
+#' @param delete.vertices Logical scalar, whether to remove vertices that do
+#' not have any adjacent edges in \code{eids}.
+#' @export
+
+subgraph.edges <- function(graph, eids, delete.vertices=TRUE) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  eids <- as.igraph.es(graph, eids)
+  delete.vertices <- as.logical(delete.vertices)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_subgraph_edges", graph, eids-1, delete.vertices,
+        PACKAGE="igraph")
+
+  res
+}
+
+#' @rdname betweenness
+#' @param vids The vertices for which the vertex betweenness estimation will be
+#' calculated.
+#' @param cutoff The maximum path length to consider when calculating the
+#' betweenness. If zero or negative then there is no such limit.
+#' @export
+
+estimate_betweenness <- function(graph, vids=V(graph), directed=TRUE, cutoff, weights=NULL, nobigint=TRUE) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  vids <- as.igraph.vs(graph, vids)
+  directed <- as.logical(directed)
+  cutoff <- as.numeric(cutoff)
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
+  weights <- E(graph)$weight 
+  } 
+  if (!is.null(weights) && any(!is.na(weights))) { 
+  weights <- as.numeric(weights) 
+  } else { 
+  weights <- NULL 
+  }
+  nobigint <- as.logical(nobigint)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_betweenness_estimate", graph, vids-1, directed, cutoff, weights, nobigint,
+        PACKAGE="igraph")
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res) <- vertex_attr(graph, "name", vids) 
+  }
+  res
+}
+
+
+
+#' Vertex and edge betweenness centrality
+#' 
+#' The vertex and edge betweenness are (roughly) defined by the number of
+#' geodesics (shortest paths) going through a vertex or an edge.
+#' 
+#' The vertex betweenness of vertex \eqn{v}{\code{v}} is defined by
+#' 
+#' \deqn{\sum_{i\ne j, i\ne v, j\ne v} g_{ivj}/g_{ij}}{sum( g_ivj / g_ij,
+#' i!=j,i!=v,j!=v)}
+#' 
+#' The edge betweenness of edge \eqn{e}{\code{e}} is defined by
+#' 
+#' \deqn{\sum_{i\ne j} g{iej}/g_{ij}.}{sum( g_iej / g_ij, i!=j).}
+#' 
+#' \code{betweenness} calculates vertex betweenness, \code{edge_betweenness}
+#' calculates edge betweenness.
+#' 
+#' \code{estimate_betweenness} only considers paths of length \code{cutoff} or
+#' smaller, this can be run for larger graphs, as the running time is not
+#' quadratic (if \code{cutoff} is small). If \code{cutoff} is zero or negative
+#' then the function calculates the exact betweenness scores.
+#' 
+#' \code{estimate_edge_betweenness} is similar, but for edges.
+#' 
+#' For calculating the betweenness a similar algorithm to the one proposed by
+#' Brandes (see References) is used.
+#' 
+#' @aliases betweenness edge.betweenness betweenness.estimate
+#' edge.betweenness.estimate edge_betweenness estimate_betweenness
+#' estimate_edge_betweenness
+#' @param graph The graph to analyze.
+#' @param v The vertices for which the vertex betweenness will be calculated.
+#' @param directed Logical, whether directed paths should be considered while
+#' determining the shortest paths.
+#' @param weights Optional positive weight vector for calculating weighted
+#' betweenness. If the graph has a \code{weight} edge attribute, then this is
+#' used by default.
+#' @param nobigint Logical scalar, whether to use big integers during the
+#' calculation. This is only required for lattice-like graphs that have very
+#' many shortest paths between a pair of vertices. If \code{TRUE} (the
+#' default), then big integers are not used.
+#' @param normalized Logical scalar, whether to normalize the betweenness
+#' scores. If \code{TRUE}, then the results are normalized according to
+#' \deqn{B^n=\frac{2B}{n^2-3n+2}}{Bnorm=2*B/(n*n-3*n+2)}, where
+#' \eqn{B^n}{Bnorm} is the normalized, \eqn{B} the raw betweenness, and \eqn{n}
+#' is the number of vertices in the graph.
+#' @return A numeric vector with the betweenness score for each vertex in
+#' \code{v} for \code{betweenness}.
+#' 
+#' A numeric vector with the edge betweenness score for each edge in \code{e}
+#' for \code{edge_betweenness}.
+#' 
+#' \code{estimate_betweenness} returns the estimated betweenness scores for
+#' vertices in \code{vids}, \code{estimate_edge_betweenness} the estimated edge
+#' betweenness score for \emph{all} edges; both in a numeric vector.
+#' @note \code{edge_betweenness} might give false values for graphs with
+#' multiple edges.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{closeness}}, \code{\link{degree}}
+#' @references Freeman, L.C. (1979). Centrality in Social Networks I:
+#' Conceptual Clarification. \emph{Social Networks}, 1, 215-239.
+#' 
+#' Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. \emph{Journal
+#' of Mathematical Sociology} 25(2):163-177, 2001.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(10, 3/10)
+#' betweenness(g)
+#' edge_betweenness(g)
+#' 
 betweenness <- function(graph, v=V(graph), directed=TRUE, weights=NULL,
                         nobigint=TRUE, normalized=FALSE) {
   
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   v <- as.igraph.vs(graph, v)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -317,25 +829,120 @@ betweenness <- function(graph, v=V(graph), directed=TRUE, weights=NULL,
                PACKAGE="igraph")
   if (normalized) {
     vc <- vcount(graph)
-    if (is.directed(graph) && directed) {
+    if (is_directed(graph) && directed) {
       res <- res / ( vc*vc-3*vc+2)
     } else {
       res <- 2*res / ( vc*vc-3*vc+2)
     }
   }
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     names(res) <- V(graph)$name[v]
   }
   res
 }
 
+
+
+#' Transitivity of a graph
+#' 
+#' Transitivity measures the probability that the adjacent vertices of a vertex
+#' are connected. This is sometimes also called the clustering coefficient.
+#' 
+#' Note that there are essentially two classes of transitivity measures, one is
+#' a vertex-level, the other a graph level property.
+#' 
+#' There are several generalizations of transitivity to weighted graphs, here
+#' we use the definition by A. Barrat, this is a local vertex-level quantity,
+#' its formula is
+#' 
+#' \deqn{C_i^w=\frac{1}{s_i(k_i-1)}\sum_{j,h}\frac{w_{ij}+w_{ih}}{2}a_{ij}a_{ih}a_{jh}}{
+#' weighted C_i = 1/s_i 1/(k_i-1) sum( (w_ij+w_ih)/2 a_ij a_ih a_jh, j, h)}
+#' 
+#' \eqn{s_i}{s_i} is the strength of vertex \eqn{i}{i}, see
+#' \code{\link{strength}}, \eqn{a_{ij}}{a_ij} are elements of the
+#' adjacency matrix, \eqn{k_i}{k_i} is the vertex degree, \eqn{w_{ij}}{w_ij}
+#' are the weights.
+#' 
+#' This formula gives back the normal not-weighted local transitivity if all
+#' the edge weights are the same.
+#' 
+#' The \code{barrat} type of transitivity does not work for graphs with
+#' multiple and/or loop edges. If you want to calculate it for a directed
+#' graph, call \code{\link{as.undirected}} with the \code{collapse} mode first.
+#' 
+#' @param graph The graph to analyze.
+#' @param type The type of the transitivity to calculate. Possible values:
+#' \describe{ \item{"global"}{The global transitivity of an undirected
+#' graph (directed graphs are considered as undirected ones as well). This is
+#' simply the ratio of the triangles and the connected triples in the graph.
+#' For directed graph the direction of the edges is ignored. }
+#' \item{"local"}{The local transitivity of an undirected graph, this is
+#' calculated for each vertex given in the \code{vids} argument. The local
+#' transitivity of a vertex is the ratio of the triangles connected to the
+#' vertex and the triples centered on the vertex. For directed graph the
+#' direction of the edges is ignored. } \item{"undirected"}{This is the
+#' same as \code{global}.} \item{"globalundirected"}{This is the same as
+#' \code{global}.} \item{"localundirected"}{This is the same as
+#' \code{local}.} \item{"barrat"}{The weighted transitivity as defined A.
+#' Barrat. See details below.} \item{"weighted"}{The same as
+#' \code{barrat}.} }
+#' @param vids The vertex ids for the local transitivity will be calculated.
+#' This will be ignored for global transitivity types.  The default value is
+#' \code{NULL}, in this case all vertices are considered. It is slightly faster
+#' to supply \code{NULL} here than \code{V(graph)}.
+#' @param weights Optional weights for weighted transitivity. It is ignored for
+#' other transitivity measures. If it is \code{NULL} (the default) and the
+#' graph has a \code{weight} edge attribute, then it is used automatically.
+#' @param isolates Character scalar, defines how to treat vertices with degree
+#' zero and one. If it is \sQuote{\code{NaN}} then they local transitivity is
+#' reported as \code{NaN} and they are not included in the averaging, for the
+#' transitivity types that calculate an average. If there are no vertices with
+#' degree two or higher, then the averaging will still result \code{NaN}. If it
+#' is \sQuote{\code{zero}}, then we report 0 transitivity for them, and they
+#' are included in the averaging, if an average is calculated.
+#' @return For \sQuote{\code{global}} a single number, or \code{NaN} if there
+#' are no connected triples in the graph.
+#' 
+#' For \sQuote{\code{local}} a vector of transitivity scores, one for each
+#' vertex in \sQuote{\code{vids}}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Wasserman, S., and Faust, K. (1994). \emph{Social Network
+#' Analysis: Methods and Applications.} Cambridge: Cambridge University Press.
+#' 
+#' Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras, Alessandro
+#' Vespignani: The architecture of complex weighted networks, Proc. Natl. Acad.
+#' Sci. USA 101, 3747 (2004)
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' transitivity(g)
+#' g2 <- sample_gnp(1000, 10/1000)
+#' transitivity(g2)   # this is about 10/1000
+#' 
+#' # Weighted version, the figure from the Barrat paper
+#' gw <- graph_from_literal(A-B:C:D:E, B-C:D, C-D)
+#' E(gw)$weight <- 1
+#' E(gw)[ V(gw)[name == "A"] %--% V(gw)[name == "E" ] ]$weight <- 5
+#' transitivity(gw, vids="A", type="local")
+#' transitivity(gw, vids="A", type="weighted")
+#' 
+#' # Weighted reduces to "local" if weights are the same
+#' gw2 <- sample_gnp(1000, 10/1000)
+#' E(gw2)$weight <- 1
+#' t1 <- transitivity(gw2, type="local")
+#' t2 <- transitivity(gw2, type="weighted")
+#' all(is.na(t1) == is.na(t2))
+#' all(na.omit(t1 == t2))
+#' 
 transitivity <- function(graph, type=c("undirected", "global", "globalundirected",
                                   "localundirected", "local", "average",
                                   "localaverage", "localaverageundirected",
                                   "barrat", "weighted"),
                          vids=NULL, weights=NULL, isolates=c("NaN", "zero")) {
   
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   type <- igraph.match.arg(type)
@@ -344,7 +951,7 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
                  "localaverage"=2, "localaverageundirected"=2, "barrat"=3,
                  "weighted"=3)
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     weights <- E(graph)$weight
   }
   if (!is.null(weights) && any(!is.na(weights))) {
@@ -386,9 +993,9 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
 }
 
 ## Generated by stimulus now
-## graph.laplacian <- function(graph, normalized=FALSE) {
+## laplacian_matrix <- function(graph, normalized=FALSE) {
 
-##   if (!is.igraph(graph)) {
+##   if (!is_igraph(graph)) {
 ##     stop("Not a graph object")
 ##   }
   
@@ -398,16 +1005,16 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
 ## }
   
 ## OLD implementation
-## graph.laplacian <- function(graph, normalized=FALSE) {
+## laplacian_matrix <- function(graph, normalized=FALSE) {
 
-##   if (!is.igraph(graph)) {
+##   if (!is_igraph(graph)) {
 ##     stop("Not a graph object")
 ##   }
-##   if (is.directed(graph)) {
+##   if (is_directed(graph)) {
 ##     warning("Laplacian of a directed graph???")
 ##   }
 
-##   M <- get.adjacency(graph)
+##   M <- as_adj(graph)
 ##   if (!normalized) {
 ##     M <- structure(ifelse(M>0, -1, 0), dim=dim(M))
 ##     diag(M) <- degree(graph)
@@ -426,12 +1033,12 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
 
 ## constraint.orig <- function(graph, nodes=V(graph), attr=NULL) {
 
-##   if (!is.igraph(graph)) {
+##   if (!is_igraph(graph)) {
 ##     stop("Not a graph object")
 ##   }
 
 ##   idx <- degree(graph) != 0
-##   A <- get.adjacency(graph, attr=attr)
+##   A <- as_adj(graph, attr=attr)
 ##   A <- A[idx, idx]
 ##   n <- sum(idx)
   
@@ -458,7 +1065,7 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
 
 ## constraint.old <- function(graph, nodes=V(graph)) {
 
-##   if (!is.igraph(graph)) {
+##   if (!is_igraph(graph)) {
 ##     stop("Not a graph object")
 ##   }
 
@@ -477,14 +1084,14 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
 ##       j <- first[b]
 
 ##       ## cj is the contribution of j
-##       cj <- are.connected(graph, i, j)      / deg[i+1]
-##       cj <- cj + are.connected(graph, j, i) / deg[i+1]
+##       cj <- are_adjacent(graph, i, j)      / deg[i+1]
+##       cj <- cj + are_adjacent(graph, j, i) / deg[i+1]
 
 ##       second <- not(i, not(j, neighbors(graph, j, mode="all")))
 ##       for (c in seq(along=second)) {
 ##         q <- second[c]
-##         cj <- cj + are.connected(graph, i, q) / deg[q+1] / deg[i+1]
-##         cj <- cj + are.connected(graph, q, i) / deg[q+1] / deg[i+1]
+##         cj <- cj + are_adjacent(graph, i, q) / deg[q+1] / deg[i+1]
+##         cj <- cj + are_adjacent(graph, q, i) / deg[q+1] / deg[i+1]
 ##       }
                             
 ##       ## Ok, we have the total contribution of j
@@ -492,21 +1099,64 @@ transitivity <- function(graph, type=c("undirected", "global", "globalundirected
 ##     }
 ##   }
 
-##   if (!is.directed(graph)) {
+##   if (!is_directed(graph)) {
 ##     res <- res/4
 ##   }
 ##   res
 ## }
 
+
+
+#' Burt's constraint
+#' 
+#' Given a graph, \code{constraint} calculates Burt's constraint for each
+#' vertex.
+#'
+#' Burt's constraint is higher if ego has less, or mutually
+#' stronger related (i.e. more redundant) contacts. Burt's measure of
+#' constraint, \eqn{C_i}{C[i]}, of vertex \eqn{i}'s ego network
+#' \eqn{V_i}{V[i]}, is defined for directed and valued graphs,
+#' \deqn{C_i=\sum_{j \in V_i \setminus \{i\}} (p_{ij}+\sum_{q \in V_i
+#'     \setminus \{i,j\}} p_{iq} p_{qj})^2}{
+#'   C[i] = sum( [sum( p[i,j] + p[i,q] p[q,j], q in V[i], q != i,j )]^2, j in
+#'   V[i], j != i).
+#' }
+#' for a graph of order (ie. number of vertices) \eqn{N}, where
+#' proportional tie strengths are defined as 
+#' \deqn{p_{ij} = \frac{a_{ij}+a_{ji}}{\sum_{k \in V_i \setminus \{i\}}(a_{ik}+a_{ki})},}{
+#'   p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),
+#' }
+#' \eqn{a_{ij}}{a[i,j]} are elements of \eqn{A} and the latter being the
+#' graph adjacency matrix. For isolated vertices, constraint is undefined.
+#' 
+#' @param graph A graph object, the input graph.
+#' @param nodes The vertices for which the constraint will be calculated.
+#' Defaults to all vertices.
+#' @param weights The weights of the edges. If this is \code{NULL} and there is
+#' a \code{weight} edge attribute this is used. If there is no such edge
+#' attribute all edges will have the same weight.
+#' @return A numeric vector of constraint scores
+#' @author Jeroen Bruggeman
+#' (\url{https://sites.google.com/site/jebrug/jeroen-bruggeman-social-science})
+#' and Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Burt, R.S. (2004). Structural holes and good ideas.
+#' \emph{American Journal of Sociology} 110, 349-399.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(20, 5/20)
+#' constraint(g)
+#' 
 constraint <- function(graph, nodes=V(graph), weights=NULL) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   nodes <- as.igraph.vs(graph, nodes)
   
   if (is.null(weights)) {
-    if ("weight" %in% list.edge.attributes(graph)) {
+    if ("weight" %in% edge_attr_names(graph)) {
       weights <- E(graph)$weight
     }
   }
@@ -514,16 +1164,51 @@ constraint <- function(graph, nodes=V(graph), weights=NULL) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_constraint", graph, nodes-1, as.numeric(weights),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     names(res) <- V(graph)$name[nodes]
   }
   res
 }
 
+
+
+#' Reciprocity of graphs
+#' 
+#' Calculates the reciprocity of a directed graph.
+#' 
+#' The measure of reciprocity defines the proporsion of mutual connections, in
+#' a directed graph. It is most commonly defined as the probability that the
+#' opposite counterpart of a directed edge is also included in the graph. Or in
+#' adjacency matrix notation: \eqn{\sum_{ij} (A\cdot A')_{ij}}{sum(i, j,
+#' (A.*A')ij) / sum(i, j, Aij)}, where \eqn{A\cdot A'}{A.*A'} is the
+#' element-wise product of matrix \eqn{A} and its transpose. This measure is
+#' calculated if the \code{mode} argument is \code{default}.
+#' 
+#' Prior to igraph version 0.6, another measure was implemented, defined as the
+#' probability of mutual connection between a vertex pair, if we know that
+#' there is a (possibly non-mutual) connection between them. In other words,
+#' (unordered) vertex pairs are classified into three groups: (1)
+#' not-connected, (2) non-reciprocaly connected, (3) reciprocally connected.
+#' The result is the size of group (3), divided by the sum of group sizes
+#' (2)+(3). This measure is calculated if \code{mode} is \code{ratio}.
+#' 
+#' @param graph The graph object.
+#' @param ignore.loops Logical constant, whether to ignore loop edges.
+#' @param mode See below.
+#' @return A numeric scalar between zero and one.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(20, 5/20, directed=TRUE)
+#' reciprocity(g)
+#' 
 reciprocity <- function(graph, ignore.loops=TRUE,
                         mode=c("default", "ratio")) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- switch(igraph.match.arg(mode), 'default'=0, 'ratio'=1)
@@ -533,29 +1218,16 @@ reciprocity <- function(graph, ignore.loops=TRUE,
         as.numeric(mode), PACKAGE="igraph")
 }
 
-rewire <- function(graph, mode=c("simple", "loops"), niter=100) {
-  
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-  
-  mode <- igraph.match.arg(mode)
-  mode <- switch(mode, "simple"=0, "loops"=1)
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_rewire", graph, as.numeric(niter), as.numeric(mode),
-        PACKAGE="igraph")
-}
 
 bonpow.dense <- function(graph, nodes=V(graph),
                          loops=FALSE, exponent=1,
                          rescale=FALSE, tol=1e-7){
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }  
   
-  d <- get.adjacency(graph)
+  d <- as_adj(graph)
   if (!loops) {
     diag(d) <- 0
   }
@@ -584,7 +1256,7 @@ bonpow.sparse <- function(graph, nodes=V(graph), loops=FALSE,
   vg <- vcount(graph)
   
   ## sparse adjacency matrix
-  d <- get.adjacency(graph, sparse=TRUE)
+  d <- as_adj(graph, sparse=TRUE)
 
   ## sparse identity matrix
   id <- Matrix::Diagonal(vg)
@@ -601,7 +1273,112 @@ bonpow.sparse <- function(graph, nodes=V(graph), loops=FALSE,
   ev[as.numeric(nodes)]
 }
 
-bonpow <- function(graph, nodes=V(graph),
+
+
+#' Find Bonacich Power Centrality Scores of Network Positions
+#' 
+#' \code{power_centrality} takes a graph (\code{dat}) and returns the Boncich power
+#' centralities of positions (selected by \code{nodes}).  The decay rate for
+#' power contributions is specified by \code{exponent} (1 by default).
+#' 
+#' Bonacich's power centrality measure is defined by
+#' \eqn{C_{BP}\left(\alpha,\beta\right)=\alpha\left(\mathbf{I}-\beta\mathbf{A}\right)^{-1}\mathbf{A}\mathbf{1}}{C_BP(alpha,beta)=alpha
+#' (I-beta A)^-1 A 1}, where \eqn{\beta}{beta} is an attenuation parameter (set
+#' here by \code{exponent}) and \eqn{\mathbf{A}}{A} is the graph adjacency
+#' matrix.  (The coefficient \eqn{\alpha}{alpha} acts as a scaling parameter,
+#' and is set here (following Bonacich (1987)) such that the sum of squared
+#' scores is equal to the number of vertices.  This allows 1 to be used as a
+#' reference value for the ``middle'' of the centrality range.)  When
+#' \eqn{\beta \rightarrow }{beta->1/lambda_A1}\eqn{
+#' 1/\lambda_{\mathbf{A}1}}{beta->1/lambda_A1} (the reciprocal of the largest
+#' eigenvalue of \eqn{\mathbf{A}}{A}), this is to within a constant multiple of
+#' the familiar eigenvector centrality score; for other values of \eqn{\beta},
+#' the behavior of the measure is quite different.  In particular, \eqn{\beta}
+#' gives positive and negative weight to even and odd walks, respectively, as
+#' can be seen from the series expansion
+#' \eqn{C_{BP}\left(\alpha,\beta\right)=\alpha \sum_{k=0}^\infty \beta^k
+#' }{C_BP(alpha,beta) = alpha sum( beta^k A^(k+1) 1, k in 0..infinity )}\eqn{
+#' \mathbf{A}^{k+1} \mathbf{1}}{C_BP(alpha,beta) = alpha sum( beta^k A^(k+1) 1,
+#' k in 0..infinity )} which converges so long as \eqn{|\beta|
+#' }{|beta|<1/lambda_A1}\eqn{ < 1/\lambda_{\mathbf{A}1}}{|beta|<1/lambda_A1}.
+#' The magnitude of \eqn{\beta}{beta} controls the influence of distant actors
+#' on ego's centrality score, with larger magnitudes indicating slower rates of
+#' decay.  (High rates, hence, imply a greater sensitivity to edge effects.)
+#' 
+#' Interpretively, the Bonacich power measure corresponds to the notion that
+#' the power of a vertex is recursively defined by the sum of the power of its
+#' alters.  The nature of the recursion involved is then controlled by the
+#' power exponent: positive values imply that vertices become more powerful as
+#' their alters become more powerful (as occurs in cooperative relations),
+#' while negative values imply that vertices become more powerful only as their
+#' alters become \emph{weaker} (as occurs in competitive or antagonistic
+#' relations).  The magnitude of the exponent indicates the tendency of the
+#' effect to decay across long walks; higher magnitudes imply slower decay.
+#' One interesting feature of this measure is its relative instability to
+#' changes in exponent magnitude (particularly in the negative case).  If your
+#' theory motivates use of this measure, you should be very careful to choose a
+#' decay parameter on a non-ad hoc basis.
+#'
+#' @aliases bonpow
+#' @param graph the input graph.
+#' @param nodes vertex sequence indicating which vertices are to be included in
+#' the calculation.  By default, all vertices are included.
+#' @param loops boolean indicating whether or not the diagonal should be
+#' treated as valid data.  Set this true if and only if the data can contain
+#' loops.  \code{loops} is \code{FALSE} by default.
+#' @param exponent exponent (decay rate) for the Bonacich power centrality
+#' score; can be negative
+#' @param rescale if true, centrality scores are rescaled such that they sum to
+#' 1.
+#' @param tol tolerance for near-singularities during matrix inversion (see
+#' \code{\link{solve}})
+#' @param sparse Logical scalar, whether to use sparse matrices for the
+#' calculation. The \sQuote{Matrix} package is required for sparse matrix
+#' support
+#' @return A vector, containing the centrality scores.
+#' @note This function was ported (ie. copied) from the SNA package.
+#' @section Warning : Singular adjacency matrices cause no end of headaches for
+#' this algorithm; thus, the routine may fail in certain cases.  This will be
+#' fixed when I get a better algorithm.  \code{power_centrality} will not symmetrize your
+#' data before extracting eigenvectors; don't send this routine asymmetric
+#' matrices unless you really mean to do so.
+#' @author Carter T. Butts
+#' (\url{http://www.faculty.uci.edu/profile.cfm?faculty_id=5057}), ported to
+#' igraph by Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{eigen_centrality}} and \code{\link{alpha_centrality}}
+#' @references Bonacich, P.  (1972).  ``Factoring and Weighting Approaches to
+#' Status Scores and Clique Identification.'' \emph{Journal of Mathematical
+#' Sociology}, 2, 113-120.
+#' 
+#' Bonacich, P.  (1987).  ``Power and Centrality: A Family of Measures.''
+#' \emph{American Journal of Sociology}, 92, 1170-1182.
+#' @keywords graphs
+#' @export
+#' @examples
+#' 
+#' # Generate some test data from Bonacich, 1987:
+#' g.c <- graph( c(1,2,1,3,2,4,3,5), dir=FALSE)
+#' g.d <- graph( c(1,2,1,3,1,4,2,5,3,6,4,7), dir=FALSE)
+#' g.e <- graph( c(1,2,1,3,1,4,2,5,2,6,3,7,3,8,4,9,4,10), dir=FALSE)
+#' g.f <- graph( c(1,2,1,3,1,4,2,5,2,6,2,7,3,8,3,9,3,10,4,11,4,12,4,13), dir=FALSE)
+#' # Compute power centrality scores
+#' for (e in seq(-0.5,.5, by=0.1)) {
+#'   print(round(power_centrality(g.c, exp=e)[c(1,2,4)], 2))
+#' }
+#' 
+#' for (e in seq(-0.4,.4, by=0.1)) {
+#'   print(round(power_centrality(g.d, exp=e)[c(1,2,5)], 2))
+#' }
+#' 
+#' for (e in seq(-0.4,.4, by=0.1)) {
+#'   print(round(power_centrality(g.e, exp=e)[c(1,2,5)], 2))
+#' }
+#' 
+#' for (e in seq(-0.4,.4, by=0.1)) {
+#'   print(round(power_centrality(g.f, exp=e)[c(1,2,5)], 2))
+#' }
+#' 
+power_centrality <- function(graph, nodes=V(graph),
                    loops=FALSE, exponent=1,
                    rescale=FALSE, tol=1e-7, sparse=TRUE){
 
@@ -612,8 +1389,8 @@ bonpow <- function(graph, nodes=V(graph),
     res <- bonpow.dense(graph, nodes, loops, exponent, rescale, tol)
   }
 
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-    names(res) <- get.vertex.attribute(graph, "name", nodes)
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    names(res) <- vertex_attr(graph, "name", nodes)
   }
   
   res
@@ -622,14 +1399,14 @@ bonpow <- function(graph, nodes=V(graph),
 alpha.centrality.dense <- function(graph, nodes=V(graph), alpha=1,
                                    loops=FALSE, exo=1, weights=NULL,
                                    tol=1e-7) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
   exo <- rep(exo, length=vcount(graph))
   exo <- matrix(exo, ncol=1)
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     ## weights == NULL and there is a "weight" edge attribute
     attr <- "weight"
   } else if (is.null(weights)) {
@@ -640,14 +1417,14 @@ alpha.centrality.dense <- function(graph, nodes=V(graph), alpha=1,
     attr <- "weight"
   } else if (any(!is.na(weights))) {
     ## weights != NULL and weights != rep(NA, x)
-    graph <- set.edge.attribute(graph, "weight", value=as.numeric(weights))
+    graph <- set_edge_attr(graph, "weight", value=as.numeric(weights))
     attr <- "weight"
   } else {
     ## weights != NULL, but weights == rep(NA, x)
     attr <- NULL
   }
 
-  d <- t(get.adjacency(graph, attr=attr, sparse=FALSE))
+  d <- t(as_adj(graph, attr=attr, sparse=FALSE))
   if (!loops) {
     diag(d) <- 0
   }
@@ -662,7 +1439,7 @@ alpha.centrality.dense <- function(graph, nodes=V(graph), alpha=1,
 alpha.centrality.sparse <- function(graph, nodes=V(graph), alpha=1,
                                    loops=FALSE, exo=1, weights=NULL,
                                    tol=1e-7) {
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
 
@@ -672,23 +1449,25 @@ alpha.centrality.sparse <- function(graph, nodes=V(graph), alpha=1,
     graph <- simplify(graph, remove.multiple=FALSE, remove.loops=TRUE)
   }  
 
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) {
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
     ## weights == NULL and there is a "weight" edge attribute
-    weights <- E(graph)$weight
+    attr <- "weight"
   } else if (is.null(weights)) {
     ## weights == NULL, but there is no "weight" edge attribute
-    weights <- rep(1, ecount(graph))
+    attr <- NULL
   } else if (is.character(weights) && length(weights)==1) {
-    weights <- get.edge.attribute(graph, weights)
+    ## name of an edge attribute, nothing to do
+    attr <- "weight"
   } else if (any(!is.na(weights))) {
-    weights <- as.numeric(weights)
+    ## weights != NULL and weights != rep(NA, x)
+    graph <- set_edge_attr(graph, "weight", value=as.numeric(weights))
+    attr <- "weight"
   } else {
     ## weights != NULL, but weights == rep(NA, x)
-    weights <- rep(1, ecount(graph))
-  } 
-  
-  el <- get.edgelist(graph, names=FALSE)
-  M <- Matrix::sparseMatrix(dims=c(vc, vc), i=el[,2], j=el[,1], x=weights)
+    attr <- NULL
+  }
+
+  M <- Matrix::t(as_adj(graph, attr = attr, sparse = TRUE))
   M <- as(M, "dgCMatrix")
   
   ## Create an identity matrix
@@ -705,7 +1484,70 @@ alpha.centrality.sparse <- function(graph, nodes=V(graph), alpha=1,
   r[ as.numeric(nodes)]
 }
 
-alpha.centrality <- function(graph, nodes=V(graph), alpha=1,
+
+
+#' Find Bonacich alpha centrality scores of network positions
+#' 
+#' \code{alpha_centrality} calculates the alpha centrality of some (or all)
+#' vertices in a graph.
+#' 
+#' The alpha centrality measure can be considered as a generalization of
+#' eigenvector centerality to directed graphs. It was proposed by Bonacich in
+#' 2001 (see reference below).
+#' 
+#' The alpha centrality of the vertices in a graph is defined as the solution
+#' of the following matrix equation: \deqn{x=\alpha A^T x+e,}{x=alpha t(A)x+e,}
+#' where \eqn{A}{A} is the (not neccessarily symmetric) adjacency matrix of the
+#' graph, \eqn{e}{e} is the vector of exogenous sources of status of the
+#' vertices and \eqn{\alpha}{alpha} is the relative importance of the
+#' endogenous versus exogenous factors.
+#'
+#' @aliases alpha.centrality
+#' @param graph The input graph, can be directed or undirected
+#' @param nodes Vertex sequence, the vertices for which the alpha centrality
+#' values are returned. (For technical reasons they will be calculated for all
+#' vertices, anyway.)
+#' @param alpha Parameter specifying the relative importance of endogenous
+#' versus exogenous factors in the determination of centrality. See details
+#' below.
+#' @param loops Whether to eliminate loop edges from the graph before the
+#' calculation.
+#' @param exo The exogenous factors, in most cases this is either a constant --
+#' the same factor for every node, or a vector giving the factor for every
+#' vertex. Note that too long vectors will be truncated and too short vectors
+#' will be replicated to match the number of vertices.
+#' @param weights A character scalar that gives the name of the edge attribute
+#' to use in the adjacency matrix. If it is \code{NULL}, then the
+#' \sQuote{weight} edge attribute of the graph is used, if there is one.
+#' Otherwise, or if it is \code{NA}, then the calculation uses the standard
+#' adjacency matrix.
+#' @param tol Tolerance for near-singularities during matrix inversion, see
+#' \code{\link{solve}}.
+#' @param sparse Logical scalar, whether to use sparse matrices for the
+#' calculation. The \sQuote{Matrix} package is required for sparse matrix
+#' support
+#' @return A numeric vector contaning the centrality scores for the selected
+#' vertices.
+#' @section Warning: Singular adjacency matrices cause problems for this
+#' algorithm, the routine may fail is certain cases.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{eigen_centrality}} and \code{\link{power_centrality}}
+#' @references Bonacich, P. and Paulette, L. (2001). ``Eigenvector-like
+#' measures of centrality for asymmetric relations'' \emph{Social Networks},
+#' 23, 191-201.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # The examples from Bonacich's paper
+#' g.1 <- graph( c(1,3,2,3,3,4,4,5) )
+#' g.2 <- graph( c(2,1,3,1,4,1,5,1) )
+#' g.3 <- graph( c(1,2,2,3,3,4,4,1,5,1) )
+#' alpha_centrality(g.1)
+#' alpha_centrality(g.2)
+#' alpha_centrality(g.3,alpha=0.5)
+#' 
+alpha_centrality <- function(graph, nodes=V(graph), alpha=1,
                              loops=FALSE, exo=1, weights=NULL,
                              tol=1e-7, sparse=TRUE) {
 
@@ -717,16 +1559,53 @@ alpha.centrality <- function(graph, nodes=V(graph), alpha=1,
     res <- alpha.centrality.dense(graph, nodes, alpha, loops,
                                   exo, weights, tol)
   }
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-    names(res) <- get.vertex.attribute(graph, "name", nodes)
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    names(res) <- vertex_attr(graph, "name", nodes)
   }
   res
 }
 
 
-graph.density <- function(graph, loops=FALSE) {
 
-  if (!is.igraph(graph)) {
+
+#' Graph density
+#' 
+#' The density of a graph is the ratio of the number of edges and the number of
+#' possible edges.
+#' 
+#' Note that this function may return strange results for graph with multiple
+#' edges, density is ill-defined for graphs with multiple edges.
+#'
+#' @aliases graph.density
+#' @param graph The input graph.
+#' @param loops Logical constant, whether to allow loop edges in the graph. If
+#' this is TRUE then self loops are considered to be possible. If this is FALSE
+#' then we assume that the graph does not contain any loop edges and that loop
+#' edges are not meaningful.
+#' @return A real constant. This function returns \code{NaN} (=0.0/0.0) for an
+#' empty graph with zero vertices.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{vcount}}, \code{\link{ecount}}, \code{\link{simplify}}
+#' to get rid of the multiple and/or loop edges.
+#' @references Wasserman, S., and Faust, K.  (1994).  Social Network Analysis:
+#' Methods and Applications.  Cambridge: Cambridge University Press.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g1 <- make_empty_graph(n=10)
+#' g2 <- make_full_graph(n=10)
+#' g3 <- sample_gnp(n=10, 0.4)
+#' 
+#' # loop edges
+#' g <- graph( c(1,2, 2,2, 2,3) )
+#' edge_density(g, loops=FALSE)              # this is wrong!!!
+#' edge_density(g, loops=TRUE)               # this is right!!!
+#' edge_density(simplify(g), loops=FALSE)    # this is also right, but different
+#' 
+edge_density <- function(graph, loops=FALSE) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }  
   
@@ -735,58 +1614,176 @@ graph.density <- function(graph, loops=FALSE) {
         PACKAGE="igraph")
 }
 
-neighborhood.size <- function(graph, order, nodes=V(graph),
-                              mode=c("all", "out", "in")) {
+#' @export
+
+ego_size <- function(graph, order, nodes=V(graph),
+                              mode=c("all", "out", "in"), mindist=0) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
   mode <- switch(mode, "out"=1, "in"=2, "all"=3)
+  mindist <- as.integer(mindist)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_neighborhood_size", graph, 
         as.igraph.vs(graph, nodes)-1, as.numeric(order), as.numeric(mode),
-        PACKAGE="igraph")
+        mindist, PACKAGE="igraph")
 }
 
-neighborhood <- function(graph, order, nodes=V(graph), mode=c("all", "out", "in")) {
+
+
+#' Neighborhood of graph vertices
+#' 
+#' These functions find the vertices not farther than a given limit from
+#' another fixed vertex, these are called the neighborhood of the vertex.
+#' 
+#' The neighborhood of a given order \code{o} of a vertex \code{v} includes all
+#' vertices which are closer to \code{v} than the order. Ie. order 0 is always
+#' \code{v} itself, order 1 is \code{v} plus its immediate neighbors, order 2
+#' is order 1 plus the immediate neighbors of the vertices in order 1, etc.
+#' 
+#' \code{ego_size} calculates the size of the neighborhoods for the
+#' given vertices with the given order.
+#' 
+#' \code{ego} calculates the neighborhoods of the given vertices with
+#' the given order parameter.
+#' 
+#' \code{make_ego_graph} is creates (sub)graphs from all neighborhoods of
+#' the given vertices with the given order parameter. This function preserves
+#' the vertex, edge and graph attributes.
+#' 
+#' \code{connect} creates a new graph by connecting each vertex to
+#' all other vertices in its neighborhood.
+#' 
+#' @aliases neighborhood neighborhood.size graph.neighborhood ego_graph
+#' connect.neighborhood connect ego_size ego
+#' @param graph The input graph.
+#' @param order Integer giving the order of the neighborhood.
+#' @param nodes The vertices for which the calculation is performed.
+#' @param mode Character constatnt, it specifies how to use the direction of
+#' the edges if a directed graph is analyzed. For \sQuote{out} only the
+#' outgoing edges are followed, so all vertices reachable from the source
+#' vertex in at most \code{order} steps are counted. For \sQuote{"in"} all
+#' vertices from which the source vertex is reachable in at most \code{order}
+#' steps are counted. \sQuote{"all"} ignores the direction of the edges. This
+#' argument is ignored for undirected graphs.
+#' @param mindist The minimum distance to include the vertex in the result.
+#' @return \code{ego_size} returns with an integer vector.
+#' 
+#' \code{ego} returns with a list of integer vectors.
+#' 
+#' \code{make_ego_graph} returns with a list of graphs.
+#' 
+#' \code{connect} returns with a new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}, the first version was
+#' done by Vincent Matossian
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' ego_size(g, 0, 1:3)
+#' ego_size(g, 1, 1:3)
+#' ego_size(g, 2, 1:3)
+#' ego(g, 0, 1:3)
+#' ego(g, 1, 1:3)
+#' ego(g, 2, 1:3)
+#' 
+#' # attributes are preserved
+#' V(g)$name <- c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")
+#' make_ego_graph(g, 2, 1:3)
+#' 
+#' # connecting to the neighborhood
+#' g <- make_ring(10)
+#' g <- connect(g, 2)
+#' 
+ego <- function(graph, order, nodes=V(graph),
+                         mode=c("all", "out", "in"), mindist=0) {
   
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
   mode <- switch(mode, "out"=1, "in"=2, "all"=3)
+  mindist <- as.integer(mindist)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_neighborhood", graph, 
                as.igraph.vs(graph, nodes)-1, as.numeric(order),
-               as.numeric(mode),
+               as.numeric(mode), mindist,
                PACKAGE="igraph")
   res <- lapply(res, function(x) x+1)
+
+  if (igraph_opt("return.vs.es")) {
+    res <- lapply(res, create_vs, graph = graph)
+  }
+
   res
 }
 
-graph.neighborhood <- function(graph, order, nodes=V(graph),
-                               mode=c("all", "out", "in")) {
+#' @rdname ego
+#' @export
 
-  if (!is.igraph(graph)) {
+make_ego_graph <- function(graph, order, nodes=V(graph),
+                  mode=c("all", "out", "in"), mindist=0) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
   mode <- switch(mode, "out"=1, "in"=2, "all"=3)
+  mindist <- as.integer(mindist)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_neighborhood_graphs", graph, 
                as.igraph.vs(graph, nodes)-1, as.numeric(order),
-               as.numeric(mode),
+               as.numeric(mode), mindist,
                PACKAGE="igraph")
   res
 }
 
-graph.coreness <- function(graph, mode=c("all", "out", "in")) {
 
-  if (!is.igraph(graph)) {
+
+#' K-core decomposition of graphs
+#' 
+#' The k-core of graph is a maximal subgraph in which each vertex has at least
+#' degree k. The coreness of a vertex is k if it belongs to the k-core but not
+#' to the (k+1)-core.
+#' 
+#' The k-core of a graph is the maximal subgraph in which every vertex has at
+#' least degree k. The cores of a graph form layers: the (k+1)-core is always a
+#' subgraph of the k-core.
+#' 
+#' This function calculates the coreness for each vertex.
+#'
+#' @aliases graph.coreness
+#' @param graph The input graph, it can be directed or undirected
+#' @param mode The type of the core in directed graphs. Character constant,
+#' possible values: \code{in}: in-cores are computed, \code{out}: out-cores are
+#' computed, \code{all}: the corresponding undirected graph is considered. This
+#' argument is ignored for undirected graphs.
+#' @return Numeric vector of integer numbers giving the coreness of each
+#' vertex.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{degree}}
+#' @references Vladimir Batagelj, Matjaz Zaversnik: An O(m) Algorithm for Cores
+#' Decomposition of Networks, 2002
+#' 
+#' Seidman S. B. (1983) Network structure and minimum degree, \emph{Social
+#' Networks}, 5, 269--287.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' g <- add_edges(g, c(1,2, 2,3, 1,3))
+#' coreness(g) 		# small core triangle in a ring
+#' 
+coreness <- function(graph, mode=c("all", "out", "in")) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -795,15 +1792,45 @@ graph.coreness <- function(graph, mode=c("all", "out", "in")) {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_coreness", graph, as.numeric(mode),
                PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
-    names(res) <- get.vertex.attribute(graph, "name")
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    names(res) <- vertex_attr(graph, "name")
   }
   res
 }
 
-topological.sort <- function(graph, mode=c("out", "all", "in")) {
 
-  if (!is.igraph(graph)) {
+
+#' Topological sorting of vertices in a graph
+#' 
+#' A topological sorting of a directed acyclic graph is a linear ordering of
+#' its nodes where each node comes before all nodes to which it has edges.
+#' 
+#' Every DAG has at least one topological sort, and may have many.  This
+#' function returns a possible topological sort among them. If the graph is not
+#' acyclic (it has at least one cycle), a partial topological sort is returned
+#' and a warning is issued.
+#'
+#' @aliases topological.sort
+#' @param graph The input graph, should be directed
+#' @param mode Specifies how to use the direction of the edges.  For
+#' \dQuote{\code{out}}, the sorting order ensures that each node comes before
+#' all nodes to which it has edges, so nodes with no incoming edges go first.
+#' For \dQuote{\code{in}}, it is quite the opposite: each node comes before all
+#' nodes from which it receives edges. Nodes with no outgoing edges go first.
+#' @return A numeric vector containing vertex ids in topologically sorted
+#' order.
+#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
+#' \email{csardi.gabor@@gmail.com} for the R interface
+#' @keywords graphs
+#' @export
+#' @examples
+#' 
+#' g <- barabasi.game(100)
+#' topo_sort(g)
+#' 
+topo_sort <- function(graph, mode=c("out", "all", "in")) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   mode <- igraph.match.arg(mode)
@@ -811,23 +1838,73 @@ topological.sort <- function(graph, mode=c("out", "all", "in")) {
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   res <- .Call("R_igraph_topological_sorting", graph, as.numeric(mode),
-               PACKAGE="igraph")
-  res+1
+               PACKAGE="igraph") + 1L
+
+  if (igraph_opt("return.vs.es")) res <- create_vs(graph, res)
+
+  res
 }
 
+
+
+#' Girth of a graph
+#' 
+#' The girth of a graph is the length of the shortest circle in it.
+#' 
+#' The current implementation works for undirected graphs only, directed graphs
+#' are treated as undirected graphs. Loop edges and multiple edges are ignored.
+#' If the graph is a forest (ie. acyclic), then zero is returned.
+#' 
+#' This implementation is based on Alon Itai and Michael Rodeh: Finding a
+#' minimum circuit in a graph \emph{Proceedings of the ninth annual ACM
+#' symposium on Theory of computing}, 1-10, 1977. The first implementation of
+#' this function was done by Keith Briggs, thanks Keith.
+#' 
+#' @param graph The input graph. It may be directed, but the algorithm searches
+#' for undirected circles anyway.
+#' @param circle Logical scalar, whether to return the shortest circle itself.
+#' @return A named list with two components: \item{girth}{Integer constant, the
+#' girth of the graph, or 0 if the graph is acyclic.} \item{circle}{Numeric
+#' vector with the vertex ids in the shortest circle.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Alon Itai and Michael Rodeh: Finding a minimum circuit in a
+#' graph \emph{Proceedings of the ninth annual ACM symposium on Theory of
+#' computing}, 1-10, 1977
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # No circle in a tree
+#' g <- make_tree(1000, 3)
+#' girth(g)
+#' 
+#' # The worst case running time is for a ring
+#' g <- make_ring(100)
+#' girth(g)
+#' 
+#' # What about a random graph?
+#' g <- sample_gnp(1000, 1/1000)
+#' girth(g)
+#' 
 girth <- function(graph, circle=TRUE) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_girth", graph, as.logical(circle),
-        PACKAGE="igraph")
+  res <- .Call("R_igraph_girth", graph, as.logical(circle),
+               PACKAGE="igraph")
+  if (igraph_opt("return.vs.es") && circle) {
+    res$circle <- create_vs(graph, res$circle)
+  }
+  res
 }
 
-is.loop <- function(graph, eids=E(graph)) {
+#' @export
+
+which_loop <- function(graph, eids=E(graph)) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -835,9 +1912,72 @@ is.loop <- function(graph, eids=E(graph)) {
         PACKAGE="igraph")
 }
 
-is.multiple <- function(graph, eids=E(graph)) {
 
-  if (!is.igraph(graph)) {
+
+#' Find the multiple or loop edges in a graph
+#' 
+#' A loop edge is an edge from a vertex to itself. An edge is a multiple edge
+#' if it has exactly the same head and tail vertices as another edge. A graph
+#' without multiple and loop edges is called a simple graph.
+#' 
+#' \code{which_loop} decides whether the edges of the graph are loop edges.
+#' 
+#' \code{any_multiple} decides whether the graph has any multiple edges.
+#' 
+#' \code{which_multiple} decides whether the edges of the graph are multiple
+#' edges.
+#' 
+#' \code{count_multiple} counts the multiplicity of each edge of a graph.
+#' 
+#' Note that the semantics for \code{which_multiple} and \code{count_multiple} is
+#' different. \code{which_multiple} gives \code{TRUE} for all occurences of a
+#' multiple edge except for one. Ie. if there are three \code{i-j} edges in the
+#' graph then \code{which_multiple} returns \code{TRUE} for only two of them while
+#' \code{count_multiple} returns \sQuote{3} for all three.
+#' 
+#' See the examples for getting rid of multiple edges while keeping their
+#' original multiplicity as an edge attribute.
+#' 
+#' @aliases has.multiple is.loop is.multiple count.multiple count_multiple
+#'   any_multiple which_loop
+#' @param graph The input graph.
+#' @param eids The edges to which the query is restricted. By default this is
+#' all edges in the graph.
+#' @return \code{any_multiple} returns a logical scalar.  \code{which_loop} and
+#' \code{which_multiple} return a logical vector. \code{count_multiple} returns a
+#' numeric vector.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{simplify}} to eliminate loop and multiple edges.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' # Loops
+#' g <- graph( c(1,1,2,2,3,3,4,5) )
+#' which_loop(g)
+#' 
+#' # Multiple edges
+#' g <- barabasi.game(10, m=3, algorithm="bag")
+#' any_multiple(g)
+#' which_multiple(g)
+#' count_multiple(g)
+#' which_multiple(simplify(g))
+#' all(count_multiple(simplify(g)) == 1)
+#' 
+#' # Direction of the edge is important
+#' which_multiple(graph( c(1,2, 2,1) ))
+#' which_multiple(graph( c(1,2, 2,1), dir=FALSE ))
+#' 
+#' # Remove multiple edges but keep multiplicity
+#' g <- barabasi.game(10, m=3, algorithm="bag")
+#' E(g)$weight <- count_multiple(g)
+#' g <- simplify(g)
+#' any(which_multiple(g))
+#' E(g)$weight
+#' 
+which_multiple <- function(graph, eids=E(graph)) {
+
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -845,9 +1985,11 @@ is.multiple <- function(graph, eids=E(graph)) {
         PACKAGE="igraph")
 }
 
-count.multiple <- function(graph, eids=E(graph)) {
+#' @export
+
+count_multiple <- function(graph, eids=E(graph)) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -855,13 +1997,102 @@ count.multiple <- function(graph, eids=E(graph)) {
         PACKAGE="igraph")
 }
 
-graph.bfs <- function(graph, root, neimode=c("out", "in", "all", "total"),
+
+
+#' Breadth-first search
+#' 
+#' Breadth-first search is an algorithm to traverse a graph. We start from a
+#' root vertex and spread along every edge \dQuote{simultaneously}.
+#' 
+#' 
+#' The callback function must have the following arguments: \describe{
+#' \item{graph}{The input graph is passed to the callback function here.}
+#' \item{data}{A named numeric vector, with the following entries:
+#' \sQuote{vid}, the vertex that was just visited, \sQuote{pred}, its
+#' predecessor, \sQuote{succ}, its successor, \sQuote{rank}, the rank of the
+#' current vertex, \sQuote{dist}, its distance from the root of the search
+#' tree.} \item{extra}{The extra argument.} } See examples below on how to use
+#' the callback function.
+#'
+#' @aliases graph.bfs
+#' @param graph The input graph.
+#' @param root Numeric vector, usually of length one. The root vertex, or root
+#' vertices to start the search from.
+#' @param neimode For directed graphs specifies the type of edges to follow.
+#' \sQuote{out} follows outgoing, \sQuote{in} incoming edges. \sQuote{all}
+#' ignores edge directions completely. \sQuote{total} is a synonym for
+#' \sQuote{all}. This argument is ignored for undirected graphs.
+#' @param unreachable Logical scalar, whether the search should visit the
+#' vertices that are unreachable from the given root vertex (or vertices). If
+#' \code{TRUE}, then additional searches are performed until all vertices are
+#' visited.
+#' @param restricted \code{NULL} (=no restriction), or a vector of vertices
+#' (ids or symbolic names). In the latter case, the search is restricted to the
+#' given vertices.
+#' @param order Logical scalar, whether to return the ordering of the vertices.
+#' @param rank Logical scalar, whether to return the rank of the vertices.
+#' @param father Logical scalar, whether to return the father of the vertices.
+#' @param pred Logical scalar, whether to return the predecessors of the
+#' vertices.
+#' @param succ Logical scalar, whether to return the successors of the
+#' vertices.
+#' @param dist Logical scalar, whether to return the distance from the root of
+#' the search tree.
+#' @param callback If not \code{NULL}, then it must be callback function. This
+#' is called whenever a vertex is visited. See details below.
+#' @param extra Additional argument to supply to the callback function.
+#' @param rho The environment in which the callback function is evaluated.
+#' @return A named list with the following entries: \item{root}{Numeric scalar.
+#' The root vertex that was used as the starting point of the search.}
+#' \item{neimode}{Character scalar. The \code{neimode} argument of the function
+#' call. Note that for undirected graphs this is always \sQuote{all},
+#' irrespectively of the supplied value.} \item{order}{Numeric vector. The
+#' vertex ids, in the order in which they were visited by the search.}
+#' \item{rank}{Numeric vector. The rank for each vertex.} \item{father}{Numeric
+#' vector. The father of each vertex, i.e. the vertex it was discovered from.}
+#' \item{pred}{Numeric vector. The previously visited vertex for each vertex,
+#' or 0 if there was no such vertex.} \item{succ}{Numeric vector. The next
+#' vertex that was visited after the current one, or 0 if there was no such
+#' vertex.} \item{dist}{Numeric vector, for each vertex its distance from the
+#' root of the search tree.}
+#' 
+#' Note that \code{order}, \code{rank}, \code{father}, \code{pred}, \code{succ}
+#' and \code{dist} might be \code{NULL} if their corresponding argument is
+#' \code{FALSE}, i.e. if their calculation is not requested.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{dfs}} for depth-first search.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Two rings
+#' bfs(make_ring(10) %du% make_ring(10), root=1, "out",
+#'           order=TRUE, rank=TRUE, father=TRUE, pred=TRUE,
+#'           succ=TRUE, dist=TRUE)
+#' 
+#' ## How to use a callback
+#' f <- function(graph, data, extra) {
+#'   print(data)
+#'   FALSE
+#' }
+#' tmp <- bfs(make_ring(10) %du% make_ring(10), root=1, "out",
+#'                  callback=f)
+#' 
+#' ## How to use a callback to stop the search
+#' ## We stop after visiting all vertices in the initial component
+#' f <- function(graph, data, extra) {
+#'  data['succ'] == -1
+#' }
+#' bfs(make_ring(10) %du% make_ring(10), root=1, callback=f)
+#' 
+#' 
+bfs <- function(graph, root, neimode=c("out", "in", "all", "total"),
                       unreachable=TRUE, restricted=NULL,
                       order=TRUE, rank=FALSE, father=FALSE,
                       pred=FALSE, succ=FALSE, dist=FALSE,
                       callback=NULL, extra=NULL, rho=parent.frame()) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
@@ -891,16 +2122,115 @@ graph.bfs <- function(graph, root, neimode=c("out", "in", "all", "total"),
   if (father) res$father <- res$father+1
   if (pred)   res$pred   <- res$pred+1
   if (succ)   res$succ   <- res$succ+1
+
+  if (igraph_opt("return.vs.es")) {
+    if (order)  res$order  <- create_vs(graph, res$order, na_ok = TRUE)
+    if (father) res$father <- create_vs(graph, res$father, na_ok = TRUE)
+    if (pred)   res$pred   <- create_vs(graph, res$pred, na_ok = TRUE)
+    if (succ)   res$succ   <- create_vs(graph, res$succ, na_ok = TRUE)
+  }
+
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    if (rank)   names(res$rank)   <- V(graph)$name
+    if (father) names(res$father) <- V(graph)$name
+    if (pred)   names(res$pred)   <- V(graph)$name
+    if (succ)   names(res$succ)   <- V(graph)$name
+    if (dist)   names(res$dist)   <- V(graph)$name
+  }
+
   res
 }
 
-graph.dfs <- function(graph, root, neimode=c("out", "in", "all", "total"),
+
+
+#' Depth-first search
+#' 
+#' Depth-first search is an algorithm to traverse a graph. It starts from a
+#' root vertex and tries to go quickly as far from as possible.
+#' 
+#' The callback functions must have the following arguments: \describe{
+#' \item{graph}{The input graph is passed to the callback function here.}
+#' \item{data}{A named numeric vector, with the following entries:
+#' \sQuote{vid}, the vertex that was just visited and \sQuote{dist}, its
+#' distance from the root of the search tree.} \item{extra}{The extra
+#' argument.} } See examples below on how to use the callback functions.
+#'
+#' @aliases graph.dfs
+#' @param graph The input graph.
+#' @param root The single root vertex to start the search from.
+#' @param neimode For directed graphs specifies the type of edges to follow.
+#' \sQuote{out} follows outgoing, \sQuote{in} incoming edges. \sQuote{all}
+#' ignores edge directions completely. \sQuote{total} is a synonym for
+#' \sQuote{all}. This argument is ignored for undirected graphs.
+#' @param unreachable Logical scalar, whether the search should visit the
+#' vertices that are unreachable from the given root vertex (or vertices). If
+#' \code{TRUE}, then additional searches are performed until all vertices are
+#' visited.
+#' @param order Logical scalar, whether to return the DFS ordering of the
+#' vertices.
+#' @param order.out Logical scalar, whether to return the ordering based on
+#' leaving the subtree of the vertex.
+#' @param father Logical scalar, whether to return the father of the vertices.
+#' @param dist Logical scalar, whether to return the distance from the root of
+#' the search tree.
+#' @param in.callback If not \code{NULL}, then it must be callback function.
+#' This is called whenever a vertex is visited. See details below.
+#' @param out.callback If not \code{NULL}, then it must be callback function.
+#' This is called whenever the subtree of a vertex is completed by the
+#' algorithm. See details below.
+#' @param extra Additional argument to supply to the callback function.
+#' @param rho The environment in which the callback function is evaluated.
+#' @return A named list with the following entries: \item{root}{Numeric scalar.
+#' The root vertex that was used as the starting point of the search.}
+#' \item{neimode}{Character scalar. The \code{neimode} argument of the function
+#' call. Note that for undirected graphs this is always \sQuote{all},
+#' irrespectively of the supplied value.} \item{order}{Numeric vector. The
+#' vertex ids, in the order in which they were visited by the search.}
+#' \item{order.out}{Numeric vector, the vertex ids, in the order of the
+#' completion of their subtree.} \item{father}{Numeric vector. The father of
+#' each vertex, i.e. the vertex it was discovered from.} \item{dist}{Numeric
+#' vector, for each vertex its distance from the root of the search tree.}
+#' 
+#' Note that \code{order}, \code{order.out}, \code{father}, and \code{dist}
+#' might be \code{NULL} if their corresponding argument is \code{FALSE}, i.e.
+#' if their calculation is not requested.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{bfs}} for breadth-first search.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A graph with two separate trees
+#' dfs(make_tree(10) %du% make_tree(10), root=1, "out",
+#'           TRUE, TRUE, TRUE, TRUE)
+#' 
+#' ## How to use a callback
+#' f.in <- function(graph, data, extra) {
+#'   cat("in:", paste(collapse=", ", data), "\n")
+#'   FALSE
+#' }
+#' f.out <- function(graph, data, extra) {
+#'   cat("out:", paste(collapse=", ", data), "\n")
+#'   FALSE
+#' }
+#' tmp <- dfs(make_tree(10), root=1, "out",
+#'                  in.callback=f.in, out.callback=f.out)
+#' 
+#' ## Terminate after the first component, using a callback
+#' f.out <- function(graph, data, extra) {
+#'  data['vid'] == 1
+#' }
+#' tmp <- dfs(make_tree(10) %du% make_tree(10), root=1,
+#'                  out.callback=f.out)
+#' 
+#' 
+dfs <- function(graph, root, neimode=c("out", "in", "all", "total"),
                       unreachable=TRUE,
                       order=TRUE, order.out=FALSE, father=FALSE, dist=FALSE,
                       in.callback=NULL, out.callback=NULL, extra=NULL,
                       rho=parent.frame()) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object");
   }
 
@@ -920,16 +2250,32 @@ graph.dfs <- function(graph, root, neimode=c("out", "in", "all", "total"),
   if (order)     res$order     <- res$order+1
   if (order.out) res$order.out <- res$order.out+1
   if (father)    res$father    <- res$father+1
+
+  if (igraph_opt("return.vs.es")) {
+    if (order)     res$order      <- V(graph)[res$order, na_ok = TRUE]
+    if (order.out) res$order.out  <- V(graph)[res$order.out, na_ok = TRUE]
+    if (father)    res$father     <- create_vs(graph, res$father, na_ok = TRUE)
+  }
+
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    if (father) names(res$father)  <- V(graph)$name
+    if (dist)   names(res$dist)    <- V(graph)$name
+  }
+
   res
 }
 
-edge.betweenness <- function(graph, e=E(graph),
+#' @rdname betweenness
+#' @param e The edges for which the edge betweenness will be calculated.
+#' @export
+
+edge_betweenness <- function(graph, e=E(graph),
                              directed=TRUE, weights=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   e <- as.igraph.es(graph, e)
   directed <- as.logical(directed)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -945,14 +2291,16 @@ edge.betweenness <- function(graph, e=E(graph),
   res[as.numeric(e)]
 }
 
-edge.betweenness.estimate <- function(graph, e=E(graph),
+#' @export
+
+estimate_edge_betweenness <- function(graph, e=E(graph),
                                       directed=TRUE, cutoff, weights=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   e <- as.igraph.es(graph, e)
   directed <- as.logical(directed)
   cutoff <- as.numeric(cutoff)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -968,9 +2316,62 @@ edge.betweenness.estimate <- function(graph, e=E(graph),
   res[as.numeric(e)]
 }
 
-clusters <- function(graph, mode=c("weak", "strong")) {
+
+
+#' Connected components of a graph
+#' 
+#' Calculate the maximal (weakly or strongly) connected components of a graph
+#' 
+#' \code{is_connected} decides whether the graph is weakly or strongly
+#' connected.
+#' 
+#' \code{components} finds the maximal (weakly or strongly) connected components
+#' of a graph.
+#' 
+#' \code{count_components} does almost the same as \code{components} but returns only
+#' the number of clusters found instead of returning the actual clusters.
+#' 
+#' \code{component_distribution} creates a histogram for the maximal connected
+#' component sizes.
+#' 
+#' The weakly connected components are found by a simple breadth-first search.
+#' The strongly connected components are implemented by two consecutive
+#' depth-first searches.
+#' 
+#' @aliases no.clusters clusters is.connected cluster.distribution components
+#'   count_components is_connected
+#' @param graph The graph to analyze.
+#' @param mode Character string, either \dQuote{weak} or \dQuote{strong}.  For
+#' directed graphs \dQuote{weak} implies weakly, \dQuote{strong} strongly
+#' connected components to search. It is ignored for undirected graphs.
+#' @param \dots Additional attributes to pass to \code{cluster}, right now only
+#' \code{mode} makes sense.
+#' @return For \code{is_connected} a logical constant.
+#' 
+#' For \code{components} a named list with three components:
+#' \item{membership}{numeric vector giving the cluster id to which each vertex
+#' belongs.} \item{csize}{numeric vector giving the sizes of the clusters.}
+#' \item{no}{numeric constant, the number of clusters.}
+#' 
+#' For \code{count_components} an integer constant is returned.
+#' 
+#' For \code{component_distribution} a numeric vector with the relative
+#' frequencies. The length of the vector is the size of the largest component
+#' plus one. Note that (for currently unknown reasons) the first element of the
+#' vector is the number of clusters of size zero, so this is always zero.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{subcomponent}}, \code{\link{groups}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnp(20, 1/20)
+#' clu <- components(g)
+#' groups(clu)
+#' 
+components <- function(graph, mode=c("weak", "strong")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   mode <- switch(igraph.match.arg(mode), "weak"=1, "strong"=2)
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -978,30 +2379,122 @@ clusters <- function(graph, mode=c("weak", "strong")) {
   res <- .Call("R_igraph_clusters", graph, mode,
         PACKAGE="igraph")
   res$membership <- res$membership + 1
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
+    names(res$membership) <- V(graph)$name
+  }
+
   res
 }
 
-unfold.tree <- function(graph, mode=c("all", "out", "in", "total"), roots) {
+
+
+#' Convert a general graph into a forest
+#' 
+#' Perform a breadth-first search on a graph and convert it into a tree or
+#' forest by replicating vertices that were found more than once.
+#' 
+#' A forest is a graph, whose components are trees.
+#' 
+#' The \code{roots} vector can be calculated by simply doing a topological sort
+#' in all components of the graph, see the examples below.
+#' 
+#' @aliases unfold.tree
+#' @param graph The input graph, it can be either directed or undirected.
+#' @param mode Character string, defined the types of the paths used for the
+#' breadth-first search. \dQuote{out} follows the outgoing, \dQuote{in} the
+#' incoming edges, \dQuote{all} and \dQuote{total} both of them. This argument
+#' is ignored for undirected graphs.
+#' @param roots A vector giving the vertices from which the breadth-first
+#' search is performed. Typically it contains one vertex per component.
+#' @return A list with two components: \item{tree}{The result, an \code{igraph}
+#' object, a tree or a forest.} \item{vertex_index}{A numeric vector, it gives
+#' a mapping from the vertices of the new graph to the vertices of the old
+#' graph.}
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_tree(10) %du% make_tree(10)
+#' V(g)$id <- seq_len(vcount(g))-1
+#' roots <- sapply(decompose(g), function(x) {
+#'             V(x)$id[ topo_sort(x)[1]+1 ] })
+#' tree <- unfold_tree(g, roots=roots)
+#' 
+unfold_tree <- function(graph, mode=c("all", "out", "in", "total"), roots) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
   roots <- as.igraph.vs(graph, roots)-1
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_unfold_tree", graph, mode, roots,
-        PACKAGE="igraph")
+                PACKAGE="igraph")
   res
 }
 
+
+
+#' Closeness centrality of vertices
+#' 
+#' Cloness centrality measures how many steps is required to access every other
+#' vertex from a given vertex.
+#' 
+#' The closeness centrality of a vertex is defined by the inverse of the
+#' average length of the shortest paths to/from all the other vertices in the
+#' graph:
+#' 
+#' \deqn{\frac{1}{\sum_{i\ne v} d_vi}}{1/sum( d(v,i), i != v)}
+#' 
+#' If there is no (directed) path between vertex \eqn{v}{\code{v}} and
+#' \eqn{i}{\code{i}} then the total number of vertices is used in the formula
+#' instead of the path length.
+#' 
+#' \code{estimate_closeness} only considers paths of length \code{cutoff} or
+#' smaller, this can be run for larger graphs, as the running time is not
+#' quadratic (if \code{cutoff} is small). If \code{cutoff} is zero or negative
+#' then the function calculates the exact closeness scores.
+#' 
+#' @aliases closeness closeness.estimate estimate_closeness
+#' @param graph The graph to analyze.
+#' @param vids The vertices for which closeness will be calculated.
+#' @param mode Character string, defined the types of the paths used for
+#' measuring the distance in directed graphs. \dQuote{in} measures the paths
+#' \emph{to} a vertex, \dQuote{out} measures paths \emph{from} a vertex,
+#' \emph{all} uses undirected paths. This argument is ignored for undirected
+#' graphs.
+#' @param normalized Logical scalar, whether to calculate the normalized
+#' closeness. Normalization is performed by multiplying the raw closeness by
+#' \eqn{n-1}, where \eqn{n} is the number of vertices in the graph.
+#' @param weights Optional positive weight vector for calculating weighted
+#' closeness. If the graph has a \code{weight} edge attribute, then this is
+#' used by default.
+#' @return Numeric vector with the closeness values of all the vertices in
+#' \code{v}.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{betweenness}}, \code{\link{degree}}
+#' @references Freeman, L.C. (1979). Centrality in Social Networks I:
+#' Conceptual Clarification. \emph{Social Networks}, 1, 215-239.
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' g2 <- make_star(10)
+#' closeness(g)
+#' closeness(g2, mode="in")
+#' closeness(g2, mode="out")
+#' closeness(g2, mode="all")
+#' 
 closeness <- function(graph, vids=V(graph),
                       mode=c("out", "in", "all", "total"), weights=NULL,
                       normalized=FALSE) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)
   mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
   weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -1015,18 +2508,91 @@ closeness <- function(graph, vids=V(graph),
   # Function call
   res <- .Call("R_igraph_closeness", graph, vids-1, mode, weights,
                normalized, PACKAGE="igraph")
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     names(res) <- V(graph)$name[vids]
   }
   res
 }
 
-graph.laplacian <- function(graph, normalized=FALSE, weights=NULL,
-                            sparse=getIgraphOpt("sparsematrices")) {
+#' @rdname closeness
+#' @param cutoff The maximum path length to consider when calculating the
+#' betweenness. If zero or negative then there is no such limit.
+#' @export
+
+estimate_closeness <- function(graph, vids=V(graph), mode=c("out", "in", "all", "total"), cutoff, weights=NULL, normalized=FALSE) {
+  # Argument checks
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  vids <- as.igraph.vs(graph, vids)
+  mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
+  cutoff <- as.numeric(cutoff)
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
+  weights <- E(graph)$weight 
+  } 
+  if (!is.null(weights) && any(!is.na(weights))) { 
+  weights <- as.numeric(weights) 
+  } else { 
+  weights <- NULL 
+  }
+  normalized <- as.logical(normalized)
+
+  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+  # Function call
+  res <- .Call("R_igraph_closeness_estimate", graph, vids-1, mode, cutoff, weights, normalized,
+        PACKAGE="igraph")
+  if (igraph_opt("add.vertex.names") && is_named(graph)) { 
+  names(res) <- vertex_attr(graph, "name", vids) 
+  }
+  res
+}
+
+
+#' Graph Laplacian
+#' 
+#' The Laplacian of a graph.
+#' 
+#' The Laplacian Matrix of a graph is a symmetric matrix having the same number
+#' of rows and columns as the number of vertices in the graph and element (i,j)
+#' is d[i], the degree of vertex i if if i==j, -1 if i!=j and there is an edge
+#' between vertices i and j and 0 otherwise.
+#' 
+#' A normalized version of the Laplacian Matrix is similar: element (i,j) is 1
+#' if i==j, -1/sqrt(d[i] d[j]) if i!=j and there is an edge between vertices i
+#' and j and 0 otherwise.
+#' 
+#' The weighted version of the Laplacian simply works with the weighted degree
+#' instead of the plain degree. I.e. (i,j) is d[i], the weighted degree of
+#' vertex i if if i==j, -w if i!=j and there is an edge between vertices i and
+#' j with weight w, and 0 otherwise. The weighted degree of a vertex is the sum
+#' of the weights of its adjacent edges.
+#'
+#' @aliases graph.laplacian
+#' @param graph The input graph.
+#' @param normalized Whether to calculate the normalized Laplacian. See
+#' definitions below.
+#' @param weights An optional vector giving edge weights for weighted Laplacian
+#' matrix. If this is \code{NULL} and the graph has an edge attribute called
+#' \code{weight}, then it will be used automatically. Set this to \code{NA} if
+#' you want the unweighted Laplacian on a graph that has a \code{weight} edge
+#' attribute.
+#' @param sparse Logical scalar, whether to return the result as a sparse
+#' matrix. The \code{Matrix} package is required for sparse matrices.
+#' @return A numeric matrix.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' laplacian_matrix(g)
+#' laplacian_matrix(g, norm=TRUE)
+#' laplacian_matrix(g, norm=TRUE, sparse=FALSE)
+#' 
+laplacian_matrix <- function(graph, normalized=FALSE, weights=NULL,
+                            sparse=igraph_opt("sparsematrices")) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   normalized <- as.logical(normalized)
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
     weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -1043,16 +2609,104 @@ graph.laplacian <- function(graph, normalized=FALSE, weights=NULL,
   if (sparse) {
     res <- igraph.i.spMatrix(res)
   }
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     rownames(res) <- colnames(res) <- V(graph)$name
   }
   res
 }
 
-is.matching <- function(graph, matching, types=NULL) {
+#' Graph matching
+#' 
+#' A matching in a graph means the selection of a set of edges that are
+#' pairwise non-adjacenct, i.e. they have no common incident vertices. A
+#' matching is maximal if it is not a proper subset of any other matching.
+#' 
+#' \code{is_matching} checks a matching vector and verifies whether its
+#' length matches the number of vertices in the given graph, its values are
+#' between zero (inclusive) and the number of vertices (inclusive), and
+#' whether there exists a corresponding edge in the graph for every matched
+#' vertex pair. For bipartite graphs, it also verifies whether the matched
+#' vertices are in different parts of the graph.
+#' 
+#' \code{is_max_matching} checks whether a matching is maximal.  A matching
+#' is maximal if and only if there exists no unmatched vertex in a graph
+#' such that one of its neighbors is also unmatched.
+#' 
+#' \code{max_bipartite_match} calculates a maximum matching in a bipartite
+#' graph. A matching in a bipartite graph is a partial assignment of
+#' vertices of the first kind to vertices of the second kind such that each
+#' vertex of the first kind is matched to at most one vertex of the second
+#' kind and vice versa, and matched vertices must be connected by an edge
+#' in the graph. The size (or cardinality) of a matching is the number of
+#' edges. A matching is a maximum matching if there exists no other
+#' matching with larger cardinality.  For weighted graphs, a maximum
+#' matching is a matching whose edges have the largest possible total
+#' weight among all possible matchings.
+#' 
+#' Maximum matchings in bipartite graphs are found by the push-relabel
+#' algorithm with greedy initialization and a global relabeling after every
+#' \eqn{n/2} steps where \eqn{n} is the number of vertices in the graph.
+#'
+#' @rdname matching
+#' @aliases is.matching is_matching is.maximal.matching is_max_matching
+#' maximum.bipartite.matching max_bipartite_match
+#' @param graph The input graph. It might be directed, but edge directions will
+#' be ignored.
+#' @param types Vertex types, if the graph is bipartite. By default they
+#' are taken from the \sQuote{\code{type}} vertex attribute, if present.
+#' @param matching A potential matching. An integer vector that gives the
+#' pair in the matching for each vertex. For vertices without a pair,
+#' supply \code{NA} here.
+#' @param weights Potential edge weights. If the graph has an edge
+#' attribute called \sQuote{\code{weight}}, and this argument is
+#' \code{NULL}, then the edge attribute is used automatically.
+#' @param eps A small real number used in equality tests in the weighted
+#' bipartite matching algorithm. Two real numbers are considered equal in
+#' the algorithm if their difference is smaller than \code{eps}. This is
+#' required to avoid the accumulation of numerical errors. By default it is
+#' set to the smallest \eqn{x}, such that \eqn{1+x \ne 1}{1+x != 1}
+#' holds. If you are running the algorithm with no weights, this argument
+#' is ignored.
+#' @return \code{is_matching} and \code{is_max_matching} return a logical
+#' scalar.
+#' 
+#' \code{max_bipartite_match} returns a list with components:
+#'   \item{matching_size}{The size of the matching, i.e. the number of edges
+#'     connecting the matched vertices.}
+#'   \item{matching_weight}{The weights of the matching, if the graph was
+#'     weighted. For unweighted graphs this is the same as the size of the
+#'     matching.}
+#'   \item{matching}{The matching itself. Numeric vertex id, or vertex
+#'     names if the graph was named. Non-matched vertices are denoted by
+#'     \code{NA}.} 
+#' @author Tamas Nepusz \email{ntamas@@gmail.com}
+#' @examples
+#' g <- graph_from_literal( a-b-c-d-e-f )
+#' m1 <- c("b", "a", "d", "c", "f", "e")   # maximal matching
+#' m2 <- c("b", "a", "d", "c", NA, NA)     # non-maximal matching
+#' m3 <- c("b", "c", "d", "c", NA, NA)     # not a matching
+#' is_matching(g, m1)
+#' is_matching(g, m2)
+#' is_matching(g, m3)
+#' is_max_matching(g, m1)
+#' is_max_matching(g, m2)
+#' is_max_matching(g, m3)
+#' 
+#' V(g)$type <- c(FALSE,TRUE)
+#' str(g, v=TRUE)
+#' max_bipartite_match(g)
+#' 
+#' g2 <- graph_from_literal( a-b-c-d-e-f-g )
+#' V(g2)$type <- rep(c(FALSE,TRUE), length=vcount(g2))
+#' str(g2, v=TRUE)
+#' max_bipartite_match(g2)
+#' #' @keywords graphs
+#' @export
+ 
+is_matching <- function(graph, matching, types=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) { 
     types <- V(graph)$type 
   } 
   if (!is.null(types)) { 
@@ -1069,10 +2723,13 @@ is.matching <- function(graph, matching, types=NULL) {
   res
 }
 
-is.maximal.matching <- function(graph, matching, types=NULL) {
+#' @export
+#' @rdname matching
+ 
+is_max_matching <- function(graph, matching, types=NULL) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) { 
     types <- V(graph)$type 
   } 
   if (!is.null(types)) { 
@@ -1089,17 +2746,20 @@ is.maximal.matching <- function(graph, matching, types=NULL) {
   res
 }
 
-maximum.bipartite.matching <- function(graph, types=NULL, weights=NULL,
+#' @export
+#' @rdname matching
+ 
+max_bipartite_match <- function(graph, types=NULL, weights=NULL,
                                        eps=.Machine$double.eps) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
-  if (is.null(types) && "type" %in% list.vertex.attributes(graph)) { 
+  if (!is_igraph(graph)) { stop("Not a graph object") }
+  if (is.null(types) && "type" %in% vertex_attr_names(graph)) { 
     types <- V(graph)$type 
   } 
   if (!is.null(types)) { 
     types <- as.logical(types) 
   }
-  if (is.null(weights) && "weight" %in% list.edge.attributes(graph)) { 
+  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) { 
     weights <- E(graph)$weight 
   } 
   if (!is.null(weights) && any(!is.na(weights))) { 
@@ -1116,9 +2776,100 @@ maximum.bipartite.matching <- function(graph, types=NULL, weights=NULL,
                PACKAGE="igraph")
 
   res$matching[ res$matching==0 ] <- NA
-  if (getIgraphOpt("add.vertex.names") && is.named(graph)) {
+  if (igraph_opt("add.vertex.names") && is_named(graph)) {
     res$matching <- V(graph)$name[res$matching]
     names(res$matching) <- V(graph)$name
   }
   res
 }
+
+
+#' Find mutual edges in a directed graph
+#' 
+#' This function checks the reciproc pair of the supplied edges.
+#' 
+#' In a directed graph an (A,B) edge is mutual if the graph also includes a
+#' (B,A) directed edge.
+#' 
+#' Note that multi-graphs are not handled properly, i.e. if the graph contains
+#' two copies of (A,B) and one copy of (B,A), then these three edges are
+#' considered to be mutual.
+#' 
+#' Undirected graphs contain only mutual edges by definition.
+#' 
+#' @aliases is.mutual which_mutual
+#' @param graph The input graph.
+#' @param es Edge sequence, the edges that will be probed. By default is
+#' includes all edges in the order of their ids.
+#' @return A logical vector of the same length as the number of edges supplied.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{reciprocity}}, \code{\link{dyad_census}} if you just
+#' want some statistics about mutual edges.
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- sample_gnm(10, 50, directed=TRUE)
+#' reciprocity(g)
+#' dyad_census(g)
+#' which_mutual(g)
+#' sum(which_mutual(g))/2 == dyad_census(g)$mut
+#' @export
+
+which_mutual <- which_mutual
+
+
+#' Average nearest neighbor degree
+#' 
+#' Calculate the average nearest neighbor degree of the given vertices and the
+#' same quantity in the function of vertex degree
+#' 
+#' Note that for zero degree vertices the answer in \sQuote{\code{knn}} is
+#' \code{NaN} (zero divided by zero), the same is true for \sQuote{\code{knnk}}
+#' if a given degree never appears in the network.
+#' 
+#' @aliases knn graph.knn
+#' @param graph The input graph. It can be directed, but it will be treated as
+#' undirected, i.e. the direction of the edges is ignored.
+#' @param vids The vertices for which the calculation is performed. Normally it
+#' includes all vertices. Note, that if not all vertices are given here, then
+#' both \sQuote{\code{knn}} and \sQuote{\code{knnk}} will be calculated based
+#' on the given vertices only.
+#' @param weights Weight vector. If the graph has a \code{weight} edge
+#' attribute, then this is used by default. If this argument is given, then
+#' vertex strength (see \code{\link{strength}}) is used instead of vertex
+#' degree. But note that \code{knnk} is still given in the function of the
+#' normal vertex degree.
+#' @return A list with two members: \item{knn}{A numeric vector giving the
+#' average nearest neighbor degree for all vertices in \code{vids}.}
+#' \item{knnk}{A numeric vector, its length is the maximum (total) vertex
+#' degree in the graph. The first element is the average nearest neighbor
+#' degree of vertices with degree one, etc.  }
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @references Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras,
+#' Alessandro Vespignani: The architecture of complex weighted networks, Proc.
+#' Natl. Acad. Sci. USA 101, 3747 (2004)
+#' @keywords graphs
+#' @examples
+#' 
+#' # Some trivial ones
+#' g <- make_ring(10)
+#' knn(g)
+#' g2 <- make_star(10)
+#' knn(g2)
+#' 
+#' # A scale-free one, try to plot 'knnk'
+#' g3 <- sample_pa(1000, m=5)
+#' knn(g3)
+#' 
+#' # A random graph
+#' g4 <- sample_gnp(1000, p=5/1000)
+#' knn(g4)
+#' 
+#' # A weighted graph
+#' g5 <- make_star(10)
+#' E(g5)$weight <- seq(ecount(g5))
+#' knn(g5)
+#' @export
+#' @include auto.R
+
+knn <- knn
diff --git a/R/structure.generators.R b/R/structure.generators.R
deleted file mode 100644
index 10789d5..0000000
--- a/R/structure.generators.R
+++ /dev/null
@@ -1,883 +0,0 @@
-
-#   IGraph R package
-#   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor at gmail.com>
-#   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
-#
-###################################################################
-
-graph <- function( edges, n=max(edges), directed=TRUE ) {
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  .Call("R_igraph_create", as.numeric(edges)-1, as.numeric(n),
-        as.logical(directed),
-        PACKAGE="igraph")
-}
-
-graph.formula <- function(..., simplify=TRUE) {
-  mf <- as.list(match.call())[-1]
-
-  ## In case 'simplify' is given
-  if ('simplify' %in% names(mf)) {
-    w <- which(names(mf)=='simplify')
-    if (length(w) > 1) { stop("'simplify' specified multiple times") }
-    mf <- mf[-w]
-  }
-
-  ## Operators first
-  f <- function(x) {
-    if (is.call(x)) {
-      return (list(as.character(x[[1]]), lapply(x[-1], f)))
-    } else {
-      return (NULL)
-    }
-  }
-  ops <- unlist(lapply(mf, f))
-  if (all(ops %in% c("-", ":"))) {
-    directed <- FALSE
-  } else if (all(ops %in% c("-", "+", ":"))) {
-    directed <- TRUE
-  } else {
-    stop("Invalid operator in formula")
-  }
-
-  f <- function(x) {
-    if (is.call(x)) {
-      if (length(x)==3) {
-        return( list(f(x[[2]]), op=as.character(x[[1]]), f(x[[3]])) )
-      } else {
-        return( list(op=as.character(x[[1]]), f(x[[2]])) )
-      }
-    } else {
-      return( c(sym=as.character(x)) )
-    }
-  }
-  
-  ret <- lapply(mf, function(x) unlist(f(x)))
-
-  v <- unique(unlist(lapply(ret, function(x) { x[ names(x)=="sym" ] })))
-
-  ## Merge symbols for ":"
-  ret <- lapply(ret, function(x) {
-    res <- list()
-    for (i in seq(along=x)) {
-      if (x[i]==":" && names(x)[i]=="op") {
-        ## SKIP
-      } else if (i>1 && x[i-1]==":" && names(x)[i-1]=="op") {
-        res[[length(res)]] <- c(res[[length(res)]], unname(x[i]))
-      } else {
-        res <- c(res, x[i])
-      }
-    }
-    res
-  })
-
-  ## Ok, create the edges
-  edges <- numeric()
-  for (i in seq(along=ret)) {
-    prev.sym <- character()
-    lhead <- rhead <- character()
-    for (j in seq(along=ret[[i]])) {
-      act <- ret[[i]][[j]]
-      if (names(ret[[i]])[j]=="op") {
-        if (length(lhead)==0) {
-          lhead <- rhead <- act
-        } else {
-          rhead <- act
-        }
-      } else if (names(ret[[i]])[j]=="sym") {
-        for (ps in prev.sym) {
-          for (ps2 in act) {
-            if (lhead=="+") {
-              edges <- c(edges, unname(c(ps2, ps)))
-            }            
-            if (!directed || rhead=="+") {
-              edges <- c(edges, unname(c(ps, ps2)))
-            }
-          }
-        }
-        lhead <- rhead <- character()
-        prev.sym <- act
-      }
-    }
-  }
-
-  ids <- seq(along=v)
-  names(ids) <- v
-  res <- graph( unname(ids[edges]), n=length(v), directed=directed)
-  if (simplify) res <- simplify(res)
-  res <- set.vertex.attribute(res, "name", value=v)
-  res
-}
-
-graph.adjacency.dense <- function(adjmatrix, mode=c("directed", "undirected", "max",
-                                               "min", "upper", "lower", "plus"),
-                                  weighted=NULL, diag=TRUE) {
-
-  mode <- igraph.match.arg(mode)
-  mode <- switch(mode,
-                 "directed"=0,
-                 "undirected"=1,
-                 "max"=1,
-                 "upper"=2,
-                 "lower"=3,
-                 "min"=4,
-                 "plus"=5)
-
-  mode(adjmatrix) <- "double"
-  
-  if (!is.null(weighted)) {
-    if (is.logical(weighted) && weighted) {
-      weighted <- "weight"
-    }
-    if (!is.character(weighted)) {
-      stop("invalid value supplied for `weighted' argument, please see docs.")
-    }
-
-    if (nrow(adjmatrix) != ncol(adjmatrix)) {
-      stop("not a square matrix")
-    }
-
-    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-    res <- .Call("R_igraph_weighted_adjacency", adjmatrix,
-                 as.numeric(mode), weighted, diag,
-                 PACKAGE="igraph")
-  } else {
-    
-    adjmatrix <- as.matrix(adjmatrix)
-    attrs <- attributes(adjmatrix)
-    adjmatrix <- as.numeric(adjmatrix)
-    attributes(adjmatrix) <- attrs
-
-    if (!diag) { diag(adjmatrix) <- 0 }
-    
-    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-    res <- .Call("R_igraph_graph_adjacency", adjmatrix, as.numeric(mode),
-                 PACKAGE="igraph")
-  }
-
-  res
-}
-
-graph.adjacency.sparse <- function(adjmatrix, mode=c("directed", "undirected", "max",
-                                                "min", "upper", "lower", "plus"),
-                                   weighted=NULL, diag=TRUE) {
-
-  mode <- igraph.match.arg(mode)
-
-  if (!is.null(weighted)) {
-    if (is.logical(weighted) && weighted) {
-      weighted <- "weight"
-    }
-    if (!is.character(weighted)) {
-      stop("invalid value supplied for `weighted' argument, please see docs.")
-    }
-  }
-
-  mysummary <- Matrix::summary
-
-  if (nrow(adjmatrix) != ncol(adjmatrix)) {
-    stop("not a square matrix")
-  }
-
-  vc <- nrow(adjmatrix)
-
-  ## to remove non-redundancies that can persist in a dgtMatrix
-  if(inherits(adjmatrix, "dgTMatrix")) {
-    adjmatrix = as(adjmatrix, "CsparseMatrix")
-  }
-  
-  if (is.null(weighted) && mode=="undirected") { mode <- "max" }
-  
-  if (mode == "directed") {
-    ## DIRECTED
-    el <- mysummary(adjmatrix)
-    if (!diag) { el <- el[ el[,1] != el[,2], ] }      
-  } else if (mode == "undirected") {
-    ## UNDIRECTED, must be symmetric if weighted
-    if (!is.null(weighted) && !Matrix::isSymmetric(adjmatrix)) {
-      stop("Please supply a symmetric matrix if you want to create a weighted graph with mode=UNDIRECTED.")
-    }
-    if (diag) {
-      adjmatrix <- Matrix::tril(adjmatrix)
-    } else {
-      adjmatrix <- Matrix::tril(adjmatrix, -1)
-    }      
-    el <- mysummary(adjmatrix)
-  } else if (mode=="max") {
-    ## MAXIMUM
-    el <- mysummary(adjmatrix)
-    rm(adjmatrix)
-    if (!diag) { el <- el[ el[,1] != el[,2], ] }
-    el <- el[ el[,3] != 0, ]
-    w <- el[,3]
-    el <- el[,1:2]
-    el <- cbind( pmin(el[,1],el[,2]), pmax(el[,1], el[,2]) )
-    o <- order(el[,1], el[,2])
-    el <- el[o,,drop=FALSE]
-    w <- w[o]
-    if (nrow(el) > 1) {
-      dd <- el[2:nrow(el),1] == el[1:(nrow(el)-1),1] &
-        el[2:nrow(el),2] == el[1:(nrow(el)-1),2]
-      dd <- which(dd)
-      if (length(dd)>0) {
-        mw <- pmax(w[dd], w[dd+1])
-        w[dd] <- mw
-        w[dd+1] <- mw
-        el <- el[-dd,,drop=FALSE]
-        w <- w[-dd]
-      }
-    }
-    el <- cbind(el, w)
-  } else if (mode=="upper") {
-    ## UPPER
-    if (diag) {
-      adjmatrix <- Matrix::triu(adjmatrix)
-    } else {
-      adjmatrix <- Matrix::triu(adjmatrix, 1)
-    }
-    el <- mysummary(adjmatrix)
-    rm(adjmatrix)
-    if (!diag) { el <- el[ el[,1] != el[,2], ] }      
-  } else if (mode=="lower") {
-    ## LOWER
-    if (diag) {
-      adjmatrix <- Matrix::tril(adjmatrix)
-    } else {
-      adjmatrix <- Matrix::tril(adjmatrix, -1)
-    }
-    el <- mysummary(adjmatrix)
-    rm(adjmatrix)
-    if (!diag) { el <- el[ el[,1] != el[,2], ] }      
-  } else if (mode=="min") {
-    ## MINIMUM
-    adjmatrix <- sign(adjmatrix) * sign(Matrix::t(adjmatrix)) * adjmatrix
-    el <- mysummary(adjmatrix)
-    if (!diag) { el <- el[ el[,1] != el[,2], ] }
-    el <- el[ el[,3] != 0, ]
-    w <- el[,3]
-    el <- el[,1:2]
-    el <- cbind( pmin(el[,1],el[,2]), pmax(el[,1], el[,2]) )
-    o <- order(el[,1], el[,2])
-    el <- el[o,]
-    w <- w[o]
-    if (nrow(el) > 1) {
-      dd <- el[2:nrow(el),1] == el[1:(nrow(el)-1),1] &
-        el[2:nrow(el),2] == el[1:(nrow(el)-1),2]
-      dd <- which(dd)
-      if (length(dd)>0) {
-        mw <- pmin(w[dd], w[dd+1])
-        w[dd] <- mw
-        w[dd+1] <- mw
-        el <- el[-dd,]
-        w <- w[-dd]
-      }
-    }
-    el <- cbind(el, w)
-  } else if (mode=="plus") {
-    ## PLUS
-    adjmatrix <- adjmatrix + Matrix::t(adjmatrix)
-    if (diag) {
-      adjmatrix <- Matrix::tril(adjmatrix)
-    } else {
-      adjmatrix <- Matrix::tril(adjmatrix, -1)
-    }
-    el <- mysummary(adjmatrix)
-    if (diag) {
-      loop <- el[,1] == el[,2]
-      el[loop,3] <- el[loop,3] / 2
-    }
-    el <- el[ el[,3] != 0, ]
-    rm(adjmatrix)
-  }
-
-  if (!is.null(weighted)) {
-    res <- graph.empty(n=vc, directed=(mode=="directed"))
-    weight <- list(el[,3])
-    names(weight) <- weighted
-    res <- add.edges(res, edges=t(as.matrix(el[,1:2])), attr=weight)
-  } else {
-    edges <- unlist(apply(el, 1, function(x) rep(unname(x[1:2]), x[3])))
-    res <- graph(n=vc, edges, directed=(mode=="directed"))
-  }
-  res
-}
-
-graph.adjacency <- function(adjmatrix, mode=c("directed", "undirected", "max",
-                                         "min", "upper", "lower", "plus"),
-                            weighted=NULL, diag=TRUE,
-                            add.colnames=NULL, add.rownames=NA) {
-
-  if (inherits(adjmatrix, "Matrix")) {
-    res <- graph.adjacency.sparse(adjmatrix, mode=mode, weighted=weighted, diag=diag)
-  } else {
-    res <- graph.adjacency.dense(adjmatrix, mode=mode, weighted=weighted, diag=diag)
-  }    
-  
-  ## Add columns and row names as attributes
-  if (is.null(add.colnames)) {
-    if (!is.null(colnames(adjmatrix))) {
-      add.colnames <- "name"
-    } else {
-      add.colnames <- NA
-    }
-  } else if (!is.na(add.colnames)) {
-    if (is.null(colnames(adjmatrix))) {
-      warning("No column names to add")
-      add.colnames <- NA
-    }
-  }
-  
-  if (is.null(add.rownames)) {
-    if (!is.null(rownames(adjmatrix))) {
-      add.rownames <- "name"
-    } else {
-      add.colnames <- NA
-    }
-  } else if (!is.na(add.rownames)) {
-    if (is.null(rownames(adjmatrix))) {
-      warning("No row names to add")
-      add.rownames <- NA
-    }
-  }
-
-  if (!is.na(add.rownames) && !is.na(add.colnames) &&
-      add.rownames == add.colnames ) {
-    warning("Same attribute for columns and rows, row names are ignored")
-    add.rownames <- NA
-  }
-
-  if (!is.na(add.colnames)) {
-    res <- set.vertex.attribute(res, add.colnames, value=colnames(adjmatrix))
-  }
-  if (!is.na(add.rownames)) {
-    res <- set.vertex.attribute(res, add.rownames, value=rownames(adjmatrix))
-  }
-
-  res
-}
-  
-
-graph.star <- function(n, mode=c("in", "out", "mutual", "undirected"),
-                       center=1 ) {
-
-  mode <- igraph.match.arg(mode)
-  mode1 <- switch(mode, "out"=0, "in"=1, "undirected"=2, "mutual"=3)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_star", as.numeric(n), as.numeric(mode1),
-               as.numeric(center)-1,
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- switch(mode, "in"="In-star", "out"="Out-star", "Star")
-    res$mode <- mode
-    res$center <- center
-  }
-  res
-}
-
-graph.full <- function(n, directed=FALSE, loops=FALSE) {
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_full", as.numeric(n), as.logical(directed),
-               as.logical(loops),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- "Full graph"
-    res$loops <- loops
-  }
-  res
-}
-
-###################################################################
-# Lattices, every kind
-###################################################################
-
-graph.lattice <- function(dimvector=NULL,length=NULL, dim=NULL, nei=1,
-                          directed=FALSE, mutual=FALSE, circular=FALSE, ...) {
-
-##   # Check
-##   if (is.null(dimvector) && (is.null(length) || is.null(dim))) {
-##     stop("Either `length' and `dim' or 'dimvector' must be set. See docs.")
-##   }
-##   if (!is.null(length) && length < 1) {
-##     stop("Invalid `length' argument, should be at least one")
-##   }
-##   if (!is.null(length) && dim < 1) {
-##     stop("Invalid `dim' argument, should be at least one")
-##   }
-##   if (!is.null(length) && any(dimvector < 1)) {
-##     stop("Invalid `dimvector', has negative or smaller than one elements")
-##   }
-##   if (mutual && !directed) {
-##     warning("`mutual' specified for undirected graph, proceeding with multiplex edges...")
-##   }
-##   if (nei < 1) {
-##     stop("`nei' should be at least one")
-##   }
-  
-##   if (!is.null(length)) {
-##     length <- as.numeric(length)
-##     dim <- as.numeric(dim)
-##     dimvector <- rep(length, times=dim)
-##   } else {
-##     dimvector <- as.numeric(dimvector)
-##   }
-##   nei <- as.numeric(nei)
-
-##   n <- prod(dimvector)
-##   res <- graph.empty(n=n, directed=directed, ...)
-##   res <- add.edges(res, .Call("REST_create_lattice", dimvector, n,
-##                               circular, mutual, PACKAGE="igraph"))
-
-##   # Connect also to local neighborhood
-##   if (nei >= 2) {
-##     neighbors <- lapply(1:length(res), function(a) get.neighborhood(res, a))
-##     res <- add.edges(res, .Call("REST_connect_neighborhood", neighbors, nei,
-##                                 mutual, PACKAGE="igraph"))
-##   }
-  
-##   res
-
-  if (is.null(dimvector)) {
-    dimvector <- rep(length, dim)
-  }
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_lattice", as.numeric(dimvector), as.numeric(nei),
-               as.logical(directed), as.logical(mutual),
-               as.logical(circular),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- "Lattice graph"
-    res$dimvector <- dimvector
-    res$nei <- nei
-    res$mutual <- mutual
-    res$circular <- circular
-  }
-  res
-}
-
-graph.ring <- function(n, directed=FALSE, mutual=FALSE, circular=TRUE) {
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_ring", as.numeric(n), as.logical(directed),
-               as.logical(mutual), as.logical(circular),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- "Ring graph"
-    res$mutual <- mutual
-    res$circular <- circular
-  }
-  res
-}
-
-###################################################################
-# Trees, regular
-###################################################################
-
-graph.tree <- function(n, children=2, mode=c("out", "in", "undirected")) {
-
-  mode <- igraph.match.arg(mode)
-  mode1 <- switch(mode, "out"=0, "in"=1, "undirected"=2);
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_tree", as.numeric(n), as.numeric(children),
-               as.numeric(mode1),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- "Tree"
-    res$children <- children
-    res$mode <- mode
-  }
-  res
-}
-
-###################################################################
-# The graph atlas
-###################################################################
-
-graph.atlas <- function(n) {
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_atlas", as.numeric(n),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- sprintf("Graph from the Atlas #%i", n)
-    res$n <- n
-  }
-  res
-}
-
-###################################################################
-# Create a graph from a data frame
-###################################################################
-
-graph.data.frame <- function(d, directed=TRUE, vertices=NULL) {
-
-  d <- as.data.frame(d)
-  if (!is.null(vertices)) { vertices <- as.data.frame(vertices) }
-  
-  if (ncol(d) < 2) {
-    stop("the data frame should contain at least two columns")
-  }
-
-  ## Handle if some elements are 'NA'
-  if (any(is.na(d[,1:2]))) {
-    warning("In `d' `NA' elements were replaced with string \"NA\"")
-    d[,1:2][ is.na(d[,1:2]) ] <- 'NA'
-  }
-  if (!is.null(vertices) && any(is.na(vertices[,1]))) {
-    warning("In `vertices[,1]' `NA' elements were replaced with string \"NA\"")
-    vertices[,1][is.na(vertices[,1])] <- 'NA'
-  }    
-  
-  names <- unique( c(as.character(d[,1]), as.character(d[,2])) )
-  if (!is.null(vertices)) {
-    names2 <- names
-    vertices <- as.data.frame(vertices)
-    if (ncol(vertices) < 1) {
-      stop("Vertex data frame contains no rows")
-    }
-    names <- as.character(vertices[,1])
-    if (any(duplicated(names))) {
-      stop("Duplicate vertex names")
-    }
-    if (any(! names2 %in% names)) {
-      stop("Some vertex names in edge list are not listed in vertex data frame")
-    }
-  }
-    
-  # create graph
-  g <- graph.empty(n=0, directed=directed)
-
-  # vertex attributes
-  attrs <- list(name=names)
-  if (!is.null(vertices)) {
-    if (ncol(vertices) > 1) {
-      for (i in 2:ncol(vertices)) {
-        newval <- vertices[,i]
-        if (class(newval) == "factor") {
-          newval <- as.character(newval)
-        }
-        attrs[[ names(vertices)[i] ]] <- newval
-      }
-    }
-  }
-
-  # add vertices
-  g <- add.vertices(g, length(names), attr=attrs)
-    
-  # create edge list
-  from <- as.character(d[,1])
-  to <- as.character(d[,2])
-  edges <- rbind(match(from, names), match(to,names))
-  
-  # edge attributes
-  attrs <- list()
-  if (ncol(d) > 2) {
-    for (i in 3:ncol(d)) {
-      newval <- d[,i]
-      if (class(newval) == "factor") {
-        newval <- as.character(newval)
-      }
-      attrs[[ names(d)[i] ]] <- newval
-    }
-  }
-
-  # add the edges
-  g <- add.edges(g, edges, attr=attrs)
-  g
-}
-
-graph.edgelist <- function(el, directed=TRUE) {
-
-  if (!is.matrix(el) || ncol(el) != 2) {
-    stop("graph.edgelist expects a matrix with two columns")
-  }
-
-  if (nrow(el) == 0) {
-    res <- graph.empty(directed=directed)
-  } else {  
-    if (is.character(el)) {
-      ## symbolic edge list
-      names <- unique(as.character(t(el)))
-      ids <- seq(names)
-      names(ids) <- names
-      res <- graph( unname(ids[t(el)]), directed=directed)
-      rm(ids)
-      V(res)$name <- names
-    } else {
-      ## normal edge list
-      res <- graph( t(el), directed=directed )
-    }
-  }
-
-  res
-}
-
-graph.extended.chordal.ring <- function(n, w) {
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_extended_chordal_ring", as.numeric(n),
-               as.matrix(w),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {  
-    res$name <- "Extended chordal ring"
-    res$w <- w
-  }
-  res
-}
-
-line.graph <- function(graph) {
-
-  if (!is.igraph(graph)) {
-    stop("Not a graph object")
-  }
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_line_graph", graph,
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- "Line graph"
-  }
-  res
-}
-  
-  
-graph.de.bruijn <- function(m, n) {
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_de_bruijn", as.numeric(m), as.numeric(n),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- sprintf("De-Bruijn graph %i-%i", m, n)
-    res$m <- m
-    res$n <- n
-  }
-  res
-}
-
-graph.kautz <- function(m, n) {
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_kautz", as.numeric(m), as.numeric(n),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- sprintf("Kautz graph %i-%i", m, n)
-    res$m <- m
-    res$n <- n
-  }
-  res
-}
-
-graph.famous <- function(name) {
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_famous", as.character(name),
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$name <- name
-  }
-  res
-}
-
-graph.full.bipartite <- function(n1, n2, directed=FALSE,
-                                 mode=c("all", "out", "in")) {
-
-  n1 <- as.integer(n1)
-  n2 <- as.integer(n2)
-  directed <- as.logical(directed)
-  mode1 <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)  
-  
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_full_bipartite", n1, n2, as.logical(directed), mode1,
-               PACKAGE="igraph")
-  if (getIgraphOpt("add.params")) {
-    res$graph$name <- "Full bipartite graph"
-    res$n1 <- n1
-    res$n2 <- n2
-    res$mode <- mode
-  }
-  set.vertex.attribute(res$graph, "type", value=res$types)
-}
-
-graph.bipartite <- function(types, edges, directed=FALSE) {
-
-  types <- as.logical(types)
-  edges <- as.numeric(edges)-1
-  directed <- as.logical(directed)
-
-  on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-  res <- .Call("R_igraph_create_bipartite", types, edges, directed,
-               PACKAGE="igraph")
-  set.vertex.attribute(res, "type", value=types)
-}
-
-graph.incidence.sparse <- function(incidence, directed, mode, multiple,
-                                   weighted) {
-  n1 <- nrow(incidence)
-  n2 <- ncol(incidence)
-  el <- Matrix::summary(incidence)
-  ## el <- summary(incidence)
-  el[,2] <- el[,2] + n1
-
-  if (!is.null(weighted)) {
-
-    if (is.logical(weighted) && weighted) {
-      weighted <- "weight"
-    }
-    if (!is.character(weighted)) {
-      stop("invalid value supplied for `weighted' argument, please see docs.")
-    }
-
-    if (!directed || mode==1) {
-      ## nothing do to
-    } else if (mode==2) {
-      el[,1:2] <- el[,c(2,1)]
-    } else if (mode==3) {
-      el <- rbind(el, el[,c(2,1,3)])
-    }
-
-    res <- graph.empty(n=n1+n2, directed=directed)
-    weight <- list(el[,3])
-    names(weight) <- weighted
-    res <- add.edges(res, edges=t(as.matrix(el[,1:2])), attr=weight)
-
-  } else {
-
-    if (multiple) {
-      el[,3] <- ceiling(el[,3])
-      el[,3][ el[,3] < 0 ] <- 0
-    } else {
-      el[,3] <- el[,3] != 0
-    }
-
-    if (!directed || mode==1) {
-      ## nothing do to
-    } else if (mode==2) {
-      el[,1:2] <- el[,c(2,1)]
-    } else if (mode==3) {
-      el <- rbind(el, el[,c(2,1,3)])
-    }
-    
-    edges <- unlist(apply(el, 1, function(x) rep(unname(x[1:2]), x[3])))
-    res <- graph(n=n1+n2, edges, directed=directed)
-  } 
-    
-  set.vertex.attribute(res, "type", value=c(rep(FALSE, n1), rep(TRUE, n2)))
-}
-
-graph.incidence.dense <- function(incidence, directed, mode, multiple,
-                                  weighted) {
-
-  if (!is.null(weighted)) {
-    if (is.logical(weighted) && weighted) {
-      weighted <- "weight"
-    }
-    if (!is.character(weighted)) {
-      stop("invalid value supplied for `weighted' argument, please see docs.")
-    }
-
-    n1 <- nrow(incidence)
-    n2 <- ncol(incidence)
-    no.edges <- sum(incidence != 0)
-    if (directed && mode==3) { no.edges <- no.edges * 2 }
-    edges <- numeric(2*no.edges)
-    weight <- numeric(no.edges)
-    ptr <- 1
-    for (i in seq_len(nrow(incidence))) {
-      for (j in seq_len(ncol(incidence))) {
-        if (incidence[i,j] != 0) {
-          if (!directed || mode==1) {
-            edges[2*ptr-1] <- i
-            edges[2*ptr] <- n1+j
-            weight[ptr] <- incidence[i,j]
-            ptr <- ptr + 1
-          } else if (mode==2) {
-            edges[2*ptr-1] <- n1+j
-            edges[2*ptr] <- i
-            weight[ptr] <- incidence[i,j]
-            ptr <- ptr + 1
-          } else if (mode==3) {
-            edges[2*ptr-1] <- i
-            edges[2*ptr] <- n1+j
-            weight[ptr] <- incidence[i,j]
-            ptr <- ptr + 1
-            edges[2*ptr-1] <- n1+j
-            edges[2*ptr] <- i
-          }
-        }
-      }
-    }
-    res <- graph.empty(n=n1+n2, directed=directed)
-    weight <- list(weight)
-    names(weight) <- weighted
-    res <- add.edges(res, edges, attr=weight)
-    res <- set.vertex.attribute(res, "type",
-                                value=c(rep(FALSE, n1), rep(TRUE, n2)))
-    
-  } else {
-
-    mode(incidence) <- "double"
-    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
-    ## Function call
-    res <- .Call("R_igraph_incidence", incidence, directed, mode, multiple,
-                 PACKAGE="igraph")
-    res <- set.vertex.attribute(res$graph, "type", value=res$types)
-
-  }
-
-  res
-}
-
-graph.incidence <- function(incidence, directed=FALSE,
-                            mode=c("all", "out", "in", "total"), 
-                            multiple=FALSE, weighted=NULL,
-                            add.names=NULL) {
-  # Argument checks
-  directed <- as.logical(directed)
-  mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3, "total"=3)
-  multiple <- as.logical(multiple)
-
-  if (inherits(incidence, "Matrix")) {
-    res <- graph.incidence.sparse(incidence, directed=directed,
-                                  mode=mode, multiple=multiple,
-                                  weighted=weighted)
-  } else {
-    incidence <- as.matrix(incidence)
-    res <- graph.incidence.dense(incidence, directed=directed, mode=mode,
-                                 multiple=multiple, weighted=weighted)
-  }
-
-  ## Add names
-  if (is.null(add.names)) {
-    if (!is.null(rownames(incidence)) && !is.null(colnames(incidence))) {
-      add.names <- "name"
-    } else {
-      add.names <- NA
-    }
-  } else if (!is.na(add.names)) {
-    if (is.null(rownames(incidence)) || is.null(colnames(incidence))) {
-      warning("Cannot add row- and column names, at least one of them is missing")
-      add.names <- NA
-    }
-  }
-  if (!is.na(add.names)) {
-    res <- set.vertex.attribute(res, add.names,
-                                value=c(rownames(incidence), colnames(incidence)))
-  }
-  res
-}
-
diff --git a/R/structure.info.R b/R/structure.info.R
index fa6f34a..c8660a2 100644
--- a/R/structure.info.R
+++ b/R/structure.info.R
@@ -20,8 +20,34 @@
 #
 ###################################################################
 
-are.connected <- function(graph, v1, v2) {
-  if (!is.igraph(graph)) {
+#' Are two vertices adjacent?
+#'
+#' The order of the vertices only matters in directed graphs,
+#' where the existence of a directed \code{(v1, v2)} edge is queried.
+#'
+#' @aliases are.connected
+#' @param graph The graph.
+#' @param v1 The first vertex, tail in directed graphs.
+#' @param v2 The second vertex, head in directed graphs.
+#' @return A logical scalar, \code{TRUE} is a \code{(v1, v2)} exists in the
+#'   graph.
+#'
+#' @family structural queries
+#' 
+#' @export
+#' @examples
+#' ug <- make_ring(10)
+#' ug
+#' are_adjacent(ug, 1, 2)
+#' are_adjacent(ug, 2, 1)
+#'
+#' dg <- make_ring(10, directed = TRUE)
+#' dg
+#' are_adjacent(ug, 1, 2)
+#' are_adjacent(ug, 2, 1)
+
+are_adjacent <- function(graph, v1, v2) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
diff --git a/R/test.R b/R/test.R
index 0a74318..a3a344b 100644
--- a/R/test.R
+++ b/R/test.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2005-2013  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,13 +19,58 @@
 #
 ###################################################################
 
-igraphtest <- function() {
+
+
+#' Run package tests
+#' 
+#' Runs all package tests.
+#' 
+#' The \code{testthat} package is needed to run all tests. The location tests
+#' themselves can be extracted from the package via \code{system.file("tests",
+#' package="igraph")}.
+#' 
+#' This function simply calls the \code{test_dir} function from the
+#' \code{testthat} package on the test directory.
+#'
+#' @aliases igraphtest
+#' @return Whatever is returned by \code{test_dir} from the \code{testthat}
+#' package.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+
+igraph_test <- function() {
   do.call(require, list("testthat"))
   tdir <- system.file("tests", package="igraph")
   do.call("test_dir", list(tdir))
 }
 
-igraph.version <- function() {
+
+
+#' Query igraph's version string
+#' 
+#' Queries igraph's original version string. See details below.
+#' 
+#' The igraph version string is the same as the version of the R package for
+#' all realeased igraph versions. For development versions and nightly builds,
+#' they might differ however.
+#' 
+#' The reason for this is, that R package version numbers are not flexible
+#' enough to cover in-between releases versions, e.g. alpha and beta versions,
+#' release candidates, etc.
+#'
+#' @aliases igraph.version
+#' @return A character scalar, the igraph version string.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @keywords graphs
+#' @export
+#' @examples
+#' 
+#' ## Compare to the package version
+#' packageDescription("igraph")$Version
+#' igraph_version()
+
+igraph_version <- function() {
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   .Call("R_igraph_version", PACKAGE="igraph")
 }
diff --git a/R/tkplot.R b/R/tkplot.R
index d5a1271..c78f14c 100644
--- a/R/tkplot.R
+++ b/R/tkplot.R
@@ -1,4 +1,3 @@
-
 #   IGraph R package
 #   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   334 Harvard street, Cambridge, MA 02139 USA
@@ -20,6 +19,8 @@
 #
 ###################################################################
 
+#' @include layout.R
+
 ###################################################################
 # Internal variables
 ###################################################################
@@ -32,14 +33,152 @@ assign(".next", 1, .tkplot.env)
 # Main function
 ###################################################################
 
+
+
+#' Interactive plotting of graphs
+#' 
+#' \code{tkplot} and its companion functions serve as an interactive graph
+#' drawing facility. Not all parameters of the plot can be changed
+#' interactively right now though, eg. the colors of vertices, edges, and also
+#' others have to be pre-defined.
+#' 
+#' \code{tkplot} is an interactive graph drawing facility. It is not very well
+#' developed at this stage, but it should be still useful.
+#' 
+#' It's handling should be quite straightforward most of the time, here are
+#' some remarks and hints.
+#' 
+#' There are different popup menus, activated by the right mouse button, for
+#' vertices and edges. Both operate on the current selection if the vertex/edge
+#' under the cursor is part of the selection and operate on the vertex/edge
+#' under the cursor if it is not.
+#' 
+#' One selection can be active at a time, either a vertex or an edge selection.
+#' A vertex/edge can be added to a selection by holding the \code{control} key
+#' while clicking on it with the left mouse button. Doing this again deselect
+#' the vertex/edge.
+#' 
+#' Selections can be made also from the \code{Select} menu. The `Select some
+#' vertices' dialog allows to give an expression for the vertices to be
+#' selected: this can be a list of numeric R expessions separated by commas,
+#' like `\code{1,2:10,12,14,15}' for example. Similarly in the `Select some
+#' edges' dialog two such lists can be given and all edges connecting a vertex
+#' in the first list to one in the second list will be selected.
+#' 
+#' In the color dialog a color name like 'orange' or RGB notation can also be
+#' used.
+#' 
+#' The \code{tkplot} command creates a new Tk window with the graphical
+#' representation of \code{graph}. The command returns an integer number, the
+#' tkplot id. The other commands utilize this id to be able to query or
+#' manipulate the plot.
+#' 
+#' \code{tk_close} closes the Tk plot with id \code{tkp.id}.
+#' 
+#' \code{tk_off} closes all Tk plots.
+#' 
+#' \code{tk_fit} fits the plot to the given rectange
+#' (\code{width} and \code{height}), if some of these are \code{NULL} the
+#' actual phisical width od height of the plot window is used.
+#' 
+#' \code{tk_reshape} applies a new layout to the plot, its optional
+#' parameters will be collected to a list analogous to \code{layout.par}.
+#' 
+#' \code{tk_postscript} creates a dialog window for saving the plot
+#' in postscript format.
+#' 
+#' \code{tk_canvas} returns the Tk canvas object that belongs to a graph
+#' plot. The canvas can be directly manipulated then, eg. labels can be added,
+#' it could be saved to a file programatically, etc. See an example below.
+#' 
+#' \code{tk_coords} returns the coordinates of the vertices in a matrix.
+#' Each row corresponds to one vertex.
+#' 
+#' \code{tk_set_coords} sets the coordinates of the vertices. A two-column
+#' matrix specifies the new positions, with each row corresponding to a single
+#' vertex.
+#' 
+#' \code{tk_center} shifts the figure to the center of its plot window.
+#' 
+#' \code{tk_rotate} rotates the figure, its parameter can be given either
+#' in degrees or in radians.
+#' 
+#' @aliases tkplot tkplot.close tkplot.off tkplot.fit.to.screen tkplot.reshape
+#' tkplot.export.postscript tkplot.canvas tkplot.getcoords tkplot.setcoords
+#' tkplot.center tkplot.rotate tk_canvas tk_center tk_close tk_postscript
+#' tk_fit tk_coords tk_off tk_reshape tk_rotate tk_set_coords
+#' @param graph The \code{graph} to plot.
+#' @param canvas.width,canvas.height The size of the tkplot drawing area.
+#' @param tkp.id The id of the tkplot window to close/reshape/etc.
+#' @param window.close Leave this on the default value.
+#' @param width The width of the rectangle for generating new coordinates.
+#' @param height The height of the rectangle for generating new coordinates.
+#' @param newlayout The new layout, see the \code{layout} parameter of tkplot.
+#' @param norm Logical, should we norm the coordinates.
+#' @param coords Two-column numeric matrix, the new coordinates of the
+#' vertices, in absolute coordinates.
+#' @param degree The degree to rotate the plot.
+#' @param rad The degree to rotate the plot, in radian.
+#' @param \dots Additional plotting parameters. See \link{igraph.plotting} for
+#' the complete list.
+#' @return \code{tkplot} returns an integer, the id of the plot, this can be
+#' used to manipulate it from the command line.
+#' 
+#' \code{tk_canvas} retuns \code{tkwin} object, the Tk canvas.
+#' 
+#' \code{tk_coords} returns a matrix with the coordinates.
+#' 
+#' \code{tk_close}, \code{tk_off}, \code{tk_fit},
+#' \code{tk_reshape}, \code{tk_postscript}, \code{tk_center}
+#' and \code{tk_rotate} return \code{NULL} invisibly.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{plot.igraph}}, \code{\link{layout}}
+#' @export
+#' @keywords graphs
+#' @examples
+#' 
+#' g <- make_ring(10)
+#' \dontrun{tkplot(g)}
+#' 
+#' \dontrun{
+#' ## Saving a tkplot() to a file programatically
+#' g <- make_star(10, center=10) %u% make_ring(9, directed=TRUE)
+#' E(g)$width <- sample(1:10, ecount(g), replace=TRUE)
+#' lay <- layout_nicely(g)
+#' 
+#' id <- tkplot(g, layout=lay)
+#' canvas <- tk_canvas(id)
+#' tkpostscript(canvas, file="/tmp/output.eps")
+#' tk_close(id)
+#' }
+#' 
+#' \dontrun{
+#' ## Setting the coordinates and adding a title label
+#' g <- make_ring(10)
+#' id <- tkplot(make_ring(10), canvas.width=450, canvas.height=500)
+#' 
+#' canvas <- tk_canvas(id)
+#' padding <- 20
+#' coords <- norm_coords(layout_in_circle(g), 0+padding, 450-padding,
+#'                       50+padding, 500-padding)
+#' tk_set_coords(id, coords)
+#' 
+#' width <- as.numeric(tkcget(canvas, "-width"))
+#' height <- as.numeric(tkcget(canvas, "-height"))
+#' tkcreate(canvas, "text", width/2, 25, text="My title",
+#'          justify="center", font=tcltk::tkfont.create(family="helvetica"
+#'                              ,size=20,weight="bold"))
+#' }
+#' 
 tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
 
-  if (!is.igraph(graph)) {
+  if (!is_igraph(graph)) {
     stop("Not a graph object")
   }
   
   # Libraries
-  require(tcltk) || stop("tcl/tk library not available")
+  requireNamespace("tcltk", quietly = TRUE) ||
+    stop("tcl/tk library not available")
 
   # Visual parameters
   params <- i.parse.plot.params(graph, list(...))
@@ -80,11 +219,11 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
   edge.lty <- i.tkplot.get.edge.lty(edge.lty)
 
   # Create window & canvas
-  top <- tktoplevel(background="lightgrey")
-  canvas <- tkcanvas(top, relief="raised",
+  top <- tcltk::tktoplevel(background="lightgrey")
+  canvas <- tcltk::tkcanvas(top, relief="raised",
                      width=canvas.width, height=canvas.height,
                      borderwidth=2)
-  tkpack(canvas, fill="both", expand=1)
+  tcltk::tkpack(canvas, fill="both", expand=1)
 
   # Create parameters
   vertex.params <- sdf(vertex.color=vertex.color,
@@ -105,13 +244,13 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
                  curved=curved)
 
   # The popup menu
-  popup.menu <- tkmenu(canvas)
-  tkadd(popup.menu, "command", label="Fit to screen", command=function() {
-    tkplot.fit.to.screen(tkp.id)})  
+  popup.menu <- tcltk::tkmenu(canvas)
+  tcltk::tkadd(popup.menu, "command", label="Fit to screen", command=function() {
+    tk_fit(tkp.id)})  
 
   # Different popup menu for vertices
-  vertex.popup.menu <- tkmenu(canvas)
-  tkadd(vertex.popup.menu, "command", label="Vertex color",
+  vertex.popup.menu <- tcltk::tkmenu(canvas)
+  tcltk::tkadd(vertex.popup.menu, "command", label="Vertex color",
         command=function() {
           tkp <- .tkplot.get(tkp.id)
           vids <- .tkplot.get.selected.vertices(tkp.id)
@@ -123,7 +262,7 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
           
           .tkplot.update.vertex.color(tkp.id, vids, color)
         })
-  tkadd(vertex.popup.menu, "command", label="Vertex size",
+  tcltk::tkadd(vertex.popup.menu, "command", label="Vertex size",
         command=function() {
           tkp <- .tkplot.get(tkp.id)
           vids <- .tkplot.get.selected.vertices(tkp.id)
@@ -137,8 +276,8 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
         })
   
   # Different popup menu for edges
-  edge.popup.menu <- tkmenu(canvas)
-  tkadd(edge.popup.menu, "command", label="Edge color",
+  edge.popup.menu <- tcltk::tkmenu(canvas)
+  tcltk::tkadd(edge.popup.menu, "command", label="Edge color",
         command=function() {
           tkp <- .tkplot.get(tkp.id)
           eids <- .tkplot.get.selected.edges(tkp.id)
@@ -152,7 +291,7 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
 
           .tkplot.update.edge.color(tkp.id, eids, color)          
         })
-  tkadd(edge.popup.menu, "command", label="Edge width",
+  tcltk::tkadd(edge.popup.menu, "command", label="Edge width",
         command=function() {
           tkp <- .tkplot.get(tkp.id)
           eids <- .tkplot.get.selected.edges(tkp.id)
@@ -174,72 +313,72 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
               vertex.popup.menu=vertex.popup.menu,
               edge.popup.menu=edge.popup.menu)
   tkp.id <- .tkplot.new(tkp)
-  tktitle(top) <- paste("Graph plot", as.character(tkp.id))
+  tcltk::tktitle(top) <- paste("Graph plot", as.character(tkp.id))
 
   # The main pull-down menu
-  main.menu <- tkmenu(top)
-  tkadd(main.menu, "command", label="Close", command=function() {
-    tkplot.close(tkp.id, TRUE)})
+  main.menu <- tcltk::tkmenu(top)
+  tcltk::tkadd(main.menu, "command", label="Close", command=function() {
+    tk_close(tkp.id, TRUE)})
   select.menu <- .tkplot.select.menu(tkp.id, main.menu)
-  tkadd(main.menu, "cascade", label="Select", menu=select.menu)  
+  tcltk::tkadd(main.menu, "cascade", label="Select", menu=select.menu)  
   layout.menu <- .tkplot.layout.menu(tkp.id, main.menu)
-  tkadd(main.menu, "cascade", label="Layout", menu=layout.menu)
-  view.menu <- tkmenu(main.menu)
-  tkadd(main.menu, "cascade", label="View", menu=view.menu)
-  tkadd(view.menu, "command", label="Fit to screen", command=function() {
-    tkplot.fit.to.screen(tkp.id)})
-  tkadd(view.menu, "command", label="Center on screen", command=function() {
-    tkplot.center(tkp.id)})
-  tkadd(view.menu, "separator")
-  view.menu.labels <- tclVar(1)
-  view.menu.grid <- tclVar(0)
-  tkadd(view.menu, "checkbutton", label="Labels",
+  tcltk::tkadd(main.menu, "cascade", label="Layout", menu=layout.menu)
+  view.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(main.menu, "cascade", label="View", menu=view.menu)
+  tcltk::tkadd(view.menu, "command", label="Fit to screen", command=function() {
+    tk_fit(tkp.id)})
+  tcltk::tkadd(view.menu, "command", label="Center on screen", command=function() {
+    tk_center(tkp.id)})
+  tcltk::tkadd(view.menu, "separator")
+  view.menu.labels <- tcltk::tclVar(1)
+  view.menu.grid <- tcltk::tclVar(0)
+  tcltk::tkadd(view.menu, "checkbutton", label="Labels",
         variable=view.menu.labels, command=function() {
           .tkplot.toggle.labels(tkp.id)})
 # grid canvas object not implemented in tcltk (?) :(
-#   tkadd(view.menu, "checkbutton", label="Grid",
+#   tcltk::tkadd(view.menu, "checkbutton", label="Grid",
 #         variable=view.menu.grid, command=function() {
 #           .tkplot.toggle.grid(tkp.id)})
-  tkadd(view.menu, "separator")
-  rotate.menu <- tkmenu(view.menu)
-  tkadd(view.menu, "cascade", label="Rotate", menu=rotate.menu)
+  tcltk::tkadd(view.menu, "separator")
+  rotate.menu <- tcltk::tkmenu(view.menu)
+  tcltk::tkadd(view.menu, "cascade", label="Rotate", menu=rotate.menu)
   sapply(c(-90,-45,-15,-5,-1,1,5,15,45,90),
          function(deg) {
-           tkadd(rotate.menu, "command",
+           tcltk::tkadd(rotate.menu, "command",
                  label=paste(deg, "degree"), command=function() {
-                   tkplot.rotate(tkp.id, degree=deg)
+                   tk_rotate(tkp.id, degree=deg)
                  })
          })
-  export.menu <- tkmenu(main.menu)
-  tkadd(main.menu, "cascade", label="Export", menu=export.menu)
-  tkadd(export.menu, "command", label="Postscript", command=function() {
-    tkplot.export.postscript(tkp.id)})
-  tkconfigure(top, "-menu", main.menu)
+  export.menu <- tcltk::tkmenu(main.menu)
+  tcltk::tkadd(main.menu, "cascade", label="Export", menu=export.menu)
+  tcltk::tkadd(export.menu, "command", label="Postscript", command=function() {
+    tk_postscript(tkp.id)})
+  tcltk::tkconfigure(top, "-menu", main.menu)
   
   # plot it
   .tkplot.create.edges(tkp.id)
   .tkplot.create.vertices(tkp.id)
   # we would need an update here
-  tkplot.fit.to.screen(tkp.id, canvas.width, canvas.height)
+  tk_fit(tkp.id, canvas.width, canvas.height)
 
   # Kill myself if window was closed
-  tkbind(top, "<Destroy>", function() tkplot.close(tkp.id, FALSE))
+  tcltk::tkbind(top, "<Destroy>", function() tk_close(tkp.id, FALSE))
 
 ###################################################################
 # The callbacks for interactive editing
 ###################################################################  
 
-  tkitembind(canvas, "vertex||label||edge", "<1>", function(x, y) {
+  tcltk::tkitembind(canvas, "vertex||label||edge", "<1>", function(x, y) {
     tkp <- .tkplot.get(tkp.id)
     canvas <- .tkplot.get(tkp.id, "canvas")
     .tkplot.deselect.all(tkp.id)
     .tkplot.select.current(tkp.id)
-#     tkitemraise(canvas, "current")
+#     tcltk::tkitemraise(canvas, "current")
   })
-  tkitembind(canvas, "vertex||label||edge", "<Control-1>", function(x,y) {
+  tcltk::tkitembind(canvas, "vertex||label||edge", "<Control-1>", function(x,y) {
     canvas <- .tkplot.get(tkp.id, "canvas")
-    curtags <- as.character(tkgettags(canvas, "current"))
-    seltags <- as.character(tkgettags(canvas, "selected"))
+    curtags <- as.character(tcltk::tkgettags(canvas, "current"))
+    seltags <- as.character(tcltk::tkgettags(canvas, "selected"))
     if ("vertex" %in% curtags && "vertex" %in% seltags) {
       if ("selected" %in% curtags) {
         .tkplot.deselect.current(tkp.id)
@@ -254,9 +393,9 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
       }
     } else if ("label" %in% curtags && "vertex" %in% seltags) {
       vtag <- curtags[pmatch("v-", curtags)]
-      tkid <- as.numeric(tkfind(canvas, "withtag",
+      tkid <- as.numeric(tcltk::tkfind(canvas, "withtag",
                                 paste(sep="", "vertex&&", vtag)))
-      vtags <- as.character(tkgettags(canvas, tkid))
+      vtags <- as.character(tcltk::tkgettags(canvas, tkid))
       if ("selected" %in% vtags) {
         .tkplot.deselect.vertex(tkp.id, tkid)
       } else {
@@ -267,22 +406,22 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
       .tkplot.select.current(tkp.id)
     }
   })
-  tkitembind(canvas, "vertex||edge||label", "<Shift-Alt-1>", function(x, y) {
+  tcltk::tkitembind(canvas, "vertex||edge||label", "<Shift-Alt-1>", function(x, y) {
     canvas <- .tkplot.get(tkp.id, "canvas")
-    tkitemlower(canvas, "current")
+    tcltk::tkitemlower(canvas, "current")
   })
-  tkitembind(canvas, "vertex||edge||label", "<Alt-1>", function(x, y) {
+  tcltk::tkitembind(canvas, "vertex||edge||label", "<Alt-1>", function(x, y) {
     canvas <- .tkplot.get(tkp.id, "canvas")
-    tkitemraise(canvas, "current")
+    tcltk::tkitemraise(canvas, "current")
   })  
-  tkbind(canvas, "<3>", function(x, y) {
+  tcltk::tkbind(canvas, "<3>", function(x, y) {
     canvas <- .tkplot.get(tkp.id, "canvas")
-    tags <- as.character(tkgettags(canvas, "current"))
+    tags <- as.character(tcltk::tkgettags(canvas, "current"))
     if ("label" %in% tags) {
       vtag <- tags[ pmatch("v-", tags) ]
-      vid <- as.character(tkfind(canvas, "withtag",
+      vid <- as.character(tcltk::tkfind(canvas, "withtag",
                                  paste(sep="", "vertex&&", vtag)))
-      tags <- as.character(tkgettags(canvas, vid))
+      tags <- as.character(tcltk::tkgettags(canvas, vid))
     }
     if ("selected" %in% tags) {
       # The selection is active
@@ -291,7 +430,7 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
       .tkplot.deselect.all(tkp.id)
       .tkplot.select.current(tkp.id)
     }
-    tags <- as.character(tkgettags(canvas, "selected"))
+    tags <- as.character(tcltk::tkgettags(canvas, "selected"))
     ## TODO: what if different types of objects are selected
     if ("vertex" %in% tags || "label" %in% tags) {
       menu <- .tkplot.get(tkp.id, "vertex.popup.menu")
@@ -300,25 +439,25 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
     } else {
       menu <- .tkplot.get(tkp.id, "popup.menu")
     }
-    x <- as.integer(x) + as.integer(tkwinfo("rootx", canvas))
-    y <- as.integer(y) + as.integer(tkwinfo("rooty", canvas))
-    .Tcl(paste("tk_popup", .Tcl.args(menu, x, y)))
+    x <- as.integer(x) + as.integer(tcltk::tkwinfo("rootx", canvas))
+    y <- as.integer(y) + as.integer(tcltk::tkwinfo("rooty", canvas))
+    tcltk::.Tcl(paste("tk_popup", tcltk::.Tcl.args(menu, x, y)))
   })
   if (tkp$params$label.dist==0) tobind <- "vertex||label"
   else tobind <- "vertex"
-  tkitembind(canvas, tobind, "<B1-Motion>", function(x, y) {
+  tcltk::tkitembind(canvas, tobind, "<B1-Motion>", function(x, y) {
     tkp <- .tkplot.get(tkp.id)
     x <- as.numeric(x)
     y <- as.numeric(y)
-    width <- as.numeric(tkwinfo("width", tkp$canvas))
-    height <- as.numeric(tkwinfo("height", tkp$canvas))
+    width <- as.numeric(tcltk::tkwinfo("width", tkp$canvas))
+    height <- as.numeric(tcltk::tkwinfo("height", tkp$canvas))
     if (x < 10) { x <- 10 }
     if (x > width-10) { x <- width-10 }
     if (y < 10) { y <- 10 }
     if (y > height-10) { y <- height-10 }
     
                                         # get the id
-    tags <- as.character(tkgettags(tkp$canvas, "selected"))
+    tags <- as.character(tcltk::tkgettags(tkp$canvas, "selected"))
     id <- as.numeric(strsplit(tags[pmatch("v-", tags)],
                               "-", fixed=TRUE)[[1]][2])
     if (is.na(id)) { return() }
@@ -327,12 +466,12 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
     .tkplot.update.vertex(tkp.id, id, x, y)
   })
   if (tkp$params$label.dist!=0) {
-    tkitembind(canvas, "label", "<B1-Motion>", function(x,y) {
+    tcltk::tkitembind(canvas, "label", "<B1-Motion>", function(x,y) {
       tkp <- .tkplot.get(tkp.id)
       x <- as.numeric(x)
       y <- as.numeric(y)
                                         # get the id
-      tags <- as.character(tkgettags(tkp$canvas, "selected"))
+      tags <- as.character(tcltk::tkgettags(tkp$canvas, "selected"))
       id <- as.numeric(strsplit(tags[pmatch("v-", tags)],
                                 "-", fixed=TRUE)[[1]][2])
       if (is.na(id)) { return() }
@@ -389,77 +528,36 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
 }
 
 .tkplot.addlayout("random",
-                  list(name="Random", f=layout.random, params=list()))
+                  list(name="Random", f=layout_randomly, params=list()))
 .tkplot.addlayout("circle",
-                  list(name="Circle", f=layout.circle, params=list()))
+                  list(name="Circle", f=layout_in_circle, params=list()))
 .tkplot.addlayout("fruchterman.reingold",
                   list(name="Fruchterman-Reingold",
-                       f=layout.fruchterman.reingold,
+                       f=layout_with_fr,
                        params=list(
                          niter=list(name="Number of iterations",
                            type="numeric",
                            default=500),
-                         maxdelta=list(name="Maximum change (n)",
-                           type="expression",
-                           default=expression(vcount(.tkplot.g))),
-                         area=list(name="Area parameter (n^2)",
+                         start.temp=list(name="Start temperature",
                            type="expression",
-                           default=expression(vcount(.tkplot.g)^2)),
-                         coolexp=list(name="Cooling exponent",
-                           type="numeric",
-                           default=3),                         
-                         repulserad=list(name="Cancellation radius (n^3)",
-                           type="expression",
-                           # FIXME: this should be area * n, but parameters
-                           # can't depend on each other....
-                           default=expression(vcount(.tkplot.g)^3))
-                         )
+                           default=expression(sqrt(vcount(.tkplot.g)))))
                        )
                   )
 .tkplot.addlayout("kamada.kawai",
                   list(name="Kamada-Kawai",
-                       f=layout.kamada.kawai,
+                       f=layout_with_kk,
                        params=list(
-                         niter=list(name="Number of iterations",
-                           type="numeric",
-                           default=1000),
-                         initemp=list(name="Initial temperature",
-                           type="numeric",
-                           default=10),
-                         coolexp=list(name="Cooling exponent",
-                           type="numeric",
-                           default=0.99)
-                         )
-                       )
-                  )
-.tkplot.addlayout("spring",
-                  list(name="Spring Embedder",
-                       f=layout.spring,
-                       params=list(
-                         mass=list(names="The vertex mass",
-                           type="numeric",
-                           default=0.1),
-                         equil=list(names="The equilibrium spring extension",
-                           type="numeric",
-                           default=1),
-                         k=list(names="The spring coefficient",
-                           type="numeric",
-                           default=0.001),
-                         repeqdis=list(names="Repulsion balance point",
-                           type="numeric",
-                           default=0.1),
-                         kfr=list(names="Friction base coefficient",
-                           type="numeric",
-                           default=0.01),
-                         repulse=list(names="Use repulsion",
-                           type="logical",
-                           default=FALSE)
-                         )
+                         maxiter=list(name="Maximum number of iterations",
+                           type="expression",
+                           default=expression(50 * vcount(.tkplot.g))),
+                         kkconst=list(name="Vertex attraction constant",
+                           type="expression",
+                           default=expression(vcount(.tkplot.g))))
                        )
                   )
 .tkplot.addlayout("reingold.tilford",
                   list(names="Reingold-Tilford",
-                       f=layout.reingold.tilford,
+                       f=layout_as_tree,
                        params=list(
                          root=list(name="Root vertex",
                            type="numeric",
@@ -472,31 +570,40 @@ tkplot <- function(graph, canvas.width=450, canvas.height=450, ...) {
 # Other public functions, misc.
 ###################################################################
 
-tkplot.close <- function(tkp.id, window.close=TRUE) {
+#' @rdname tkplot
+#' @export
+
+tk_close <- function(tkp.id, window.close=TRUE) {
   if (window.close) {
     cmd <- paste(sep="", "tkp.", tkp.id, "$top")
     top <- eval(parse(text=cmd), .tkplot.env)
-    tkbind(top, "<Destroy>", "")
-    tkdestroy(top)
+    tcltk::tkbind(top, "<Destroy>", "")
+    tcltk::tkdestroy(top)
   }
   cmd <- paste(sep="", "tkp.", tkp.id)
   rm(list=cmd, envir=.tkplot.env)
   invisible(NULL)
 }
 
-tkplot.off <- function() {
-  eapply(.tkplot.env, function(tkp) { tkdestroy(tkp$top) })
+#' @rdname tkplot
+#' @export
+
+tk_off <- function() {
+  eapply(.tkplot.env, function(tkp) { tcltk::tkdestroy(tkp$top) })
   rm(list=ls(.tkplot.env), envir=.tkplot.env)
   invisible(NULL)
 }
 
-tkplot.fit.to.screen <- function(tkp.id, width=NULL, height=NULL) {
+#' @rdname tkplot
+#' @export
+
+tk_fit <- function(tkp.id, width=NULL, height=NULL) {
   tkp <- .tkplot.get(tkp.id)
   if (is.null(width)) {
-    width  <- as.numeric(tkwinfo("width", tkp$canvas))
+    width  <- as.numeric(tcltk::tkwinfo("width", tkp$canvas))
   }
   if (is.null(height)) {
-    height <- as.numeric(tkwinfo("height", tkp$canvas))
+    height <- as.numeric(tcltk::tkwinfo("height", tkp$canvas))
   }
   coords <- .tkplot.get(tkp.id, "coords")
   # Shift to zero
@@ -517,10 +624,13 @@ tkplot.fit.to.screen <- function(tkp.id, width=NULL, height=NULL) {
   invisible(NULL)
 }
 
-tkplot.center <- function(tkp.id) {
+#' @rdname tkplot
+#' @export
+
+tk_center <- function(tkp.id) {
   tkp <- .tkplot.get(tkp.id)
-  width  <- as.numeric(tkwinfo("width", tkp$canvas))
-  height <- as.numeric(tkwinfo("height", tkp$canvas))
+  width  <- as.numeric(tcltk::tkwinfo("width", tkp$canvas))
+  height <- as.numeric(tcltk::tkwinfo("height", tkp$canvas))
   coords <- .tkplot.get(tkp.id, "coords")
   canvas.center.x <- width/2
   canvas.center.y <- height/2
@@ -539,26 +649,37 @@ tkplot.center <- function(tkp.id) {
   invisible(NULL)
 }
   
-tkplot.reshape <- function(tkp.id, newlayout, ...) {
+#' @rdname tkplot
+#' @param params Extra parameters in a list, to pass to the layout function.
+#' @export
+
+tk_reshape <- function(tkp.id, newlayout, ..., params) {
   tkp <- .tkplot.get(tkp.id)
-  .tkplot.set(tkp.id, "coords", newlayout(tkp$graph, ...))
-  tkplot.fit.to.screen(tkp.id)
+  new_coords <- do_call(newlayout, .args=c(list(tkp$graph), list(...), params))
+  .tkplot.set(tkp.id, "coords", new_coords)
+  tk_fit(tkp.id)
   .tkplot.update.vertices(tkp.id)
   invisible(NULL)
 }
 
-tkplot.export.postscript <- function(tkp.id) {
+#' @rdname tkplot
+#' @export
+
+tk_postscript <- function(tkp.id) {
 
   tkp <- .tkplot.get(tkp.id)
 
-  filename <- tkgetSaveFile(initialfile="Rplots.eps",
+  filename <- tcltk::tkgetSaveFile(initialfile="Rplots.eps",
                             defaultextension="eps",
                             title="Export graph to PostScript file")
-  tkpostscript(tkp$canvas, file=filename)
+  tcltk::tkpostscript(tkp$canvas, file=filename)
   invisible(NULL)
 }
 
-tkplot.getcoords <- function(tkp.id, norm=FALSE) {
+#' @rdname tkplot
+#' @export
+
+tk_coords <- function(tkp.id, norm=FALSE) {
   coords <- .tkplot.get(tkp.id, "coords")
   coords[,2] <- max(coords[,2]) - coords[,2]
   if (norm) {
@@ -572,14 +693,20 @@ tkplot.getcoords <- function(tkp.id, norm=FALSE) {
   coords
 }
 
-tkplot.setcoords <- function(tkp.id, coords) {
+#' @rdname tkplot
+#' @export
+
+tk_set_coords <- function(tkp.id, coords) {
   stopifnot(is.matrix(coords), ncol(coords)==2)
   .tkplot.set(tkp.id, "coords", coords)
   .tkplot.update.vertices(tkp.id)
   invisible(NULL)
 }
 
-tkplot.rotate <- function(tkp.id, degree=NULL, rad=NULL) {
+#' @rdname tkplot
+#' @export
+
+tk_rotate <- function(tkp.id, degree=NULL, rad=NULL) {
   coords <- .tkplot.get(tkp.id, "coords")
 
   if (is.null(degree) && is.null(rad)) {
@@ -598,11 +725,14 @@ tkplot.rotate <- function(tkp.id, degree=NULL, rad=NULL) {
   coords[,2] <- r * sin(phi)
   
   .tkplot.set(tkp.id, "coords", coords)
-  tkplot.center(tkp.id)
+  tk_center(tkp.id)
   invisible(NULL)
 }
 
-tkplot.canvas <- function(tkp.id) {
+#' @rdname tkplot
+#' @export
+
+tk_canvas <- function(tkp.id) {
   .tkplot.get(tkp.id)$canvas
 }
 
@@ -681,11 +811,11 @@ tkplot.canvas <- function(tkp.id) {
   vertex.frame.color <- ifelse(length(tkp$params$vertex.frame.color)>1,
                                tkp$params$vertex.frame.color[id],
                                tkp$params$vertex.frame.color)
-  item <- tkcreate(tkp$canvas, "oval", x-vertex.size, y-vertex.size,
+  item <- tcltk::tkcreate(tkp$canvas, "oval", x-vertex.size, y-vertex.size,
                    x+vertex.size, y+vertex.size, width=1,
                    outline=vertex.frame.color,  fill=vertex.color)
-  tkaddtag(tkp$canvas, "vertex", "withtag", item)
-  tkaddtag(tkp$canvas, paste("v-", id, sep=""), "withtag", item)
+  tcltk::tkaddtag(tkp$canvas, "vertex", "withtag", item)
+  tcltk::tkaddtag(tkp$canvas, paste("v-", id, sep=""), "withtag", item)
   if (!is.na(label)) {
     label.degree <- ifelse(length(tkp$params$label.degree)>1,
                            tkp$params$label.degree[id],
@@ -704,12 +834,12 @@ tkplot.canvas <- function(tkp.id) {
       { afill <- label.color }
     else
       { afill <- "red" }
-    litem <- tkcreate(tkp$canvas, "text", label.x, label.y,
+    litem <- tcltk::tkcreate(tkp$canvas, "text", label.x, label.y,
                       text=as.character(label), state="normal",
                       fill=label.color, activefill=afill,
                       font=tkp$params$vertex.params[id, "label.font"])
-    tkaddtag(tkp$canvas, "label", "withtag", litem)
-    tkaddtag(tkp$canvas, paste("v-", id, sep=""), "withtag", litem)
+    tcltk::tkaddtag(tkp$canvas, "label", "withtag", litem)
+    tcltk::tkaddtag(tkp$canvas, paste("v-", id, sep=""), "withtag", litem)
   }
   item
 }
@@ -737,7 +867,7 @@ tkplot.canvas <- function(tkp.id) {
     (vertex.size+6+4*(ceiling(log10(id))))
   label.y <- y+label.dist*sin(label.degree)*
     (vertex.size+6+4*(ceiling(log10(id))))
-  tkcoords(tkp$canvas, paste("label&&v-", id, sep=""),
+  tcltk::tkcoords(tkp$canvas, paste("label&&v-", id, sep=""),
            label.x, label.y)
 }
 
@@ -745,16 +875,16 @@ tkplot.canvas <- function(tkp.id) {
   tkp <- .tkplot.get(tkp.id)
   vertex.size <- tkp$params$vertex.params[id, "vertex.size"]
   # Vertex
-  tkcoords(tkp$canvas, paste("vertex&&v-", id, sep=""),
+  tcltk::tkcoords(tkp$canvas, paste("vertex&&v-", id, sep=""),
            x-vertex.size, y-vertex.size,
            x+vertex.size, y+vertex.size)
   # Label
   .tkplot.update.label(tkp.id, id, x, y)
   
   # Edges
-  edge.from.ids <- as.numeric(tkfind(tkp$canvas, "withtag",
+  edge.from.ids <- as.numeric(tcltk::tkfind(tkp$canvas, "withtag",
                                      paste("from-", id, sep="")))
-  edge.to.ids <- as.numeric(tkfind(tkp$canvas, "withtag",
+  edge.to.ids <- as.numeric(tcltk::tkfind(tkp$canvas, "withtag",
                                    paste("to-", id, sep="")))
   for (i in seq(along=edge.from.ids)) {
     .tkplot.update.edge(tkp.id, edge.from.ids[i])
@@ -814,11 +944,11 @@ tkplot.canvas <- function(tkp.id) {
                    tags=c("edge", paste(sep="", "edge-", id),
                      paste(sep="", "from-", from),
                      paste(sep="", "to-", to))), smooth=smooth)
-    do.call(tkcreate, args)
+    do.call(tcltk::tkcreate, args)
   } else {
     ## loop edge
     ## the coordinates are not correct but we will call update anyway...
-    tkcreate(tkp$canvas, "line", from.c[1], from.c[2],
+    tcltk::tkcreate(tkp$canvas, "line", from.c[1], from.c[2],
              from.c[1]+20, from.c[1]-10, from.c[2]+30, from.c[2],
              from.c[1]+20, from.c[1]+10, from.c[1], from.c[2],
              width=edge.width, activewidth=2*edge.width,
@@ -840,12 +970,12 @@ tkplot.canvas <- function(tkp.id) {
     ## not correct for loop edges but we will update anyway...
     label.x <- (to.c[1]+from.c[1])/2
     label.y <- (to.c[2]+from.c[2])/2
-    litem <- tkcreate(tkp$canvas, "text", label.x, label.y,
+    litem <- tcltk::tkcreate(tkp$canvas, "text", label.x, label.y,
                       text=as.character(edge.label), state="normal",
                       fill=label.color,
                       font=tkp$params$edge.label.font)
-    tkaddtag(tkp$canvas, "label", "withtag", litem)
-    tkaddtag(tkp$canvas, paste(sep="", "edge-", id), "withtag", litem)
+    tcltk::tkaddtag(tkp$canvas, "label", "withtag", litem)
+    tcltk::tkaddtag(tkp$canvas, paste(sep="", "edge-", id), "withtag", litem)
   }
 }
 
@@ -853,7 +983,7 @@ tkplot.canvas <- function(tkp.id) {
 .tkplot.create.edges <- function(tkp.id) {
   tkp <- .tkplot.get(tkp.id)
   n <- ecount(tkp$graph)
-  edgematrix <- get.edgelist(tkp$graph, names=FALSE)
+  edgematrix <- as_edgelist(tkp$graph, names=FALSE)
   mapply(function(from, to, id) .tkplot.create.edge(tkp.id, from, to, id),
          edgematrix[,1],
          edgematrix[,2], 1:nrow(edgematrix))
@@ -862,7 +992,7 @@ tkplot.canvas <- function(tkp.id) {
 # Update an edge with given itemid (not edge id!)
 .tkplot.update.edge <- function(tkp.id, itemid) {
   tkp <- .tkplot.get(tkp.id)
-  tags <- as.character(tkgettags(tkp$canvas, itemid))
+  tags <- as.character(tcltk::tkgettags(tkp$canvas, itemid))
   from <- as.numeric(substring(grep("from-", tags, value=TRUE, fixed=TRUE),6))
   to <- as.numeric(substring(grep("to-", tags, value=TRUE, fixed=TRUE),4))
   from.c <- tkp$coords[from,]
@@ -882,13 +1012,13 @@ tkplot.canvas <- function(tkp.id) {
     from.c[2] <- from.c[2] + vertex.size2*sin(phi)
     if (is.logical(curved)) curved <- curved * 0.5
     if (curved == 0) {
-      tkcoords(tkp$canvas, itemid, from.c[1], from.c[2], to.c[1], to.c[2])
+      tcltk::tkcoords(tkp$canvas, itemid, from.c[1], from.c[2], to.c[1], to.c[2])
     } else {
       midx <- (from.c[1]+to.c[1])/2
       midy <- (from.c[2]+to.c[2])/2        
       spx <- midx - curved * 1/2 * (from.c[2]-to.c[2])
       spy <- midy + curved * 1/2 * (from.c[1]-to.c[1])
-      tkcoords(tkp$canvas, itemid, from.c[1], from.c[2], spx, spy,
+      tcltk::tkcoords(tkp$canvas, itemid, from.c[1], from.c[2], spx, spy,
                to.c[1], to.c[2])
     }
   } else {
@@ -906,7 +1036,7 @@ tkplot.canvas <- function(tkp.id) {
     phi <- phi+loop.angle/180*pi
     cc[,1] <- xx+r*cos(phi)
     cc[,2] <- yy+r*sin(phi)
-    tkcoords(tkp$canvas, itemid, cc[1,1], cc[1,2], cc[2,1], cc[2,2],
+    tcltk::tkcoords(tkp$canvas, itemid, cc[1,1], cc[1,2], cc[2,1], cc[2,2],
              cc[3,1], cc[3,2], cc[4,1], cc[4,2], cc[5,1]+0.001, cc[5,2]+0.001)
   }
 
@@ -922,9 +1052,9 @@ tkplot.canvas <- function(tkp.id) {
       label.x <- xx+cos(loop.angle/180*pi)*30
       label.y <- yy+sin(loop.angle/180*pi)*30
     }
-    litem <- as.numeric(tkfind(tkp$canvas, "withtag",
+    litem <- as.numeric(tcltk::tkfind(tkp$canvas, "withtag",
                                paste(sep="", "label&&edge-", edgeid)))
-    tkcoords(tkp$canvas, litem, label.x, label.y)
+    tcltk::tkcoords(tkp$canvas, litem, label.x, label.y)
   }
 }
 
@@ -933,7 +1063,7 @@ tkplot.canvas <- function(tkp.id) {
                     1 - .tkplot.get(tkp.id, "params")$labels.state)
   tkp <- .tkplot.get(tkp.id)
   state <- ifelse(tkp$params$labels.state==1, "normal", "hidden")
-  tkitemconfigure(tkp$canvas, "label", "-state", state)  
+  tcltk::tkitemconfigure(tkp$canvas, "label", "-state", state)  
 }
 
 .tkplot.toggle.grid <- function(tkp.id) {
@@ -942,9 +1072,9 @@ tkplot.canvas <- function(tkp.id) {
   tkp <- .tkplot.get(tkp.id)
   state <- ifelse(tkp$params$grid==1, "normal", "hidden")
   if (state=="hidden") {
-    tkdelete(tkp$canvas, "grid")
+    tcltk::tkdelete(tkp$canvas, "grid")
   } else {
-    tkcreate(tkp$canvas, "grid", 0, 0, 10, 10, tags=c("grid"))
+    tcltk::tkcreate(tkp$canvas, "grid", 0, 0, 10, 10, tags=c("grid"))
   }
 }
 
@@ -953,7 +1083,7 @@ tkplot.canvas <- function(tkp.id) {
   vparams <- tkp$params$vertex.params
   vparams[vids, "vertex.color"] <- newcolor
   .tkplot.set(tkp.id, "params$vertex.params", vparams)
-  tkitemconfigure(tkp$canvas, "selected&&vertex", "-fill", newcolor)
+  tcltk::tkitemconfigure(tkp$canvas, "selected&&vertex", "-fill", newcolor)
 }
 
 .tkplot.update.edge.color <- function(tkp.id, eids, newcolor) {
@@ -976,7 +1106,7 @@ tkplot.canvas <- function(tkp.id) {
     .tkplot.set(tkp.id, "params$edge.color", colors)
   }
 
-  tkitemconfigure(tkp$canvas, "selected&&edge", "-fill", newcolor)
+  tcltk::tkitemconfigure(tkp$canvas, "selected&&edge", "-fill", newcolor)
 }
 
 .tkplot.update.edge.width <- function(tkp.id, eids, newwidth) {
@@ -999,7 +1129,7 @@ tkplot.canvas <- function(tkp.id) {
     .tkplot.set(tkp.id, "params$edge.width", widths)
   }
 
-  tkitemconfigure(tkp$canvas, "selected&&edge", "-width", newwidth)
+  tcltk::tkitemconfigure(tkp$canvas, "selected&&edge", "-width", newwidth)
 }
   
 
@@ -1018,25 +1148,25 @@ tkplot.canvas <- function(tkp.id) {
   if (length(labels)==0) return(FALSE)
   
   answers <- as.list(rep("", length(labels)))
-  dialog <- tktoplevel()
-  vars <- lapply(answers, tclVar)
+  dialog <- tcltk::tktoplevel()
+  vars <- lapply(answers, tcltk::tclVar)
 
   retval <- list()
 
   OnOK <- function() {
-    retval <<- lapply(vars, tclvalue)
-    tkdestroy(dialog)
+    retval <<- lapply(vars, tcltk::tclvalue)
+    tcltk::tkdestroy(dialog)
   }
   
-  OK.but <- tkbutton(dialog, text="   OK   ", command=OnOK)
+  OK.but <- tcltk::tkbutton(dialog, text="   OK   ", command=OnOK)
   for (i in seq(along=labels)) {
-    tkgrid(tklabel(dialog, text=labels[[i]]))
-    tmp <- tkentry(dialog, width="40",textvariable=vars[[i]])
-    tkgrid(tmp)
-    tkbind(tmp, "<Return>", OnOK)
+    tcltk::tkgrid(tcltk::tklabel(dialog, text=labels[[i]]))
+    tmp <- tcltk::tkentry(dialog, width="40",textvariable=vars[[i]])
+    tcltk::tkgrid(tmp)
+    tcltk::tkbind(tmp, "<Return>", OnOK)
   }
-  tkgrid(OK.but)
-  tkwait.window(dialog)
+  tcltk::tkgrid(OK.but)
+  tcltk::tkwait.window(dialog)
 
   retval <- lapply(retval, function(v)
                    { eval(parse(text=paste("c(", v, ")"))) })
@@ -1044,28 +1174,28 @@ tkplot.canvas <- function(tkp.id) {
 }
 
 .tkplot.select.number <- function(label, initial, low=1, high=100) {
-  dialog <- tktoplevel()
-  SliderValue <- tclVar(as.character(initial))
-  SliderValueLabel <- tklabel(dialog,text=as.character(tclvalue(SliderValue)))
-  tkgrid(tklabel(dialog,text=label), SliderValueLabel)
-  tkconfigure(SliderValueLabel, textvariable=SliderValue)
-  slider <- tkscale(dialog, from=high, to=low,
+  dialog <- tcltk::tktoplevel()
+  SliderValue <- tcltk::tclVar(as.character(initial))
+  SliderValueLabel <- tcltk::tklabel(dialog,text=as.character(tcltk::tclvalue(SliderValue)))
+  tcltk::tkgrid(tcltk::tklabel(dialog,text=label), SliderValueLabel)
+  tcltk::tkconfigure(SliderValueLabel, textvariable=SliderValue)
+  slider <- tcltk::tkscale(dialog, from=high, to=low,
                     showvalue=F, variable=SliderValue,
                     resolution=1, orient="horizontal")  
   OnOK <- function() {
-    SliderValue <<- as.numeric(tclvalue(SliderValue))
-    tkdestroy(dialog)
+    SliderValue <<- as.numeric(tcltk::tclvalue(SliderValue))
+    tcltk::tkdestroy(dialog)
   }
   OnCancel <- function() {
     SliderValue <<- NA
-    tkdestroy(dialog)
+    tcltk::tkdestroy(dialog)
   }
-  OK.but <- tkbutton(dialog, text="   OK   ", command=OnOK)
-  cancel.but <- tkbutton(dialog, text=" Cancel ", command=OnCancel)
-  tkgrid(slider)
-  tkgrid(OK.but, cancel.but)
+  OK.but <- tcltk::tkbutton(dialog, text="   OK   ", command=OnOK)
+  cancel.but <- tcltk::tkbutton(dialog, text=" Cancel ", command=OnCancel)
+  tcltk::tkgrid(slider)
+  tcltk::tkgrid(OK.but, cancel.but)
   
-  tkwait.window(dialog)
+  tcltk::tkwait.window(dialog)
   return(SliderValue)
 }
   
@@ -1075,7 +1205,7 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.deselect.all <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  ids <- as.numeric(tkfind(canvas, "withtag", "selected"))
+  ids <- as.numeric(tcltk::tkfind(canvas, "withtag", "selected"))
   for (i in ids) {
     .tkplot.deselect.this(tkp.id, i)
   }
@@ -1083,7 +1213,7 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.select.all.vertices <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  vertices <- as.numeric(tkfind(canvas, "withtag", "vertex"))
+  vertices <- as.numeric(tcltk::tkfind(canvas, "withtag", "vertex"))
   for (i in vertices) {
     .tkplot.select.vertex(tkp.id, i)
   }
@@ -1093,7 +1223,7 @@ tkplot.canvas <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
   vids <- unique(vids)
   for (i in vids) {
-    tkid <- as.numeric(tkfind(canvas, "withtag",
+    tkid <- as.numeric(tcltk::tkfind(canvas, "withtag",
                               paste(sep="", "vertex&&v-", i)))
     .tkplot.select.vertex(tkp.id, tkid)
   }
@@ -1101,7 +1231,7 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.select.all.edges <- function(tkp.id, vids) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  edges <- as.numeric(tkfind(canvas, "withtag", "edge"))
+  edges <- as.numeric(tcltk::tkfind(canvas, "withtag", "edge"))
   for (i in edges) {
     .tkplot.select.edge(tkp.id, i)
   }
@@ -1111,9 +1241,9 @@ tkplot.canvas <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
   fromtags <- sapply(from, function(i) { paste(sep="", "from-", i) })
   totags <- sapply(from, function(i) { paste(sep="", "to-", i) })
-  edges <- as.numeric(tkfind(canvas, "withtag", "edge"))
+  edges <- as.numeric(tcltk::tkfind(canvas, "withtag", "edge"))
   for (i in edges) {
-    tags <- as.character(tkgettags(canvas, i))
+    tags <- as.character(tcltk::tkgettags(canvas, i))
     ftag <- tags[ pmatch("from-", tags) ]
     ttag <- tags[ pmatch("to-", tags) ]
     if (ftag %in% fromtags && ttag %in% totags) {
@@ -1124,67 +1254,67 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.select.vertex <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkaddtag(canvas, "selected", "withtag", tkid)
-  tkitemconfigure(canvas, tkid, "-outline", "red",
+  tcltk::tkaddtag(canvas, "selected", "withtag", tkid)
+  tcltk::tkitemconfigure(canvas, tkid, "-outline", "red",
                   "-width", 2)
 }
 
 .tkplot.select.edge <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkaddtag(canvas, "selected", "withtag", tkid)
-  tkitemconfigure(canvas, tkid, "-dash", "-")
+  tcltk::tkaddtag(canvas, "selected", "withtag", tkid)
+  tcltk::tkitemconfigure(canvas, tkid, "-dash", "-")
 }
 
 .tkplot.select.label <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkaddtag(canvas, "selected", "withtag", tkid)
+  tcltk::tkaddtag(canvas, "selected", "withtag", tkid)
 }  
 
 .tkplot.deselect.vertex <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkdtag(canvas, tkid, "selected")
+  tcltk::tkdtag(canvas, tkid, "selected")
   tkp <- .tkplot.get(tkp.id)
-  tags <- as.character(tkgettags(canvas, tkid))
+  tags <- as.character(tcltk::tkgettags(canvas, tkid))
   id <- as.numeric(substring(tags[pmatch("v-", tags)], 3))
   vertex.frame.color <- ifelse(length(tkp$params$vertex.frame.color)>1,
                                tkp$params$vertex.frame.color[id],
                                tkp$params$vertex.frame.color)  
-  tkitemconfigure(canvas, tkid, "-outline", vertex.frame.color,
+  tcltk::tkitemconfigure(canvas, tkid, "-outline", vertex.frame.color,
                   "-width", 1)
 }
 
 .tkplot.deselect.edge <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkdtag(canvas, tkid, "selected")
+  tcltk::tkdtag(canvas, tkid, "selected")
   tkp <- .tkplot.get(tkp.id)
-  tags <- as.character(tkgettags(canvas, tkid))
+  tags <- as.character(tcltk::tkgettags(canvas, tkid))
   id <- as.numeric(substring(tags[pmatch("edge-", tags)], 6))
   edge.lty <- ifelse(length(tkp$params$edge.lty)>1,
                      tkp$params$edge.lty[[id]],
                      tkp$params$edge.lty)
-  tkitemconfigure(canvas, tkid, "-dash", edge.lty)
+  tcltk::tkitemconfigure(canvas, tkid, "-dash", edge.lty)
 }
 
 .tkplot.deselect.label <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkdtag(canvas, tkid, "selected")
+  tcltk::tkdtag(canvas, tkid, "selected")
 }
 
 .tkplot.select.current <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkid <- as.numeric(tkfind(canvas, "withtag", "current"))
+  tkid <- as.numeric(tcltk::tkfind(canvas, "withtag", "current"))
   .tkplot.select.this(tkp.id, tkid)
 }
 
 .tkplot.deselect.current <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkid <- as.numeric(tkfind(canvas, "withtag", "current"))
+  tkid <- as.numeric(tcltk::tkfind(canvas, "withtag", "current"))
   .tkplot.deselect.this(tkp.id, tkid)
 }
 
 .tkplot.select.this <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tags <- as.character(tkgettags(canvas, tkid))
+  tags <- as.character(tcltk::tkgettags(canvas, tkid))
   if ("vertex" %in% tags) {
     .tkplot.select.vertex(tkp.id, tkid)
   } else if ("edge" %in% tags) {
@@ -1193,7 +1323,7 @@ tkplot.canvas <- function(tkp.id) {
     tkp <- .tkplot.get(tkp.id)
     if (tkp$params$label.dist == 0) {
       id <- tags[pmatch("v-", tags)]
-      tkid <- as.character(tkfind(canvas, "withtag",
+      tkid <- as.character(tcltk::tkfind(canvas, "withtag",
                                   paste(sep="", "vertex&&", id)))
       .tkplot.select.vertex(tkp.id, tkid)
     } else {
@@ -1204,7 +1334,7 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.deselect.this <- function(tkp.id, tkid) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tags <- as.character(tkgettags(canvas, tkid))
+  tags <- as.character(tcltk::tkgettags(canvas, tkid))
   if ("vertex" %in% tags) {
     .tkplot.deselect.vertex(tkp.id, tkid)
   } else if ("edge" %in% tags) {
@@ -1213,7 +1343,7 @@ tkplot.canvas <- function(tkp.id) {
     tkp <- .tkplot.get(tkp.id)
     if (tkp$params$label.dist == 0) {
       id <- tags[pmatch("v-", tags)]
-      tkid <- as.character(tkfind(canvas, "withtag",
+      tkid <- as.character(tcltk::tkfind(canvas, "withtag",
                                   paste(sep="", "vertex&&", id)))
       .tkplot.deselect.vertex(tkp.id, tkid)
     } else {
@@ -1224,10 +1354,10 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.get.selected.vertices <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkids <- as.numeric(tkfind(canvas, "withtag", "vertex&&selected"))
+  tkids <- as.numeric(tcltk::tkfind(canvas, "withtag", "vertex&&selected"))
 
   ids <- sapply(tkids, function(tkid) {
-    tags <- as.character(tkgettags(canvas, tkid))
+    tags <- as.character(tcltk::tkgettags(canvas, tkid))
     id <- as.numeric(substring(tags [pmatch("v-", tags)], 3))
     id})
 
@@ -1236,10 +1366,10 @@ tkplot.canvas <- function(tkp.id) {
 
 .tkplot.get.selected.edges <- function(tkp.id) {
   canvas <- .tkplot.get(tkp.id, "canvas")
-  tkids <- as.numeric(tkfind(canvas, "withtag", "edge&&selected"))
+  tkids <- as.numeric(tcltk::tkfind(canvas, "withtag", "edge&&selected"))
 
   ids <- sapply(tkids, function(tkid) {
-    tags <- as.character(tkgettags(canvas, tkid))
+    tags <- as.character(tcltk::tkgettags(canvas, tkid))
     id <- as.numeric(substring(tags [pmatch("edge-", tags)], 6))
     id})
 
@@ -1251,41 +1381,41 @@ tkplot.canvas <- function(tkp.id) {
 ###################################################################
 
 .tkplot.select.menu <- function(tkp.id, main.menu) {
-  select.menu <- tkmenu(main.menu)
+  select.menu <- tcltk::tkmenu(main.menu)
 
-  tkadd(select.menu, "command", label="Select all vertices",
+  tcltk::tkadd(select.menu, "command", label="Select all vertices",
         command=function() {
           .tkplot.deselect.all(tkp.id)
           .tkplot.select.all.vertices(tkp.id)
         })
-  tkadd(select.menu, "command", label="Select all edges",
+  tcltk::tkadd(select.menu, "command", label="Select all edges",
         command=function() {
           .tkplot.deselect.all(tkp.id)
           .tkplot.select.all.edges(tkp.id)
         })
-  tkadd(select.menu, "command", label="Select some vertices...",
+  tcltk::tkadd(select.menu, "command", label="Select some vertices...",
         command=function() {
           vids <- .tkplot.get.numeric.vector("Select vertices")
           .tkplot.select.some.vertices(tkp.id, vids[[1]])
         })
-  tkadd(select.menu, "command", label="Select some edges...",
+  tcltk::tkadd(select.menu, "command", label="Select some edges...",
         command=function() {
           fromto <- .tkplot.get.numeric.vector("Select edges from vertices",
                                                "to vertices")
           .tkplot.select.some.edges(tkp.id, fromto[[1]], fromto[[2]])
         })
-  tkadd(select.menu, "separator")
-  tkadd(select.menu, "command", label="Deselect everything",
+  tcltk::tkadd(select.menu, "separator")
+  tcltk::tkadd(select.menu, "command", label="Deselect everything",
         command=function() { .tkplot.deselect.all(tkp.id) })
 
   select.menu
 }
 
 .tkplot.layout.menu <- function(tkp.id, main.menu) {
-  layout.menu <- tkmenu(main.menu)
+  layout.menu <- tcltk::tkmenu(main.menu)
   
   sapply(.tkplot.getlayoutlist(), function(n) {
-    tkadd(layout.menu, "command", label=.tkplot.getlayoutname(n),
+    tcltk::tkadd(layout.menu, "command", label=.tkplot.getlayoutname(n),
           command=function() {
             .tkplot.layout.dialog(tkp.id, n)
           })
@@ -1299,7 +1429,7 @@ tkplot.canvas <- function(tkp.id) {
 
   # No parameters
   if (length(layout$params)==0) {
-    return(tkplot.reshape(tkp.id, layout$f, params=list()))
+    return(tk_reshape(tkp.id, layout$f, params=list()))
   }
   
   submit <- function() {
@@ -1308,92 +1438,93 @@ tkplot.canvas <- function(tkp.id) {
     for (i in seq(along=layout$params)) {
       realparams[[i]] <-
         params[[i]] <- switch(layout$params[[i]]$type,
-                              "numeric"=as.numeric(tkget(values[[i]])),
-                              "character"=as.character(tkget(values[[i]])),
-                              "logical"=as.logical(tclvalue(values[[i]])),
-                              "choice"=as.character(tclvalue(values[[i]])),
-                              "initial"=as.logical(tclvalue(values[[i]]))
+                              "numeric"=as.numeric(tcltk::tkget(values[[i]])),
+                              "character"=as.character(tcltk::tkget(values[[i]])),
+                              "logical"=as.logical(tcltk::tclvalue(values[[i]])),
+                              "choice"=as.character(tcltk::tclvalue(values[[i]])),
+                              "initial"=as.logical(tcltk::tclvalue(values[[i]])),
+                              "expression"=as.numeric(tcltk::tkget(values[[i]]))
                               )
       if (layout$params[[i]]$type=="initial" &&
           params[[i]]) {
-        realparams[[i]] <- tkplot.getcoords(tkp.id, norm=TRUE)
+        realparams[[i]] <- tk_coords(tkp.id, norm=TRUE)
       }
     }
-    if (as.logical(tclvalue(save.default))) {
+    if (as.logical(tcltk::tclvalue(save.default))) {
       .tkplot.layouts.newdefaults(layout.name, params)
     }
-    tkdestroy(dialog)
-    tkplot.reshape(tkp.id, layout$f, params=realparams)
+    tcltk::tkdestroy(dialog)
+    tk_reshape(tkp.id, layout$f, params=realparams)
   }
   
-  dialog <- tktoplevel(.tkplot.get(tkp.id, "top"))
+  dialog <- tcltk::tktoplevel(.tkplot.get(tkp.id, "top"))
   
-  tkwm.title(dialog, paste("Layout parameters for graph plot", tkp.id))
-  tkwm.transient(dialog, .tkplot.get(tkp.id, "top"))
+  tcltk::tkwm.title(dialog, paste("Layout parameters for graph plot", tkp.id))
+  tcltk::tkwm.transient(dialog, .tkplot.get(tkp.id, "top"))
 
-  tkgrid(tklabel(dialog, text=paste(layout$name, "layout"),
-                 font=tkfont.create(family="helvetica",size=20,weight="bold")),
+  tcltk::tkgrid(tcltk::tklabel(dialog, text=paste(layout$name, "layout"),
+                 font=tcltk::tkfont.create(family="helvetica",size=20,weight="bold")),
          row=0, column=0, columnspan=2, padx=10, pady=10)
                  
   row <- 1
   values <- list()
   for (i in seq(along=layout$params)) {
     
-    tkgrid(tklabel(dialog, text=paste(sep="", layout$params[[i]]$name, ":")),
+    tcltk::tkgrid(tcltk::tklabel(dialog, text=paste(sep="", layout$params[[i]]$name, ":")),
                    row=row, column=0, sticky="ne", padx=5, pady=5)
     
     if (layout$params[[i]]$type %in% c("numeric", "character")) {
-      values[[i]] <- tkentry(dialog)
-      tkinsert(values[[i]], 0, as.character(layout$params[[i]]$default))
-      tkgrid(values[[i]], row=row, column=1, sticky="nw", padx=5, pady=5)
+      values[[i]] <- tcltk::tkentry(dialog)
+      tcltk::tkinsert(values[[i]], 0, as.character(layout$params[[i]]$default))
+      tcltk::tkgrid(values[[i]], row=row, column=1, sticky="nw", padx=5, pady=5)
     } else if (layout$params[[i]]$type=="logical") {
-      values[[i]] <- tclVar(as.character(layout$params[[i]]$default))
-      tmp <- tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
+      values[[i]] <- tcltk::tclVar(as.character(layout$params[[i]]$default))
+      tmp <- tcltk::tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
                            variable=values[[i]])
-      tkgrid(tmp, row=row, column=1, sticky="nw", padx=5, pady=5)
+      tcltk::tkgrid(tmp, row=row, column=1, sticky="nw", padx=5, pady=5)
     } else if (layout$params[[i]]$type=="choice") {
-      tmp.frame <- tkframe(dialog)
-      tkgrid(tmp.frame, row=row, column=1, sticky="nw", padx=5, pady=5)
-      values[[i]] <- tclVar(layout$params[[i]]$default)
+      tmp.frame <- tcltk::tkframe(dialog)
+      tcltk::tkgrid(tmp.frame, row=row, column=1, sticky="nw", padx=5, pady=5)
+      values[[i]] <- tcltk::tclVar(layout$params[[i]]$default)
       for (j in 1:length(layout$params[[i]]$values)) {
-        tmp <- tkradiobutton(tmp.frame, variable=values[[i]],
+        tmp <- tcltk::tkradiobutton(tmp.frame, variable=values[[i]],
                              value=layout$params[[i]]$values[j],
                              text=layout$params[[i]]$values[j])
-        tkpack(tmp, anchor="nw")
+        tcltk::tkpack(tmp, anchor="nw")
       }
     } else if (layout$params[[i]]$type=="initial") {
-      values[[i]] <- tclVar(as.character(layout$params[[i]]$default))
-      tkgrid(tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
+      values[[i]] <- tcltk::tclVar(as.character(layout$params[[i]]$default))
+      tcltk::tkgrid(tcltk::tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
                            variable=values[[i]]),
              row=row, column=1, sticky="nw", padx=5, pady=5)
     } else if (layout$param[[i]]$type=="expression") {
-      values[[i]] <- tkentry(dialog)
+      values[[i]] <- tcltk::tkentry(dialog)
       .tkplot.g <- .tkplot.get(tkp.id, "graph")
-      tkinsert(values[[i]], 0, as.character(eval(layout$params[[i]]$default)))
-      tkgrid(values[[i]], row=row, column=1, sticky="nw", padx=5, pady=5)
+      tcltk::tkinsert(values[[i]], 0, as.character(eval(layout$params[[i]]$default)))
+      tcltk::tkgrid(values[[i]], row=row, column=1, sticky="nw", padx=5, pady=5)
     }      
 
     row <- row + 1
     
   } # for along layout$params
 
-  tkgrid(tklabel(dialog, text="Set these as defaults"), sticky="ne",
+  tcltk::tkgrid(tcltk::tklabel(dialog, text="Set these as defaults"), sticky="ne",
          row=row, column=0, padx=5, pady=5)
-  save.default <- tclVar("FALSE")
-  tkgrid(tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
+  save.default <- tcltk::tclVar("FALSE")
+  tcltk::tkgrid(tcltk::tkcheckbutton(dialog, onvalue="TRUE", offvalue="FALSE",
                        variable=save.default, text=""), row=row,
          column=1, sticky="nw", padx=5, pady=5)
   row <- row + 1
   
-  tkgrid(tkbutton(dialog, text="OK", command=submit), row=row, column=0)
-  tkgrid(tkbutton(dialog, text="Cancel",
-                  command=function() { tkdestroy(dialog); invisible(TRUE) }),
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="OK", command=submit), row=row, column=0)
+  tcltk::tkgrid(tcltk::tkbutton(dialog, text="Cancel",
+                  command=function() { tcltk::tkdestroy(dialog); invisible(TRUE) }),
          row=row, column=1)
 }
 
 .tkplot.select.color <- function(initialcolor) {
   
-  color <- tclvalue(tcl("tk_chooseColor", initialcolor=initialcolor,
+  color <- tcltk::tclvalue(tcltk::tcl("tk_chooseColor", initialcolor=initialcolor,
                         title="Choose a color"))
   return(color);
 }
@@ -1422,7 +1553,7 @@ tkplot.canvas <- function(tkp.id) {
 }
 
 .tkplot.convert.font <- function(font, family, cex) {
-  tk.fonts <- as.character(tkfont.names())
+  tk.fonts <- as.character(tcltk::tkfont.names())
   if (as.character(font) %in% tk.fonts) {
     ## already defined Tk font
     as.character(font)
@@ -1466,7 +1597,7 @@ tkplot.canvas <- function(tkp.id) {
       tkfamily <- family
     }
     
-    newfont <- tkfont.create(family=tkfamily, slant=slant, weight=weight,
+    newfont <- tcltk::tkfont.create(family=tkfamily, slant=slant, weight=weight,
                              size=as.integer(12*cex))
     as.character(newfont)
   }
diff --git a/R/topology.R b/R/topology.R
index 0bded0f..3c83a3d 100644
--- a/R/topology.R
+++ b/R/topology.R
@@ -2,7 +2,7 @@
 #   IGraph R package
 #   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
 #   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
@@ -12,7 +12,7 @@
 #   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
@@ -20,51 +20,53 @@
 #
 ###################################################################
 
+#' @export
+
 graph.get.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1,
                                        vertex.color2, edge.color1,
                                        edge.color2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
-  if (missing(vertex.color1)) { 
-    if ("color" %in% list.vertex.attributes(graph1)) { 
-      vertex.color1 <- V(graph1)$color 
-    } else { 
-      vertex.color1 <- NULL 
-    } 
-  } 
-  if (!is.null(vertex.color1)) { 
-    vertex.color1 <- as.integer(vertex.color1)-1L 
-  }
-  if (missing(vertex.color2)) { 
-    if ("color" %in% list.vertex.attributes(graph2)) { 
-      vertex.color2 <- V(graph2)$color 
-    } else { 
-      vertex.color2 <- NULL 
-    } 
-  } 
-  if (!is.null(vertex.color2)) { 
-    vertex.color2 <- as.integer(vertex.color2)-1L 
-  }
-  if (missing(edge.color1)) { 
-    if ("color" %in% list.edge.attributes(graph1)) { 
-      edge.color1 <- E(graph1)$color 
-    } else { 
-      edge.color1 <- NULL 
-    } 
-  } 
-  if (!is.null(edge.color1)) { 
-    edge.color1 <- as.integer(edge.color1)-1L 
-  }
-  if (missing(edge.color2)) { 
-    if ("color" %in% list.edge.attributes(graph2)) { 
-      edge.color2 <- E(graph2)$color 
-    } else { 
-      edge.color2 <- NULL 
-    } 
-  } 
-  if (!is.null(edge.color2)) { 
-    edge.color2 <- as.integer(edge.color2)-1L 
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
+  if (missing(vertex.color1)) {
+    if ("color" %in% vertex_attr_names(graph1)) {
+      vertex.color1 <- V(graph1)$color
+    } else {
+      vertex.color1 <- NULL
+    }
+  }
+  if (!is.null(vertex.color1)) {
+    vertex.color1 <- as.integer(vertex.color1)-1L
+  }
+  if (missing(vertex.color2)) {
+    if ("color" %in% vertex_attr_names(graph2)) {
+      vertex.color2 <- V(graph2)$color
+    } else {
+      vertex.color2 <- NULL
+    }
+  }
+  if (!is.null(vertex.color2)) {
+    vertex.color2 <- as.integer(vertex.color2)-1L
+  }
+  if (missing(edge.color1)) {
+    if ("color" %in% edge_attr_names(graph1)) {
+      edge.color1 <- E(graph1)$color
+    } else {
+      edge.color1 <- NULL
+    }
+  }
+  if (!is.null(edge.color1)) {
+    edge.color1 <- as.integer(edge.color1)-1L
+  }
+  if (missing(edge.color2)) {
+    if ("color" %in% edge_attr_names(graph2)) {
+      edge.color2 <- E(graph2)$color
+    } else {
+      edge.color2 <- NULL
+    }
+  }
+  if (!is.null(edge.color2)) {
+    edge.color2 <- as.integer(edge.color2)-1L
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -72,62 +74,57 @@ graph.get.isomorphisms.vf2 <- function(graph1, graph2, vertex.color1,
   res <- .Call("R_igraph_get_isomorphisms_vf2", graph1, graph2, vertex.color1,
                vertex.color2, edge.color1, edge.color2,
                PACKAGE="igraph")
-  
-  res <- lapply(res, "+", 1)
 
-  if (getIgraphOpt("add.vertex.names") && is.named(graph2)) {
-    for (i in seq_along(res)) {
-      names(res[[i]]) <- V(graph2)$name[ res[[i]] ]
-    }
-  }
-  res
+  lapply(res, function(x) V(graph2)[x + 1])
 }
 
+#' @export
+
 graph.get.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1,
                                           vertex.color2, edge.color1,
                                           edge.color2) {
   # Argument checks
-  if (!is.igraph(graph1)) { stop("Not a graph object") }
-  if (!is.igraph(graph2)) { stop("Not a graph object") }
-  if (missing(vertex.color1)) { 
-    if ("color" %in% list.vertex.attributes(graph1)) { 
-      vertex.color1 <- V(graph1)$color 
-    } else { 
-      vertex.color1 <- NULL 
-    } 
-  } 
-  if (!is.null(vertex.color1)) { 
-    vertex.color1 <- as.integer(vertex.color1)-1L 
-  }
-  if (missing(vertex.color2)) { 
-    if ("color" %in% list.vertex.attributes(graph2)) { 
-      vertex.color2 <- V(graph2)$color 
-    } else { 
-      vertex.color2 <- NULL 
-    } 
-  } 
-  if (!is.null(vertex.color2)) { 
-    vertex.color2 <- as.integer(vertex.color2)-1L 
-  }
-  if (missing(edge.color1)) { 
-    if ("color" %in% list.edge.attributes(graph1)) { 
-      edge.color1 <- E(graph1)$color 
-    } else { 
-      edge.color1 <- NULL 
-    } 
-  } 
-  if (!is.null(edge.color1)) { 
-    edge.color1 <- as.integer(edge.color1)-1L 
-  }
-  if (missing(edge.color2)) { 
-    if ("color" %in% list.edge.attributes(graph2)) { 
-      edge.color2 <- E(graph2)$color 
-    } else { 
-      edge.color2 <- NULL 
-    } 
-  } 
-  if (!is.null(edge.color2)) { 
-    edge.color2 <- as.integer(edge.color2)-1L 
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
+  if (missing(vertex.color1)) {
+    if ("color" %in% vertex_attr_names(graph1)) {
+      vertex.color1 <- V(graph1)$color
+    } else {
+      vertex.color1 <- NULL
+    }
+  }
+  if (!is.null(vertex.color1)) {
+    vertex.color1 <- as.integer(vertex.color1)-1L
+  }
+  if (missing(vertex.color2)) {
+    if ("color" %in% vertex_attr_names(graph2)) {
+      vertex.color2 <- V(graph2)$color
+    } else {
+      vertex.color2 <- NULL
+    }
+  }
+  if (!is.null(vertex.color2)) {
+    vertex.color2 <- as.integer(vertex.color2)-1L
+  }
+  if (missing(edge.color1)) {
+    if ("color" %in% edge_attr_names(graph1)) {
+      edge.color1 <- E(graph1)$color
+    } else {
+      edge.color1 <- NULL
+    }
+  }
+  if (!is.null(edge.color1)) {
+    edge.color1 <- as.integer(edge.color1)-1L
+  }
+  if (missing(edge.color2)) {
+    if ("color" %in% edge_attr_names(graph2)) {
+      edge.color2 <- E(graph2)$color
+    } else {
+      edge.color2 <- NULL
+    }
+  }
+  if (!is.null(edge.color2)) {
+    edge.color2 <- as.integer(edge.color2)-1L
   }
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -136,19 +133,14 @@ graph.get.subisomorphisms.vf2 <- function(graph1, graph2, vertex.color1,
                vertex.color1, vertex.color2, edge.color1, edge.color2,
                PACKAGE="igraph")
 
-  res <- lapply(res, "+", 1)
-
-  if (getIgraphOpt("add.vertex.names") && is.named(graph2)) {
-    for (i in seq_along(res)) {
-      names(res[[i]]) <- V(graph2)$name[ res[[i]] ]
-    }
-  }
-  res
+  lapply(res, function(x) V(graph1)[x + 1])
 }
 
+#' @export
+
 graph.isoclass.subgraph <- function(graph, vids) {
   # Argument checks
-  if (!is.igraph(graph)) { stop("Not a graph object") }
+  if (!is_igraph(graph)) { stop("Not a graph object") }
   vids <- as.igraph.vs(graph, vids)-1
 
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
@@ -158,12 +150,14 @@ graph.isoclass.subgraph <- function(graph, vids) {
   res
 }
 
+#' @export
+
 graph.subisomorphic.lad <- function(pattern, target, domains=NULL,
                                     induced=FALSE, map=TRUE, all.maps=FALSE,
                                     time.limit=Inf) {
   # Argument checks
-  if (!is.igraph(pattern)) { stop("Not a graph object") }
-  if (!is.igraph(target)) { stop("Not a graph object") }
+  if (!is_igraph(pattern)) { stop("Not a graph object") }
+  if (!is_igraph(target)) { stop("Not a graph object") }
   induced <- as.logical(induced)
   if (time.limit==Inf) {
     time.limit <- 0L
@@ -181,7 +175,7 @@ graph.subisomorphic.lad <- function(pattern, target, domains=NULL,
     }
     domains <- lapply(domains, function(x) as.igraph.vs(target, x)-1)
   }
-  
+
   on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
   # Function call
   res <- .Call("R_igraph_subisomorphic_lad", pattern, target, domains,
@@ -190,21 +184,694 @@ graph.subisomorphic.lad <- function(pattern, target, domains=NULL,
 
   if (map) {
     res$map <- res$map + 1
-    if (getIgraphOpt("add.vertex.names") && is.named(target)) {
+    if (igraph_opt("add.vertex.names") && is_named(target)) {
       names(res$map) <- V(target)$name[res$map]
     }
   }
-  if (all.maps) {
-    res$maps <- lapply(res$maps, function(x) x + 1)
-    if (getIgraphOpt("add.vertex.names") && is.named(target)) {
-      for (i in seq_along(res$maps)) {
-        names(res$maps[[i]]) <- V(target)$name[ res$maps[[i]] ]
-      }
-    }
-  }
+  if (all.maps) res$maps <- lapply(res$maps, function(x) V(target)[x+1])
+
   res
 }
 
+## ----------------------------------------------------------------------
+## NEW API
+
+#' Decide if two graphs are isomorphic
+#'
+#' @section \sQuote{auto} method:
+#' It tries to select the appropriate method based on the two graphs.
+#' This is the algorithm it uses:
+#' \enumerate{
+#'   \item If the two graphs do not agree on their order and size
+#'     (i.e. number of vertices and edges), then return \code{FALSE}.
+#'   \item If the graphs have three or four vertices, then the
+#'     \sQuote{direct} method is used.
+#'   \item If the graphs are directed, then the \sQuote{vf2} method is
+#'     used.
+#'   \item Otherwise the \sQuote{bliss} method is used.
+#' }
+#'
+#' @section \sQuote{direct} method:
+#' This method only works on graphs with three or four vertices,
+#' and it is based on a pre-calculated and stored table. It does not
+#' have any extra arguments.
+#'
+#' @section \sQuote{vf2} method:
+#' This method uses the VF2 algorithm by Cordella, Foggia et al., see
+#' references below. It supports vertex and edge colors and have the
+#' following extra arguments:
+#' \describe{
+#'   \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+#'     colors of the vertices for colored graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} vertex attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments. See also examples
+#'     below.}
+#'   \item{edge.color1, edge.color2}{Optional integer vectors giving the
+#'     colors of the edges for edge-colored (sub)graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} edge attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments.}
+#' }
+#'
+#' @section \sQuote{bliss} method:
+#' Uses the BLISS algorithm by Junttila and Kaski, and it works for
+#' undirected graphs. For both graphs the
+#' \code{\link{canonical_permutation}} and then the \code{\link{permute}}
+#' function is called to transfer them into canonical form; finally the
+#' canonical forms are compared.
+#' Extra arguments:
+#' \describe{
+#'   \item{sh1}{Character constant, the heuristics to use in the BLISS
+#'     algorithm, for \code{graph1}. See the \code{sh} argument of
+#'     \code{\link{canonical_permutation}} for possible values.}
+#'   \item{sh2}{Character constant, the heuristics to use in the BLISS
+#'     algorithm, for \code{graph2}. See the \code{sh} argument of
+#'     \code{\link{canonical_permutation}} for possible values.}
+#' }
+#' \code{sh1} and \code{sh2} default to \sQuote{fm}.
+#'
+#' @param graph1 The first graph.
+#' @param graph2 The second graph.
+#' @param method The method to use. Possible values: \sQuote{auto},
+#'   \sQuote{direct}, \sQuote{vf2}, \sQuote{bliss}. See their details
+#'   below.
+#' @param ... Additional arguments, passed to the various methods.
+#' @return Logical scalar, \code{TRUE} if the graphs are isomorphic.
+#'
+#' @aliases graph.isomorphic graph.isomorphic.34 graph.isomorphic.vf2
+#'   graph.isomorphic.bliss
+#'
+#' @references
+#'  Tommi Junttila and Petteri Kaski: Engineering an Efficient Canonical
+#'  Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of the
+#'  Ninth Workshop on Algorithm Engineering and Experiments and the Fourth
+#'  Workshop on Analytic Algorithms and Combinatorics.} 2007.
+#'
+#'  LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+#'  for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+#'  on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+#'
+#' @export
+#' @family graph isomorphism
+#' @examples
+#' # create some non-isomorphic graphs
+#' g1 <- graph_from_isomorphism_class(3, 10)
+#' g2 <- graph_from_isomorphism_class(3, 11)
+#' isomorphic(g1, g2)
+#'
+#' # create two isomorphic graphs, by permuting the vertices of the first
+#' g1 <- barabasi.game(30, m=2, directed=FALSE)
+#' g2 <- permute(g1, sample(vcount(g1)))
+#' # should be TRUE
+#' isomorphic(g1, g2)
+#' isomorphic(g1, g2, method = "bliss")
+#' isomorphic(g1, g2, method = "vf2")
+#'
+#' # colored graph isomorphism
+#' g1 <- make_ring(10)
+#' g2 <- make_ring(10)
+#' isomorphic(g1, g2)
+#'
+#' V(g1)$color <- rep(1:2, length = vcount(g1))
+#' V(g2)$color <- rep(2:1, length = vcount(g2))
+#' # consider colors by default
+#' count_isomorphisms(g1, g2)
+#' # ignore colors
+#' count_isomorphisms(g1, g2, vertex.color1 = NULL,
+#'     vertex.color2 = NULL)
+
+isomorphic <- function(graph1, graph2, method = c("auto", "direct",
+                 "vf2", "bliss"), ...) {
+
+  if (!is_igraph(graph1)) { stop("Not a graph object") }
+  if (!is_igraph(graph2)) { stop("Not a graph object") }
+  method <- igraph.match.arg(method)
+
+  if (method == "auto") {
+    on.exit( .Call("R_igraph_finalizer", PACKAGE="igraph") )
+    .Call("R_igraph_isomorphic", graph1, graph2, PACKAGE="igraph")
+
+  } else if (method == "direct") {
+    on.exit(.Call("R_igraph_finalizer", PACKAGE = "igraph"))
+    .Call("R_igraph_isomorphic_34", graph1, graph2, PACKAGE = "igraph")
+
+  } else if (method == "vf2") {
+    graph.isomorphic.vf2(graph1, graph2, ...)$iso
+
+  } else if (method == "bliss") {
+    graph.isomorphic.bliss(graph1, graph2, ...)$iso
+
+  }
+}
+
+#' @export
+#' @rdname isomorphic
+#' @inheritParams isomorphic
+
+is_isomorphic_to <- isomorphic
+
+
+#' Decide if a graph is subgraph isomorphic to another one
+#'
+#' @section \sQuote{auto} method:
+#' This method currently selects \sQuote{lad}, always, as it seems
+#' to be superior on most graphs.
+#'
+#' @section \sQuote{lad} method:
+#' This is the LAD algorithm by Solnon, see the reference below. It has
+#' the following extra arguments:
+#' \describe{
+#'   \item{domains}{If not \code{NULL}, then it specifies matching
+#'     restrictions. It must be a list of \code{target} vertex sets, given
+#'     as numeric vertex ids or symbolic vertex names. The length of the
+#'     list must be \code{vcount(pattern)} and for each vertex in
+#'     \code{pattern} it gives the allowed matching vertices in
+#'     \code{target}. Defaults to \code{NULL}.}
+#'   \item{induced}{Logical scalar, whether to search for an induced
+#'     subgraph. It is \code{FALSE} by default.}
+#'   \item{time.limit}{The processor time limit for the computation, in
+#'     seconds. It defaults to \code{Inf}, which means no limit.}
+#' }
+#'
+#' @section \sQuote{vf2} method:
+#' This method uses the VF2 algorithm by Cordella, Foggia et al., see
+#' references below. It supports vertex and edge colors and have the
+#' following extra arguments:
+#' \describe{
+#'   \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+#'     colors of the vertices for colored graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} vertex attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments. See also examples
+#'     below.}
+#'   \item{edge.color1, edge.color2}{Optional integer vectors giving the
+#'     colors of the edges for edge-colored (sub)graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} edge attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments.}
+#' }
+#'
+#' @param pattern The smaller graph, it might be directed or
+#'   undirected. Undirected graphs are treated as directed graphs with
+#'   mutual edges.
+#' @param target The bigger graph, it might be directed or
+#'   undirected. Undirected graphs are treated as directed graphs with
+#'   mutual edges.
+#' @param method The method to use. Possible values: \sQuote{auto},
+#'   \sQuote{lad}, \sQuote{vf2}. See their details below.
+#' @param ... Additional arguments, passed to the various methods.
+#' @return Logical scalar, \code{TRUE} if the \code{pattern} is
+#'   isomorphic to a (possibly induced) subgraph of \code{target}.
+#'
+#' @aliases graph.subisomorphic.vf2 graph.subisomorphic.lad
+#'
+#' @references
+#'  LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+#'  for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+#'  on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+#'
+#'  C. Solnon: AllDifferent-based Filtering for Subgraph Isomorphism,
+#'  \emph{Artificial Intelligence} 174(12-13):850--864, 2010.
+#'
+#' @export
+#' @family graph isomorphism
+#' @examples
+#' # A LAD example
+#' pattern <- make_graph(~ 1:2:3:4:5,
+#'                       1 - 2:5, 2 - 1:5:3, 3 - 2:4, 4 - 3:5, 5 - 4:2:1)
+#' target <- make_graph(~ 1:2:3:4:5:6:7:8:9,
+#'                     1 - 2:5:7, 2 - 1:5:3, 3 - 2:4, 4 - 3:5:6:8:9,
+#'                     5 - 1:2:4:6:7, 6 - 7:5:4:9, 7 - 1:5:6,
+#'                     8 - 4:9, 9 - 6:4:8)
+#' domains <- list(`1` = c(1,3,9), `2` = c(5,6,7,8), `3` = c(2,4,6,7,8,9),
+#'                 `4` = c(1,3,9), `5` = c(2,4,8,9))
+#' subgraph_isomorphisms(pattern, target)
+#' subgraph_isomorphisms(pattern, target, induced = TRUE)
+#' subgraph_isomorphisms(pattern, target, domains = domains)
+#'
+#' # Directed LAD example
+#' pattern <- make_graph(~ 1:2:3, 1 -+ 2:3)
+#' uring <- make_ring(10)
+#' dring <- make_ring(10, directed = TRUE)
+#' subgraph_isomorphic(pattern, uring)
+#' subgraph_isomorphic(pattern, dring)
+
+subgraph_isomorphic <- function(pattern, target,
+                                method = c("auto", "lad", "vf2"), ...) {
+
+  method <- igraph.match.arg(method)
+
+  if (method == "auto") method <- "lad"
+
+  if (method == "lad") {
+    graph.subisomorphic.lad(pattern, target, map = FALSE, all.maps = FALSE,
+                            ...)$iso
+
+  } else if (method == "vf2") {
+    graph.subisomorphic.vf2(target, pattern, ...)$iso
+
+  }
+}
+
+
+#' @export
+#' @rdname subgraph_isomorphic
+#' @inheritParams subgraph_isomorphic
+
+is_subgraph_isomorphic_to <- subgraph_isomorphic
+
+
+#' Count the number of isomorphic mappings between two graphs
+#'
+#' @param graph1 The first graph.
+#' @param graph2 The second graph.
+#' @param method Currently only \sQuote{vf2} is supported, see
+#'   \code{\link{isomorphic}} for details about it and extra arguments.
+#' @param ... Passed to the individual methods.
+#' @return Number of isomirphic mappings between the two graphs.
+#'
+#' @include auto.R
+#' @aliases graph.count.isomorphisms.vf2
+#'
+#' @references
+#'  LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+#'  for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+#'  on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+#'
+#' @export
+#' @family graph isomorphism
+#' @examples
+#' # colored graph isomorphism
+#' g1 <- make_ring(10)
+#' g2 <- make_ring(10)
+#' isomorphic(g1, g2)
+#'
+#' V(g1)$color <- rep(1:2, length = vcount(g1))
+#' V(g2)$color <- rep(2:1, length = vcount(g2))
+#' # consider colors by default
+#' count_isomorphisms(g1, g2)
+#' # ignore colors
+#' count_isomorphisms(g1, g2, vertex.color1 = NULL,
+#'     vertex.color2 = NULL)
+
+count_isomorphisms <- function(graph1, graph2, method = "vf2", ...) {
+
+  method <- igraph.match.arg(method)
+
+  if (method == "vf2") {
+    graph.count.isomorphisms.vf2(graph1, graph2, ...)
+  }
+
+}
+
+
+#' Count the isomorphic mappings between a graph and the subgraphs of
+#' another graph
+#'
+#' @section \sQuote{lad} method:
+#' This is the LAD algorithm by Solnon, see the reference below. It has
+#' the following extra arguments:
+#' \describe{
+#'   \item{domains}{If not \code{NULL}, then it specifies matching
+#'     restrictions. It must be a list of \code{target} vertex sets, given
+#'     as numeric vertex ids or symbolic vertex names. The length of the
+#'     list must be \code{vcount(pattern)} and for each vertex in
+#'     \code{pattern} it gives the allowed matching vertices in
+#'     \code{target}. Defaults to \code{NULL}.}
+#'   \item{induced}{Logical scalar, whether to search for an induced
+#'     subgraph. It is \code{FALSE} by default.}
+#'   \item{time.limit}{The processor time limit for the computation, in
+#'     seconds. It defaults to \code{Inf}, which means no limit.}
+#' }
+#'
+#' @section \sQuote{vf2} method:
+#' This method uses the VF2 algorithm by Cordella, Foggia et al., see
+#' references below. It supports vertex and edge colors and have the
+#' following extra arguments:
+#' \describe{
+#'   \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+#'     colors of the vertices for colored graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} vertex attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments. See also examples
+#'     below.}
+#'   \item{edge.color1, edge.color2}{Optional integer vectors giving the
+#'     colors of the edges for edge-colored (sub)graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} edge attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments.}
+#' }
+#'
+#' @param pattern The smaller graph, it might be directed or
+#'   undirected. Undirected graphs are treated as directed graphs with
+#'   mutual edges.
+#' @param target The bigger graph, it might be directed or
+#'   undirected. Undirected graphs are treated as directed graphs with
+#'   mutual edges.
+#' @param method The method to use. Possible values:
+#'   \sQuote{lad}, \sQuote{vf2}. See their details below.
+#' @param ... Additional arguments, passed to the various methods.
+#' @return Logical scalar, \code{TRUE} if the \code{pattern} is
+#'   isomorphic to a (possibly induced) subgraph of \code{target}.
+#'
+#' @aliases graph.count.subisomorphisms.vf2
+#'
+#' @references
+#'  LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+#'  for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+#'  on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+#'
+#'  C. Solnon: AllDifferent-based Filtering for Subgraph Isomorphism,
+#'  \emph{Artificial Intelligence} 174(12-13):850--864, 2010.
+#'
+#' @export
+#' @family graph isomorphism
+
+count_subgraph_isomorphisms <- function(pattern, target,
+                                        method = c("lad", "vf2"), ...) {
+
+  method <- igraph.match.arg(method)
+
+  if (method == "lad") {
+    length(graph.subisomorphic.lad(pattern, target, all.maps = TRUE, ...)$maps)
+
+  } else if (method == "vf2") {
+    graph.count.subisomorphisms.vf2(target, pattern, ...)
+  }
+
+}
+
+
+#' Calculate all isomorphic mappings between the vertices of two graphs
+#'
+#' @param graph1 The first graph.
+#' @param graph2 The second graph.
+#' @param method Currently only \sQuote{vf2} is supported, see
+#'   \code{\link{isomorphic}} for details about it and extra arguments.
+#' @param ... Extra arguments, passed to the various methods.
+#' @return A list of vertex sequences, corresponding to all
+#'   mappings from the first graph to the second.
+#'
+#' @aliases graph.get.isomorphisms.vf2
+#'
+#' @export
+#' @family graph isomorphism
+
+isomorphisms <- function(graph1, graph2, method = "vf2", ...) {
+
+  method <- igraph.match.arg(method)
+
+  if (method == "vf2") {
+    graph.get.isomorphisms.vf2(graph1, graph2, ...)
+  }
+
+}
+
+
+#' All isomorphic mappings between a graph and subgraphs of another graph
+#'
+#' @section \sQuote{lad} method:
+#' This is the LAD algorithm by Solnon, see the reference below. It has
+#' the following extra arguments:
+#' \describe{
+#'   \item{domains}{If not \code{NULL}, then it specifies matching
+#'     restrictions. It must be a list of \code{target} vertex sets, given
+#'     as numeric vertex ids or symbolic vertex names. The length of the
+#'     list must be \code{vcount(pattern)} and for each vertex in
+#'     \code{pattern} it gives the allowed matching vertices in
+#'     \code{target}. Defaults to \code{NULL}.}
+#'   \item{induced}{Logical scalar, whether to search for an induced
+#'     subgraph. It is \code{FALSE} by default.}
+#'   \item{time.limit}{The processor time limit for the computation, in
+#'     seconds. It defaults to \code{Inf}, which means no limit.}
+#' }
+#'
+#' @section \sQuote{vf2} method:
+#' This method uses the VF2 algorithm by Cordella, Foggia et al., see
+#' references below. It supports vertex and edge colors and have the
+#' following extra arguments:
+#' \describe{
+#'   \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+#'     colors of the vertices for colored graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} vertex attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments. See also examples
+#'     below.}
+#'   \item{edge.color1, edge.color2}{Optional integer vectors giving the
+#'     colors of the edges for edge-colored (sub)graph isomorphism. If they
+#'     are not given, but the graph has a \dQuote{color} edge attribute,
+#'     then it will be used. If you want to ignore these attributes, then
+#'     supply \code{NULL} for both of these arguments.}
+#' }
+#'
+#' @param pattern The smaller graph, it might be directed or
+#'   undirected. Undirected graphs are treated as directed graphs with
+#'   mutual edges.
+#' @param target The bigger graph, it might be directed or
+#'   undirected. Undirected graphs are treated as directed graphs with
+#'   mutual edges.
+#' @param method The method to use. Possible values: \sQuote{auto},
+#'   \sQuote{lad}, \sQuote{vf2}. See their details below.
+#' @param ... Additional arguments, passed to the various methods.
+#' @return A list of vertex sequences, corresponding to all
+#'   mappings from the first graph to the second.
+#'
+#' @aliases graph.get.subisomorphisms.vf2
+#'
+#' @export
+#' @family graph isomorphism
+
+subgraph_isomorphisms <- function(pattern, target,
+                                  method = c("lad", "vf2"), ...) {
+
+  method <- igraph.match.arg(method)
+
+  if (method == "lad") {
+    graph.subisomorphic.lad(pattern, target, all.maps = TRUE, ...)$maps
+
+  } else if (method == "vf2") {
+    graph.get.subisomorphisms.vf2(target, pattern, ...)
+  }
+
+}
+
+
+#' Isomorphism class of a graph
+#'
+#' The isomorphism class is a non-negative integer number.
+#' Graphs (with the same number of vertices) having the same isomorphism
+#' class are isomorphic and isomorphic graphs always have the same
+#' isomorphism class. Currently it can handle only graphs with 3 or 4
+#' vertices.
+#'
+#' @param graph The input graph.
+#' @param v Optionally a vertex sequence. If not missing, then an induced
+#'   subgraph of the input graph, consisting of this vertices, is used.
+#' @return An integer number.
+#'
+#' @aliases graph.isoclass graph.isoclass.subgraph
+#'
+#' @export
+#' @family graph isomorphism
+#' @examples
+#' # create some non-isomorphic graphs
+#' g1 <- graph_from_isomorphism_class(3, 10)
+#' g2 <- graph_from_isomorphism_class(3, 11)
+#' isomorphism_class(g1)
+#' isomorphism_class(g2)
+#' isomorphic(g1, g2)
+
+isomorphism_class <- function(graph, v) {
+
+  if (missing(v)) {
+    graph.isoclass(graph)
+
+  } else {
+    graph.isoclass.subgraph(graph, v)
+  }
+
+}
+
+
+#' Create a graph from an isomorphism class
+#'
+#' The isomorphism class is a non-negative integer number.
+#' Graphs (with the same number of vertices) having the same isomorphism
+#' class are isomorphic and isomorphic graphs always have the same
+#' isomorphism class. Currently it can handle only graphs with 3 or 4
+#' vertices.
+#'
+#' @param size The number of vertices in the graph.
+#' @param number The isomorphism class.
+#' @param directed Whether to create a directed graph (the default).
+#' @return An igraph object, the graph of the given size, directedness
+#'   and isomorphism class.
+#'
+#' @aliases graph.isocreate
+#' @include auto.R
+#'
+#' @family graph isomorphism
+
+graph_from_isomorphism_class <- graph_from_isomorphism_class
+
+
+#' Canonical permutation of a graph
+#' 
+#' The canonical permutation brings every isomorphic graphs into the same
+#' (labeled) graph.
+#' 
+#' \code{canonical_permutation} computes a permutation which brings the graph
+#' into canonical form, as defined by the BLISS algorithm.  All isomorphic
+#' graphs have the same canonical form.
+#' 
+#' See the paper below for the details about BLISS. This and more information
+#' is available at \url{http://www.tcs.hut.fi/Software/bliss/index.html}.
+#' 
+#' The possible values for the \code{sh} argument are: \describe{
+#' \item{"f"}{First non-singleton cell.} \item{"fl"}{First largest
+#' non-singleton cell.} \item{"fs"}{First smallest non-singleton cell.}
+#' \item{"fm"}{First maximally non-trivially connectec non-singleton
+#' cell.} \item{"flm"}{Largest maximally non-trivially connected
+#' non-singleton cell.} \item{"fsm"}{Smallest maximally non-trivially
+#' connected non-singleton cell.} } See the paper in references for details
+#' about these.
+#' 
+#' @aliases canonical.permutation canonical_permutation
+#' @param graph The input graph, treated as undirected.
+#' @param sh Type of the heuristics to use for the BLISS algorithm. See details
+#' for possible values.
+#' @return A list with the following members: \item{labeling}{The canonical
+#' parmutation which takes the input graph into canonical form. A numeric
+#' vector, the first element is the new label of vertex 0, the second element
+#' for vertex 1, etc. } \item{info}{Some information about the BLISS
+#' computation. A named list with the following members: \describe{
+#' \item{"nof_nodes"}{The number of nodes in the search tree.}
+#' \item{"nof_leaf_nodes"}{The number of leaf nodes in the search tree.}
+#' \item{"nof_bad_nodes"}{Number of bad nodes.}
+#' \item{"nof_canupdates"}{Number of canrep updates.}
+#' \item{"max_level"}{Maximum level.} \item{"group_size"}{The size
+#' of the automorphism group of the input graph, as a string. This number is
+#' exact if igraph was compiled with the GMP library, and approximate
+#' otherwise.} } }
+#' @author Tommi Junttila for BLISS, Gabor Csardi
+#' \email{csardi.gabor@@gmail.com} for the igraph and R interfaces.
+#' @seealso \code{\link{permute}} to apply a permutation to a graph,
+#' \code{\link{graph.isomorphic}} for deciding graph isomorphism, possibly
+#' based on canonical labels.
+#' @references Tommi Junttila and Petteri Kaski: Engineering an Efficient
+#' Canonical Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of
+#' the Ninth Workshop on Algorithm Engineering and Experiments and the Fourth
+#' Workshop on Analytic Algorithms and Combinatorics.} 2007.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## Calculate the canonical form of a random graph
+#' g1 <- sample_gnm(10, 20)
+#' cp1 <- canonical_permutation(g1)
+#' cf1 <- permute(g1, cp1$labeling)
+#' 
+#' ## Do the same with a random permutation of it
+#' g2 <- permute(g1, sample(vcount(g1)))
+#' cp2 <- canonical_permutation(g2)
+#' cf2 <- permute(g2, cp2$labeling)
+#' 
+#' ## Check that they are the same
+#' el1 <- as_edgelist(cf1)
+#' el2 <- as_edgelist(cf2)
+#' el1 <- el1[ order(el1[,1], el1[,2]), ]
+#' el2 <- el2[ order(el2[,1], el2[,2]), ]
+#' all(el1 == el2)
+#' @export
+
+canonical_permutation <- canonical_permutation
+
+
+#' Permute the vertices of a graph
+#' 
+#' Create a new graph, by permuting vertex ids.
+#' 
+#' This function creates a new graph from the input graph by permuting its
+#' vertices according to the specified mapping. Call this function with the
+#' output of \code{\link{canonical_permutation}} to create the canonical form
+#' of a graph.
+#' 
+#' \code{permute} keeps all graph, vertex and edge attributes of the graph.
+#' 
+#' @aliases permute.vertices permute
+#' @param graph The input graph, it can directed or undirected.
+#' @param permutation A numeric vector giving the permutation to apply. The
+#' first element is the new id of vertex 1, etc. Every number between one and
+#' \code{vcount(graph)} must appear exactly once.
+#' @return A new graph object.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{canonical_permutation}}
+#' @keywords graphs
+#' @examples
+#' 
+#' # Random permutation of a random graph
+#' g <- sample_gnm(20, 50)
+#' g2 <- permute(g, sample(vcount(g)))
+#' graph.isomorphic(g, g2)
+#' 
+#' # Permutation keeps all attributes
+#' g$name <- "Random graph, Gnm, 20, 50"
+#' V(g)$name <- letters[1:vcount(g)]
+#' E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
+#' g2 <- permute(g, sample(vcount(g)))
+#' graph.isomorphic(g, g2)
+#' g2$name
+#' V(g2)$name
+#' E(g2)$weight
+#' all(sort(E(g2)$weight) == sort(E(g)$weight))
+#' @export
+
+permute <- permute
+
 
-# Rest generated by stimulus
+#' Number of automorphisms
+#' 
+#' Calculate the number of automorphisms of a graph, i.e. the number of
+#' isomorphisms to itself.
+#' 
+#' An automorphism of a graph is a permutation of its vertices which brings the
+#' graph into itself.
+#' 
+#' This function calculates the number of automorphism of a graph using the
+#' BLISS algorithm. See also the BLISS homepage at
+#' \url{http://www.tcs.hut.fi/Software/bliss/index.html}.
+#' 
+#' @aliases graph.automorphisms automorphisms
+#' @param graph The input graph, it is treated as undirected.
+#' @param sh The splitting heuristics for the BLISS algorithm. Possible values
+#' are: \sQuote{\code{f}}: first non-singleton cell, \sQuote{\code{fl}}: first
+#' largest non-singleton cell, \sQuote{\code{fs}}: first smallest non-singleton
+#' cell, \sQuote{\code{fm}}: first maximally non-trivially connected
+#' non-singleton cell, \sQuote{\code{flm}}: first largest maximally
+#' non-trivially connected non-singleton cell, \sQuote{\code{fsm}}: first
+#' smallest maximally non-trivially connected non-singleton cell.
+#' @return A named list with the following members: \item{group_size}{The size
+#' of the automorphism group of the input graph, as a string. This number is
+#' exact if igraph was compiled with the GMP library, and approximate
+#' otherwise.} \item{nof_nodes}{The number of nodes in the search tree.}
+#' \item{nof_leaf_nodes}{The number of leaf nodes in the search tree.}
+#' \item{nof_bad_nodes}{Number of bad nodes.} \item{nof_canupdates}{Number of
+#' canrep updates.} \item{max_level}{Maximum level.}
+#' @author Tommi Junttila (\url{http://users.ics.aalto.fi/tjunttil/}) for BLISS
+#' and Gabor Csardi \email{csardi.gabor@@gmail.com} for the igraph glue code
+#' and this manual page.
+#' @seealso \code{\link{canonical_permutation}}, \code{\link{permute}}
+#' @references Tommi Junttila and Petteri Kaski: Engineering an Efficient
+#' Canonical Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of
+#' the Ninth Workshop on Algorithm Engineering and Experiments and the Fourth
+#' Workshop on Analytic Algorithms and Combinatorics.} 2007.
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A ring has n*2 automorphisms, you can "turn" it by 0-9 vertices
+#' ## and each of these graphs can be "flipped"
+#' g <- make_ring(10)
+#' automorphisms(g)
+#' @export
 
+automorphisms <- automorphisms
diff --git a/R/triangles.R b/R/triangles.R
new file mode 100644
index 0000000..b1da545
--- /dev/null
+++ b/R/triangles.R
@@ -0,0 +1,73 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2015  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+
+#' Find triangles in graphs
+#' 
+#' Count how many triangles a vertex is part of, in a graph, or just list the
+#' triangles of a graph.
+#' 
+#' \code{triangles} lists all triangles of a graph. For efficiency, all
+#' triangles are returned in a single vector. The first three vertices belong
+#' to the first triangle, etc.
+#' 
+#' \code{count_triangles} counts how many triangles a vertex is part of.
+#' 
+#' @aliases count_triangles adjacent.triangles triangles
+#' @param graph The input graph. It might be directed, but edge directions are
+#' ignored.
+#' @param vids The vertices to query, all of them by default. This might be a
+#' vector of numeric ids, or a character vector of symbolic vertex names for
+#' named graphs.
+#' @return For \code{triangles} a numeric vector of vertex ids, the first three
+#' vertices belong to the first triangle found, etc.
+#' 
+#' For \code{triangles} a numeric vector, the number of triangles for all
+#' vertices queried.
+#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
+#' @seealso \code{\link{transitivity}}
+#' @keywords graphs
+#' @examples
+#' 
+#' ## A small graph
+#' kite <- make_graph("Krackhardt_Kite")
+#' plot(kite)
+#' matrix(triangles(kite), nrow=3)
+#' 
+#' ## Adjacenct triangles
+#' atri <- count_triangles(kite)
+#' plot(kite, vertex.label=atri)
+#' 
+#' ## Always true
+#' sum(count_triangles(kite)) == length(triangles(kite))
+#' 
+#' ## Should match, local transitivity is the
+#' ## number of adjacent triangles divided by the number
+#' ## of adjacency triples
+#' transitivity(kite, type="local")
+#' count_triangles(kite) / (degree(kite) * (degree(kite)-1)/2)
+#' @export
+#' @include auto.R
+
+count_triangles <- count_triangles
diff --git a/R/utils.R b/R/utils.R
new file mode 100644
index 0000000..2902c5b
--- /dev/null
+++ b/R/utils.R
@@ -0,0 +1,99 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+make_call <- function(f, ..., .args = list()) {
+  if (is.character(f)) f <- as.name(f)
+  as.call(c(f, ..., .args))
+}
+
+do_call <- function(f, ..., .args = list(), .env = parent.frame()) {
+  f <- substitute(f)
+
+  call <- make_call(f, ..., .args)
+  eval(call, .env)
+}
+
+add_class <- function(x, class) {
+  if (!is(x, class)) {
+    class(x) <- c(class, class(x))
+  }
+  x
+}
+
+`%||%` <- function (lhs, rhs) {
+  lres <- withVisible(eval(lhs, envir = parent.frame()))
+  if (is.null(lres$value)) {
+    eval(rhs, envir = parent.frame())
+  } else {
+    if (lres$visible) {
+      lres$value
+    } else {
+      invisible(lres$value)
+    }
+  }
+}
+
+`%&&%` <- function(lhs, rhs) {
+  lres <- withVisible(eval(lhs, envir = parent.frame()))
+  if (!is.null(lres$value)) {
+    eval(rhs, envir = parent.frame())
+  } else {
+    if (lres$visible) {
+      lres$value
+    } else {
+      invisible(lres$value)
+    }
+  }
+}
+
+## Grab all arguments of the parent call, in a list
+
+grab_args <- function() {
+  envir <- parent.frame()
+  func <- sys.function(-1)
+  call <- sys.call(-1)
+  dots <- match.call(func, call, expand.dots=FALSE)$...
+  c(as.list(envir), dots)
+}
+
+capitalize <- function(x) {
+  x <- tolower(x)
+  substr(x, 1, 1) <- toupper(substr(x, 1, 1))
+  x
+}
+
+address <- function(x) {
+  .Call("R_igraph_address", x, PACKAGE = "igraph")
+}
+
+`%+%` <- function(x, y) {
+  stopifnot(is.character(x), is.character(y))
+  paste0(x, y)
+}
+
+chr <- as.character
+
+drop_null <- function(x) {
+  x [!sapply(x, is.null)]
+}
diff --git a/R/uuid.R b/R/uuid.R
new file mode 100644
index 0000000..ced0625
--- /dev/null
+++ b/R/uuid.R
@@ -0,0 +1,13 @@
+
+generate_uuid <- function(use_time = NA) {
+  .Call("UUID_gen", as.logical(use_time), PACKAGE="igraph")
+}
+
+
+get_graph_id <- function(graph) {
+  if (!warn_version(graph)) {
+    .Call("R_igraph_get_graph_id", graph, PACKAGE = "igraph")
+  } else {
+    NA_character_
+  }
+}
diff --git a/R/versions.R b/R/versions.R
new file mode 100644
index 0000000..1f1c0c5
--- /dev/null
+++ b/R/versions.R
@@ -0,0 +1,120 @@
+
+## ----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## ----------------------------------------------------------------------
+
+#' Igraph data structure versions
+#'
+#' Igraph's internal data representation changes sometimes between
+#' versions. This means that it is not possible to use igraph objects
+#' that were created (and possibly saved to a file) with an older
+#' igraph version.
+#'
+#' \code{graph_version} queries the current data format,
+#' or the data format of a possibly older igraph graph.
+#'
+#' \code{\link{upgrade_graph}} can convert an older data format
+#' to the current one.
+#'
+#' @param graph The input graph. If it is missing, then
+#'   the version number of the current data format is returned.
+#' @return A character scalar.
+#'
+#' @seealso upgrade_graph to convert the data format of a graph.
+#' @export
+
+graph_version <- function(graph) {
+  if (missing(graph)) {
+    "0.8.0"
+
+  } else {
+    stopifnot(is_igraph(graph))
+    .Call("R_igraph_graph_version", graph, PACKAGE = "igraph")
+  }
+}
+
+#' Igraph data structure versions
+#'
+#' Igraph's internal data representation changes sometimes between
+#' versions. This means that it is not possible to use igraph objects
+#' that were created (and possibly saved to a file) with an older
+#' igraph version.
+#'
+#' \code{\link{graph_version}} queries the current data format,
+#' or the data format of a possibly older igraph graph.
+#'
+#' \code{upgrade_graph} can convert an older data format
+#' to the current one.
+#'
+#' @param graph The input graph.
+#' @return The graph in the current format.
+#'
+#' @seealso graph_version to check the current data format version
+#' or the version of a graph.
+#' @export
+
+upgrade_graph <- function(graph) {
+
+  stopifnot(is_igraph(graph))
+
+  g_ver <- graph_version(graph)
+  p_ver <- graph_version()
+
+  if (g_ver < p_ver) {
+
+    if ((g_ver == "0.4.0" && p_ver == "0.8.0")) {
+      .Call("R_igraph_add_env", graph, PACKAGE = "igraph")
+
+    } else if (g_ver == "0.7.999" && p_ver == "0.8.0") {
+      .Call("R_igraph_add_version_to_env", graph, PACKAGE = "igraph")
+
+    } else {
+      stop("Don't know how to upgrade graph from ", g_ver, " to ", p_ver)
+    }
+
+  } else if (g_ver > p_ver) {
+    stop("Don't know how to downgrade graph from ", g_ver, " to ", p_ver)
+
+  } else {
+    graph
+  }
+}
+
+## Check that the version is the latest
+
+check_version <- function(graph) {
+  if (graph_version() != graph_version(graph)) {
+    stop("This graph was created by an old(er) igraph version.\n",
+         "  Call upgrade_graph() on it to use with the current igraph version")
+  }
+}
+
+warn_version <- function(graph) {
+  if (graph_version() != graph_version(graph)) {
+    message("This graph was created by an old(er) igraph version.\n",
+            "  Call upgrade_graph() on it to use with the current igraph version\n",
+            "  For now we convert it on the fly...")
+    TRUE
+  } else {
+    FALSE
+  }
+}
diff --git a/R/weakref.R b/R/weakref.R
new file mode 100644
index 0000000..e1afe43
--- /dev/null
+++ b/R/weakref.R
@@ -0,0 +1,41 @@
+
+## -----------------------------------------------------------------------
+##
+##   IGraph R package
+##   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+##   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
+##
+## -----------------------------------------------------------------------
+
+make_weak_ref <- function(key, value, finalizer = NULL) {
+  base::.Call("R_igraph_make_weak_ref", key, value,
+              finalizer, PACKAGE = "igraph")
+}
+
+weak_ref_key <- function(ref) {
+  base::.Call("R_igraph_weak_ref_key", ref, PACKAGE = "igraph")
+}
+
+weak_ref_value <- function(ref) {
+  base::.Call("R_igraph_weak_ref_value", ref, PACKAGE = "igraph")
+}
+
+weak_ref_run_finalizer <- function(ref) {
+  base::.Call("R_igraph_weak_ref_run_finalizer", ref,
+              PACKAGE = "igraph")
+}
diff --git a/R/zzz-deprecate.R b/R/zzz-deprecate.R
new file mode 100644
index 0000000..82594cf
--- /dev/null
+++ b/R/zzz-deprecate.R
@@ -0,0 +1,610 @@
+
+#   IGraph R package
+#   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+#   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
+#
+###################################################################
+
+#' @include attributes.R auto.R basic.R bipartite.R centrality.R
+#' @include cliques.R cocitation.R cohesive.blocks.R community.R
+#' @include components.R console.R conversion.R decomposition.R demo.R
+#' @include epi.R fit.R flow.R foreign.R games.R glet.R hrg.R indexing.R
+#' @include interface.R iterators.R layout.R minimum.spanning.tree.R
+#' @include motifs.R nexus.R operators.R other.R package.R par.R plot.R
+#' @include plot.common.R plot.shapes.R pp.R print.R scg.R socnet.R
+#' @include sparsedf.R structural.properties.R
+#' @include structure.info.R test.R tkplot.R topology.R layout_drl.R
+NULL
+
+## For the future, right now, we do not warn or even message
+
+deprecated <- function(old, new) {
+  assign(old, new, envir = asNamespace(packageName()))
+}
+
+#' @export add.edges
+deprecated("add.edges", add_edges)
+#' @export add.vertex.shape
+deprecated("add.vertex.shape", add_shape)
+#' @export add.vertices
+deprecated("add.vertices", add_vertices)
+#' @export adjacent.triangles
+deprecated("adjacent.triangles", count_triangles)
+#' @export articulation.points
+deprecated("articulation.points", articulation_points)
+#' @export aging.prefatt.game
+deprecated("aging.prefatt.game", sample_pa_age)
+#' @export aging.ba.game
+deprecated("aging.ba.game", sample_pa_age)
+#' @export aging.barabasi.game
+deprecated("aging.barabasi.game", sample_pa_age)
+#' @export alpha.centrality
+deprecated("alpha.centrality", alpha_centrality)
+#' @export are.connected
+deprecated("are.connected", are_adjacent)
+#' @export asPhylo
+deprecated("asPhylo", as_phylo)
+#' @method asPhylo communities
+deprecated("asPhylo.communities", as_phylo.communities)
+#' @method asPhylo igraphHRG
+deprecated("asPhylo.igraphHRG", as_phylo.igraphHRG)
+#' @export assortativity.degree
+deprecated("assortativity.degree", assortativity_degree)
+#' @export assortativity.nominal
+deprecated("assortativity.nominal", assortativity_nominal)
+#' @export asymmetric.preference.game
+deprecated("asymmetric.preference.game", sample_asym_pref)
+#' @export authority.score
+deprecated("authority.score", authority_score)
+#' @export autocurve.edges
+deprecated("autocurve.edges", curve_multiple)
+#' @export average.path.length
+deprecated("average.path.length", mean_distance)
+
+#' @export ba.game
+deprecated("ba.game", sample_pa)
+#' @export barabasi.game
+deprecated("barabasi.game", sample_pa)
+#' @export betweenness.estimate
+deprecated("betweenness.estimate", estimate_betweenness)
+#' @export biconnected.components
+deprecated("biconnected.components", biconnected_components)
+#' @export bipartite.mapping
+deprecated("bipartite.mapping", bipartite_mapping)
+#' @export bipartite.projection
+deprecated("bipartite.projection", bipartite_projection)
+#' @export bipartite.projection.size
+deprecated("bipartite.projection.size", bipartite_projection_size)
+#' @export bipartite.random.game
+deprecated("bipartite.random.game", sample_bipartite)
+#' @export blockGraphs
+deprecated("blockGraphs", graphs_from_cohesive_blocks)
+#' @export bonpow
+deprecated("bonpow", power_centrality)
+
+#' @export callaway.traits.game
+deprecated("callaway.traits.game", sample_traits_callaway)
+#' @export canonical.permutation
+deprecated("canonical.permutation", canonical_permutation)
+#' @export centralization.betweenness
+deprecated("centralization.betweenness", centr_betw)
+#' @export centralization.betweenness.tmax
+deprecated("centralization.betweenness.tmax", centr_betw_tmax)
+#' @export centralization.closeness
+deprecated("centralization.closeness", centr_clo)
+#' @export centralization.closeness.tmax
+deprecated("centralization.closeness.tmax", centr_clo_tmax)
+#' @export centralization.degree
+deprecated("centralization.degree", centr_degree)
+#' @export centralization.degree.tmax
+deprecated("centralization.degree.tmax", centr_degree_tmax)
+#' @export centralization.evcent
+deprecated("centralization.evcent", centr_eigen)
+#' @export centralization.evcent.tmax
+deprecated("centralization.evcent.tmax", centr_eigen_tmax)
+#' @export centralize.scores
+deprecated("centralize.scores", centralize)
+#' @export cited.type.game
+deprecated("cited.type.game", sample_cit_types)
+#' @export citing.cited.type.game
+deprecated("citing.cited.type.game", sample_cit_cit_types)
+#' @export clique.number
+deprecated("clique.number", clique_num)
+#' @export closeness.estimate
+deprecated("closeness.estimate", estimate_closeness)
+#' @export cluster.distribution
+deprecated("cluster.distribution", component_distribution)
+#' @export clusters
+deprecated("clusters", components)
+#' @export code.length
+deprecated("code.length", code_len)
+#' @export cohesive.blocks
+deprecated("cohesive.blocks", cohesive_blocks)
+#' @export connect.neighborhood
+deprecated("connect.neighborhood", connect)
+#' @export contract.vertices
+deprecated("contract.vertices", contract)
+#' @export convex.hull
+deprecated("convex.hull", convex_hull)
+#' @export count.multiple
+deprecated("count.multiple", count_multiple)
+#' @export cutat
+deprecated("cutat", cut_at)
+
+#' @export decompose.graph
+deprecated("decompose.graph", decompose)
+#' @export degree.distribution
+deprecated("degree.distribution", degree_distribution)
+#' @export degree.sequence.game
+deprecated("degree.sequence.game", sample_degseq)
+#' @export delete.edges
+deprecated("delete.edges", delete_edges)
+#' @export delete.vertices
+deprecated("delete.vertices", delete_vertices)
+#' @export dendPlot
+deprecated("dendPlot", plot_dendrogram)
+#' @method dendPlot communities
+deprecated("dendPlot.communities", plot_dendrogram.communities)
+#' @method dendPlot igraphHRG
+deprecated("dendPlot.igraphHRG", plot_dendrogram.igraphHRG)
+#' @export dominator.tree
+deprecated("dominator.tree", dominator_tree)
+#' @export dyad.census
+deprecated("dyad.census", dyad_census)
+
+#' @export ecount
+deprecated("ecount", gsize)
+#' @export edge.betweenness
+deprecated("edge.betweenness", edge_betweenness)
+#' @export edge.betweenness.community
+deprecated("edge.betweenness.community", cluster_edge_betweenness)
+#' @export edge.betweenness.estimate
+deprecated("edge.betweenness.estimate", estimate_edge_betweenness)
+#' @export edge.connectivity
+deprecated("edge.connectivity", edge_connectivity)
+#' @export edge.disjoint.paths
+deprecated("edge.disjoint.paths", edge_disjoint_paths)
+#' @export establishment.game
+deprecated("establishment.game", sample_traits)
+#' @export evcent
+deprecated("evcent", eigen_centrality)
+
+#' @export farthest.nodes
+deprecated("farthest.nodes", farthest_vertices)
+#' @export fastgreedy.community
+deprecated("fastgreedy.community", cluster_fast_greedy)
+#' @export forest.fire.game
+deprecated("forest.fire.game", sample_forestfire)
+
+#' @export get.adjedgelist
+deprecated("get.adjedgelist", as_adj_edge_list)
+#' @export get.adjlist
+deprecated("get.adjlist", as_adj_list)
+#' @export get.adjacency
+deprecated("get.adjacency", as_adjacency_matrix)
+#' @export get.data.frame
+deprecated("get.data.frame", as_data_frame)
+#' @export get.edge.attribute
+deprecated("get.edge.attribute", edge_attr)
+#' @export get.edgelist
+deprecated("get.edgelist", as_edgelist)
+#' @export get.graph.attribute
+deprecated("get.graph.attribute", graph_attr)
+#' @export get.incidence
+deprecated("get.incidence", as_incidence_matrix)
+#' @export get.stochastic
+deprecated("get.stochastic", stochastic_matrix)
+#' @export get.vertex.attribute
+deprecated("get.vertex.attribute", vertex_attr)
+#' @export graph.adhesion
+deprecated("graph.adhesion", adhesion)
+#' @export graph.adjacency
+deprecated("graph.adjacency", graph_from_adjacency_matrix)
+#' @export graph.adjlist
+deprecated("graph.adjlist", graph_from_adj_list)
+#' @export graph.atlas
+deprecated("graph.atlas", graph_from_atlas)
+#' @export graph.automorphisms
+deprecated("graph.automorphisms", automorphisms)
+#' @export graph.bfs
+deprecated("graph.bfs", bfs)
+#' @export graph.bipartite
+deprecated("graph.bipartite", make_bipartite_graph)
+#' @export graph.cohesion
+deprecated("graph.cohesion", cohesion)
+#' @export graph.complementer
+deprecated("graph.complementer", complementer)
+#' @export graph.compose
+deprecated("graph.compose", compose)
+#' @export graph.coreness
+deprecated("graph.coreness", coreness)
+#' @export graph.data.frame
+deprecated("graph.data.frame", graph_from_data_frame)
+#' @export graph.de.bruijn
+deprecated("graph.de.bruijn", make_de_bruijn_graph)
+#' @export graph.density
+deprecated("graph.density", edge_density)
+#' @export graph.disjoint.union
+deprecated("graph.disjoint.union", disjoint_union)
+#' @export graph.dfs
+deprecated("graph.dfs", dfs)
+#' @export graph.difference
+deprecated("graph.difference", difference)
+#' @export graph.diversity
+deprecated("graph.diversity", diversity)
+#' @export graph.edgelist
+deprecated("graph.edgelist", graph_from_edgelist)
+#' @export graph.eigen
+deprecated("graph.eigen", spectrum)
+#' @export graph.empty
+deprecated("graph.empty", make_empty_graph)
+#' @export graph.extended.chordal.ring
+deprecated("graph.extended.chordal.ring", make_chordal_ring)
+#' @export graph.formula
+deprecated("graph.formula", graph_from_literal)
+#' @export graph.full
+deprecated("graph.full", make_full_graph)
+#' @export graph.full.bipartite
+deprecated("graph.full.bipartite", make_full_bipartite_graph)
+#' @export graph.full.citation
+deprecated("graph.full.citation", make_full_citation_graph)
+#' @export graph.graphdb
+deprecated("graph.graphdb", graph_from_graphdb)
+#' @export graph.incidence
+deprecated("graph.incidence", graph_from_incidence_matrix)
+#' @export graph.isocreate
+deprecated("graph.isocreate", graph_from_isomorphism_class)
+#' @export graph.kautz
+deprecated("graph.kautz", make_kautz_graph)
+#' @export graph.knn
+deprecated("graph.knn", knn)
+#' @export graph.laplacian
+deprecated("graph.laplacian", laplacian_matrix)
+#' @export graph.lattice
+deprecated("graph.lattice", make_lattice)
+#' @export graph.lcf
+deprecated("graph.lcf", graph_from_lcf)
+#' @export graph.maxflow
+deprecated("graph.maxflow", max_flow)
+#' @export graph.mincut
+deprecated("graph.mincut", min_cut)
+#' @export graph.motifs
+deprecated("graph.motifs", motifs)
+#' @export graph.motifs.est
+deprecated("graph.motifs.est", sample_motifs)
+#' @export graph.motifs.no
+deprecated("graph.motifs.no", count_motifs)
+#' @export graph.neighborhood
+deprecated("graph.neighborhood", make_ego_graph)
+#' @export graph.star
+deprecated("graph.star", make_star)
+#' @export graph.strength
+deprecated("graph.strength", strength)
+#' @export graph.tree
+deprecated("graph.tree", make_tree)
+#' @export graph.union
+deprecated("graph.union", union.igraph)
+#' @export graph.ring
+deprecated("graph.ring", make_ring)
+#' @export graphlets.candidate.basis
+deprecated("graphlets.candidate.basis", graphlet_basis)
+#' @export graphlets.project
+deprecated("graphlets.project", graphlet_proj)
+#' @export growing.random.game
+deprecated("growing.random.game", sample_growing)
+#' @export grg.game
+deprecated("grg.game", sample_grg)
+
+#' @export has.multiple
+deprecated("has.multiple", any_multiple)
+#' @export hrg.consensus
+deprecated("hrg.consensus", consensus_tree)
+#' @export hrg.create
+deprecated("hrg.create", hrg)
+#' @export hrg.dendrogram
+deprecated("hrg.dendrogram", hrg_tree)
+#' @export hrg.game
+deprecated("hrg.game", sample_hrg)
+#' @export hrg.fit
+deprecated("hrg.fit", fit_hrg)
+#' @export hrg.predict
+deprecated("hrg.predict", predict_edges)
+#' @export hub.score
+deprecated("hub.score", hub_score)
+
+#' @export igraph.arpack.default
+deprecated("igraph.arpack.default", arpack_defaults)
+#' @export igraph.console
+deprecated("igraph.console", console)
+#' @export igraph.eigen.default
+deprecated("igraph.eigen.default", eigen_defaults)
+#' @export igraph.sample
+deprecated("igraph.sample", sample_seq)
+#' @export igraph.version
+deprecated("igraph.version", igraph_version)
+#' @export igraphdemo
+deprecated("igraphdemo", igraph_demo)
+#' @export igraphtest
+deprecated("igraphtest", igraph_test)
+#' @export independence.number
+deprecated("independence.number", ivs_size)
+#' @export independent.vertex.sets
+deprecated("independent.vertex.sets", ivs)
+#' @export infomap.community
+deprecated("infomap.community", cluster_infomap)
+#' @export induced.subgraph
+deprecated("induced.subgraph", induced_subgraph)
+#' @export interconnected.islands.game
+deprecated("interconnected.islands.game", sample_islands)
+#' @export is.bipartite
+deprecated("is.bipartite", is_bipartite)
+#' @export is.chordal
+deprecated("is.chordal", is_chordal)
+#' @export is.connected
+deprecated("is.connected", is_connected)
+#' @export is.dag
+deprecated("is.dag", is_dag)
+#' @export is.degree.sequence
+deprecated("is.degree.sequence", is_degseq)
+#' @export is.directed
+deprecated("is.directed", is_directed)
+#' @export is.graphical.degree.sequence
+deprecated("is.graphical.degree.sequence", is_graphical)
+#' @export is.hierarchical
+deprecated("is.hierarchical", is_hierarchical)
+#' @export is.igraph
+deprecated("is.igraph", is_igraph)
+#' @export is.loop
+deprecated("is.loop", which_loop)
+#' @export is.matching
+deprecated("is.matching", is_matching)
+#' @export is.maximal.matching
+deprecated("is.maximal.matching", is_max_matching)
+#' @export is.minimal.separator
+deprecated("is.minimal.separator", is_min_separator)
+#' @export is.multiple
+deprecated("is.multiple", which_multiple)
+#' @export is.mutual
+deprecated("is.mutual", which_mutual)
+#' @export is.named
+deprecated("is.named", is_named)
+#' @export is.separator
+deprecated("is.separator", is_separator)
+#' @export is.simple
+deprecated("is.simple", is_simple)
+#' @export is.weighted
+deprecated("is.weighted", is_weighted)
+
+#' @export k.regular.game
+deprecated("k.regular.game", sample_k_regular)
+
+#' @export label.propagation.community
+deprecated("label.propagation.community", cluster_label_prop)
+#' @export largest.cliques
+deprecated("largest.cliques", largest_cliques)
+#' @export largest.independent.vertex.sets
+deprecated("largest.independent.vertex.sets", largest_ivs)
+#' @export lastcit.game
+deprecated("lastcit.game", sample_last_cit)
+#' @export layout.auto
+deprecated("layout.auto", layout_nicely)
+#' @export layout.bipartite
+deprecated("layout.bipartite", layout_as_bipartite)
+#' @export layout.davidson.harel
+deprecated("layout.davidson.harel", layout_with_dh)
+#' @export layout.drl
+deprecated("layout.drl", layout_with_drl)
+#' @export layout.gem
+deprecated("layout.gem", layout_with_gem)
+#' @export layout.graphopt
+deprecated("layout.graphopt", layout_with_graphopt)
+#' @export layout.grid
+deprecated("layout.grid", layout_on_grid)
+#' @export layout.mds
+deprecated("layout.mds", layout_with_mds)
+#' @export layout.merge
+deprecated("layout.merge", merge_coords)
+#' @export layout.norm
+deprecated("layout.norm", norm_coords)
+#' @export layout.star
+deprecated("layout.star", layout_as_star)
+#' @export layout.sugiyama
+deprecated("layout.sugiyama", layout_with_sugiyama)
+#' @export leading.eigenvector.community
+deprecated("leading.eigenvector.community", cluster_leading_eigen)
+#' @export line.graph
+deprecated("line.graph", make_line_graph)
+#' @export list.edge.attributes
+deprecated("list.edge.attributes", edge_attr_names)
+#' @export list.graph.attributes
+deprecated("list.graph.attributes", graph_attr_names)
+#' @export list.vertex.attributes
+deprecated("list.vertex.attributes", vertex_attr_names)
+
+#' @export maxcohesion
+deprecated("maxcohesion", max_cohesion)
+#' @export maximal.cliques
+deprecated("maximal.cliques", max_cliques)
+#' @export maximal.cliques.count
+deprecated("maximal.cliques.count", count_max_cliques)
+#' @export maximal.independent.vertex.sets
+deprecated("maximal.independent.vertex.sets", maximal_ivs)
+#' @export minimal.st.separators
+deprecated("minimal.st.separators", min_st_separators)
+#' @export maximum.bipartite.matching
+deprecated("maximum.bipartite.matching", max_bipartite_match)
+#' @export maximum.cardinality.search
+deprecated("maximum.cardinality.search", max_cardinality)
+#' @export minimum.size.separators
+deprecated("minimum.size.separators", min_separators)
+#' @export minimum.spanning.tree
+deprecated("minimum.spanning.tree", mst)
+#' @export mod.matrix
+deprecated("mod.matrix", modularity_matrix)
+#' @export multilevel.community
+deprecated("multilevel.community", cluster_louvain)
+
+#' @export neighborhood
+deprecated("neighborhood", ego)
+#' @export neighborhood.size
+deprecated("neighborhood.size", ego_size)
+#' @export nexus.get
+deprecated("nexus.get", nexus_get)
+#' @export nexus.info
+deprecated("nexus.info", nexus_info)
+#' @export nexus.list
+deprecated("nexus.list", nexus_list)
+#' @export nexus.search
+deprecated("nexus.search", nexus_search)
+#' @export no.clusters
+deprecated("no.clusters", count_components)
+
+#' @export optimal.community
+deprecated("optimal.community", cluster_optimal)
+
+#' @export page.rank
+deprecated("page.rank", page_rank)
+#' @export page.rank.old
+deprecated("page.rank.old", page_rank_old)
+#' @export path.length.hist
+deprecated("path.length.hist", distance_table)
+#' @export permute.vertices
+deprecated("permute.vertices", permute)
+#' @export piecewise.layout
+deprecated("piecewise.layout", layout_components)
+#' @export plotHierarchy
+deprecated("plotHierarchy", plot_hierarchy)
+#' @export power.law.fit
+deprecated("power.law.fit", fit_power_law)
+#' @export preference.game
+deprecated("preference.game", sample_pref)
+
+#' @export read.graph
+deprecated("read.graph", read_graph)
+#' @export remove.edge.attribute
+deprecated("remove.edge.attribute", delete_edge_attr)
+#' @export remove.graph.attribute
+deprecated("remove.graph.attribute", delete_graph_attr)
+#' @export remove.vertex.attribute
+deprecated("remove.vertex.attribute", delete_vertex_attr)
+#' @export running.mean
+deprecated("running.mean", running_mean)
+
+#' @export sbm.game
+deprecated("sbm.game", sample_sbm)
+#' @export scgGrouping
+deprecated("scgGrouping", scg_group)
+#' @export scgNormEps
+deprecated("scgNormEps", scg_eps)
+#' @export scgSemiProjectors
+deprecated("scgSemiProjectors", scg_semi_proj)
+#' @export set.edge.attribute
+deprecated("set.edge.attribute", set_edge_attr)
+#' @export set.graph.attribute
+deprecated("set.graph.attribute", set_graph_attr)
+#' @export set.vertex.attribute
+deprecated("set.vertex.attribute", set_vertex_attr)
+#' @export shortest.paths
+deprecated("shortest.paths", distances)
+#' @export showtrace
+deprecated("showtrace", show_trace)
+#' @export spinglass.community
+deprecated("spinglass.community", cluster_spinglass)
+#' @export stCuts
+deprecated("stCuts", st_cuts)
+#' @export stMincuts
+deprecated("stMincuts", st_min_cuts)
+#' @export static.fitness.game
+deprecated("static.fitness.game", sample_fitness)
+#' @export static.power.law.game
+deprecated("static.power.law.game", sample_fitness_pl)
+#' @export subgraph.centrality
+deprecated("subgraph.centrality", subgraph_centrality)
+
+#' @export tkplot.canvas
+deprecated("tkplot.canvas", tk_canvas)
+#' @export tkplot.center
+deprecated("tkplot.center", tk_center)
+#' @export tkplot.close
+deprecated("tkplot.close", tk_close)
+#' @export tkplot.export.postscript
+deprecated("tkplot.export.postscript", tk_postscript)
+#' @export tkplot.fit.to.screen
+deprecated("tkplot.fit.to.screen", tk_fit)
+#' @export tkplot.getcoords
+deprecated("tkplot.getcoords", tk_coords)
+#' @export tkplot.off
+deprecated("tkplot.off", tk_off)
+#' @export tkplot.reshape
+deprecated("tkplot.reshape", tk_reshape)
+#' @export tkplot.rotate
+deprecated("tkplot.rotate", tk_rotate)
+#' @export tkplot.setcoords
+deprecated("tkplot.setcoords", tk_set_coords)
+
+#' @export topological.sort
+deprecated("topological.sort", topo_sort)
+#' @export triad.census
+deprecated("triad.census", triad_census)
+
+#' @export unfold.tree
+deprecated("unfold.tree", unfold_tree)
+
+#' @export vcount
+deprecated("vcount", gorder)
+#' @export vertex.connectivity
+deprecated("vertex.connectivity", vertex_connectivity)
+#' @export vertex.disjoint.paths
+deprecated("vertex.disjoint.paths", vertex_disjoint_paths)
+
+#' @export walktrap.community
+deprecated("walktrap.community", cluster_walktrap)
+#' @export watts.strogatz.game
+deprecated("watts.strogatz.game", sample_smallworld)
+#' @export write.graph
+deprecated("write.graph", write_graph)
+#' @export graph.famous
+deprecated("graph.famous", make_famous_graph)
+#' @export igraph.from.graphNEL
+deprecated("igraph.from.graphNEL", graph_from_graphnel)
+#' @export igraph.to.graphNEL
+deprecated("igraph.to.graphNEL", as_graphnel)
+#' @export getIgraphOpt
+deprecated("getIgraphOpt", igraph_opt)
+#' @export igraph.options
+deprecated("igraph.options", igraph_options)
+#' @export graph.intersection
+deprecated("graph.intersection", intersection)
+#' @export exportPajek
+deprecated("exportPajek", export_pajek)
+#' @export get.diameter
+deprecated("get.diameter", get_diameter)
+#' @export get.all.shortest.paths
+deprecated("get.all.shortest.paths", all_shortest_paths)
+#' @export get.shortest.paths
+deprecated("get.shortest.paths", shortest_paths)
+#' @export graph
+deprecated("graph", make_graph)
+#' @export vertex.shapes
+deprecated("vertex.shapes", shapes)
+#' @export igraph.shape.noclip
+deprecated("igraph.shape.noclip", shape_noclip)
+#' @export igraph.shape.noplot
+deprecated("igraph.shape.noplot", shape_noplot)
+#' @export create.communities
+deprecated("create.communities", make_clusters)
diff --git a/configure b/configure
index 1f0ce63..568ff62 100755
--- a/configure
+++ b/configure
@@ -1926,6 +1926,63 @@ fi
 
 } # ac_fn_c_check_header_mongrel
 
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$4=yes"
+else
+  eval "$4=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$4
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_member
+
 # ac_fn_cxx_try_link LINENO
 # -------------------------
 # Try to link conftest.$ac_ext, and return whether this succeeded.
@@ -4302,6 +4359,42 @@ fi
 
 
 
+for ac_header in  \
+		   net/if.h \
+		   netinet/in.h \
+		   net/if_dl.h \
+		   sys/sockio.h \
+		   sys/un.h \
+		   sys/socket.h \
+		   sys/ioctl.h \
+		   sys/time.h \
+		   sys/file.h \
+
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#include <sys/types.h>
+	 #include <sys/socket.h>
+"
+if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then :
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_SA_LEN 1
+_ACEOF
+
+fi
+
+
 graphml_support=yes
 # Check whether --enable-graphml was given.
 if test "${enable_graphml+set}" = set; then :
@@ -4526,7 +4619,7 @@ GLPK_LIBS=""
 $as_echo "#define IGRAPH_THREAD_LOCAL /**/" >>confdefs.h
 
 
-ac_config_files="$ac_config_files src/Makevars"
+ac_config_files="$ac_config_files src/Makevars.tmp:src/Makevars.in"
 
 
 cat >confcache <<\_ACEOF
@@ -5219,7 +5312,7 @@ for ac_config_target in $ac_config_targets
 do
   case $ac_config_target in
     "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;;
-    "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;;
+    "src/Makevars.tmp") CONFIG_FILES="$CONFIG_FILES src/Makevars.tmp:src/Makevars.in" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
@@ -5765,6 +5858,24 @@ $as_echo "$as_me: $ac_file is unchanged" >&6;}
 
   esac
 
+
+  case $ac_file$ac_mode in
+    "src/Makevars.tmp":F)
+    if test -f src/Makevars && cmp -s src/Makevars.tmp src/Makevars; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating src/Makevars" >&5
+$as_echo "$as_me: creating src/Makevars" >&6;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: src/Makevars is unchanged" >&5
+$as_echo "$as_me: src/Makevars is unchanged" >&6;}
+      rm src/Makevars.tmp
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: creating src/Makevars" >&5
+$as_echo "$as_me: creating src/Makevars" >&6;}
+      mv src/Makevars.tmp src/Makevars
+    fi
+
+ ;;
+
+  esac
 done # for ac_tag
 
 
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..ab578ed
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,146 @@
+AC_INIT(igraph, @VERSION@, csardi.gabor at gmail.com)
+AC_CONFIG_SRCDIR(src/rinterface.c)
+AC_CONFIG_HEADERS(src/config.h)
+
+: ${R_HOME=`R RHOME`}
+if test -z "${R_HOME}"; then
+   echo "could not determine R_HOME"
+   exit 1
+fi
+CC=`"${R_HOME}/bin/R" CMD config CC`
+CXX=`"${R_HOME}/bin/R" CMD config CXX`
+FC=`"${R_HOME}/bin/R" CMD config FC`
+CFLAGS=`"${R_HOME}/bin/R" CMD config CFLAGS`
+CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXXFLAGS`
+CPPFLAGS=`"${R_HOME}/bin/R" CMD config CPPFLAGS`
+FCFLAGS=`"${R_HOME}/bin/R" CMD config FCFLAGS`
+FLIBS=`"${R_HOME}/bin/R" CMD config FLIBS`
+
+AC_LANG(C)
+AC_PROG_CC
+
+# Fortran compiler, we need to check if it is the GNU compiler
+AC_PROG_FC
+if test "x$ac_cv_fc_compiler_gnu" == xyes; then
+  AC_DEFINE([HAVE_GFORTRAN], [1], [Define to 1 if using the GNU fortran compiler])
+fi
+
+
+# Tricky check for C++ compiler, because Autoconf has a weird bug:
+# http://lists.gnu.org/archive/html/autoconf/2006-03/msg00067.html
+AC_PROG_CXX
+AC_LANG_PUSH([C++])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <iostream>
+const char hw[] = "Hello, World\n";]],
+                [[std::cout << hw;]])],
+        [AC_PROG_CXXCPP
+        cxx_error=no],
+        [AC_MSG_ERROR([no C++ compiler found or it cannot create executables])])
+AC_LANG_POP([C++])
+
+LIBS_SAVE=$LIBS
+LIBS="$LIBS -lm"
+AC_CHECK_FUNCS([rintf finite expm1 rint log2 logbl snprintf log1p round fmin stpcpy])
+AC_CHECK_DECL([stpcpy],
+	[AC_DEFINE([HAVE_STPCPY_SIGNATURE], [1], [Define to 1 if the stpcpy function has a signature])])
+LIBS=$LIBS_SAVE
+
+AC_CHECK_HEADER([sys/times.h], 
+      [AC_DEFINE([HAVE_TIMES_H], [1], [Define to 1 if you have the sys/times.h header])])
+
+AC_CHECK_HEADERS([ \
+		   net/if.h \
+		   netinet/in.h \
+		   net/if_dl.h \
+		   sys/sockio.h \
+		   sys/un.h \
+		   sys/socket.h \
+		   sys/ioctl.h \
+		   sys/time.h \
+		   sys/file.h \
+		])
+
+AC_CHECK_MEMBER([struct sockaddr.sa_len],
+		AC_DEFINE_UNQUOTED([HAVE_SA_LEN], [1], [Define if struct sockaddr contains sa_len]), [],
+	[#include <sys/types.h>
+	 #include <sys/socket.h>])
+
+graphml_support=yes
+AC_ARG_ENABLE(graphml,
+              AC_HELP_STRING([--disable-graphml], [Disable support for GraphML format]),
+              [graphml_support=$enableval], [graphml_support=yes])
+
+HAVE_LIBXML=0
+if test $graphml_support = yes; then
+  AC_PATH_PROG([XML2CONFIG], [xml2-config], [none])
+  if test "$XML2CONFIG" = "none"; then
+    graphml_support=no
+  else
+    XML2_LIBS=`$XML2CONFIG --libs`
+    XML2_CFLAGS=`$XML2CONFIG --cflags`
+    AC_CHECK_LIB([xml2], [xmlSAXUserParseFile], [
+      OLDCFLAGS=${CFLAGS}
+      OLDCPPFLAGS=${CPPFLAGS}
+      CFLAGS=${XML2_CFLAGS}
+      CPPFLAGS=${XML2_CFLAGS}
+      AC_CHECK_HEADER([libxml/parser.h], [
+        HAVE_LIBXML=1
+	AC_DEFINE([HAVE_LIBXML], [1], [Define to 1 if you have the libxml2 libraries installed])
+        CFLAGS="${OLDCFLAGS} ${XML2_CFLAGS}"
+	CPPFLAGS="${OLDCFLAGS} ${XML2_CFLAGS}"
+	AC_SUBST(XML2_LIBS)
+	AC_SUBST(XML2_CFLAGS)
+      ], [
+        graphml_support=no
+        CFLAGS=${OLDCFLAGS}
+	CPPFLAGS=${OLDCPPFLAGS}
+      ])
+    ], [
+      graphml_support=no
+    ])
+  fi
+fi
+AC_SUBST(HAVE_LIBXML)
+
+AC_LANG_PUSH([C++])
+HAVE_GMP=0
+GMP_LIBS=""
+gmp_support=no
+AC_ARG_ENABLE(gmp, AC_HELP_STRING([--disable-gmp], [Compile without the GMP library]))
+if test "x$enable_gmp" != "xno"; then
+  AC_CHECK_LIB([gmp], [__gmpz_add], [
+    AC_CHECK_HEADER([gmp.h], [
+      HAVE_GMP=1
+      AC_DEFINE([HAVE_GMP], [1], [Define to 1 if you have the GMP library])
+      gmp_support=yes
+      GMP_LIBS="-lgmp"      
+    ])
+  ])
+fi
+AC_SUBST(HAVE_GMP)
+AC_SUBST(GMP_LIBS)
+AC_LANG_POP([C++])
+
+glpk_support=yes
+AC_DEFINE([HAVE_GLPK], [1], [Define to 1 if you have the GLPK library])
+HAVE_GLPK=1
+GLPK_LIBS=""
+AC_SUBST(HAVE_GLPK)
+AC_SUBST(GLPK_LIBS)
+
+AC_DEFINE(IGRAPH_THREAD_LOCAL, [], [We don't care about thread-local storage in R])
+
+AC_CONFIG_FILES([src/Makevars.tmp:src/Makevars.in], [
+    if test -f src/Makevars && cmp -s src/Makevars.tmp src/Makevars; then
+      AC_MSG_NOTICE([creating src/Makevars])
+      AC_MSG_NOTICE([src/Makevars is unchanged])
+      rm src/Makevars.tmp
+    else
+      AC_MSG_NOTICE([creating src/Makevars])
+      mv src/Makevars.tmp src/Makevars
+    fi
+  ]
+)
+
+AC_OUTPUT
diff --git a/configure.in b/configure.in
deleted file mode 100644
index 703e4bd..0000000
--- a/configure.in
+++ /dev/null
@@ -1,119 +0,0 @@
-AC_INIT(igraph, @VERSION@, csardi.gabor at gmail.com)
-AC_CONFIG_SRCDIR(src/rinterface.c)
-AC_CONFIG_HEADERS(src/config.h)
-
-: ${R_HOME=`R RHOME`}
-if test -z "${R_HOME}"; then
-   echo "could not determine R_HOME"
-   exit 1
-fi
-CC=`"${R_HOME}/bin/R" CMD config CC`
-CXX=`"${R_HOME}/bin/R" CMD config CXX`
-FC=`"${R_HOME}/bin/R" CMD config FC`
-CFLAGS=`"${R_HOME}/bin/R" CMD config CFLAGS`
-CXXFLAGS=`"${R_HOME}/bin/R" CMD config CXXFLAGS`
-CPPFLAGS=`"${R_HOME}/bin/R" CMD config CPPFLAGS`
-FCFLAGS=`"${R_HOME}/bin/R" CMD config FCFLAGS`
-FLIBS=`"${R_HOME}/bin/R" CMD config FLIBS`
-
-AC_LANG(C)
-AC_PROG_CC
-
-# Fortran compiler, we need to check if it is the GNU compiler
-AC_PROG_FC
-if test "x$ac_cv_fc_compiler_gnu" == xyes; then
-  AC_DEFINE([HAVE_GFORTRAN], [1], [Define to 1 if using the GNU fortran compiler])
-fi
-
-
-# Tricky check for C++ compiler, because Autoconf has a weird bug:
-# http://lists.gnu.org/archive/html/autoconf/2006-03/msg00067.html
-AC_PROG_CXX
-AC_LANG_PUSH([C++])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
-#include <iostream>
-const char hw[] = "Hello, World\n";]],
-                [[std::cout << hw;]])],
-        [AC_PROG_CXXCPP
-        cxx_error=no],
-        [AC_MSG_ERROR([no C++ compiler found or it cannot create executables])])
-AC_LANG_POP([C++])
-
-LIBS_SAVE=$LIBS
-LIBS="$LIBS -lm"
-AC_CHECK_FUNCS([rintf finite expm1 rint log2 logbl snprintf log1p round fmin stpcpy])
-AC_CHECK_DECL([stpcpy],
-	[AC_DEFINE([HAVE_STPCPY_SIGNATURE], [1], [Define to 1 if the stpcpy function has a signature])])
-LIBS=$LIBS_SAVE
-
-AC_CHECK_HEADER([sys/times.h], 
-      [AC_DEFINE([HAVE_TIMES_H], [1], [Define to 1 if you have the sys/times.h header])])
-
-graphml_support=yes
-AC_ARG_ENABLE(graphml,
-              AC_HELP_STRING([--disable-graphml], [Disable support for GraphML format]),
-              [graphml_support=$enableval], [graphml_support=yes])
-
-HAVE_LIBXML=0
-if test $graphml_support = yes; then
-  AC_PATH_PROG([XML2CONFIG], [xml2-config], [none])
-  if test "$XML2CONFIG" = "none"; then
-    graphml_support=no
-  else
-    XML2_LIBS=`$XML2CONFIG --libs`
-    XML2_CFLAGS=`$XML2CONFIG --cflags`
-    AC_CHECK_LIB([xml2], [xmlSAXUserParseFile], [
-      OLDCFLAGS=${CFLAGS}
-      OLDCPPFLAGS=${CPPFLAGS}
-      CFLAGS=${XML2_CFLAGS}
-      CPPFLAGS=${XML2_CFLAGS}
-      AC_CHECK_HEADER([libxml/parser.h], [
-        HAVE_LIBXML=1
-	AC_DEFINE([HAVE_LIBXML], [1], [Define to 1 if you have the libxml2 libraries installed])
-        CFLAGS="${OLDCFLAGS} ${XML2_CFLAGS}"
-	CPPFLAGS="${OLDCFLAGS} ${XML2_CFLAGS}"
-	AC_SUBST(XML2_LIBS)
-	AC_SUBST(XML2_CFLAGS)
-      ], [
-        graphml_support=no
-        CFLAGS=${OLDCFLAGS}
-	CPPFLAGS=${OLDCPPFLAGS}
-      ])
-    ], [
-      graphml_support=no
-    ])
-  fi
-fi
-AC_SUBST(HAVE_LIBXML)
-
-AC_LANG_PUSH([C++])
-HAVE_GMP=0
-GMP_LIBS=""
-gmp_support=no
-AC_ARG_ENABLE(gmp, AC_HELP_STRING([--disable-gmp], [Compile without the GMP library]))
-if test "x$enable_gmp" != "xno"; then
-  AC_CHECK_LIB([gmp], [__gmpz_add], [
-    AC_CHECK_HEADER([gmp.h], [
-      HAVE_GMP=1
-      AC_DEFINE([HAVE_GMP], [1], [Define to 1 if you have the GMP library])
-      gmp_support=yes
-      GMP_LIBS="-lgmp"      
-    ])
-  ])
-fi
-AC_SUBST(HAVE_GMP)
-AC_SUBST(GMP_LIBS)
-AC_LANG_POP([C++])
-
-glpk_support=yes
-AC_DEFINE([HAVE_GLPK], [1], [Define to 1 if you have the GLPK library])
-HAVE_GLPK=1
-GLPK_LIBS=""
-AC_SUBST(HAVE_GLPK)
-AC_SUBST(GLPK_LIBS)
-
-AC_DEFINE(IGRAPH_THREAD_LOCAL, [], [We don't care about thread-local storage in R])
-
-AC_CONFIG_FILES([src/Makevars])
-
-AC_OUTPUT
diff --git a/demo/centrality.R b/demo/centrality.R
index 5c56c76..3605ff9 100644
--- a/demo/centrality.R
+++ b/demo/centrality.R
@@ -1,21 +1,17 @@
 
-pause <- function() {
-  cat("Press ENTER/RETURN/NEWLINE to continue.")
-  readLines(n=1)
-  invisible()
-}
+pause <- function() {}
 
 ### Traditional approaches: degree, closeness, betweenness
-g <- graph.formula(Andre----Beverly:Diane:Fernando:Carol,
-                   Beverly--Andre:Diane:Garth:Ed,
-                   Carol----Andre:Diane:Fernando,
-                   Diane----Andre:Carol:Fernando:Garth:Ed:Beverly,
-                   Ed-------Beverly:Diane:Garth,
-                   Fernando-Carol:Andre:Diane:Garth:Heather,
-                   Garth----Ed:Beverly:Diane:Fernando:Heather,
-                   Heather--Fernando:Garth:Ike,
-                   Ike------Heather:Jane,
-                   Jane-----Ike )
+g <- graph_from_literal(Andre----Beverly:Diane:Fernando:Carol,
+               Beverly--Andre:Diane:Garth:Ed,
+               Carol----Andre:Diane:Fernando,
+               Diane----Andre:Carol:Fernando:Garth:Ed:Beverly,
+               Ed-------Beverly:Diane:Garth,
+               Fernando-Carol:Andre:Diane:Garth:Heather,
+               Garth----Ed:Beverly:Diane:Fernando:Heather,
+               Heather--Fernando:Garth:Ike,
+               Ike------Heather:Jane,
+               Jane-----Ike )
 
 pause()
 
@@ -65,24 +61,24 @@ plotG(g)
 pause()
 
 ### Eigenvector centrality
-V(g)$label <- paste(sep="\n", V(g)$name, round(evcent(g)$vector, 2))
+V(g)$label <- paste(sep="\n", V(g)$name, round(eigen_centrality(g)$vector, 2))
 plotG(g)
 
 pause()
 
 ### PageRank
-V(g)$label <- paste(sep="\n", V(g)$name, round(page.rank(g)$vector, 2))
+V(g)$label <- paste(sep="\n", V(g)$name, round(page_rank(g)$vector, 2))
 plotG(g)
 
 pause()
 
 ### Correlation between centrality measures
-karate <- graph.famous("Zachary")
+karate <- make_graph("Zachary")
 cent <- list(`Degree`=degree(g),
              `Closeness`=closeness(g),
              `Betweenness`=betweenness(g),
-             `Eigenvector`=evcent(g)$vector,
-             `PageRank`=page.rank(g)$vector)
+             `Eigenvector`=eigen_centrality(g)$vector,
+             `PageRank`=page_rank(g)$vector)
 
 pause()
 
@@ -108,32 +104,32 @@ pause()
 ## pause()
 
 ## ### Is it a simple graph?
-## is.simple(jg)
+## is_simple(jg)
 
 ## pause()
 
 ## ### Is it connected?
-## is.connected(jg)
+## is_connected(jg)
 
 ## pause()
 
 ## ### How many components?
-## no.clusters(jg)
+## count_components(jg)
 
 ## pause()
 
 ## ### How big are these?
-## table(clusters(jg)$csize)
+## table(components(jg)$csize)
 
 ## pause()
 
 ## ### In-degree distribution
-## plot(degree.distribution(jg, mode="in"), log="xy")
+## plot(degree_distribution(jg, mode="in"), log="xy")
 
 ## pause()
 
 ## ### Out-degree distribution
-## plot(degree.distribution(jg, mode="out"), log="xy")
+## plot(degree_distribution(jg, mode="out"), log="xy")
 
 ## pause()
 
@@ -145,7 +141,7 @@ pause()
 ## pause()
 
 ## ### Density
-## graph.density(jg)
+## density(jg)
 
 ## pause()
 
@@ -155,26 +151,26 @@ pause()
 ## pause()
 
 ## ### Transitivity of a random graph of the same size
-## g <- erdos.renyi.game(vcount(jg), ecount(jg), type="gnm")
+## g <- sample_gnm(vcount(jg), ecount(jg))
 ## transitivity(g)
 
 ## pause()
 
 ## ### Transitivity of a random graph with the same degree distribution
-## g <- degree.sequence.game(degree(jg, mode="out"), degree(jg, mode="in"),
+## g <- sample_degseq(degree(jg, mode="out"), degree(jg, mode="in"),
 ##                           method="simple")
 ## transitivity(g)
 
 ## pause()
 
 ## ### Authority and Hub scores
-## AS <- authority.score(jg)$vector
-## HS <- hub.score(jg)$vector
+## AS <- authority_score(jg)$vector
+## HS <- hub_score(jg)$vector
 
 ## pause()
 
 ## ### Time evolution of authority scores
-## AS <- authority.score(jg)$vector
+## AS <- authority_score(jg)$vector
 ## center <- which.max(AS)
 ## startyear <- V(jg)[center]$year
 
@@ -185,7 +181,7 @@ pause()
 ##   print(y)
 ##   keep <- which(V(jg)$year <= y)
 ##   g2 <- subgraph(jg, keep)
-##   as <- abs(authority.score(g2, scale=FALSE)$vector)
+##   as <- abs(authority_score(g2, scale=FALSE)$vector)
 ##   w <- match(V(jg)[center]$usid, V(g2)$usid)
 ##   as[w]
 ## }
diff --git a/demo/cohesive.R b/demo/cohesive.R
index 7fdc033..d4af205 100644
--- a/demo/cohesive.R
+++ b/demo/cohesive.R
@@ -1,27 +1,23 @@
 
-pause <- function() {
-  cat("Press ENTER/RETURN/NEWLINE to continue.")
-  readLines(n=1)
-  invisible()
-}
+pause <- function() {}
 
 ### The Zachary Karate club network
 
-karate <- graph.famous("Zachary")
+karate <- make_graph("Zachary")
 summary(karate)
 
 pause()
 
 ### Create a layout that is used from now on
 
-karate$layout <- layout.auto(karate)
+karate$layout <- layout_nicely(karate)
 plot(karate)
 
 pause()
 
 ### Run cohesive blocking on it
 
-cbKarate <- cohesive.blocks(karate)
+cbKarate <- cohesive_blocks(karate)
 cbKarate
 
 pause()
@@ -36,7 +32,7 @@ pause()
 ### See the hierarchy tree first
 
 hierarchy(cbKarate)
-plotHierarchy(cbKarate)
+plot_hierarchy(cbKarate)
 
 ## Plot the first level, blocks 1 & 2
 
diff --git a/demo/community.R b/demo/community.R
index 1f89225..1567b06 100644
--- a/demo/community.R
+++ b/demo/community.R
@@ -1,19 +1,15 @@
 
-pause <- function() {
-  cat("Press ENTER/RETURN/NEWLINE to continue.")
-  readLines(n=1)
-  invisible()
-}
+pause <- function() {}
 
 ### A modular graph has dense subgraphs
-mod <- graph.full(10) %du% graph.full(10) %du% graph.full(10)
+mod <- make_full_graph(10) %du% make_full_graph(10) %du% make_full_graph(10)
 perfect <- c(rep(1,10), rep(2,10), rep(3,10))
 perfect
 
 pause()
 
 ### Plot it with community (=component) colors
-plot(mod, vertex.color=perfect, layout=layout.fruchterman.reingold)
+plot(mod, vertex.color=perfect, layout=layout_with_fr)
 
 pause()
 
@@ -33,13 +29,13 @@ modularity(mod, c(rep(1, 10), rep(2,20)))
 pause()
 
 ### A real little network, Zachary's karate club data
-karate <- graph.famous("Zachary")
-karate$layout <- layout.kamada.kawai(karate, niter=1000)
+karate <- make_graph("Zachary")
+karate$layout <- layout_with_kk(karate, niter=1000)
 
 pause()
 
 ### Greedy algorithm
-fc <- fastgreedy.community(karate)
+fc <- cluster_fast_greedy(karate)
 memb <- membership(fc)
 plot(karate, vertex.color=memb)
   
@@ -60,13 +56,13 @@ diag(pref.mat) <- diag(pref.mat) + 10/31
 pause()
 
 ### Create the network with the given vertex preferences
-G <- preference.game(128*4, types=16, pref.matrix=pref.mat)
+G <- sample_pref(128*4, types=16, pref.matrix=pref.mat)
 
 pause()
 
 ### Run spinglass community detection with two gamma parameters
-sc1 <- spinglass.community(G, spins=4, gamma=1.0)
-sc2.2 <- spinglass.community(G, spins=16, gamma=2.2)
+sc1 <- cluster_spinglass(G, spins=4, gamma=1.0)
+sc2.2 <- cluster_spinglass(G, spins=16, gamma=2.2)
 
 pause()
 
@@ -76,7 +72,7 @@ if (require(Matrix)) {
 } else {
   myimage <- image
 }
-A <- get.adjacency(G)
+A <- as_adj(G)
 myimage(A)
 
 pause()
@@ -104,45 +100,45 @@ communities <- list()
 
 pause()
 
-### edge.betweenness.community
-ebc <- edge.betweenness.community(karate)
+### cluster_edge_betweenness
+ebc <- cluster_edge_betweenness(karate)
 communities$`Edge betweenness` <- ebc
 
 pause()
 
-### fastgreedy.community
-fc <- fastgreedy.community(karate)
+### cluster_fast_greedy
+fc <- cluster_fast_greedy(karate)
 communities$`Fast greedy` <- fc
 
 pause()
 
-### leading.eigenvector.community
-lec <- leading.eigenvector.community(karate)
+### cluster_leading_eigen
+lec <- cluster_leading_eigen(karate)
 communities$`Leading eigenvector` <- lec
 
 pause()
 
-### spinglass.community
-sc <- spinglass.community(karate, spins=10)
+### cluster_spinglass
+sc <- cluster_spinglass(karate, spins=10)
 communities$`Spinglass` <- sc
 
 pause()
 
-### walktrap.community
-wt <- walktrap.community(karate)
+### cluster_walktrap
+wt <- cluster_walktrap(karate)
 communities$`Walktrap` <- wt
 
 pause()
 
-### label.propagation.community
-labprop <- label.propagation.community(karate)
+### cluster_label_prop
+labprop <- cluster_label_prop(karate)
 communities$`Label propagation` <- labprop
 
 pause()
 
 ### Plot everything
 layout(rbind(1:3, 4:6))
-coords <- layout.kamada.kawai(karate)
+coords <- layout_with_kk(karate)
 lapply(seq_along(communities), function(x) {
   m <- modularity(communities[[x]])
   par(mar=c(1,1,3,1))
@@ -168,7 +164,7 @@ clique.community <- function(graph, k) {
   clq.graph <- simplify(graph(edges))
   V(clq.graph)$name <- 
     seq(length=vcount(clq.graph))
-  comps <- decompose.graph(clq.graph)
+  comps <- decompose(clq.graph)
   
   lapply(comps, function(x) {
     unique(unlist(clq[ V(x)$name ]))
@@ -179,13 +175,13 @@ pause()
 
 ### Apply it to a graph, this is the example graph from
 ##  the original publication
-g <- graph.formula(A-B:F:C:E:D, B-A:D:C:E:F:G, C-A:B:F:E:D, D-A:B:C:F:E,
-                   E-D:A:C:B:F:V:W:U, F-H:B:A:C:D:E, G-B:J:K:L:H,
-                   H-F:G:I:J:K:L, I-J:L:H, J-I:G:H:L, K-G:H:L:M,
-                   L-H:G:I:J:K:M, M-K:L:Q:R:S:P:O:N, N-M:Q:R:P:S:O,
-                   O-N:M:P, P-Q:M:N:O:S, Q-M:N:P:V:U:W:R, R-M:N:V:W:Q,
-                   S-N:P:M:U:W:T, T-S:V:W:U, U-E:V:Q:S:W:T,
-                   V-E:U:W:T:R:Q, W-U:E:V:Q:R:S:T)
+g <- graph_from_literal(A-B:F:C:E:D, B-A:D:C:E:F:G, C-A:B:F:E:D, D-A:B:C:F:E,
+               E-D:A:C:B:F:V:W:U, F-H:B:A:C:D:E, G-B:J:K:L:H,
+               H-F:G:I:J:K:L, I-J:L:H, J-I:G:H:L, K-G:H:L:M,
+               L-H:G:I:J:K:M, M-K:L:Q:R:S:P:O:N, N-M:Q:R:P:S:O,
+               O-N:M:P, P-Q:M:N:O:S, Q-M:N:P:V:U:W:R, R-M:N:V:W:Q,
+               S-N:P:M:U:W:T, T-S:V:W:U, U-E:V:Q:S:W:T,
+               V-E:U:W:T:R:Q, W-U:E:V:Q:R:S:T)
 
 pause()
 
diff --git a/demo/crashR.R b/demo/crashR.R
index df579b5..aba9cb6 100644
--- a/demo/crashR.R
+++ b/demo/crashR.R
@@ -1,9 +1,5 @@
 
-pause <- function() {
-  cat("Press ENTER/RETURN/NEWLINE to continue.")
-  readLines(n=1)
-  invisible()
-}
+pause <- function() {}
 
 ### R objects, (real) numbers
 a <- 3
@@ -186,8 +182,8 @@ g2
 pause()
 
 ### Is this object an igraph graph?
-is.igraph(g)
-is.igraph(1:10)
+is_igraph(g)
+is_igraph(1:10)
 
 pause()
 
@@ -199,8 +195,8 @@ ecount(g)
 pause()
 
 ### Is the graph directed?
-is.directed(g)
-is.directed(g2)
+is_directed(g)
+is_directed(g2)
 
 pause()
 
@@ -218,14 +214,14 @@ pause()
 g <- graph( c(1,2,1,2, 1,3, 2,3, 4,5), n=5 )
 g
 
-is.simple(g)
-is.multiple(g)
+is_simple(g)
+which_multiple(g)
 
 pause()
 
 ### Remove multiple edges
 g <- simplify(g)
-is.simple(g)
+is_simple(g)
 
 pause()
 
@@ -233,19 +229,19 @@ pause()
 g <- graph( c(1,1,1,2, 1,3, 2,3, 4,5), n=5 )
 g
 
-is.simple(g)
-is.loop(g)
+is_simple(g)
+which_loop(g)
 
 pause()
 
 ### Remove loop edges
 g <- simplify(g)
-is.simple(g)
+is_simple(g)
 
 pause()
 
 ### Naming vertices
-g <- graph.ring(10)
+g <- make_ring(10)
 V(g)$name <- letters[1:10]
 V(g)$name
 g
@@ -254,44 +250,44 @@ print(g, v=T)
 pause()
 
 ### Create undirected example graph
-g2 <- graph.formula(Alice-Bob:Cecil:Daniel, 
-                    Cecil:Daniel-Eugene:Gordon )
+g2 <- graph_from_literal(Alice-Bob:Cecil:Daniel, 
+                Cecil:Daniel-Eugene:Gordon )
 print(g2, v=T)
 
 pause()
 
 ### Remove Alice
-g3 <- delete.vertices(g2, match("Alice", V(g2)$name))
+g3 <- delete_vertices(g2, match("Alice", V(g2)$name))
 
 pause()
 
 ### Add three new vertices
-g4 <- add.vertices(g3, 3)
+g4 <- add_vertices(g3, 3)
 print(g4, v=T)
-igraph.options(print.vertex.attributes=TRUE, 
-               plot.layout=layout.fruchterman.reingold)
+igraph_options(print.vertex.attributes=TRUE, 
+               plot.layout=layout_with_fr)
 g4
 plot(g4)                      
 
 pause()
 
 ### Add three new vertices, with names this time
-g4 <- add.vertices(g3, 3, attr=list(name=c("Helen", "Ike", "Jane")))
+g4 <- add_vertices(g3, 3, attr=list(name=c("Helen", "Ike", "Jane")))
 g4
 
 pause()
 
 ### Add some edges as well
-g4 <- add.edges(g4, match(c("Helen", "Jane", "Ike", "Jane"), V(g4)$name ))
+g4 <- add_edges(g4, match(c("Helen", "Jane", "Ike", "Jane"), V(g4)$name ))
 g4
 
 pause()
 
 ### Edge sequences, first create a directed example graph
-g2 <- graph.formula(Alice -+ Bob:Cecil:Daniel, 
-                    Cecil:Daniel +-+ Eugene:Gordon )
+g2 <- graph_from_literal(Alice -+ Bob:Cecil:Daniel, 
+                Cecil:Daniel +-+ Eugene:Gordon )
 print(g2, v=T)
-plot(g2, layout=layout.kamada.kawai, vertex.label=V(g2)$name)
+plot(g2, layout=layout_with_kk, vertex.label=V(g2)$name)
 
 pause()
 
@@ -306,7 +302,7 @@ E(g2, P=c(1,2))
 pause()
 
 ### Delete this edge
-g3 <- delete.edges(g2, E(g2, P=c(1,2)))
+g3 <- delete_edges(g2, E(g2, P=c(1,2)))
 g3
 
 pause()
diff --git a/demo/hrg.R b/demo/hrg.R
index c5809b1..e9d9b42 100644
--- a/demo/hrg.R
+++ b/demo/hrg.R
@@ -1,9 +1,5 @@
 
-pause <- function() {
-  cat("Press ENTER/RETURN/NEWLINE to continue.")
-  readLines(n=1)
-  invisible()
-}
+pause <- function() {}
 
 ### Download the Zachary Karate Club network from Nexus
 
@@ -14,7 +10,7 @@ pause()
 
 ### Optimalize modularity
 
-optcom <- optimal.community(karate)
+optcom <- cluster_optimal(karate)
 V(karate)$comm <- membership(optcom)
 plot(optcom, karate)
 
@@ -22,7 +18,7 @@ pause()
 
 ### Fit a HRG model to the network
 
-hrg <- hrg.fit(karate)
+hrg <- fit_hrg(karate)
 hrg
 
 pause()
@@ -56,14 +52,14 @@ pause()
 
 ### Plot it as a dendrogram, looks better if the 'ape' package is installed
 
-dendPlot(hrg)
+plot_dendrogram(hrg)
 
 pause()
 
 ### Make a very hierarchical graph
 
-g1 <- graph.full(5)
-g2 <- graph.ring(5)
+g1 <- make_full_graph(5)
+g2 <- make_ring(5)
 
 g <- g1 + g2
 g <- g + edge(1, vcount(g1)+1)
@@ -74,21 +70,21 @@ pause()
 
 ### Fit HRG
 
-ghrg <- hrg.fit(g)
-dendPlot(ghrg)
+ghrg <- fit_hrg(g)
+plot_dendrogram(ghrg)
 
 pause()
 
 ### Create a consensus dendrogram from multiple samples, takes longer...
 
-hcons <- hrg.consensus(g)
+hcons <- consensus_tree(g)
 hcons$consensus
 
 pause()
 
 ### Predict missing edges
 
-pred <- hrg.predict(g)
+pred <- predict_edges(g)
 pred
 
 pause()
@@ -96,14 +92,14 @@ pause()
 ### Add some the top 5 predicted edges to the graph, colored red
 
 E(g)$color <- "grey"
-lay <- layout.auto(g)
-g2 <- add.edges(g, t(pred$edges[1:5,]), color="red")
+lay <- layout_nicely(g)
+g2 <- add_edges(g, t(pred$edges[1:5,]), color="red")
 plot(g2, layout=lay)
 
 pause()
 
 ### Add four more predicted edges, colored orange
 
-g3 <- add.edges(g2, t(pred$edges[6:9,]), color="orange")
+g3 <- add_edges(g2, t(pred$edges[6:9,]), color="orange")
 plot(g3, layout=lay)
 
diff --git a/demo/smallworld.R b/demo/smallworld.R
index 1518b69..fa61b99 100644
--- a/demo/smallworld.R
+++ b/demo/smallworld.R
@@ -1,20 +1,14 @@
 
-pause <- function() {
-  cat("Press ENTER/RETURN/NEWLINE to continue.")
-  readLines(n=1)
-  invisible()
-}
-
-pause()
+pause <- function() {}
 
 ### Create a star-like graph
-t1 <- graph.formula(A-B:C:D:E)
+t1 <- graph_from_literal(A-B:C:D:E)
 t1
 
 pause()
 
 ### Define its plotting properties
-t1$layout <- layout.circle
+t1$layout <- layout_in_circle
 V(t1)$color <- "white"
 V(t1)[name=="A"]$color <- "orange"
 V(t1)$size <- 40
@@ -32,7 +26,7 @@ plot(t1, main=paste("Transitivity of 'A':", tr))
 pause()
 
 ### Add an edge and recalculate transitivity
-t2 <- add.edges(t1, V(t1)[name %in% c("C","D")], color="red", width=3)
+t2 <- add_edges(t1, V(t1)[name %in% c("C","D")], color="red", width=3)
 tr <- transitivity(t2, type="local")[1]
 plot(t2, main=paste("Transitivity of 'A':", round(tr,4)))
 
@@ -40,23 +34,23 @@ pause()
 
 ### Add two more edges
 newe <- match(c("B", "C", "B", "E"), V(t2)$name)-1
-t3 <- add.edges(t2, newe, color="red", width=3)
+t3 <- add_edges(t2, newe, color="red", width=3)
 tr <- transitivity(t3, type="local")[1]
 plot(t3, main=paste("Transitivity of 'A':", round(tr,4)))
 
 pause()
 
 ### A one dimensional, circular lattice
-ring <- graph.ring(50)
-ring$layout <- layout.circle
+ring <- make_ring(50)
+ring$layout <- layout_in_circle
 V(ring)$size <- 3
 plot(ring, vertex.label=NA, main="Ring graph")
 
 pause()
 
 ### Watts-Strogatz model
-ws1 <- watts.strogatz.game(1, 50, 3, p=0)
-ws1$layout <- layout.circle
+ws1 <- sample_smallworld(1, 50, 3, p=0)
+ws1$layout <- layout_in_circle
 V(ws1)$size <- 3
 E(ws1)$curved <- 1
 plot(ws1, vertex.label=NA, main="regular graph")
@@ -82,14 +76,14 @@ transitivity(ws1)
 pause()
 
 ### Path lengths, regular graph
-average.path.length(ws1)
+mean_distance(ws1)
 
 pause()
 
 ### Function to test regular graph with given size
 try.ring.pl <- function(n) {
-  g <- watts.strogatz.game(1, n, 3, p=0)
-  average.path.length(g)
+  g <- sample_smallworld(1, n, 3, p=0)
+  mean_distance(g)
 }
 try.ring.pl(10)
 try.ring.pl(100)
@@ -104,18 +98,18 @@ plot(ring.size, ring.pl, type="b")
 pause()
 
 ### Path lengths, random graph
-rg <- erdos.renyi.game(50, 50*3, type="gnm")
-rg$layout <- layout.circle
+rg <- sample_gnm(50, 50 * 3)
+rg$layout <- layout_in_circle
 V(rg)$size <- 3
 plot(rg, vertex.label=NA, main="Random graph")
-average.path.length(rg)
+mean_distance(rg)
 
 pause()
 
 ### Path length of random graphs
 try.random.pl <- function(n) {
-  g <- erdos.renyi.game(n, n*3, type="gnm")
-  average.path.length(g)
+  g <- sample_gnm(n, n*3)
+  mean_distance(g)
 }
 try.random.pl(100)
 
@@ -139,18 +133,18 @@ transitivity(rg, type="localaverage")
 pause()
 
 ### Rewiring
-ws2 <- watts.strogatz.game(1, 50, 3, p=0.1)
-ws2$layout <- layout.circle
+ws2 <- sample_smallworld(1, 50, 3, p=0.1)
+ws2$layout <- layout_in_circle
 V(ws2)$size <- 3
 plot(ws2, vertex.label=NA)
-average.path.length(ws2)
+mean_distance(ws2)
 
 pause()
 
 ### Path lengths in randomized lattices
 try.rr.pl <- function(n, p) {
-  g <- watts.strogatz.game(1, n, 3, p=p)
-  average.path.length(g)
+  g <- sample_smallworld(1, n, 3, p=p)
+  mean_distance(g)
 }
 rr.pl.0.1 <- sapply(ring.size, try.rr.pl, p=0.1)
 plot(ring.size, rr.pl.0.1, type="b")
@@ -164,9 +158,9 @@ pause()
 
 ### Create the graph in the Watts-Strogatz paper
 ws.paper <- function(p, n=1000) {
-  g <- watts.strogatz.game(1, n, 10, p=p)
+  g <- sample_smallworld(1, n, 10, p=p)
   tr <- transitivity(g, type="localaverage")
-  pl <- average.path.length(g)
+  pl <- mean_distance(g)
   c(tr, pl)
 }
 
diff --git a/inst/AUTHORS b/inst/AUTHORS
index aeb346c..a84a476 100644
--- a/inst/AUTHORS
+++ b/inst/AUTHORS
@@ -7,6 +7,7 @@ Adelchi Azzalini	igraph.options based on the sm package
 Tamas Badics		GLPK
 Gregory Benison		Minimum cut calculation
 Adrian Bowman		igraph.options based on the sm package
+Walter Böhm		LSAP
 Keith Briggs		Parts from the Very Nauty Graph Library
       			Geometric random graphs
 			Girth
@@ -41,6 +42,7 @@ Brian Gough		GSL random number generators (not used in R)
 Tom Gregorovic		Multilevel community detection
 M.Grigoriadis		GLPK
 Oscar Gustafsson	GLPK
+Kurt Hornik		LSAP
 Paul Hsieh		pstdint.h
 Ross Ihaka		Some random number generators (not used in R)
 Tommi Junttila		BLISS graph isomorphism library
@@ -90,6 +92,7 @@ James Theiler		GSL random number generators (not used in R)
 Samuel Thiriot		Interconnected islands graph generator
 Vincent A. Traag	spinglass community detection
 Magnus Torfason		R operators that work by name
+Theodore Y. Ts'o        libuuid
 Minh Van Nguyen		Microscopic update rules
      	 		Various test cases
      	 		Many documentation and other fixes
@@ -97,6 +100,7 @@ M. Vento		VF2 graph isomorphism algorithm
 Fabien Viger		gengraph graph generator
 Phuong Vu		ARPACK
 P.J. Weinberger		f2c
+Hadley Wickham          lazyeval
 Garrett A. Wollman	qsort
 B.N. Wylie 		DrL layout generator
 Chao Yang		ARPACK
@@ -110,6 +114,7 @@ The R Development Core Team 	Some random number generators (not used in R)
       		       		R: as.dendrogram from stats package
 The Regents of the University of California	qsort
 Xerox PARC		      	Sparse matrix column ordering
+R Studio                        lazyeval
 
 Other contributors
 ------------------
diff --git a/inst/NEWS.md b/inst/NEWS.md
new file mode 100644
index 0000000..c741ad7
--- /dev/null
+++ b/inst/NEWS.md
@@ -0,0 +1,1034 @@
+
+# igraph 1.0.0
+
+June 21, 2015
+
+## Release notes
+
+This is a new major version of igraph, and then why not call
+it 1.0.0. This does not mean that it is ready, it'll never be
+ready.
+
+The biggest changes in the release are
+- the new function names. Most functions were renamed to
+  make them more consistent and readable. (Relax, old names
+  can still be used, no need to update any code.)
+- Better operations for vertex and edge sequences. Most functions
+  return proper vertex/edge sequences instead of numeric ids.
+- The versatile `make_()` and `make_graph()` functions to
+  create graphs.
+
+## Major changes
+
+- Many functions were renamed. Old names are not documented,
+  but can still be used.
+- A generic `make_graph()` function to create graphs.
+- A generic `layout_()` (not the underscore!) function
+  to create graph layouts, see also `add_layout_()`.
+- The igraph data type has changed. You need to call
+  `upgrade_graph()` on graphs created with previous igraph
+  versions.
+- Vertex and edge sequence operations: union, intersection, etc.
+- Vertex and edge sequences can only be used with the graphs they
+  belong to. This is now strictly checked.
+- Most functions that return a (sub)set of vertices
+  or edges return vertex or edge sequences instead.
+- Vertex and edge sequences have a `[[` operator now,
+  for easy viewing of vertex/edge metadata.
+- Vertex and edge sequences are implemented as weak references.
+  See also the `as_ids()` function to convert them to simple ids.
+- Vertex order can be specified for the circle layout now.
+- Davidson-Harel layout algorithm `layout_with_dh()`.
+- GEM layout algorithm `layout_with_gem()`.
+- Neighborhood functions have a `mindist` parameter for the
+  smallest distance to consider.
+- `all_simple_paths()` function to list all simple paths in a graph.
+- `triangles()` lists all triangles in a graph.
+- Fruchterman-Reingold and Kamada-Kawai layout algorithms
+  rewritten from scratch. They are much faster and follow the
+  original publications closely.
+- Nicer printing of graphs, vertex and edge sequences.
+- `local_scan()` function calculates scan statistics.
+- Embeddings: `embed_adjacency_matrix()` and `embed_laplacian_matrix()`.
+- Product operator: `*`, the same graph multiple times. Can be also
+  used as `rep()`.
+- Better default colors, color palettes for vertices.
+- Random walk on a graph: `random_walk()`
+- `adjacenct_vertices()` and `incident_edges()` functions,
+  they are vectorized, as opposed to `neighhors()` and `incident()`.
+- Convert a graph to a _long_ data frame with `as_long_data_frame()`.
+
+## Bug fixes
+
+Too many to list. Please try if your issue was fixed and (re-)report
+it if not. Thanks!
+
+# igraph 0.7.1
+
+April 21, 2014
+
+## Release Notes
+
+Some bug fixes, to make sure that the code included in
+'Statistical Analysis of Network Data with R' works. See
+https://github.com/kolaczyk/sand
+
+## Detailed changes:
+
+- Graph drawing: fix labels of curved edges, issue #181.
+- Graph drawing: allow fixing edge labels at given positions,
+  issue #181.
+- Drop the 'type' vertex attribute after bipartite projection,
+  the projections are not bipartite any more, issue #255.
+- Print logical attributes in header properly (i.e. encoded by `l`,
+  not `x`,  which is for complex attributes. Issue #578.
+- Add a constructor for `communities` objects, see `create.communities()`.
+  Issue #547.
+- Better error handling in the GraphML parser.
+- GraphML reader is a bit more lenient now; makes it possible to read
+  GraphML files saved from yWorks apps.
+- Fixed a bug in `constaint()`, issue #580.
+- Bipartite projection now detects invalid edges instead of giving
+  a cryptic error, issue #543.
+- Fixed the `simplify` argument of `graph.formula()`, which was
+  broken, issue #586.
+- The function `crossing()` adds better names to the result,
+  fixes issue #587.
+- The `sir()` function gives an error if the input graph is
+  not simple, fixes issue #582.
+- Calling igraph functions from igraph callbacks is not allowed now,
+  fixes issue #571.
+
+# igraph 0.7.0
+
+February 4, 2014
+
+## Release Notes
+
+There are a bunch of new features in the library itself, and 
+other important changes in the life of the project. Thanks everyone
+for sending code and reporting bugs!
+
+### igraph @ github
+
+igraph's development has moved from Launchpad to github. 
+This has actually happened several month ago, but never 
+announced officially. The place for reporting bugs is 
+at https://github.com/igraph/igraph/issues.
+
+### New homepage
+
+igraph's homepage is now hosted at http://igraph.org, and it is 
+brand new. We wanted to make it easier to use and modern.
+
+### Better nightly downloads
+
+You can download nightly builds from igraph at 
+http://igraph.org/nightly. Source and binary R packages (for windows
+and OSX), are all built.
+
+## New features and bug fixes
+
+- Added a demo for hierarchical random graphs, invoke it via
+  `demo(hrg)`.
+- Make attribute prefixes optional when writing a GraphML file.
+- Added function `mod.matrix()`.
+- Support edge weights in leading eigenvector community detection.
+- Added the LAD library for checking (sub)graph isomorphism, version 1.
+- Logical attributes.
+- Added `layout.bipartite()` function, a simple two-column layout
+  for bipartite graphs.
+- Support incidence matrices in bipartite Pajek files.
+- Pajek files in matrix format are now directed by default, unless they
+  are bipartite.
+- Support weighted (and signed) networks in Pajek when file is in
+  matrix format.
+- Fixed a bug in `barabasi.game()`, algorithm psumtree-multiple 
+  just froze.
+- Function `layout.mds()` by default returns a layout matrix now.
+- Added support for Boolean attributes in the GraphML and GML readers
+  and writer.
+- Change MDS layout coordinates, first dim is according to first
+  eigenvalue, etc.
+- `plot.communities()` (`plot.igraph()`, really) draws a border
+  around the marked groups by default.
+- printing graphs now converts the `name` graph attribute to character
+- Convenience functions to query and set all attributes at once:
+  `vertex.attriubutes()`, `graph.attributes()` and `edge.attributes()`.
+- Function `graph.disjoint.union()` handles attributes now.
+- Rewrite `graph.union()` to handle attributes properly.
+- `rewire()`: now supports the generation and destruction of loops.
+- Erdos-Renyi type bipartite random graphs: `bipartite.random.game()`.
+- Support the new options (predecessors and inbound_edges) of
+  `get_shortest_paths()`, reorganized the output of
+  `get.shortest.paths()` completely. 
+- Added `graphlets()` and related functions.
+- Fix modularity values of multilevel community if there are no merges
+  at all.
+- Fixed bug when deleting edges with FALSE in the matrix notation.
+- Fix `bonpow()` and `alpha.centrality()` and make sure that the
+  sparse solver is called.
+- `tkplot()` news: enable setting coordinates from the command line
+  via `tkplot.setcoords()` and access to the canvas via 
+  `tkplot.canvas()`.
+- Fixed a potential crash in `igraph_edge_connectivity()`, because of an
+  un-initialized variable in the C code.
+- Avoiding overflow in `closeness()` and related functions.
+- Check for NAs after converting 'type' to logical in 
+  `bipartite.projection()`.
+- `graphNEL` conversion functions only load the 'graph' package if it was 
+  not loaded before and they load it at the end of the search path, 
+  to minimize conflicts.
+- Fixed a bug when creating graphs from adjacency matrices, we now convert
+  them to double, in case they are integers.
+- Fixed an invalid memory read (and a potential crash) in the infomap
+  community detection.
+- Fixed a memory leak in the functions with attribute combinations.
+- Removed some memory leaks from the SCG functions.
+- Fixed some memory leaks in the ray tracer.
+- Fixed memory leak in `graph.bfs()` and `graph.dfs()`.
+- Fix a bug in triad census that set the first element of the result
+  to NaN.
+- Fixed a crash in `is.chordal()`.
+- Fixed a bug in weighted mudularity calculation, sum of the weights
+  was truncated to an integer.
+- Fixed a bug in weighted multilevel communtiies, the maximum weight
+  was rounded to an integer.
+- Fixed a bug in `centralization.closeness.tmax()`.
+- Reimplement push-relabel maximum flow with gap heuristics.
+- Maximum flow functions now return some statistics about the push
+  relabel algorithm steps.
+- Function `arpack()` now gives error message if unknown options are
+  given.
+- Fixed missing whitespace in Pajek writer when the ID attribute was
+  numeric.
+- Fixed a bug that caused the GML reader to crash when the ID
+  attribute was non-numeric.
+- Fixed issue #500, potential segfault if the two graphs in BLISS
+  differ in the number of vertices or edges.
+- Added `igraphtest()` function.
+- Fix dyad census instability, sometimes incorrect results were
+  reported.
+- Dyad census detects integer overflow now and gives a warning.
+- Function `add.edges()` does not allow now zeros in the vertex set.
+- Added a function to count the number of adjacent triangles:
+  `adjacenct.triangles()`.
+- Added `graph.eigen()` function, eigenproblems on adjacency matrices.
+- Added some workarounds for functions that create a lot of
+  graphs, `decompose.graph()` and `graph.neighborhood()` use it. 
+  Fixes issue #508.
+- Added weights support for `optimal.community()`, closes #511.
+- Faster maximal clique finding.
+- Added a function to count maximum cliques.
+- Set operations: union, intersection, disjoint, union, difference,
+  compose now work based on vertex names (if they are present) and
+  keep attributes, closes #20.
+- Removed functions `graph.intersection.by.name()`,
+  `graph.union.by.name()`, `graph.difference.by.name()`.
+- The `+` operator on graphs now calls `graph.union()` if both 
+  argument graphs are named, and calls `graph.disjoint.union()`
+  otherwise.
+- Added function `igraph.version()`.
+- Generate graphs from a stochastic block model: `sbm.game()`.
+- Do not suggest the stats, XML, jpeg and png packages any more.
+- Fixed a `set.vertex/edge.attribute` bug that changed both
+  graph objects, after copying (#533)
+- Fixed a bug in `barabasi.game` that caused crashes.
+- We use PRPACK to calculate PageRank scores
+  see https://github.com/dgleich/prpack
+- Added`'which` argument to `bipartite.projection` (#307).
+- Add `normalized` argument to closeness functions, fixes issue #3.
+- R: better handling of complex attributes, `[[` on vertex/edge sets,
+  fixes #231.
+- Implement the `start` argument in `hrg.fit` (#225).
+- Set root vertex in Reingold-Tilford layout, solves #473.
+- Fix betweenness normalization for directed graphs.
+- Fixed a bug in `graph.density` that resulted in incorrect values for
+  undirected graphs with loops
+- Fixed a bug when many graphs were created in one C call
+  (e.g. by `graph.decompose`), causing #550.
+- Fixed sparse `graph.adjacency` bugs for graphs with one edge,
+  and graphs with zero edges.
+- Fixed a bug that made Bellman-Ford shortest paths calculations fail.
+- Fixed a `graph.adjacency` bug for undirected, weighted graphs and
+  sparse matrices.
+- `main`, `sub`, `xlab` and `ylab` are proper graphics parameters
+  now (#555).
+- `graph.data.frame` coerces arguments to data frame (#557).
+- Fixed a minimum cut bug for weighted undirected graphs (#564).
+- Functions for simulating epidemics (SIR model) on networks,
+  see the `sir` function.
+- Fixed argument ordering in `graph.mincut` and related functions.
+- Avoid copying attributes in query functions and print (#573),
+  these functions are much faster now for graphs with many
+  vertices/edges and attributes.
+- Speed up writing GML and GraphML files, if some attributes are
+  integer. It was really-really slow.
+- Fix multiple root vertices in `graph.bfs` (#575).
+
+# igraph 0.6.6
+
+Released Oct 28, 2013
+
+Some bugs fixed:
+
+- Fixed a potential crash in the infomap.community() function.
+- Various fixed for the operators that work on vertex names (#136).
+- Fixed an example in the arpack() manual page.
+- arpack() now gives error message if unknown options
+  are supplied (#492).
+- Better arpack() error messages.
+- Fixed missing whitespace in Pajek writer when ID attribute
+  was numeric.
+- Fixed dyad census instability, sometimes incorrect 
+  results were reported (#496).
+- Fixed a bug that caused the GML reader to crash when the ID
+  attribute was non-numeric
+- Fixed a potential segfault if the two graphs in BLISS
+  differ in the number of vertices or edges (#500).
+- Added the igraphtest() function to run tests from R (#485).
+- Dyad census detects integer overflow now and gives a warning (#497).
+- R: add.edges() does not allow now zeros in the vertex set (#503).
+- Add C++ namespace to the files that didn't have one. 
+  Fixes some incompatibility with other packages (e.g. rgl) 
+  and mysterious crashes (#523).
+- Fixed a bug that caused a side effect in set.vertex.attributes(),
+  set.edge.attributes() and set.graph.attributes() (#533).
+- Fixed a bug in degree.distribution() and cluster.distribution()
+  (#257).
+
+# igraph 0.6.5-2
+
+Released May 16, 2013
+
+Worked two CRAN check problems, and a gfortran bug (string bound
+checking does not work if code is called from C and without string
+length arguments at the "right" place).
+
+Otherwise identical to 0.6.5-1.
+
+# igraph 0.6.5-1
+
+Released February 27, 2013
+
+Fixing an annoying bug, that broke two other packages on CRAN:
+
+- Setting graph attributes failed sometimes, if the attributes were 
+  lists or other complex objects.
+
+# igraph 0.6.5
+
+Released February 24, 2013
+
+This is a minor release, to fix some very annoying bugs in 0.6.4:
+
+- igraph should now work well with older R versions.
+- Eliminate gap between vertex and edge when plotting an edge without an arrow.
+  Fixes #1118448.
+- Fixed an out-of-bounds array indexing error in the DrL layout, that
+  potentially caused crashes.
+- Fixed a crash in weighted betweenness calculation.
+- Plotting: fixed a bug that caused misplaced arrows at rectangle 
+  vertex shapes. 
+
+# igraph 0.6.4
+
+Released February 2, 2013
+
+The version number is not a mistake, we jump to 0.6.4 from 0.6, 
+for technical reasons. This version was actually never really
+released, but some R packages of this version were uplodaded to 
+CRAN, so we include this version in this NEW file.
+
+# New features and bug fixes
+
+- Added a vertex shape API for defining new vertex shapes, and also 
+  a couple of new vertex shapes.
+- Added the get.data.frame() function, opposite of graph.data.frame().
+- Added bipartite support to the Pajek reader and writer, closes bug
+  #1042298.
+- degree.sequence.game() has a new method now: "simple_no_multiple".
+- Added the is.degree.sequence() and is.graphical.degree.sequence()
+  functions.
+- rewire() has a new method: "loops", that can create loop edges.
+- Walktrap community detection now handles isolates.
+- layout.mds() returns a layout matrix now.
+- layout.mds() uses LAPACK instead of ARPACK.
+- Handle the '~' character in write.graph and read.graph. Bug
+  #1066986.
+- Added k.regular.game().
+- Use vertex names to plot if no labels are specified in the function
+  call or as vetex attributes. Fixes issue #1085431.
+- power.law.fit() can now use a C implementation.
+
+- Fixed a bug in barabasi.game() when out.seq was an empty vector.
+- Fixed a bug that made functions with a progress bar fail if called 
+  from another package.
+- Fixed a bug when creating graphs from a weighted integer adjacency 
+  matrix via graph.adjacency(). Bug #1019624.
+- Fixed overflow issues in centralization calculations.
+- Fixed a minimal.st.separators() bug, some vertex sets were incorrectly
+  reported as separators. Bug #1033045.
+- Fixed a bug that mishandled vertex colors in VF2 isomorphism
+  functions. Bug #1032819.
+- Pajek exporter now always quotes strings, thanks to Elena Tea Russo.
+- Fixed a bug with handling small edge weights in shortest paths 
+  calculation in shortest.paths() (Dijkstra's algorithm.) Thanks to 
+  Martin J Reed.
+- Weighted transitivity uses V(graph) as 'vids' if it is NULL.
+- Fixed a bug when 'pie' vertices were drawn together with other 
+  vertex shapes.
+- Speed up printing graphs.
+- Speed up attribute queries and other basic operations, by avoiding 
+  copying of the graph. Bug #1043616.
+- Fixed a bug in the NCV setting for ARPACK functions. It cannot be
+  bigger than the matrix size.
+- layout.merge()'s DLA mode has better defaults now.
+- Fixed a bug in layout.mds() that resulted vertices on top of each
+  other.
+- Fixed a bug in layout.spring(), it was not working properly.
+- Fixed layout.svd(), which was completely defunct.
+- Fixed a bug in layout.graphopt() that caused warnings and on 
+  some platforms crashes.
+- Fixed community.to.membership(). Bug #1022850.
+- Fixed a graph.incidence() crash if it was called with a non-matrix
+  argument.
+- Fixed a get.shortest.paths bug, when output was set to "both".
+- Motif finding functions return NA for isomorphism classes that are
+  not motifs (i.e. not connected). Fixes bug #1050859. 
+- Fixed get.adjacency() when attr is given, and the attribute has some
+  complex type. Bug #1025799. 
+- Fixed attribute name in graph.adjacency() for dense matrices. Bug
+  #1066952. 
+- Fixed erratic behavior of alpha.centrality().
+- Fixed igraph indexing, when attr is given. Bug #1073705.
+- Fixed a bug when calculating the largest cliques of a directed
+  graph. Bug #1073800.
+- Fixed a bug in the maximal clique search, closes #1074402.
+- Warn for negative weights when calculating PageRank.
+- Fixed dense, unweighted graph.adjacency when diag=FALSE. Closes
+  issue #1077425. 
+- Fixed a bug in eccentricity() and radius(), the results were often
+  simply wrong.
+- Fixed a bug in get.all.shortest.paths() when some edges had zero weight.
+- graph.data.frame() is more careful when vertex names are numbers, to
+  avoid their scientific notation. Fixes issue #1082221. 
+- Better check for NAs in vertex names. Fixes issue #1087215
+- Fixed a potential crash in the DrL layout generator.
+- Fixed a bug in the Reingold-Tilford layout when the graph is
+  directed and mode != ALL.
+
+# igraph 0.6
+
+Released June 11, 2012
+
+See also the release notes at 
+http://igraph.sf.net/relnotes-0.6.html
+
+# R: Major new features
+
+- Vertices and edges are numbered from 1 instead of 0. 
+  Note that this makes most of the old R igraph code incompatible
+  with igraph 0.6. If you want to use your old code, please use 
+  the igraph0 package. See more at http://igraph.sf.net/relnotes-0.6.html.
+- The '[' and '[[' operators can now be used on igraph graphs, 
+  for '[' the graph behaves as an adjacency matrix, for '[[' is 
+  is treated as an adjacency list. It is also much simpler to
+  manipulate the graph structure, i.e. add/remove edges and vertices, 
+  with some new operators. See more at ?graph.structure.
+- In all functions that take a vector or list of vertices or edges, 
+  vertex/edge names can be given instead of the numeric ids.
+- New package 'igraphdata', contains a number of data sets that can
+  be used directly in igraph.
+- Igraph now supports loading graphs from the Nexus online data
+  repository, see nexus.get(), nexus.info(), nexus.list() and 
+  nexus.search().
+- All the community structure finding algorithm return a 'communities'
+  object now, which has a bunch of useful operations, see 
+  ?communities for details.
+- Vertex and edge attributes are handled much better now. They 
+  are kept whenever possible, and can be combined via a flexible API.
+  See ?attribute.combination.
+- R now prints igraph graphs to the screen in a more structured and 
+  informative way. The output of summary() was also updated
+  accordingly.
+
+# R: Other new features
+
+- It is possible to mark vertex groups on plots, via
+  shading. Communities and cohesive blocks are plotted using this by
+  default.
+- Some igraph demos are now available, see a list via 
+  'demo(package="igraph")'.
+- igraph now tries to select the optimal layout algorithm, when
+  plotting a graph.
+- Added a simple console, using Tcl/Tk. It contains a text area
+  for status messages and also a status bar. See igraph.console().
+- Reimplemented igraph options support, see igraph.options() and 
+  getIgraphOpt().
+- Igraph functions can now print status messages.
+
+# R: New or updated functions
+
+## Community detection
+
+- The multi-level modularity optimization community structure detection 
+  algorithm by Blondel et al. was added, see multilevel.community().
+- Distance between two community structures: compare.communities().
+- Community structure via exact modularity optimization,
+  optimal.community().
+- Hierarchical random graphs and community finding, porting the code
+  from Aaron Clauset. See hrg.game(), hrg.fit(), etc.
+- Added the InfoMAP community finding method, thanks to Emmanuel
+  Navarro for the code. See infomap.community().
+
+## Shortest paths
+
+- Eccentricity (eccentricity()), and radius (radius()) calculations.
+- Shortest path calculations with get.shortest.paths() can now 
+  return the edges along the shortest paths.
+- get.all.shortest.paths() now supports edge weights.
+
+## Centrality
+
+- Centralization scores for degree, closeness, betweenness and 
+  eigenvector centrality. See centralization.scores().
+- Personalized Page-Rank scores, see page.rank().
+- Subgraph centrality, subgraph.centrality().
+- Authority (authority.score()) and hub (hub.score()) scores support 
+  edge weights now.
+- Support edge weights in betweenness and closeness calculations.
+- bonpow(), Bonacich's power centrality and alpha.centrality(), 
+  Alpha centrality calculations now use sparse matrices by default.
+- Eigenvector centrality calculation, evcent() now works for 
+  directed graphs.
+- Betweenness calculation can now use arbitrarily large integers,
+  this is required for some lattice-like graphs to avoid overflow.
+
+## Input/output and file formats
+
+- Support the DL file format in graph.read(). See 
+  http://www.analytictech.com/networks/dataentry.htm.
+- Support writing the LEDA file format in write.graph().
+
+## Plotting and layouts
+
+- Star layout: layout.star().
+- Layout based on multidimensional scaling, layout.mds().
+- New layouts layout.grid() and layout.grid.3d().
+- Sugiyama layout algorithm for layered directed acyclic graphs, 
+  layout.sugiyama().
+
+## Graph generators
+
+- New graph generators: static.fitness.game(), static.power.law.game().
+- barabasi.game() was rewritten and it supports three algorithms now,
+  the default algorithm does not generate multiple or loop edges.
+  The graph generation process can now start from a supplied graph.
+- The Watts-Strogatz graph generator, igraph_watts_strogatz() can 
+  now create graphs without loop edges.
+
+## Others
+
+- Added the Spectral Coarse Graining algorithm, see scg(). 
+- The cohesive.blocks() function was rewritten in C, it is much faster
+  now. It has a nicer API, too. See demo("cohesive").
+- Added generic breadth-first and depth-first search implementations
+  with many callbacks, graph.bfs() and graph_dfs().
+- Support vertex and edge coloring in the VF2 (sub)graph isomorphism 
+  functions (graph.isomorphic.vf2(), graph.count.isomorphisms.vf2(), 
+  graph.get.isomorphisms.vf2(), graph.subisomorphic.vf2(), 
+  graph.count.subisomorphisms.vf2(), graph.get.subisomorphisms.vf2()).
+- Assortativity coefficient, assortativity(), assortativity.nominal()
+  and assortativity.degree().
+- Vertex operators that work by vertex names: 
+  graph.intersection.by.name(), graph.union.by.name(), 
+  graph.difference.by.name(). Thanks to Magnus Torfason for 
+  contributing his code!
+- Function to calculate a non-induced subraph: subgraph.edges().
+- More comprehensive maximum flow and minimum cut calculation, 
+  see functions graph.maxflow(), graph.mincut(), stCuts(), stMincuts().
+- Check whether a directed graph is a DAG, is.dag().
+- has.multiple() to decide whether a graph has multiple edges.
+- Added a function to calculate a diversity score for the vertices,
+  graph.diversity().
+- Graph Laplacian calculation (graph.laplacian()) supports edge 
+  weights now.
+- Biconnected component calculation, biconnected.components() 
+  now returns the components themselves.
+- bipartite.projection() calculates multiplicity of edges.
+- Maximum cardinality search: maximum.cardinality.search() and 
+  chordality test: is.chordal()
+- Convex hull computation, convex.hull().
+- Contract vertices, contract.vertices().
+
+# igraph 0.5.3
+
+Released November 22, 2009
+
+## Bugs corrected in the R interface
+
+- Some small changes to make 'R CMD check' clean
+- Fixed a bug in graph.incidence, the 'directed' and 'mode' arguments 
+  were not handled correctly
+- Betweenness and edge betweenness functions work for graphs with
+  many shortest paths now (up to the limit of long long int)
+- When compiling the package, the configure script fails if there is
+  no C compiler available
+- igraph.from.graphNEL creates the right number of loop edges now
+- Fixed a bug in bipartite.projection() that caused occasional crashes 
+  on some systems
+
+# igraph 0.5.2
+
+Released April 10, 2009
+
+See also the release notes at
+http://igraph.sf.net/relnotes-0.5.2.html
+
+## New in the R interface
+
+- Added progress bar support to beweenness() and
+  betweenness.estimate(), layout.drl()
+- Speeded up betweenness estimation
+- Speeded up are.connected()
+- Johnson's shortest paths algorithm added
+- shortest.paths() has now an 'algorithm' argument to choose from the
+  various implementations manually
+- Always quote symbolic vertex names when printing graphs or edges
+- Average nearest neighbor degree calculation, graph.knn()
+- Weighted degree (also called strength) calculation, graph.strength()
+- Some new functions to support bipartite graphs: graph.bipartite(),
+  is.bipartite(), get.indicence(), graph.incidence(),
+  bipartite.projection(), bipartite.projection.size()
+- Support for plotting curved edges with plot.igraph() and tkplot()
+- Added support for weighted graphs in alpha.centrality()
+- Added the label propagation community detection algorithm by
+  Raghavan et al., label.propagation.community()
+- cohesive.blocks() now has a 'cutsetHeuristic' argument to choose
+  between two cutset algorithms
+- Added a function to "unfold" a tree, unfold.tree()
+- New tkplot() arguments to change the drawing area
+- Added a minimal GUI, invoke it with tkigraph()
+- The DrL layout generator, layout.drl() has a three dimensional mode
+  now.
+
+## Bugs corrected in the R interface
+
+- Fixed a bug in VF2 graph isomorphism functions
+- Fixed a bug when a sparse adjacency matrix was requested in
+  get.adjacency() and the graph was named
+- VL graph generator in degree.sequence.game() checks now that
+  the sum of the degrees is even
+- Many fixes for supporting various compilers, e.g. GCC 4.4 and Sun's
+  C compiler
+- Fixed memory leaks in graph.automorphisms(), Bellman-Ford
+  shortest.paths(), independent.vertex.sets()
+- Fix a bug when a graph was imported from LGL and exported to NCOL
+  format (#289596)
+- cohesive.blocks() creates its temporary file in the session
+  temporary directory
+- write.graph() and read.graph() now give error messages when unknown
+  arguments are given
+- The GraphML reader checks the name of the attributes to avoid adding
+  a duplicate 'id' attribute
+- It is possible to change the 'ncv' ARPACK parameter for
+  leading.eigenvector.community()
+- Fixed a bug in path.length.hist(), 'unconnected' was wrong
+  for unconnected and undirected graphs
+- Better handling of attribute assingment via iterators, this is now
+  also clarified in the manual
+- Better error messages for unknown vertex shapes
+- Make R package unload cleanly if unloadNamespace() is used
+- Fixed a bug in plotting square shaped vertices (#325244)
+- Fixed a bug in graph.adjacency() when the matrix is a sparse matrix
+  of class "dgTMatrix"
+
+# igraph 0.5.1
+
+Released July 14, 2008
+
+See also the release notes at 
+http://igraph.sf.net/relnotes-0.5.1.html
+
+## New in the R interface
+
+- A new layout generator called DrL.
+- Uniform sampling of random connected undirected graphs with a 
+  given degree sequence.
+- Edge labels are plotted at 1/3 of the edge, this is better if 
+  the graph has mutual edges.
+- Initial and experimental vertex shape support in 'plot'.
+- New function, 'graph.adjlist' creates igraph graphs from
+  adjacency lists.
+- Conversion to/from graphNEL graphs, from the 'graph' R package.
+- Fastgreedy community detection can utilize edge weights now, this 
+  was missing from the R interface.
+- The 'arrow.width' graphical parameter was added.
+- graph.data.frame has a new argument 'vertices'.
+- graph.adjacency and get.adjacency support sparse matrices, 
+  the 'Matrix' package is required to use this functionality.
+- graph.adjacency adds column/row names as 'name' attribute.
+- Weighted shortest paths using Dijkstra's or the Belmann-Ford 
+  algorithm.
+- Shortest path functions return 'Inf' for unreachable vertices.
+- New function 'is.mutual' to find mutual edges in a directed graph.
+- Added inverse log-weighted similarity measure (a.k.a. Adamic/Adar
+  similarity).
+- preference.game and asymmetric.preference.game were 
+  rewritten, they are O(|V|+|E|) now, instead of O(|V|^2).
+- Edge weight support in function 'get.shortest.paths', it uses 
+  Dijkstra's algorithm.
+
+## Bugs corrected in the R interface
+  
+- A bug was corrected in write.pajek.bgraph.
+- Several bugs were corrected in graph.adjacency.
+- Pajek reader bug corrected, used to segfault if '*Vertices' 
+  was missing.
+- Directedness is handled correctly when writing GML files.
+  (But note that 'correct' conflicts the standard here.)
+- Corrected a bug when calculating weighted, directed PageRank on an 
+  undirected graph. (Which does not make sense anyway.)
+- Several bugs were fixed in the Reingold-Tilford layout to avoid 
+  edge crossings.
+- A bug was fixed in the GraphML reader, when the value of a graph
+  attribute was not specified.
+- Fixed a bug in the graph isomorphism routine for small (3-4 vertices)
+  graphs.
+- Corrected the random sampling implementation (igraph_random_sample),
+  now it always generates unique numbers. This affects the 
+  Gnm Erdos-Renyi generator, it always generates simple graphs now.
+- The basic igraph constructor (igraph_empty_attrs, all functions 
+  are expected to call this internally) now checks whether the number
+  of vertices is finite.
+- The LGL, NCOL and Pajek graph readers handle errors properly now.
+- The non-symmetric ARPACK solver returns results in a consistent form
+  now.
+- The fast greedy community detection routine now checks that the graph
+  is simple.
+- The LGL and NCOL parsers were corrected to work with all 
+  kinds of end-of-line encodings.
+- Hub & authority score calculations initialize ARPACK parameters now.
+- Fixed a bug in the Walktrap community detection routine, when applied 
+  to unconnected graphs.
+- Several small memory leaks were removed, and a big one from the Spinglass
+  community structure detection function
+
+# igraph 0.5
+
+Released February 14, 2008
+
+See also the release notes at http://igraph.sf.net/relnotes-0.5.html
+
+## New in the R interface
+
+- The 'rescale', 'asp' and 'frame' graphical parameters were added
+- Create graphs from a formula notation (graph.formula)
+- Handle graph attributes properly
+- Calculate the actual minimum cut for undirected graphs
+- Adjacency lists, get.adjlist and get.adjedgelist added
+- Eigenvector centrality computation is much faster now
+- Proper R warnings, instead of writing the warning to the terminal
+- R checks graphical parameters now, the unknown ones are not just
+  ignored, but an error message is given  
+- plot.igraph has an 'add' argument now to compose plots with multiple
+  graphs
+- plot.igraph supports the 'main' and 'sub' arguments
+- layout.norm is public now, it can normalize a layout
+- It is possible to supply startup positions to layout generators
+- Always free memory when CTRL+C/ESC is pressed, in all operating
+  systems
+- plot.igraph can plot square vertices now, see the 'shape' parameter
+- graph.adjacency rewritten when creating weighted graphs
+- We use match.arg whenever possible. This means that character scalar 
+  options can be abbreviated and they are always case insensitive
+
+- VF2 graph isomorphism routines can check subgraph isomorphism now,
+  and they are able to return matching(s)
+- The BLISS graph isomorphism algorithm is included in igraph now. See
+  canonical.permutation, graph.isomorphic.bliss
+- We use ARPACK for eigenvalue/eigenvector calculation. This means that the
+  following functions were rewritten: page.rank,
+  leading.eigenvector.community.*, evcent. New functions based on
+  ARPACK: hub.score, authority.score, arpack.
+- Edge weights for Fruchterman-Reingold layout (layout.fruchterman.reingold).
+- Line graph calculation (line.graph)
+- Kautz and de Bruijn graph generators (graph.kautz, graph.de.bruijn)
+- Support for writing graphs in DOT format
+- Jaccard and Dice similarity coefficients added (similarity.jaccard,
+  similarity.dice)
+- Counting the multiplicity of edges (count.multiple)
+- The graphopt layout algorithm was added, layout.graphopt
+- Generation of "famous" graphs (graph.famous).
+- Create graphs from LCF notation (graph.cf).
+- Dyad census and triad cencus functions (dyad.census, triad.census)
+- Cheking for simple graphs (is.simple)
+- Create full citation networks (graph.full.citation)
+- Create a histogram of path lengths (path.length.hist)
+- Forest fire model added (forest.fire.game)
+- DIMACS reader can handle different file types now
+- Biconnected components and articulation points (biconnected.components,
+  articulation.points)
+- Kleinberg's hub and authority scores (hub.score, authority.score)
+- as.undirected handles attributes now
+- Geometric random graph generator (grg.game) can return the
+  coordinates of the vertices
+- Function added to convert leading eigenvector community structure result to
+  a membership vector (community.le.to.membership)
+- Weighted fast greedy community detection
+- Weighted page rank calculation
+- Functions for estimating closeness, betweenness, edge betweenness by 
+  introducing a cutoff for path lengths (closeness.estimate,
+  betweenness.estimate, edge.betweenness.estimate)
+- Weighted modularity calculation
+- Function for permuting vertices (permute.vertices)
+- Betweenness and closeness calculations are speeded up
+- read.graph can handle all possible line terminators now (\r, \n, \r\n, \n\r)
+- Error handling was rewritten for walktrap community detection,
+  the calculation can be interrupted now
+- The maxflow/mincut functions allow to supply NULL pointer for edge
+  capacities, implying unit capacities for all edges
+
+## Bugs corrected in the R interface
+
+- Fixed a bug in cohesive.blocks, cohesive blocks were sometimes not
+  calculated correctly
+
+# igraph 0.4.5
+
+Released January 1, 2008
+
+New:
+- Cohesive block finding in the R interface, thanks to Peter McMahan
+  for contributing his code. See James Moody and Douglas R. White,
+  2003, in Structural Cohesion and Embeddedness: A Hierarchical
+  Conception of Social Groups American Sociological Review 68(1):1-25 
+- Biconnected components and articulation points.
+- R interface: better printing of attributes.
+- R interface: graph attributes can be used via '$'.
+
+Bug fixed:
+- Erdos-Renyi random graph generators rewritten.
+
+# igraph 0.4.4
+
+Released October 3, 2007
+
+This release should work seemlessly with the new R 2.6.0 version.
+Some other bugs were also fixed:
+- A bug was fixed in the Erdos-Renyi graph generator, which sometimes
+  added an extra vertex.
+
+# igraph 0.4.3
+
+Released August 13, 2007
+
+The next one in the sequence of bugfix releases. Thanks to many people
+sending bug reports. Here are the changes:
+- Some memory leaks removed when using attributes from R or Python.
+- GraphML parser: entities and character data in multiple chunks are
+  now handled correctly. 
+- A bug corrected in edge betweenness community structure detection,
+  it failed if called many times from the same program/session.
+- Edge betweeness community structure: handle unconnected graphs properly.
+- Fixed bug related to fast greedy community detection in unconnected graphs.
+- Use a different kind of parser (Push) for reading GraphML
+  files. This is almost invisible for users but fixed a
+  nondeterministic bug when reading in GraphML files.
+- R interface: plot now handles properly if called with a vector as
+  the edge.width argument for directed graphs.
+- R interface: bug (typo) corrected for walktrap.community and
+  weighted graphs. 
+
+# igraph 0.4.2
+
+Released June 7, 2007
+
+This is another bugfix release, as there was a serious bug in the 
+R package of the previous version: it could not read and write graphs
+to files in any format under MS Windows.
+
+Some other bits added: 
+- circular Reingold-Tilford layout generator for trees
+- corrected a bug, Pajek files are written properly under MS Windows now.
+- arrow.size graphical edge parameter added in the R interface.
+
+# igraph 0.4.1
+
+Released May 23, 2007
+
+This is a minor release, it corrects a number of bugs, mostly in the 
+R package.
+
+# igraph 0.4
+
+Released May 21, 2007
+
+The major new additions in this release is a bunch of community
+detection algorithms and support for the GML file format. Here 
+is the complete list of changes:
+
+## New in the R interface
+
+- as the internal representation changed, graphs stored with 'save' 
+  with an older igraph version cannot be read back with the new
+  version reliably.
+- neighbors returns ordered lists
+- is.loop and is.multiple were added
+
+- topological sorting
+- VF2 isomorphism algorithm
+- support for reading graphs from the Graph Database for isomorphism
+- graph.mincut can calculate the actual minimum cut
+- girth calculation added, thanks to Keith Briggs
+- support for reading and writing GML files
+
+- Walktrap community detection algorithm added, thanks to Matthieu Latapy 
+  and Pascal Pons
+- edge betweenness based community detection algorithm added
+- fast greedy algorithm for community detection by Clauset et al. added
+  thanks to Aaron Clauset for sharing his code  
+- leading eigenvector community detection algorithm by Mark Newman added
+- functions for creating dendrograms from the output of the 
+  community detection algorithms added
+- community.membership supporting function added, creates 
+  a membership vector from a community structure merge tree
+- modularity calculation added
+
+- graphics parameter handling is completely rewritten, uniform handling 
+  of colors and fonts, make sure you read ?igraph.plotting
+- new plotting parameter for edges: arrow.mode
+- a bug corrected when playing a nonlinear barabasi.game
+- better looking plotting in 3d using rglplot: edges are 3d too
+- rglplot layout is allowed to be two dimensional now
+- rglplot suspends updates while drawing, this makes it faster
+- loop edges are correctly plotted by all three plotting functions
+
+- better printing of attributes when printing graphs
+- summary of a graph prints attribute names
+- is.igraph rewritten to make it possible to inherit from the 'igraph' class
+- somewhat better looking progress meter for functions which support it
+
+## Others
+
+- many functions benefit from the new internal representation and are 
+  faster now: transitivity, reciprocity, graph operator functions like 
+  intersection and union, etc.
+
+## Bugs corrected
+
+- corrected a bug when reading Pajek files: directed graphs were read
+  as undirected 
+
+# igraph 0.3.2
+
+Released Dec 19, 2006
+
+This is a new major release, it contains many new things:
+
+## Changes in the R interface
+
+- bonpow function ported from SNA to calculate Bonacich power centrality
+- get.adjacency supports attributes now, this means that it sets the
+  colnames  and rownames attributes and can return attribute values in
+  the matrix instead of 0/1
+- grg.game, geometric random graphs
+- graph.density, graph density calculation
+- edge and vertex attributes can be added easily now when added new
+  edges with add.edges or new vertices with add.vertices
+- graph.data.frame creates graph from data frames, this can be used to 
+  create graphs with edge attributes easily
+- plot.igraph and tkplot can plot self-loop edges now
+- graph.edgelist to create a graph from an edge list, can also handle 
+  edge lists with symbolic names
+- get.edgelist has now a 'names' argument and can return symbolic
+  vertex names instead of vertex ids, by default id uses the 'name'
+  vertex attribute is returned 
+- printing graphs on screen also prints symbolic symbolic names
+  (the 'name' attribute if present)
+- maximum flow and minimum cut functions: graph.maxflow, graph.mincut
+- vertex and edge connectivity: edge.connectivity, vertex.connectivity
+- edge and vertex disjoint paths: edge.disjoint.paths, 
+  vertex.disjoint.paths
+- White's cohesion and adhesion measure: graph.adhesion, graph.cohesion
+- dimacs file format added
+- as.directed handles attributes now
+- constraint corrected, it handles weighted graphs as well now
+- weighted attribute to graph.adjacency
+- spinglass-based community structure detection, the Joerg Reichardt --
+  Stefan Bornholdt algorithm added: spinglass.community
+- graph.extended.chordal.ring, extended chordal ring generation
+- no.clusters calculates the number of clusters without calculating
+  the clusters themselves
+- minimum spanning tree functions updated to keep attributes
+- transitivity can calculate local transitivity as well
+- neighborhood related functions added: neighborhood,
+  neighborhood.size, graph.neighborhood
+- new graph generators based on vertex types: preference.game and
+  asymmetric.preference.game
+
+## Bugs corrected
+
+- attribute handling bug when deleting edges corrected
+- GraphML escaping and NaN handling corrected
+- bug corrected to make it possible compile the R package without the 
+  libxml2 library
+- a bug in Erdos-Renyi graph generation corrected: it had problems 
+  with generating large directed graphs
+- bug in constraint calculation corrected, it works well now
+- fixed memory leaks in the GraphML reader
+- error handling bug corrected in the GraphML reader
+- bug corrected in R version of graph.laplacian when normalized
+  Laplacian is requested
+- memory leak corrected in get.all.shortest.paths in the R package
+
+# igraph 0.2.1
+
+Released Aug 23, 2006
+
+This is a bug-fix release. Bugs fixed:
+- reciprocity corrected to avoid segfaults
+- some docs updates
+- various R package updates to make it conform to the CRAN rules
+
+# igraph 0.2
+
+Released Aug 18, 2006
+
+Release time at last! There are many new things in igraph 0.2, the
+most important ones:
+- reading writing Pajek and GraphML formats with attributes
+  (not all Pajek and GraphML files are supported, see documentation
+  for details)
+- the RANDEDU fast motif search algorithm is implemented
+- many new graph generators, both games and regular graphs
+- many new structural properties: transitivity, reciprocity, etc.
+- graph operators: union, intersection, difference, structural holes, etc.
+- conversion between directed and undirected graphs
+- new layout algorithms for trees and large graphs, 3D layouts
+and many more.
+
+New things specifically in the R package:
+- support for CTRL+C
+- new functions: Graph Laplacian, Burt's constraint, etc.
+- vertex/edge sequences totally rewritten, smart indexing (see manual)
+- new R manual and tutorial: `Network Analysis with igraph', still 
+  under development but useful
+- very basic 3D plotting using OpenGL
+
+Although this release was somewhat tested on Linux, MS Windows, Mac
+OSX, Solaris 8 and FreeBSD, no heavy testing was done, so it might
+contain bugs, and we kindly ask you to send bug reports to make igraph
+better.
+
+# igraph 0.1
+
+Released Jan 30, 2006
+
+After about a year of development this is the first "official" release 
+of the igraph library. This release should be considered as beta 
+software, but it should be useful in general. Please send your 
+questions and comments.
+
+
diff --git a/inst/README.md b/inst/README.md
new file mode 100644
index 0000000..53a0330
--- /dev/null
+++ b/inst/README.md
@@ -0,0 +1,32 @@
+
+# R/igraph
+
+R/igraph is an R package of the igraph network analysis library.
+
+## Installation
+
+You can install the stable version of R/igraph from CRAN:
+
+```r
+install.packages("igraph")
+```
+
+For the development version, you can use Github, with the `devtools`
+package:
+
+```r
+devtools::install_github("igraph/rigraph")
+```
+
+## Documentation
+
+See the [igraph homepage](http://igraph.org/r) for the complete manual.
+
+## Contributions
+
+Please read our
+[contribution guide](https://github.com/igraph/rigraph/blob/dev/CONTRIBUTING.md).
+
+## License
+
+GNU GPL version 2 or later
diff --git a/inst/benchmarks/correlated.R b/inst/benchmarks/correlated.R
new file mode 100644
index 0000000..2397d0e
--- /dev/null
+++ b/inst/benchmarks/correlated.R
@@ -0,0 +1,8 @@
+
+time_group("correlated E-R graphs, v1")
+
+time_that("sample_correlated_gnp is fast", replications=10,
+          init={ library(igraph) },
+          { sample_correlated_gnp_pair(100, corr=.8, p=5/100) })
+
+
diff --git a/inst/benchmarks/local.scan.R b/inst/benchmarks/local.scan.R
new file mode 100644
index 0000000..9453ce1
--- /dev/null
+++ b/inst/benchmarks/local.scan.R
@@ -0,0 +1,57 @@
+
+time_group("local scan v1")
+
+init   <- expression({library(igraph); set.seed(42) })
+reinit <- expression({g  <- random.graph.game(1000, p=.1)
+                      E(g)$weight <- sample(ecount(g))
+                      gp <- random.graph.game(1000, p=.1)
+                      E(gp)$weight <- sample(ecount(gp))
+                    })
+
+time_that("us, scan-0, unweighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, k=0) })
+
+time_that("us, scan-0, weighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, k=0, weighted=TRUE) })
+
+time_that("us, scan-1, unweighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, k=1) })
+
+time_that("us, scan-1, weighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, k=1, weighted=TRUE) })
+
+time_that("us, scan-2, unweighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, k=2) })
+
+time_that("us, scan-2, weighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, k=2, weighted=TRUE) })
+
+time_that("them, scan-0, unweighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, gp, k=0) })
+
+time_that("them, scan-0, weighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, gp, k=0, weighted=TRUE) })
+
+time_that("them, scan-1, unweighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, gp, k=1)} )
+
+time_that("them, scan-1, weighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, gp, k=1, weighted=TRUE) })
+
+time_that("them, scan-2, unweighted",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, gp, k=2) })
+
+time_that("them, scan-2, weigthed",
+          replications=10, init=init, reinit=reinit,
+          { local_scan(g, gp, k=2, weighted=TRUE) })
diff --git a/inst/benchmarks/time_dirSelect.R b/inst/benchmarks/time_dirSelect.R
new file mode 100644
index 0000000..94f8916
--- /dev/null
+++ b/inst/benchmarks/time_dirSelect.R
@@ -0,0 +1,7 @@
+
+time_group("dimensionality selection")
+
+time_that("dimensionaility selection is fast", replications=10,
+          init = { library(igraph) },
+          reinit = { sv <- c(rnorm(2000), rnorm(2000)/5) },
+          { dim_select(sv) })
diff --git a/inst/benchmarks/time_fr_layout.R b/inst/benchmarks/time_fr_layout.R
new file mode 100644
index 0000000..7a670c4
--- /dev/null
+++ b/inst/benchmarks/time_fr_layout.R
@@ -0,0 +1,12 @@
+
+time_group("Fruchterman-Reingold layout")
+
+time_that("FR layout is fast, connected", replications=10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- sample_pa(400) },
+          { layout_with_fr(g, niter=500) })
+
+time_that("FR layout is fast, unconnected", replications=10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- sample_gnm(400, 400) },
+          { layout_with_fr(g, niter=500) })
diff --git a/inst/benchmarks/time_kk_layout.R b/inst/benchmarks/time_kk_layout.R
new file mode 100644
index 0000000..eb6854c
--- /dev/null
+++ b/inst/benchmarks/time_kk_layout.R
@@ -0,0 +1,17 @@
+
+time_group("Kamada-Kawai layout")
+
+time_that("KK layout is fast, connected", replications=10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- sample_pa(400) },
+          { layout_with_kk(g, maxiter=500) })
+
+time_that("KK layout is fast, unconnected", replications=10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- sample_gnm(400, 400) },
+          { layout_with_kk(g, maxiter=500) })
+
+time_that("KK layout is fast for large graphs", replications=10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- sample_pa(3000) },
+          { layout_with_kk(g, maxiter=500) })
diff --git a/inst/benchmarks/time_print.R b/inst/benchmarks/time_print.R
new file mode 100644
index 0000000..28ed27b
--- /dev/null
+++ b/inst/benchmarks/time_print.R
@@ -0,0 +1,54 @@
+
+time_group("Printing graphs to the screen")
+
+time_that("Print large graphs without attributes", replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000)) },
+          { print(g) })
+
+time_that("Summarize large graphs without attributes", replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000)) },
+          { summary(g) })
+
+time_that("Print large graphs with large graph attributes",
+          replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000));
+                     g <- set_graph_attr(g, "foo", 1:1000000) },
+          { print(g) })
+
+time_that("Summarize large graphs with large graph attributes",
+          replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000));
+                     g <- set_graph_attr(g, "foo", 1:1000000) },
+          { summary(g) })
+
+time_that("Print large graphs with vertex attributes", replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000));
+                     g <- set_vertex_attr(g, 'foo',
+                             value = as.character(seq_len(gorder(g)))) },
+          { print(g) })
+
+time_that("Summarize large graphs with vertex attributes", replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000));
+                     g <- set_vertex_attr(g, 'foo',
+                             value = as.character(seq_len(gorder(g)))) },
+          { print(g) })
+
+time_that("Print large graphs with edge attributes", replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000));
+                     g <- set_edge_attr(g, 'foo',
+                             value = as.character(seq_len(gsize(g)))) },
+          { print(g) })
+
+time_that("Summarize large graphs with edge attributes", replications = 10,
+          init = { library(igraph); set.seed(42) },
+          reinit = { g <- make_lattice(c(1000, 1000));
+                     g <- set_edge_attr(g, 'foo',
+                             value = as.character(seq_len(gsize(g)))) },
+          { print(g) })
diff --git a/inst/benchmarks/time_sgm.R b/inst/benchmarks/time_sgm.R
new file mode 100644
index 0000000..b1dad43
--- /dev/null
+++ b/inst/benchmarks/time_sgm.R
@@ -0,0 +1,11 @@
+
+time_group("Seeded graph matching")
+
+time_that("SGM is fast(er)", replications=10,
+          init = { library(igraph); set.seed(42); vc <- 200; nos=10 },
+          reinit = { g1 <- erdos.renyi.game(vc, .01);
+                     perm <- c(1:nos, sample(vc-nos)+nos)
+                     g2 <- sample_correlated_gnp(g1, corr=.7, p=g1$p, perm=perm)
+                   },
+          { match_vertices(g1[], g2[], m=nos, start=matrix(1/(vc-nos), vc-nos, vc-nos),
+                iteration = 20) })
diff --git a/inst/benchmarks/time_sir.R b/inst/benchmarks/time_sir.R
index cb1c082..309f947 100644
--- a/inst/benchmarks/time_sir.R
+++ b/inst/benchmarks/time_sir.R
@@ -3,5 +3,5 @@ time_group("SIR epidemics models on networks")
 
 time_that("SIR is fast", replications=10,
           init = { library(igraph); set.seed(42) },
-          reinit = { g <- erdos.renyi.game(40, 40, type="gnm") },
+          reinit = { g <- sample_gnm(40, 40) },
           { sir(g, beta=5, gamma=1, no.sim=100) })
diff --git a/inst/tests/dyad.census.R b/inst/tests/dyad.census.R
index b81ee5e..68a69d4 100644
--- a/inst/tests/dyad.census.R
+++ b/inst/tests/dyad.census.R
@@ -1,24 +1,24 @@
 
-context("dyad.census")
+context("dyad_census")
 
-test_that("dyad.census works", {
+test_that("dyad_census works", {
 
   library(igraph)
 
-  g1 <- graph.ring(10)
-  expect_that(dc1 <- dyad.census(g1), gives_warning("undirected"))
+  g1 <- make_ring(10)
+  expect_that(dc1 <- dyad_census(g1), gives_warning("undirected"))
   expect_that(dc1, equals(list(mut=10, asym=0, null=35)))
 
-  g2 <- graph.ring(10, directed=TRUE, mutual=TRUE)
-  dc2 <- dyad.census(g2)
+  g2 <- make_ring(10, directed=TRUE, mutual=TRUE)
+  dc2 <- dyad_census(g2)
   expect_that(dc2, equals(list(mut=10, asym=0, null=35)))
 
-  g3 <- graph.ring(10, directed=TRUE, mutual=FALSE)
-  dc3 <- dyad.census(g3)
+  g3 <- make_ring(10, directed=TRUE, mutual=FALSE)
+  dc3 <- dyad_census(g3)
   expect_that(dc3, equals(list(mut=0, asym=10, null=35)))
 
-  g4 <- graph.empty(2000000)
-  expect_that(dc4 <- dyad.census(g4), gives_warning("Integer overflow"))
+  g4 <- make_empty_graph(2000000)
+  expect_that(dc4 <- dyad_census(g4), gives_warning("Integer overflow"))
   expect_that(dc4, equals(list(mut=0, asym=0, null=0)))
   
 })
diff --git a/inst/tests/test-constructor-modifiers.R b/inst/tests/test-constructor-modifiers.R
new file mode 100644
index 0000000..c11aaf5
--- /dev/null
+++ b/inst/tests/test-constructor-modifiers.R
@@ -0,0 +1,116 @@
+
+context("Constructor modifiers")
+
+
+test_that("without_attr", {
+
+  set.seed(42)
+  g <- sample_gnp(10, 2/10) %>%
+    delete_graph_attr("name") %>%
+    delete_graph_attr("type") %>%
+    delete_graph_attr("loops") %>%
+    delete_graph_attr("p")
+  
+  set.seed(42)
+  g2 <- sample_(gnp(10, 2/10), without_attr())
+
+  expect_true(identical_graphs(g, g2))
+  expect_equal(graph_attr_names(g2), character())
+  expect_equal(vertex_attr_names(g2), character())
+  expect_equal(edge_attr_names(g2), character())
+
+})
+
+
+test_that("without_loops", {
+
+  g <- make_graph(~ A - A:B:C, B - A:B:C, simplify = FALSE) %>%
+     simplify(remove.multiple = FALSE)
+
+  g2 <- make_(from_literal(A - A:B:C, B - A:B:C, simplify = FALSE),
+              without_loops())
+              
+  expect_true(identical_graphs(g, g2))
+  expect_true(all(!which_loop(g2)))
+
+})
+
+
+test_that("without_multiple", {
+
+  g <- make_graph(~ A - A:B:C, B - A:B:C, simplify = FALSE) %>%
+     simplify(remove.loops = FALSE)
+
+  g2 <- make_(from_literal(A - A:B:C, B - A:B:C, simplify = FALSE),
+              without_multiples())
+              
+  expect_true(identical_graphs(g, g2))
+  expect_true(all(!which_multiple(g2)))
+
+})
+
+
+test_that("simplified", {
+
+  g <- make_graph(~ A - A:B:C, B - A:B:C)
+
+  g2 <- make_(from_literal(A - A:B:C, B - A:B:C, simplify = FALSE),
+              simplified())
+  
+  expect_true(identical_graphs(g, g2))
+  expect_true(all(!which_multiple(g2)))
+  expect_true(all(!which_loop(g2)))
+  
+})
+
+
+test_that("with_vertex_", {
+
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_vertex_attr("color", value = "red") %>%
+    set_vertex_attr("foo", value = paste0("xx", 1:3))
+
+  g2 <- make_(from_literal(A - A:B:C, B - A:B:C),
+              with_vertex_(color = "red",
+                           foo = paste0("xx", 1:3))
+              )
+
+  expect_true(identical_graphs(g, g2))
+  expect_equal(V(g2)$color, rep("red", gorder(g2)))
+  expect_equal(V(g2)$foo, paste0("xx", 1:3))
+  
+})
+
+
+test_that("with_edge_", {
+
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_edge_attr("color", value = "red") %>%
+    set_edge_attr("foo", value = seq_len(3))
+
+  g2 <- make_(from_literal(A - A:B:C, B - A:B:C),
+              with_edge_(color = "red",
+                         foo = seq_len(3)))
+
+  expect_true(identical_graphs(g, g2))
+  expect_equal(E(g)$color, E(g2)$color)
+  expect_equal(E(g)$foo, E(g2)$foo)
+  
+})
+
+
+test_that("with_graph_", {
+
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_graph_attr("color", value = "red") %>%
+    set_graph_attr("foo", value = 1:5)
+
+  g2 <- make_(from_literal(A - A:B:C, B - A:B:C),
+              with_graph_(color = "red",
+                          foo = 1:5))
+
+  expect_true(identical_graphs(g, g2))
+  expect_equal(g$color, g2$color)
+  expect_equal(g$foo, g2$foo)
+  
+})
diff --git a/inst/tests/test-index-es.R b/inst/tests/test-index-es.R
new file mode 100644
index 0000000..ebb8270
--- /dev/null
+++ b/inst/tests/test-index-es.R
@@ -0,0 +1,40 @@
+
+context("VS/ES indexing")
+
+test_that("I can index a vs twice", {
+
+  edges <- data.frame(
+    stringsAsFactors = TRUE,
+    from    = c("BOS", "JFK", "DEN", "BOS", "JFK", "DEN"),
+    to      = c("JFK", "DEN", "ABQ", "JFK", "DEN", "ABQ"),
+    carrier = c("foo", "foo", "foo", "bar", "bar", "bar")
+  )
+
+  vertices <- data.frame(
+    stringsAsFactors = TRUE,
+    id      = c("BOS", "JFK", "DEN", "ABQ"),
+    state   = c("MA",  "NY",  "CO",  "NM")
+  )
+
+  g <- graph_from_data_frame(edges, vertices = vertices)
+
+  x <- V(g)[ 3:4 ] [ state == 'NM' ]
+
+  expect_equal(x, V(g)['ABQ'])
+})
+
+test_that("I can index an es twice", {
+
+  edges <- data.frame(
+    stringsAsFactors = TRUE,
+    from    = c("BOS", "JFK", "DEN", "BOS", "JFK", "DEN"),
+    to      = c("JFK", "DEN", "ABQ", "JFK", "DEN", "ABQ"),
+    carrier = c("foo", "foo", "foo", "bar", "bar", "bar")
+  )
+
+  g <- graph_from_data_frame(edges)
+
+  x <- E(g)['BOS' %->% 'JFK'][carrier == 'foo']
+
+  expect_equal(x, E(g)[ carrier == 'foo' & from('BOS') & to('JFK')])
+})
diff --git a/inst/tests/test-isomorphism.R b/inst/tests/test-isomorphism.R
new file mode 100644
index 0000000..dbb55e5
--- /dev/null
+++ b/inst/tests/test-isomorphism.R
@@ -0,0 +1,121 @@
+
+context("New isomorphism API")
+
+test_that("isomorphic", {
+
+  g <- graph_(from_literal(A - B - C - A))
+  expect_true(isomorphic(g, g))
+  expect_true(isomorphic(g, g, method = "direct"))
+  expect_true(isomorphic(g, g, method = "vf2"))
+  expect_true(isomorphic(g, g, method = "bliss"))
+
+  g2 <- graph_(from_literal(A - B - C))
+  expect_false(isomorphic(g, g2))
+  expect_false(isomorphic(g, g2, method = "direct"))
+  expect_false(isomorphic(g, g2, method = "vf2"))
+  expect_false(isomorphic(g, g2, method = "bliss"))
+  
+})
+
+test_that("subgraph_isomorphic", {
+
+  g <- graph_(from_literal(A - B - C - D - E - A))
+  g2 <- graph_(from_literal(A - B - C - D))
+
+  expect_true(subgraph_isomorphic(g2, g))
+  expect_true(subgraph_isomorphic(g2, g, method = "vf2"))
+  expect_true(subgraph_isomorphic(g2, g, method = "lad"))
+
+  g3 <- graph_(from_literal(A - B - C - A))
+  expect_false(subgraph_isomorphic(g3, g))
+  expect_false(subgraph_isomorphic(g3, g, method = "vf2"))
+  expect_false(subgraph_isomorphic(g3, g, method = "lad"))
+  
+})
+
+test_that("count_isomorphisms", {
+
+  g <- graph_(from_literal(A - B - C - D - A))
+  expect_equal(count_isomorphisms(g, g), 8)
+
+  g2 <- graph_(from_literal(A - B - C - A))
+  expect_equal(count_isomorphisms(g, g2), 0)
+  
+})
+
+test_that("count_subgraph_isomorphisms", {
+
+  g <- graph_(from_literal(A - B - C - D - A))
+  g2 <- graph_(from_literal(A - B - C - D))
+
+  expect_equal(count_subgraph_isomorphisms(g2, g, method = "lad"), 8)
+  expect_equal(count_subgraph_isomorphisms(g2, g, method = "vf2"), 8)
+
+  g3 <- graph_(from_literal(A - B - C - A))
+  expect_equal(count_subgraph_isomorphisms(g3, g, method = "lad"), 0)
+  expect_equal(count_subgraph_isomorphisms(g3, g, method = "vf2"), 0)
+  
+})
+
+test_that("isomorphisms", {
+
+  g <- graph_(from_literal(A - B - C - D - A))
+  g2 <- graph_(from_literal(W - X - Y - Z - W))
+
+  res <- list(V(g2)[1,2,3,4],
+              V(g2)[1,4,3,2],
+              V(g2)[2,1,4,3],
+              V(g2)[2,3,4,1],
+              V(g2)[3,2,1,4],
+              V(g2)[3,4,1,2],
+              V(g2)[4,1,2,3],
+              V(g2)[4,3,2,1])
+                
+  expect_equivalent(isomorphisms(g, g2), res)
+
+  g3 <- graph_(from_literal(X - Y - Z - X))
+  expect_equal(isomorphisms(g, g3), list())
+
+})
+
+test_that("subgraph_isomorphisms, lad", {
+
+  g <- graph_(from_literal(A - B - C - D - A))
+  g2 <- graph_(from_literal(Z - X - Y))
+
+  res <- list(V(g)[1,4,3],
+              V(g)[1,2,3],
+              V(g)[2,1,4],
+              V(g)[2,3,4],
+              V(g)[3,2,1],
+              V(g)[3,4,1],
+              V(g)[4,3,2],
+              V(g)[4,1,2])
+  
+  expect_equivalent(subgraph_isomorphisms(g2, g, method = "lad"), res)
+
+  g3 <- graph_(from_literal(X - Y - Z - X))
+  expect_equal(subgraph_isomorphisms(g3, g, method = "lad"), list())
+
+})
+
+test_that("subgraph_isomorphisms, vf2", {
+
+  g <- graph_(from_literal(A - B - C - D - A))
+  g2 <- graph_(from_literal(Z - X - Y))
+
+  res <- list(V(g)[1,2,3],
+              V(g)[1,4,3],
+              V(g)[2,1,4],
+              V(g)[2,3,4],
+              V(g)[3,2,1],
+              V(g)[3,4,1],
+              V(g)[4,1,2],
+              V(g)[4,3,2])
+  
+  expect_equivalent(subgraph_isomorphisms(g2, g, method = "vf2"), res)
+
+  g3 <- graph_(from_literal(X - Y - Z - X))
+  expect_equal(subgraph_isomorphisms(g3, g, method = "vf2"), list())
+
+})
diff --git a/inst/tests/test-make.R b/inst/tests/test-make.R
new file mode 100644
index 0000000..19f08a2
--- /dev/null
+++ b/inst/tests/test-make.R
@@ -0,0 +1,61 @@
+
+context("Make API")
+
+test_that("make_ works, order of arguments does not matter", {
+
+  g0 <- make_undirected_graph(1:10)
+  g1 <- make_(undirected_graph(1:10))
+  g2 <- make_(undirected_graph(), 1:10)
+  g3 <- make_(1:10, undirected_graph())
+
+  expect_true(identical_graphs(g0, g1))
+  expect_true(identical_graphs(g0, g2))
+  expect_true(identical_graphs(g0, g3))
+  
+})
+
+test_that("sample_, graph_ also work", {
+
+  g0 <- make_undirected_graph(1:10)
+  g1 <- sample_(undirected_graph(1:10))
+  g2 <- sample_(undirected_graph(), 1:10)
+  g3 <- sample_(1:10, undirected_graph())
+  
+  expect_true(identical_graphs(g0, g1))
+  expect_true(identical_graphs(g0, g2))
+  expect_true(identical_graphs(g0, g3))
+
+  g4 <- graph_(undirected_graph(1:10))
+  g5 <- graph_(undirected_graph(), 1:10)
+  g6 <- graph_(1:10, undirected_graph())
+
+  expect_true(identical_graphs(g0, g4))
+  expect_true(identical_graphs(g0, g5))
+  expect_true(identical_graphs(g0, g6))
+
+})
+
+test_that("error messages are proper", {
+
+  expect_error(make_(), "Don't know how to make_")
+  expect_error(make_(1:10), "Don't know how to make_")
+
+  expect_error(graph_(), "Don't know how to graph_")
+  expect_error(graph_(1:10), "Don't know how to graph_")
+  expect_error(graph_(directed_graph(), directed_graph()),
+               "Don't know how to graph_")
+
+  expect_error(sample_(), "Don't know how to sample_")
+  expect_error(sample_(1:10), "Don't know how to sample_")
+  expect_error(sample_(directed_graph(), directed_graph()),
+               "Don't know how to sample_")
+
+})
+
+test_that("we pass arguments unevaluated", {
+
+  g0 <- graph_from_literal(A -+ B:C)
+  g1 <- graph_(from_literal(A -+ B:C))
+  expect_true(identical_graphs(g0, g1))
+
+})
diff --git a/inst/tests/test-make_graph.R b/inst/tests/test-make_graph.R
new file mode 100644
index 0000000..c2652b6
--- /dev/null
+++ b/inst/tests/test-make_graph.R
@@ -0,0 +1,57 @@
+
+context("make_graph")
+
+test_that("make_graph works", {
+
+  g <- make_graph(1:10)
+  g2 <- make_empty_graph(n = 10) + edges(1:10)
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("make_graph works for numeric edges and isolates", {
+
+  g <- make_graph(1:10, n = 20)
+  g2 <- make_empty_graph(n = 20) + edges(1:10)
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("make_graph handles names", {
+
+  g <- make_graph(letters[1:10])
+  g2 <- make_empty_graph() + vertices(letters[1:10]) + edges(letters[1:10])
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("make_graph hadles names and isolates", {
+
+  g <- make_graph(letters[1:10], isolates = letters[11:20])
+  g2 <- make_empty_graph() + vertices(letters[1:20]) + edges(letters[1:10])
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("make_graph gives warning for ignored arguments", {
+
+  expect_warning(
+    make_graph(letters[1:10], n = 10)
+  )
+
+  expect_warning(
+    make_graph(1:10, isolates = 11:12)
+  )
+
+})
+
+test_that("a make_graph bug is fixed", {
+
+  E <- cbind(1, 3)
+  d <- 3
+  g <- graph(as.vector(t(E)), d, FALSE)
+
+  expect_equal(vcount(g), 3)
+  expect_equal(ecount(g), 1)
+
+})
diff --git a/inst/tests/test-new-layout-api.R b/inst/tests/test-new-layout-api.R
new file mode 100644
index 0000000..74a9d88
--- /dev/null
+++ b/inst/tests/test-new-layout-api.R
@@ -0,0 +1,59 @@
+
+`%>%` <- magrittr::`%>%`
+
+context("New layout API")
+
+test_that("two step layouting works", {
+
+  g <- make_ring(10)
+  l1 <- layout_as_star(g)
+  l2 <- layout_(g, as_star())
+  expect_identical(l1, l2)
+
+})
+
+test_that("parameters go through", {
+
+  g <- make_ring(10)
+  l1 <- layout_as_star(g, center = 5)
+  l2 <- layout_(g, as_star(center = 5))
+  expect_identical(l1, l2)
+
+})
+
+test_that("parameters are evaluated early", {
+
+  g <- make_ring(10)
+  l1 <- layout_as_star(g, center = 5)
+
+  cc <- 5
+  spec <- as_star(center = cc)
+  cc <- 10
+  l2 <- layout_(g, spec)
+  expect_identical(l1, l2)
+
+})
+
+test_that("piping form is OK, too", {
+
+  g <- make_ring(10)
+  l1 <- layout_as_star(g, center = 5)
+  l2 <- g %>%
+    layout_(as_star(center = 5))
+  expect_identical(l1, l2)
+
+})
+
+test_that("add_layout_ works", {
+
+  g <- make_ring(10)
+  l1 <- layout_as_star(g, center = 5)
+  l2 <- add_layout_(g, as_star(center = 5))$layout
+  expect_identical(l1, l2)
+
+  l3 <- g %>%
+    add_layout_(as_star(center = 5)) %>%
+    graph_attr("layout")
+  expect_identical(l1, l3)
+
+})
diff --git a/inst/tests/test-notable.R b/inst/tests/test-notable.R
new file mode 100644
index 0000000..40906ae
--- /dev/null
+++ b/inst/tests/test-notable.R
@@ -0,0 +1,38 @@
+
+context("Notable graphs")
+
+test_that("notable graphs work with make_graph", {
+
+  g <- make_graph("Levi")
+  g2 <- graph.famous("Levi")
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("make_graph for notable graphs is case insensitive", {
+
+  g <- make_graph("Levi")
+  g2 <- make_graph("levi")
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("spaces are replaced in make_graph for notable graphs", {
+
+  g <- make_graph("Krackhardt_Kite")
+  g2 <- make_graph("Krackhardt kite")
+  expect_true(identical_graphs(g, g2))
+
+})
+
+test_that("warnings are given for extra arguments in make_graph for notables", {
+
+  g0 <- make_graph("Levi")
+  expect_warning(g1 <- make_graph("Levi", n = 10))
+  expect_warning(g2 <- make_graph("Levi", isolates = "foo"))
+  expect_warning(g3 <- make_graph("Levi", directed = FALSE))
+  expect_true(identical_graphs(g0, g1))
+  expect_true(identical_graphs(g0, g2))
+  expect_true(identical_graphs(g0, g3))
+
+})
diff --git a/inst/tests/test-old-data-type.R b/inst/tests/test-old-data-type.R
new file mode 100644
index 0000000..135d7c1
--- /dev/null
+++ b/inst/tests/test-old-data-type.R
@@ -0,0 +1,68 @@
+
+context("Old data type and VS/ES")
+
+test_that("VS/ES work with old data type", {
+
+  karate <-
+    structure(list(
+      34,
+      FALSE,
+      c(1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 
+        13, 17, 19, 21, 31, 2, 3, 7, 13, 17, 19, 21, 30, 3, 7, 8, 9, 
+        13, 27, 28, 32, 7, 12, 13, 6, 10, 6, 10, 16, 16, 30, 32, 33, 
+        33, 33, 32, 33, 32, 33, 32, 33, 33, 32, 33, 32, 33, 25, 27, 29, 
+        32, 33, 25, 27, 31, 31, 29, 33, 33, 31, 33, 32, 33, 32, 33, 32, 
+        33, 33),
+      c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 
+        1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 
+        5, 5, 6, 8, 8, 8, 9, 13, 14, 14, 15, 15, 18, 18, 19, 20, 20, 
+        22, 22, 23, 23, 23, 23, 23, 24, 24, 24, 25, 26, 26, 27, 28, 28, 
+        29, 29, 30, 30, 31, 31, 32),
+      c(0, 1, 16, 2, 17, 24, 3, 4, 5, 
+        35, 37, 6, 18, 25, 32, 7, 26, 27, 8, 36, 38, 9, 10, 33, 11, 19, 
+        28, 34, 39, 40, 12, 20, 13, 21, 14, 22, 57, 62, 29, 58, 63, 30, 
+        59, 66, 23, 41, 15, 64, 65, 69, 31, 42, 46, 48, 50, 53, 55, 60, 
+        71, 73, 75, 43, 44, 45, 47, 49, 51, 52, 54, 56, 61, 67, 68, 70, 
+        72, 74, 76, 77),
+      c(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
+        13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 
+        29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 
+        45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 
+        61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 
+        77),
+      c(0, 0, 1, 3, 6, 7, 8, 11, 15, 17, 18, 21, 22, 24, 28, 28, 
+        28, 30, 32, 32, 34, 34, 36, 36, 36, 36, 38, 38, 41, 42, 44, 46, 
+        50, 61, 78),
+      c(0, 16, 24, 32, 35, 37, 40, 41, 41, 44, 45, 45, 
+        45, 45, 46, 48, 50, 50, 50, 52, 53, 55, 55, 57, 62, 65, 66, 68, 
+        69, 71, 73, 75, 77, 78, 78),
+      list(c(1, 0, 1), structure(list(
+        name = "Zachary's karate club network",
+        Citation = "Wayne W. Zachary. An Information Flow Model for Conflict and Fission in Small Groups. Journal of Anthropological Research Vol. 33, No. 4 452-473", 
+        Author = "Wayne W. Zachary"), .Names = c("name", "Citation", "Author")),
+           structure(list(
+             Faction = c(1, 1, 1, 1, 1, 1, 1, 1, 
+               2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 
+               2, 2, 2, 2, 2),
+             name = c("Mr Hi", "Actor 2", "Actor 3", "Actor 4", 
+               "Actor 5", "Actor 6", "Actor 7", "Actor 8", "Actor 9", "Actor 10", 
+               "Actor 11", "Actor 12", "Actor 13", "Actor 14", "Actor 15", "Actor 16", 
+               "Actor 17", "Actor 18", "Actor 19", "Actor 20", "Actor 21", "Actor 22", 
+               "Actor 23", "Actor 24", "Actor 25", "Actor 26", "Actor 27", "Actor 28", 
+               "Actor 29", "Actor 30", "Actor 31", "Actor 32", "Actor 33", "John A"
+                      )), .Names = c("Faction", "name")),
+           structure(list(
+             weight = c(4, 
+               5, 3, 3, 3, 3, 2, 2, 2, 3, 1, 3, 2, 2, 2, 2, 6, 3, 4, 5, 1, 2, 
+               2, 2, 3, 4, 5, 1, 3, 2, 2, 2, 3, 3, 3, 2, 3, 5, 3, 3, 3, 3, 3, 
+               4, 2, 3, 3, 2, 3, 4, 1, 2, 1, 3, 1, 2, 3, 5, 4, 3, 5, 4, 2, 3, 
+               2, 7, 4, 2, 4, 2, 2, 4, 2, 3, 3, 4, 4, 5)), .Names = "weight"))),
+              class = "igraph")
+
+  karate2 <- upgrade_graph(karate)
+  vs <- V(karate)
+  vs2 <- V(karate2)
+
+  expect_equal(length(vs), length(vs2))
+  expect_equal(vs$name, vs2$name)
+})
diff --git a/inst/tests/test-random_walk.R b/inst/tests/test-random_walk.R
new file mode 100644
index 0000000..5c57beb
--- /dev/null
+++ b/inst/tests/test-random_walk.R
@@ -0,0 +1,28 @@
+
+context("Random walks")
+
+test_that("Undirected", {
+
+  set.seed(42)
+  g <- make_ring(10)
+  w <- random_walk(g, start = 1, steps = 10)
+  expect_equivalent(w, structure(c(1L, 10L, 9L, 8L, 9L, 10L, 9L, 10L,
+                                   1L, 10L), class = "igraph.vs"))
+
+})
+
+test_that("Directed", {
+
+  set.seed(42)
+  g <- make_ring(10, directed = TRUE)
+  w <- as_ids(random_walk(g, start = 1, steps = 5))
+  expect_equal(w, 1:5)
+
+  w2 <- as_ids(random_walk(g, start = 5, steps = 5, mode = "in"))
+  expect_equal(w2, 5:1)
+
+  set.seed(42)
+  w3 <- as_ids(random_walk(g, start = 1, steps = 5, mode = "all"))
+  expect_equal(w3, c(1, 10, 9, 8, 9))
+
+})
diff --git a/inst/tests/test-version.R b/inst/tests/test-version.R
new file mode 100644
index 0000000..397098a
--- /dev/null
+++ b/inst/tests/test-version.R
@@ -0,0 +1,20 @@
+
+context("igraph_version")
+
+test_that("igraph_version returns a version string", {
+
+  ## This is essentially a semver regex, we do not allow a
+  ## leading 'v' and space after
+  regex <- paste0(
+    "\\b",                                             # word boundary
+    "(?:0|[1-9][0-9]*)\\.",                           # major
+    "(?:0|[1-9][0-9]*)\\.",                           # minor
+    "(?:0|[1-9][0-9]*)",                              # patch
+    "(?:-[\\da-zA-Z\\-]+(?:\\.[\\da-zA-Z\\-]+)*)?",   # prerelease
+    "(?:\\+[\\da-zA-Z\\-]+(?:\\.[\\da-zA-Z\\-]+)*)?", # word boundary
+    "\\b"
+  )
+
+  expect_true(grepl(regex, igraph_version()))
+
+})
diff --git a/inst/tests/test-versions.R b/inst/tests/test-versions.R
new file mode 100644
index 0000000..8e2e719
--- /dev/null
+++ b/inst/tests/test-versions.R
@@ -0,0 +1,25 @@
+
+context("Data version and conversion")
+
+test_that("we create graphs of the current version", {
+
+  g <- make_ring(10)
+  v1 <- graph_version(g)
+  v2 <- graph_version()
+  expect_equal(v1, v2)
+
+})
+
+test_that("we can upgrade from 0.4.0 to 0.8.0", {
+
+  g <- make_ring(10)
+  g <- unclass(g)
+  g[[10]] <- NULL
+  class(g) <- "igraph"
+
+  expect_equal(graph_version(g), "0.4.0")
+
+  g2 <- upgrade_graph(g)
+  expect_equal(graph_version(g2), "0.8.0")
+
+})
diff --git a/inst/tests/test-vs-es-printing.R b/inst/tests/test-vs-es-printing.R
new file mode 100644
index 0000000..aa9ed6e
--- /dev/null
+++ b/inst/tests/test-vs-es-printing.R
@@ -0,0 +1,88 @@
+
+context("Detailed printing of vs and es")
+
+test_that("vs printing", {
+
+  set.seed(42)
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_vertex_attr("color", value = "red") %>%
+    set_vertex_attr("weight", value = sample(1:10, 3))
+
+  o1 <- c("+ 1/3 vertex, named:", "  name color weight",
+          "1    A   red     10")
+  expect_output(V(g)[[1]], paste(o1, collapse = "\n"), fixed = TRUE)
+
+  o2 <- c("+ 1/3 vertex, named:", "  name color weight",
+          "2    B   red      9")
+  expect_output(V(g)[[2]], paste(o2, collapse = "\n"), fixed = TRUE)
+
+  o3 <- c("+ 2/3 vertices, named:", "  name color weight",
+          "1    A   red     10", "2    B   red      9")
+  expect_output(V(g)[[1:2]], paste(o3, collapse = "\n"), fixed = TRUE)
+
+  o4 <- c("+ 2/3 vertices, named:", "  name color weight",
+          "2    B   red      9",  "3    C   red      3")
+  expect_output(V(g)[[2:3]], paste(o4, collapse = "\n"), fixed = TRUE)
+
+})
+
+test_that("vs printing, complex attributes", {
+
+  set.seed(42)
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_vertex_attr("color", value = "red") %>%
+    set_vertex_attr("weight", value = sample(1:10, 3)) %>%
+    set_vertex_attr("cplx", value = replicate(3, 1:4, simplify = FALSE))
+
+  o1 <- c("+ 1/3 vertex, named:", "$name", "[1] \"A\"", "", "$color",
+          "[1] \"red\"", "", "$weight", "[1] 10", "", "$cplx", "$cplx[[1]]",
+          "[1] 1 2 3 4", "", "")
+  expect_output(V(g)[[1]], paste(o1, collapse = "\n"), fixed = TRUE)
+
+  o2 <- c("+ 2/3 vertices, named:", "$name", "[1] \"B\" \"C\"", "", "$color",
+          "[1] \"red\" \"red\"", "", "$weight", "[1] 9 3", "", "$cplx",
+          "$cplx[[1]]", "[1] 1 2 3 4", "", "$cplx[[2]]", "[1] 1 2 3 4",
+          "", "")
+  expect_output(V(g)[[2:3]], paste(o2, collapse = "\n"), fixed = TRUE)
+
+})
+
+test_that("es printing", {
+
+  set.seed(42)
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_edge_attr("color", value = "red") %>%
+    set_edge_attr("weight", value = sample(1:10, 3))
+
+  o1 <- c("+ 1/3 edge (vertex names):",
+          "  tail head tid hid color weight",
+          "1    B    A   2   1   red     10")
+  expect_output(E(g)[[1]], paste(o1, collapse = "\n"), fixed = TRUE)
+
+  o2 <- c("+ 2/3 edges (vertex names):",
+          "  tail head tid hid color weight",
+          "2    C    A   3   1   red      9",
+          "3    C    B   3   2   red      3")
+  expect_output(E(g)[[2:3]], paste(o2, collapse = "\n"), fixed = TRUE)
+
+})
+
+test_that("es printing, complex attributes", {
+
+  set.seed(42)
+  g <- make_graph(~ A - A:B:C, B - A:B:C) %>%
+    set_edge_attr("color", value = "red") %>%
+    set_edge_attr("weight", value = sample(1:10, 3)) %>%
+    set_edge_attr("cmpx", value = replicate(3, 1:4, simplify = FALSE))
+
+  o1 <- c("+ 1/3 edge (vertex names):", "$color", "[1] \"red\"", "",
+          "$weight", "[1] 10", "", "$cmpx", "$cmpx[[1]]", "[1] 1 2 3 4",
+          "", "")
+  expect_output(E(g)[[1]], paste(o1, collapse = "\n"), fixed = TRUE)
+
+  o2 <- c("+ 2/3 edges (vertex names):", "$color", "[1] \"red\" \"red\"",
+          "", "$weight", "[1] 9 3", "", "$cmpx", "$cmpx[[1]]",
+          "[1] 1 2 3 4", "", "$cmpx[[2]]", "[1] 1 2 3 4", "", "")
+  expect_output(E(g)[[2:3]], paste(o2, collapse = "\n"), fixed = TRUE)
+
+})
diff --git a/inst/tests/test-vs-es-quirks.R b/inst/tests/test-vs-es-quirks.R
new file mode 100644
index 0000000..3e6ed41
--- /dev/null
+++ b/inst/tests/test-vs-es-quirks.R
@@ -0,0 +1,32 @@
+
+context("Vertex and edge sequence quirks")
+
+test_that("graph is not updated if not in LHS", {
+
+  g <- make_(ring(10),
+             with_vertex_(name = LETTERS[1:10]),
+             with_edge_(weight = 1:10))
+
+  vs <- V(g)[1:5]
+  vs$name <- letters[1:5]
+  expect_equal(V(g)$name, LETTERS[1:10])
+
+  es <- E(g)
+  es$weight <- 0
+  expect_equal(E(g)$weight, 1:10)
+
+})
+
+test_that("graph is updated if in LHS", {
+
+  g <- make_(ring(10),
+             with_vertex_(name = LETTERS[1:10]),
+             with_edge_(weight = 1:10))
+
+  V(g)[1:5]$name <- letters[1:5]
+  expect_equal(V(g)$name, c(letters[1:5], LETTERS[6:10]))
+
+  E(g)[1:5]$weight <- 0
+  expect_equal(E(g)$weight, c(rep(0, 5), 6:10))
+
+})
diff --git a/inst/tests/test-vs-es.R b/inst/tests/test-vs-es.R
new file mode 100644
index 0000000..876b614
--- /dev/null
+++ b/inst/tests/test-vs-es.R
@@ -0,0 +1,272 @@
+
+context("Vertex and edge sequences")
+
+test_that("we can create vertex/edge seqs", {
+
+  g <- make_ring(10)
+  V(g) %&&% expect_true(TRUE)
+  E(g) %&&% expect_true(TRUE)
+
+  V(g)$name <- letters[1:10]
+  V(g) %&&% expect_true(TRUE)
+  E(g) %&&% expect_true(TRUE)
+
+  g <- make_ring(10)
+  E(g)$name <- LETTERS[1:10]
+  E(g) %&&% expect_true(TRUE)
+
+})
+
+test_that("vs/es keeps names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+  vs <- V(g)
+
+  expect_equal(vs$name, names(vs))
+
+  vs2 <- vs[4:7]
+  expect_equal(vs2$name, names(vs2))
+
+  E(g)$name <- LETTERS[1:10]
+  es <- E(g)
+
+  expect_equal(es$name, names(es))
+
+  es2 <- es[4:7]
+  expect_equal(es2$name, names(es2))
+})
+
+test_that("vs/es refers to the graph", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  expect_identical(get_vs_graph(vs), g)
+  expect_identical(get_es_graph(es), g)
+
+})
+
+test_that("vs/es refers to the original graph", {
+
+  g <- g2 <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  g <- g + 4
+
+  expect_identical(get_vs_graph(vs), g2)
+  expect_identical(get_es_graph(es), g2)
+
+})
+
+test_that("vs/es references are weak", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  rm(g)
+  gc()
+
+  expect_null(get_vs_graph(vs))
+  expect_null(get_es_graph(es))
+  
+})
+
+test_that("save/load breaks references", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  tmp <- tempfile()
+  on.exit(try(unlink(tmp)))
+  
+  save(vs, es, file = tmp)
+  rm(vs, es)
+  gc()
+
+  load(tmp)
+  expect_null(get_vs_graph(vs))
+  expect_null(get_es_graph(es))
+
+})
+
+test_that("we can use vs/es with broken refs", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  rm(g)
+  gc()
+
+  g2 <- make_ring(10)
+  ## TODO
+  
+})
+
+test_that("vs/es keeps names after graph is deleted", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+  vs <- V(g)
+
+  E(g)$name <- LETTERS[1:10]
+  es <- E(g)
+  
+  rm(g)
+  gc()
+  
+  expect_equal(names(vs), letters[1:10])
+
+  vs2 <- vs[4:7]
+  expect_equal(names(vs2), letters[4:7])
+
+  expect_equal(names(es), LETTERS[1:10])
+
+  es2 <- es[4:7]
+  expect_equal(names(es2), LETTERS[4:7])
+})
+
+test_that("both edge and vertex names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+  E(g)$name <- LETTERS[1:10]
+
+  es <- E(g)
+  expect_equal(as.vector(es), 1:10)
+  expect_equal(names(es), LETTERS[1:10])
+  el <- as_edgelist(g)
+  expect_equal(attr(es, "vnames"), paste(el[,1], el[,2], sep = "|"))
+
+  x1 <- es[LETTERS[4:7]]
+  x2 <- E(g)[4:7]
+  expect_equal(as.vector(x1), as.vector(x2))
+  expect_equal(names(x1), names(x2))
+  expect_equal(attr(x1, "vnames"), attr(x2, "vnames"))
+
+  y1 <- es[c('a|b', 'd|e')]
+  y2 <- E(g)[c(1,4)]
+  expect_equal(as.vector(y1), as.vector(y2))
+  expect_equal(names(y1), names(y2))
+  expect_equal(attr(y1, "vnames"), attr(y2, "vnames"))
+
+})
+
+test_that("printing connected vs/es works", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  expect_output(print(vs), fixed = TRUE,
+    "+ 10/10 vertices:\n [1]  1  2  3  4  5  6  7  8  9 10")
+  expect_output(print(es), fixed = TRUE,
+    "+ 10/10 edges:\n [1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 6-- 7 7-- 8 8-- 9 9--10 1--10")
+
+  vs2 <- vs[1:5]
+  es2 <- es[1:5]
+
+  expect_output(print(vs2), fixed = TRUE,
+    "+ 5/10 vertices:\n[1] 1 2 3 4 5")
+  expect_output(print(es2), fixed = TRUE,
+    "+ 5/10 edges:\n[1] 1--2 2--3 3--4 4--5 5--6")
+
+  vs3 <- vs[numeric()]
+  es3 <- es[numeric()]
+
+  expect_output(print(vs3), fixed = TRUE, "+ 0/10 vertices:")
+  expect_output(print(es3), fixed = TRUE, "+ 0/10 edges:")
+
+  V(g)$name <- letters[1:10]
+  vs <- V(g)
+  es <- E(g)
+
+  expect_output(print(vs), fixed = TRUE,
+    "+ 10/10 vertices, named:\n [1] a b c d e f g h i j")
+  expect_output(print(es), fixed = TRUE,
+    "+ 10/10 edges (vertex names):\n [1] a--b b--c c--d d--e e--f f--g g--h h--i i--j a--j")
+
+  vs2 <- vs[1:5]
+  es2 <- es[1:5]
+
+  expect_output(print(vs2), fixed = TRUE,
+    "+ 5/10 vertices, named:\n[1] a b c d e")
+  expect_output(print(es2), fixed = TRUE,
+    "+ 5/10 edges (vertex names):\n[1] a--b b--c c--d d--e e--f")
+
+  vs3 <- vs[numeric()]
+  es3 <- es[numeric()]
+
+  expect_output(print(vs3), fixed = TRUE, "+ 0/10 vertices, named:")
+  expect_output(print(es3), fixed = TRUE, "+ 0/10 edges (vertex names):")
+})
+
+test_that("printing unconnected vs/es works", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)
+
+  rm(g)
+  gc()
+
+  expect_output(print(vs), fixed = TRUE,
+    "+ 10/? vertices:\n [1]  1  2  3  4  5  6  7  8  9 10")                
+  expect_output(print(es), fixed = TRUE,
+    "+ 10/? edges, unknown graph:\n [1]  1  2  3  4  5  6  7  8  9 10")
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+  vs <- V(g)
+  es <- E(g)
+
+  rm(g)
+  gc()
+
+  expect_output(print(vs), fixed = TRUE,
+    "+ 10/? vertices, named:\n [1] a b c d e f g h i j")
+  expect_output(print(es), fixed = TRUE,
+    "+ 10/? edges, unknown graph (vertex names):\n [1] a|b b|c c|d d|e e|f f|g g|h h|i i|j a|j")
+  
+})
+
+test_that("unconnected vs/es can be reused with the same graph", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  es <- E(g)[1:5]
+
+  tmp <- tempfile()
+  on.exit(unlink(tmp))
+  save(g, es, vs, file = tmp)
+
+  rm(g, es, vs)
+  gc()
+
+  load(tmp)
+
+  expect_equal(degree(g, v = vs), rep(2, 10))
+  expect_true(identical_graphs(
+    delete_edges(g, es),
+    delete_edges(g, 1:5)
+  ))
+})
+
+test_that("indexing without arguments", {
+
+  g <- make_ring(10)
+
+  x <- V(g)[]
+  expect_equal(V(g), x)
+
+  x2 <- V(g)[[]]
+  v <- V(g)
+  attr(v, "single") <- TRUE
+
+  expect_equal(v, x2)
+})
diff --git a/inst/tests/test-vs-indexing-lapply.R b/inst/tests/test-vs-indexing-lapply.R
new file mode 100644
index 0000000..0531a33
--- /dev/null
+++ b/inst/tests/test-vs-indexing-lapply.R
@@ -0,0 +1,11 @@
+
+context("VS/ES indexing")
+
+test_that("VS/ES indexing works in tricky situations", {
+
+  g <- make_ring(10)
+  x <- list(V(g)[1:5], V(g)[6:10])
+  lapply(x, function(i) { V(g)[i] })
+  lapply(x, function(i) { V(g)[[i]] })
+
+})
diff --git a/inst/tests/test-vs-operators.R b/inst/tests/test-vs-operators.R
new file mode 100644
index 0000000..410a491
--- /dev/null
+++ b/inst/tests/test-vs-operators.R
@@ -0,0 +1,651 @@
+
+context("VS/ES operators")
+
+test_that("c on attached vs", {
+  g <- make_ring(10)
+
+  vg <- V(g)[1:5]
+  vg2 <- V(g)[6:10]
+  expect_equivalent(c(vg, vg2), V(g))
+  expect_equal(get_vs_graph_id(c(vg, vg2)), get_graph_id(g))
+
+  vg <- V(g)
+  vg2 <- V(g)[FALSE]
+  expect_equivalent(c(vg, vg2), V(g))
+  expect_equivalent(c(vg2, vg), V(g))
+
+  vg <- V(g)[c(2,5,6,8)]
+  expect_equivalent(c(vg, vg), V(g)[c(2,5,6,8,2,5,6,8)])
+})
+
+test_that("c on detached vs", {
+  g <- make_ring(10)
+
+  vg <- V(g)[1:5]
+  vg2 <- V(g)[6:10]
+
+  vg3 <- V(g)
+  vg4 <- V(g)[FALSE]
+
+  vg5 <- V(g)[c(2,5,6,8)]
+  vg6 <- V(g)[c(2,5,6,8,2,5,6,8)]
+
+  rm(g)
+  gc()
+
+  expect_equivalent(c(vg, vg2), vg3)
+  expect_equivalent(c(vg3, vg4), vg3)
+  expect_equivalent(c(vg4, vg3), vg3)
+  expect_equivalent(c(vg5, vg5), vg6)
+})
+
+test_that("c on attached vs, names", {
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  vg <- V(g)[1:5]
+  vg2 <- V(g)[6:10]
+  expect_equivalent(c(vg, vg2), V(g))
+  expect_equal(names(c(vg, vg2)), names(V(g)))
+
+  vg <- V(g)
+  vg2 <- V(g)[FALSE]
+  expect_equivalent(c(vg, vg2), V(g))
+  expect_equal(names(c(vg, vg2)), names(V(g)))
+  expect_equivalent(c(vg2, vg), V(g))
+  expect_equal(names(c(vg2, vg)), names(V(g)))
+
+  vg <- V(g)[c(2,5,6,8)]
+  expect_equivalent(c(vg, vg), V(g)[c(2,5,6,8,2,5,6,8)])
+  expect_equal(names(c(vg, vg)), names(V(g)[c(2,5,6,8,2,5,6,8)]))
+})
+
+test_that("c on detached vs, names", {
+  g <- make_ring(10)
+
+  vg <- V(g)[1:5]
+  vg2 <- V(g)[6:10]
+
+  vg3 <- V(g)
+  vg4 <- V(g)[FALSE]
+
+  vg5 <- V(g)[c(2,5,6,8)]
+  vg6 <- V(g)[c(2,5,6,8,2,5,6,8)]
+
+  rm(g)
+  gc()
+
+  expect_equivalent(c(vg, vg2), vg3)
+  expect_equal(names(c(vg, vg2)), names(vg3))
+  expect_equivalent(c(vg3, vg4), vg3)
+  expect_equal(names(c(vg3, vg4)), names(vg3))
+  expect_equivalent(c(vg4, vg3), vg3)
+  expect_equal(names(c(vg3, vg4)), names(vg3))
+  expect_equivalent(c(vg5, vg5), vg6)
+  expect_equal(names(c(vg5, vg5)), names(vg6))
+})
+
+
+
+test_that("union on attached vs", {
+
+  g <- make_ring(10)
+
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  vu <- union(v1, v2)
+  expect_equivalent(vu, V(g))
+
+  expect_equivalent(union(V(g)), V(g))
+
+  v3 <- V(g)[FALSE]
+  expect_equivalent(union(V(g), v3), V(g))
+  expect_equivalent(union(v3, V(g), v3), V(g))
+  expect_equivalent(union(v3), v3)
+  expect_equivalent(union(v3, v3, v3), v3)
+  expect_equivalent(union(v3, v3), v3)
+})
+
+test_that("union on detached vs", {
+
+  g <- make_ring(10)
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  vu <- union(v1, v2)
+  v3 <- V(g)[FALSE]
+
+  rm(g)
+  gc()
+
+  expect_equivalent(vu, vg)
+
+  expect_equivalent(union(vg), vg)
+
+  expect_equivalent(union(vg, v3), vg)
+  expect_equivalent(union(v3, vg, v3), vg)
+  expect_equivalent(union(v3), v3)
+  expect_equivalent(union(v3, v3, v3), v3)
+  expect_equivalent(union(v3, v3), v3)
+
+})
+
+test_that("union on attached vs, names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  vu <- union(v1, v2)
+  expect_equivalent(vu, V(g))
+  expect_equal(names(vu), names(V(g)))
+
+  expect_equivalent(union(V(g)), V(g))
+  expect_equal(names(union(V(g))), names(V(g)))
+
+  v3 <- V(g)[FALSE]
+  expect_equivalent(union(V(g), v3), V(g))
+  expect_equal(names(union(V(g), v3)), names(V(g)))
+
+  expect_equivalent(union(v3, V(g), v3), V(g))
+  expect_equal(names(union(v3, V(g), v3)), names(V(g)))
+
+  expect_equivalent(union(v3), v3)
+  expect_equal(names(union(v3)), names(v3))
+
+  expect_equivalent(union(v3, v3, v3), v3)
+  expect_equal(names(union(v3, v3, v3)), names(v3))
+
+  expect_equivalent(union(v3, v3), v3)
+  expect_equal(names(union(v3, v3)), names(v3))
+
+})
+
+test_that("union on detached vs, names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+
+  rm(g)
+  gc()
+
+  vu <- union(v1, v2)
+  expect_equivalent(vu, vg)
+  expect_equal(names(vu), names(vg))
+
+  expect_equivalent(union(vg), vg)
+  expect_equal(names(union(vg)), names(vg))
+
+  expect_equivalent(union(vg, v3), vg)
+  expect_equal(names(union(vg, v3)), names(vg))
+
+  expect_equivalent(union(v3, vg, v3), vg)
+  expect_equal(names(union(v3, vg, v3)), names(vg))
+
+  expect_equivalent(union(v3), v3)
+  expect_equal(names(union(v3)), names(v3))
+
+  expect_equivalent(union(v3, v3, v3), v3)
+  expect_equal(names(union(v3, v3, v3)), names(v3))
+
+  expect_equivalent(union(v3, v3), v3)
+  expect_equal(names(union(v3, v3)), names(v3))
+
+})
+
+
+
+test_that("intersection on attached vs", {
+
+  g <- make_ring(10)
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  v12 <- V(g)[6:7]
+  v13 <- V(g)[FALSE]
+  v14 <- V(g)[1:3]
+  v24 <- V(g)[FALSE]
+
+  vi1 <- intersection(v1, v2)
+  expect_equivalent(vi1, v12)
+
+  vi2 <- intersection(v1, v3)
+  expect_equivalent(vi2, v13)
+
+  vi3 <- intersection(v1, v4)
+  expect_equivalent(vi3, v14)
+
+  vi4 <- intersection(v1, vg)
+  expect_equivalent(vi4, v1)
+
+  vi5 <- intersection(v2, v4)
+  expect_equivalent(vi5, v24)
+
+  vi6 <- intersection(v3, vg)
+  expect_equivalent(vi6, v3)
+
+})
+
+test_that("intersection on detached vs", {
+
+  g <- make_ring(10)
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  v12 <- V(g)[6:7]
+  v13 <- V(g)[FALSE]
+  v14 <- V(g)[1:3]
+  v24 <- V(g)[FALSE]
+
+  rm(g)
+  gc()
+
+  vi1 <- intersection(v1, v2)
+  expect_equivalent(vi1, v12)
+
+  vi2 <- intersection(v1, v3)
+  expect_equivalent(vi2, v13)
+
+  vi3 <- intersection(v1, v4)
+  expect_equivalent(vi3, v14)
+
+  vi4 <- intersection(v1, vg)
+  expect_equivalent(vi4, v1)
+
+  vi5 <- intersection(v2, v4)
+  expect_equivalent(vi5, v24)
+
+  vi6 <- intersection(v3, vg)
+  expect_equivalent(vi6, v3)
+
+})
+
+test_that("intersection on attached vs, names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  v12 <- V(g)[6:7]
+  v13 <- V(g)[FALSE]
+  v14 <- V(g)[1:3]
+  v24 <- V(g)[FALSE]
+
+  vi1 <- intersection(v1, v2)
+  expect_equivalent(vi1, v12)
+  expect_equal(names(vi1), names(v12))
+
+  vi2 <- intersection(v1, v3)
+  expect_equivalent(vi2, v13)
+  expect_equal(names(vi2), names(v13))
+
+  vi3 <- intersection(v1, v4)
+  expect_equivalent(vi3, v14)
+  expect_equal(names(vi3), names(v14))
+
+  vi4 <- intersection(v1, vg)
+  expect_equivalent(vi4, v1)
+  expect_equal(names(vi4), names(v1))
+
+  vi5 <- intersection(v2, v4)
+  expect_equivalent(vi5, v24)
+  expect_equal(names(vi5), names(v24))
+
+  vi6 <- intersection(v3, vg)
+  expect_equivalent(vi6, v3)
+  expect_equal(names(vi6), names(v3))
+
+})
+
+test_that("intersection on detached vs, names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  v12 <- V(g)[6:7]
+  v13 <- V(g)[FALSE]
+  v14 <- V(g)[1:3]
+  v24 <- V(g)[FALSE]
+
+  rm(g)
+  gc()
+
+  vi1 <- intersection(v1, v2)
+  expect_equivalent(vi1, v12)
+  expect_equal(names(vi1), names(v12))
+
+  vi2 <- intersection(v1, v3)
+  expect_equivalent(vi2, v13)
+  expect_equal(names(vi2), names(v13))
+
+  vi3 <- intersection(v1, v4)
+  expect_equivalent(vi3, v14)
+  expect_equal(names(vi3), names(v14))
+
+  vi4 <- intersection(v1, vg)
+  expect_equivalent(vi4, v1)
+  expect_equal(names(vi4), names(v1))
+
+  vi5 <- intersection(v2, v4)
+  expect_equivalent(vi5, v24)
+  expect_equal(names(vi5), names(v24))
+
+  vi6 <- intersection(v3, vg)
+  expect_equivalent(vi6, v3)
+  expect_equal(names(vi6), names(v3))
+
+})
+
+
+
+test_that("difference on attached vs", {
+
+  g <- make_ring(10)
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  vr1 <- V(g)[8:10]
+  vr2 <- V(g)
+  vr3 <- V(g)[1:5]
+  vr4 <- V(g)[4:7]
+  vr5 <- V(g)[FALSE]
+  vr6 <- V(g)[FALSE]
+
+  vd1 <- difference(vg, v1)
+  vd2 <- difference(vg, v3)
+  vd3 <- difference(v1, v2)
+  vd4 <- difference(v1, v4)
+  vd5 <- difference(v3, v3)
+  vd6 <- difference(v3, v4)
+
+  expect_equivalent(vd1, vr1)
+  expect_equivalent(vd2, vr2)
+  expect_equivalent(vd3, vr3)
+  expect_equivalent(vd4, vr4)
+  expect_equivalent(vd5, vr5)
+  expect_equivalent(vd6, vr6)
+
+})
+
+test_that("difference on detached vs", {
+
+  g <- make_ring(10)
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  vr1 <- V(g)[8:10]
+  vr2 <- V(g)
+  vr3 <- V(g)[1:5]
+  vr4 <- V(g)[4:7]
+  vr5 <- V(g)[FALSE]
+  vr6 <- V(g)[FALSE]
+
+  rm(g)
+  gc()
+
+  vd1 <- difference(vg, v1)
+  vd2 <- difference(vg, v3)
+  vd3 <- difference(v1, v2)
+  vd4 <- difference(v1, v4)
+  vd5 <- difference(v3, v3)
+  vd6 <- difference(v3, v4)
+
+  expect_equivalent(vd1, vr1)
+  expect_equivalent(vd2, vr2)
+  expect_equivalent(vd3, vr3)
+  expect_equivalent(vd4, vr4)
+  expect_equivalent(vd5, vr5)
+  expect_equivalent(vd6, vr6)
+
+})
+
+test_that("difference on attached vs, names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  vr1 <- V(g)[8:10]
+  vr2 <- V(g)
+  vr3 <- V(g)[1:5]
+  vr4 <- V(g)[4:7]
+  vr5 <- V(g)[FALSE]
+  vr6 <- V(g)[FALSE]
+
+  vd1 <- difference(vg, v1)
+  vd2 <- difference(vg, v3)
+  vd3 <- difference(v1, v2)
+  vd4 <- difference(v1, v4)
+  vd5 <- difference(v3, v3)
+  vd6 <- difference(v3, v4)
+
+  expect_equivalent(vd1, vr1)
+  expect_equal(names(vd1), names(vr1))
+
+  expect_equivalent(vd2, vr2)
+  expect_equal(names(vd2), names(vr2))
+
+  expect_equivalent(vd3, vr3)
+  expect_equal(names(vd3), names(vr3))
+
+  expect_equivalent(vd4, vr4)
+  expect_equal(names(vd4), names(vr4))
+
+  expect_equivalent(vd5, vr5)
+  expect_equal(names(vd5), names(vr5))
+
+  expect_equivalent(vd6, vr6)
+  expect_equal(names(vd6), names(vr6))
+
+})
+
+test_that("difference on detached vs, names", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  vg <- V(g)
+  v1 <- V(g)[1:7]
+  v2 <- V(g)[6:10]
+  v3 <- V(g)[FALSE]
+  v4 <- V(g)[1:3]
+
+  vr1 <- V(g)[8:10]
+  vr2 <- V(g)
+  vr3 <- V(g)[1:5]
+  vr4 <- V(g)[4:7]
+  vr5 <- V(g)[FALSE]
+  vr6 <- V(g)[FALSE]
+
+  rm(g)
+  gc()
+
+  vd1 <- difference(vg, v1)
+  vd2 <- difference(vg, v3)
+  vd3 <- difference(v1, v2)
+  vd4 <- difference(v1, v4)
+  vd5 <- difference(v3, v3)
+  vd6 <- difference(v3, v4)
+
+  expect_equivalent(vd1, vr1)
+  expect_equal(names(vd1), names(vr1))
+
+  expect_equivalent(vd2, vr2)
+  expect_equal(names(vd2), names(vr2))
+
+  expect_equivalent(vd3, vr3)
+  expect_equal(names(vd3), names(vr3))
+
+  expect_equivalent(vd4, vr4)
+  expect_equal(names(vd4), names(vr4))
+
+  expect_equivalent(vd5, vr5)
+  expect_equal(names(vd5), names(vr5))
+
+  expect_equivalent(vd6, vr6)
+  expect_equal(names(vd6), names(vr6))
+
+})
+
+
+
+test_that("rev on attached vs", {
+
+  for (i in 1:10) {
+    g <- make_ring(10)
+    idx <- seq_len(i)
+    vg <- V(g)[idx]
+    vgr <- V(g)[rev(idx)]
+    vg2 <- rev(vg)
+    expect_equivalent(vg2, vgr)
+  }
+
+})
+
+test_that("rev on detached vs", {
+
+  for (i in 1:10) {
+    g <- make_ring(10)
+    idx <- seq_len(i)
+    vg <- V(g)[idx]
+    vgr <- V(g)[rev(idx)]
+    rm(g)
+    gc()
+    vg2 <- rev(vg)
+    expect_equivalent(vg2, vgr)
+  }
+
+})
+
+test_that("rev on attached vs, names", {
+
+  for (i in 1:10) {
+    g <- make_ring(10)
+    V(g)$name <- letters[1:10]
+    idx <- seq_len(i)
+    vg <- V(g)[idx]
+    vgr <- V(g)[rev(idx)]
+    vg2 <- rev(vg)
+    expect_equivalent(vg2, vgr)
+    expect_equal(names(vg2), names(vgr))
+  }
+
+})
+
+test_that("rev on detached vs, names", {
+
+  for (i in 1:10) {
+    g <- make_ring(10)
+    V(g)$name <- letters[1:10]
+    idx <- seq_len(i)
+    vg <- V(g)[idx]
+    vgr <- V(g)[rev(idx)]
+    rm(g)
+    gc()
+    vg2 <- rev(vg)
+    expect_equivalent(vg2, vgr)
+    expect_equal(names(vg2), names(vgr))
+  }
+
+})
+
+unique_tests <- list(
+  list(1:5,        1:5),
+  list(c(1,1,2:5), 1:5),
+  list(c(1,1,1,1), 1),
+  list(c(1,2,2,2), 1:2),
+  list(c(2,2,1,1), 2:1),
+  list(c(1,2,1,2), 1:2),
+  list(c(),        c())
+)
+
+test_that("unique on attached vs", {
+
+  sapply(unique_tests, function(d) {
+    g <- make_ring(10)
+    vg <- unique(V(g)[ d[[1]] ])
+    vr <- V(g)[ d[[2]] ]
+    expect_equivalent(vg, vr)
+  })
+
+})
+
+test_that("unique on detached vs", {
+
+  sapply(unique_tests, function(d) {
+    g <- make_ring(10)
+    vg <- V(g)[ d[[1]] ]
+    vr <- V(g)[ d[[2]] ]
+    rm(g)
+    gc()
+    vg <- unique(vg)
+    expect_equivalent(vg, vr)
+  })
+
+})
+
+test_that("unique on attached vs, names", {
+
+  sapply(unique_tests, function(d) {
+    g <- make_ring(10)
+    V(g)$name <- letters[1:10]
+    vg <- unique(V(g)[ d[[1]] ])
+    vr <- V(g)[ d[[2]] ]
+    expect_equivalent(vg, vr)
+  })
+
+})
+
+test_that("unique on detached vs, names", {
+
+  sapply(unique_tests, function(d) {
+    g <- make_ring(10)
+    V(g)$name <- letters[1:10]
+    vg <- V(g)[ d[[1]] ]
+    vr <- V(g)[ d[[2]] ]
+    rm(g)
+    gc()
+    vg <- unique(vg)
+    expect_equivalent(vg, vr)
+  })
+
+})
diff --git a/inst/tests/test-weakref.R b/inst/tests/test-weakref.R
new file mode 100644
index 0000000..fac8cd2
--- /dev/null
+++ b/inst/tests/test-weakref.R
@@ -0,0 +1,106 @@
+
+context("Weak references")
+
+test_that("we can create weak references", {
+
+  g <- new.env()
+  g$foo <- "bar"
+  value <- "foobar"
+  vs <- make_weak_ref(key = g, value = value)
+
+  expect_identical(typeof(vs), "weakref")
+  expect_identical(weak_ref_key(vs), g)
+  expect_identical(weak_ref_value(vs), value)
+
+})
+
+test_that("weak references are weak", {
+
+  g <- new.env()
+  g$foo <- "bar"
+  value <- "foobar"
+  vs <- make_weak_ref(key = g, value = value)
+
+  rm(g)
+  gc()
+  expect_null(weak_ref_key(vs))
+  expect_null(weak_ref_value(vs))
+
+})
+
+test_that("weak reference finalizer is called", {
+
+  g <- new.env()
+  g$foo <- "bar"
+  value <- "foobar"
+  hello <- ""
+  fin <- function(env) hello <<- "world"
+  vs <- make_weak_ref(key = g, value = value, finalizer = fin)
+
+  rm(g)
+  gc()
+
+  expect_equal(hello, "world")
+
+})
+
+test_that("weak reference on an embedded env", {
+
+  g <- list(yes = new.env())
+  g[[1]]$foo <- "bar"
+  value <- "foobar"
+  vs <- make_weak_ref(key = g[[1]], value = value)
+
+  rm(g)
+  gc()
+  expect_null(weak_ref_key(vs))
+  expect_null(weak_ref_value(vs))
+})
+
+test_that("embed myself, and weak ref", {
+
+  g <- list(yes = new.env())
+  assign("foo", g, envir = g[[1]])
+  value <- "foobar"
+  hello <- ""
+  fin <- function(env) hello <<- "world"
+  vs <- make_weak_ref(key = g[[1]], value = value, finalizer = fin)
+
+  rm(g)
+  gc()
+  expect_null(weak_ref_key(vs))
+  expect_null(weak_ref_value(vs))
+  expect_equal(hello, "world")
+
+})
+
+test_that("embed myself, and weak ref as attribute", {
+
+  g <- list(yes = new.env())
+  assign("foo", g, envir = g[[1]])
+  value <- "foobar"
+  hello <- ""
+  fin <- function(env) hello <<- "world"
+  z <- "footoo"
+  attr(z, "env") <- make_weak_ref(key = g[[1]], value = value,
+                                  finalizer = fin)
+
+  rm(g)
+  gc()
+  expect_null(weak_ref_key(attr(z, "env")))
+  expect_null(weak_ref_value(attr(z, "env")))
+  expect_equal(hello, "world")
+
+})
+
+test_that("weak refs work for vs", {
+
+  g <- make_ring(10)
+  vs <- V(g)
+  expect_true(!is.null(get_vs_ref(g)))
+  expect_true(!is.null(weak_ref_key(attr(vs, "env"))))
+
+  rm(g)
+  gc()
+  expect_null(weak_ref_key(attr(vs, "env")))
+})
diff --git a/inst/tests/test_add.edges.R b/inst/tests/test_add.edges.R
index 6a0f1c4..501dd0c 100644
--- a/inst/tests/test_add.edges.R
+++ b/inst/tests/test_add.edges.R
@@ -1,45 +1,48 @@
 
-context("add.edges")
+context("add_edges")
 
-test_that("add.edges keeps edge id order", {
+test_that("add_edges keeps edge id order", {
   library(igraph)
-  g <- graph.empty(10)
-  g2 <- add.edges(g, (edges <- c(1,2, 2,3, 3,4, 1,6, 1,7, 9,10)) )
-  expect_that(ecount(g2), equals(length(edges)/2))
-  expect_that(get.edge.ids(g2, edges), equals(seq_len(length(edges)/2)))
+  g <- make_empty_graph(10)
+  edges <- c(1,2, 2,3, 3,4, 1,6, 1,7, 9,10)
+  g2 <- add_edges(g, edges)
+  ec <- ecount(g2)
+  ec2 <- length(edges)/2
+  expect_equal(ec, ec2)
+  expect_equal(get.edge.ids(g2, edges), seq_len(length(edges)/2))
 })
 
-test_that("add.edges adds attributes", {
+test_that("add_edges adds attributes", {
   library(igraph)
-  g <- graph.empty(10)
-  g3 <- add.edges(g, (edges <- c(1,5, 2,6, 3,10, 4,5)),
+  g <- make_empty_graph(10)
+  g3 <- add_edges(g, (edges <- c(1,5, 2,6, 3,10, 4,5)),
                   attr=list(weight=(weights <- c(1,2,1,-1))) )
   expect_that(ecount(g3), equals(length(edges)/2))
   expect_that(get.edge.ids(g3, edges), equals(seq_len(length(edges)/2)))
   expect_that(E(g3)$weight, equals(weights))
 })
 
-test_that("add.edges unknown attributes to NA", {
+test_that("add_edges unknown attributes to NA", {
   library(igraph)
-  g <- graph.empty(10)
-  g2 <- add.edges(g, (edges <- c(1,2, 2,3, 3,4, 1,6, 1,7, 9,10)) )
-  g4 <- add.edges(g2, c(1,4, 4,6, 7,1), attr=list(weight=c(-1,1,-2.5)))
+  g <- make_empty_graph(10)
+  g2 <- add_edges(g, (edges <- c(1,2, 2,3, 3,4, 1,6, 1,7, 9,10)) )
+  g4 <- add_edges(g2, c(1,4, 4,6, 7,1), attr=list(weight=c(-1,1,-2.5)))
   expect_that(all(is.na(E(g4)$weight[seq_len(length(edges)/2)])), is_true())
 })
 
-test_that("add.edges appends attributes properly", {
+test_that("add_edges appends attributes properly", {
   library(igraph)
-  g <- graph.empty(10)
-  g3 <- add.edges(g, (edges1 <- c(1,5, 2,6, 3,10, 4,5)),
+  g <- make_empty_graph(10)
+  g3 <- add_edges(g, (edges1 <- c(1,5, 2,6, 3,10, 4,5)),
                   attr=list(weight=(weights1 <- c(1,2,1,-1))) )
-  g5 <- add.edges(g3, (edges2 <- c(10,9, 10,10, 1,1)),
+  g5 <- add_edges(g3, (edges2 <- c(10,9, 10,10, 1,1)),
                   attr=list(weight=(weights2 <- c(100,100,100))) )
   expect_that(E(g5)$weight, equals(c(weights1, weights2)))
 })
 
-test_that("add.edges signals error for zero vertex ids", {
+test_that("add_edges signals error for zero vertex ids", {
   library(igraph)
-  g <- graph.full(5) %du% graph.full(5) %du% graph.full(5)
-  expect_that(add.edges(g, c(0,5, 0,10, 5,10)),
+  g <- make_full_graph(5) %du% make_full_graph(5) %du% make_full_graph(5)
+  expect_that(add_edges(g, c(0,5, 0,10, 5,10)),
               throws_error("Invalid vertex id"))
 })
diff --git a/inst/tests/test_add.vertices.R b/inst/tests/test_add.vertices.R
index 9c0d346..782ee77 100644
--- a/inst/tests/test_add.vertices.R
+++ b/inst/tests/test_add.vertices.R
@@ -1,19 +1,19 @@
 
-context("add.vertices")
+context("add_vertices")
 
-test_that("add.vertices works", {
+test_that("add_vertices works", {
   library(igraph)
-  g <- graph.formula(A-B-C-D-E)
-  g2 <- add.vertices(g, (nv <- 4))
+  g <- graph_from_literal(A-B-C-D-E)
+  g2 <- add_vertices(g, (nv <- 4))
   expect_that(vcount(g2), equals(vcount(g) + nv))
   expect_that(ecount(g2), equals(ecount(g)))
-  expect_that(get.edgelist(g2), equals(get.edgelist(g)))
+  expect_that(as_edgelist(g2), equals(as_edgelist(g)))
 })
 
-test_that("add.vertices handles attributes properly", {
+test_that("add_vertices handles attributes properly", {
   library(igraph)
-  g <- graph.formula(A-B-C-D-E)
-  g3 <- add.vertices(g, (nv <- 3),
+  g <- graph_from_literal(A-B-C-D-E)
+  g3 <- add_vertices(g, (nv <- 3),
                      attr=list(name=(names <- c("F","G","H")),
                        weight=weights <- 1:3))
   expect_that(V(g3)$name, equals(c(V(g)$name, names)))
diff --git a/inst/tests/test_adjacency.spectral.embedding.R b/inst/tests/test_adjacency.spectral.embedding.R
new file mode 100644
index 0000000..6159970
--- /dev/null
+++ b/inst/tests/test_adjacency.spectral.embedding.R
@@ -0,0 +1,234 @@
+
+context("adjacency spectral embedding")
+
+std <- function(x) {
+  x <- zapsmall(x)
+  apply(x, 2, function(col) {
+    if (any(col < 0) && col[which(col != 0)[1]] < 0) { -col } else { col }
+  })
+}
+
+mag_order <- function(x) {
+  order(abs(x), sign(x), decreasing=TRUE)
+}
+
+mag_sort <- function(x) {
+  x[mag_order(x)]
+}
+
+test_that("Undirected, unweighted case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 15, type="gnm", directed=FALSE)
+
+  no <- 7
+  A <- g[]
+  A <- A + 1/2 * diag(degree(g))
+  ss <- eigen(A)
+
+  U <- std(ss$vectors)
+  X <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+
+  au_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_la$D, equals(ss$values[1:no]))
+  expect_that(au_la$D, equals(ss$values[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+  expect_that(std(au_la$X), equals(X[,1:no]))
+
+  au_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_lm$D, equals(mag_sort(ss$values)[1:no]))
+  expect_that(au_lm$D, equals(mag_sort(ss$values)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(ss$values)][,1:no])))
+  expect_that(std(au_lm$X), equals(X[,mag_order(ss$values)][,1:no]))
+
+  au_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_sa$D, equals(ss$values[vcount(g)-1:no+1]))
+  expect_that(au_sa$D, equals(ss$values[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+  expect_that(std(au_sa$X), equals(X[,vcount(g)-1:no+1]))
+})
+
+test_that("Undirected, weighted case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+  E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
+
+  no <- 3
+  A <- g[]
+  A <- A + 1/2 * diag(degree(g))
+  ss <- eigen(A)
+
+  U <- std(ss$vectors)
+  X <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+
+  au_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_la$D, equals(ss$values[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+  expect_that(au_la$D, equals(ss$values[1:no]))
+  expect_that(std(au_la$X), equals(X[,1:no]))
+  
+  au_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_lm$D, equals(mag_sort(ss$values)[1:no]))
+  expect_that(au_lm$D, equals(mag_sort(ss$values)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(ss$values)][,1:no])))
+  expect_that(std(au_lm$X), equals(X[,mag_order(ss$values)][,1:no]))
+
+  au_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+  expect_that(std(au_sa$X), equals(X[,vcount(g)-1:no+1]))
+})
+
+test_that("Directed, unweighted case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=TRUE)
+
+  no <- 3
+  A <- g[]
+  A <- A + 1/2 * diag(degree(g))
+  ss <- svd(A)
+
+  U <- std(ss$u)
+  V <- std(ss$v)
+  X <- std(ss$u %*% sqrt(diag(ss$d)))
+  Y <- std(ss$v %*% sqrt(diag(ss$d)))
+
+  au_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_la$D, equals(ss$d[1:no]))
+  expect_that(au_la$D, equals(ss$d[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+  expect_that(std(as_la$Y), equals(std(V[,1:no])))
+  expect_that(std(au_la$X), equals(X[,1:no]))
+  expect_that(std(au_la$Y), equals(Y[,1:no]))
+
+  au_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_lm$D, equals(ss$d[1:no]))
+  expect_that(au_lm$D, equals(ss$d[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,1:no])))
+  expect_that(std(as_lm$Y), equals(std(V[,1:no])))
+  expect_that(std(au_lm$X), equals(X[,1:no]))
+  expect_that(std(au_lm$Y), equals(Y[,1:no]))
+
+  au_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(as_sa$D, equals(ss$d[vcount(g)-1:no+1]))
+  expect_that(au_sa$D, equals(ss$d[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+  expect_that(std(as_sa$Y), equals(std(V[,vcount(g)-1:no+1])))
+  expect_that(std(au_sa$X), equals(X[,vcount(g)-1:no+1]))
+  expect_that(std(au_sa$Y), equals(Y[,vcount(g)-1:no+1]))
+})
+
+test_that("Directed, weighted case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=TRUE)
+  E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
+
+  no <- 3
+  A <- g[]
+  A <- A + 1/2 * diag(degree(g))
+  ss <- svd(A)
+
+  U <- std(ss$u)
+  V <- std(ss$v)
+  X <- std(ss$u %*% sqrt(diag(ss$d)))
+  Y <- std(ss$v %*% sqrt(diag(ss$d)))
+
+  au_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_la <- embed_adjacency_matrix(g, no=no, which="la",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+  expect_that(std(as_la$Y), equals(std(V[,1:no])))
+  expect_that(std(au_la$X), equals(X[,1:no]))
+  expect_that(std(au_la$Y), equals(Y[,1:no]))
+
+  au_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_lm <- embed_adjacency_matrix(g, no=no, which="lm",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(std(as_lm$X), equals(std(U[,1:no])))
+  expect_that(std(as_lm$Y), equals(std(V[,1:no])))
+  expect_that(std(au_lm$X), equals(X[,1:no]))
+  expect_that(std(au_lm$Y), equals(Y[,1:no]))
+
+  au_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=TRUE)
+  as_sa <- embed_adjacency_matrix(g, no=no, which="sa",
+                                        cvec=degree(g)/2, scaled=FALSE)
+
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+  expect_that(std(as_sa$Y), equals(std(V[,vcount(g)-1:no+1])))
+  expect_that(std(au_sa$X), equals(X[,vcount(g)-1:no+1]))
+  expect_that(std(au_sa$Y), equals(Y[,vcount(g)-1:no+1]))
+})
+
+test_that("Issue #50 is resolved", {
+
+  library(igraph)
+  set.seed(12345)
+
+  g <- erdos.renyi.game(15, .4)
+  w <- -log(runif(ecount(g)))
+  X1 <- embed_adjacency_matrix(g, 2, weights= w)
+
+  E(g)$weight <- w
+  X2 <- embed_adjacency_matrix(g, 2)
+
+  expect_that(X1$D, equals(X2$D))
+
+})
+
+test_that("Issue #51 is resolved", {
+  library(igraph)
+  set.seed(12345)
+
+  pref.matrix <- diag(0.2, 2) + 0.2
+  block.sizes <- c(800, 800)
+  n <- sum(block.sizes)
+  g <- sbm.game(n, pref.matrix, block.sizes, directed=TRUE)
+
+  for (i in 1:25) {
+    ase <-  embed_adjacency_matrix(g, 2)
+    expect_that(mean(ase$X %*% t(ase$Y)), equals(0.299981018354173))
+  }
+})
diff --git a/inst/tests/test_all.st.cuts.R b/inst/tests/test_all.st.cuts.R
index 10fcd49..f0212e4 100644
--- a/inst/tests/test_all.st.cuts.R
+++ b/inst/tests/test_all.st.cuts.R
@@ -5,26 +5,28 @@ test_that("all.st.cuts works", {
 
   library(igraph)
 
-  g <- graph.formula( a -+ b -+ c -+ d -+ e )
-  cc <- stCuts(g, source="a", target="e")
-  expect_that(cc$cuts, equals(list(1,2,3,4)))
-  expect_that(cc$partition1s, equals(list(1, 1:2, 1:3, 1:4)))
+  unvs <- function(x) lapply(x, as.vector)
 
-  g2 <- graph.formula( s -+ a:b -+ t, a -+ 1:2:3 -+ b )
-  cc <- stCuts(g2, source="s", target="t")
-  expect_that(cc$cuts, equals(list(c(1,2), c(1,7), c(2,3,4,5,6),
+  g <- graph_from_literal( a -+ b -+ c -+ d -+ e )
+  cc <- st_cuts(g, source="a", target="e")
+  expect_that(unvs(cc$cuts), equals(list(1,2,3,4)))
+  expect_that(unvs(cc$partition1s), equals(list(1, 1:2, 1:3, 1:4)))
+
+  g2 <- graph_from_literal( s -+ a:b -+ t, a -+ 1:2:3 -+ b )
+  cc <- st_cuts(g2, source="s", target="t")
+  expect_that(unvs(cc$cuts), equals(list(c(1,2), c(1,7), c(2,3,4,5,6),
                                    c(2,3,4,5,10), c(2,3,4,6,9),
                                    c(2,3,4,9,10), c(2,3,5,6,8),
                                    c(2,3,5,8,10), c(2,3,6,8,9),
                                    c(2,3,8,9,10), c(3,7))))
-  expect_that(cc$partition1s,
+  expect_that(unvs(cc$partition1s),
               equals(list(1, c(1,3), c(1,2), c(1,2,7), c(1,2,6),
                           c(1,2,6,7), c(1,2,5), c(1,2,5,7), c(1,2,5,6),
                           c(1,2,5,6,7), c(1,2,5,6,7,3))))
 
-  g3 <- graph.formula( s -+ a:b -+ t, a -+ 1:2:3:4:5 -+ b )
-  cc <- stMincuts(g2, source="s", target="t")
+  g3 <- graph_from_literal( s -+ a:b -+ t, a -+ 1:2:3:4:5 -+ b )
+  cc <- st_min_cuts(g2, source="s", target="t")
   expect_that(cc$value, equals(2))
-  expect_that(cc$cuts, equals(list(c(1,2), c(1,7), c(3,7))))
-  expect_that(cc$partition1s, equals(list(1, c(1,3), c(1,3,2,7,6,5))))
+  expect_that(unvs(cc$cuts), equals(list(c(1,2), c(1,7), c(3,7))))
+  expect_that(unvs(cc$partition1s), equals(list(1, c(1,3), c(1,3,2,7,6,5))))
 })
diff --git a/inst/tests/test_alpha.centrality.R b/inst/tests/test_alpha.centrality.R
index 679f9f8..56b7356 100644
--- a/inst/tests/test_alpha.centrality.R
+++ b/inst/tests/test_alpha.centrality.R
@@ -1,34 +1,34 @@
 
-context("alpha.centrality")
+context("alpha_centrality")
 
-test_that("dense alpha.centrality works", {
+test_that("dense alpha_centrality works", {
   library(igraph)
   g.1 <- graph( c(1,3,2,3,3,4,4,5) )
-  ac1 <- alpha.centrality(g.1, sparse=FALSE)
+  ac1 <- alpha_centrality(g.1, sparse=FALSE)
   expect_that(ac1, equals(c(1, 1, 3, 4, 5)))
   
   g.2 <- graph( c(2,1,3,1,4,1,5,1) )
-  ac2 <- alpha.centrality(g.2, sparse=FALSE)
+  ac2 <- alpha_centrality(g.2, sparse=FALSE)
   expect_that(ac2, equals(c(5,1,1,1,1)))
   
   g.3 <- graph( c(1,2,2,3,3,4,4,1,5,1) )
-  ac3 <- alpha.centrality(g.3, alpha=0.5, sparse=FALSE)
+  ac3 <- alpha_centrality(g.3, alpha=0.5, sparse=FALSE)
   expect_that(ac3, equals(c(76, 68, 64, 62, 30)/30))
 })
 
-test_that("sparse alpha.centrality works", {
+test_that("sparse alpha_centrality works", {
   if (require(Matrix, quietly=TRUE)) {
     library(igraph)
     g.1 <- graph( c(1,3,2,3,3,4,4,5) )
-    ac1 <- alpha.centrality(g.1, sparse=TRUE)
+    ac1 <- alpha_centrality(g.1, sparse=TRUE)
     expect_that(ac1, equals(c(1, 1, 3, 4, 5)))
   
     g.2 <- graph( c(2,1,3,1,4,1,5,1) )
-    ac2 <- alpha.centrality(g.2, sparse=TRUE)
+    ac2 <- alpha_centrality(g.2, sparse=TRUE)
     expect_that(ac2, equals(c(5,1,1,1,1)))
     
     g.3 <- graph( c(1,2,2,3,3,4,4,1,5,1) )
-    ac3 <- alpha.centrality(g.3, alpha=0.5, sparse=TRUE)
+    ac3 <- alpha_centrality(g.3, alpha=0.5, sparse=TRUE)
     expect_that(ac3, equals(c(76, 68, 64, 62, 30)/30))
   }
 })
@@ -36,34 +36,49 @@ test_that("sparse alpha.centrality works", {
 ##############################
 ## weighted version
 
-test_that("weighted dense alpha.centrality works", {
+test_that("weighted dense alpha_centrality works", {
   library(igraph)
-  star <- graph.star(10)
+  star <- make_star(10)
   E(star)$weight <- sample(ecount(star))
 
-  ac1 <- alpha.centrality(star, sparse=FALSE)
+  ac1 <- alpha_centrality(star, sparse=FALSE)
   expect_that(ac1, equals(c(46, 1, 1, 1, 1, 1, 1, 1, 1, 1)))
 
-  ac2 <- alpha.centrality(star, weights="weight", sparse=FALSE)
+  ac2 <- alpha_centrality(star, weights="weight", sparse=FALSE)
   expect_that(ac2, equals(c(46, 1, 1, 1, 1, 1, 1, 1, 1, 1)))
   
-  ac3 <- alpha.centrality(star, weights=NA, sparse=FALSE)
+  ac3 <- alpha_centrality(star, weights=NA, sparse=FALSE)
   expect_that(ac3, equals(c(vcount(star), 1, 1, 1, 1, 1, 1, 1, 1, 1)))
 })
 
-test_that("weighted sparse alpha.centrality works", {
+test_that("weighted sparse alpha_centrality works", {
   if (require("Matrix", quietly=TRUE)) {
     library(igraph)
-    star <- graph.star(10)
+    star <- make_star(10)
     E(star)$weight <- sample(ecount(star))
     
-    ac1 <- alpha.centrality(star, sparse=TRUE)
+    ac1 <- alpha_centrality(star, sparse=TRUE)
     expect_that(ac1, equals(c(46, 1, 1, 1, 1, 1, 1, 1, 1, 1)))
     
-    ac2 <- alpha.centrality(star, weights="weight", sparse=TRUE)
+    ac2 <- alpha_centrality(star, weights="weight", sparse=TRUE)
     expect_that(ac2, equals(c(46, 1, 1, 1, 1, 1, 1, 1, 1, 1)))
     
-    ac3 <- alpha.centrality(star, weights=NA, sparse=TRUE)
+    ac3 <- alpha_centrality(star, weights=NA, sparse=TRUE)
     expect_that(ac3, equals(c(vcount(star), 1, 1, 1, 1, 1, 1, 1, 1, 1)))
   }
 })
+
+test_that("undirected, alpha centrality works, #653", {
+  if (require("Matrix", quietly = TRUE)) {
+    library(igraph)
+    g <- make_ring(10)
+
+    ac1 <- alpha_centrality(g, sparse = TRUE)
+    ac2 <- alpha_centrality(g, sparse = FALSE)
+    expect_that(ac1, equals(ac2))
+
+    g2 <- as.directed(g, mode="mutual")
+    ac3 <- alpha_centrality(g, sparse = FALSE)
+    expect_that(ac1, equals(ac3))
+  }
+})
diff --git a/inst/tests/test_are.connected.R b/inst/tests/test_are.connected.R
index c6931ca..3f62711 100644
--- a/inst/tests/test_are.connected.R
+++ b/inst/tests/test_are.connected.R
@@ -1,23 +1,23 @@
 
-context("are.connected")
+context("are_adjacent")
 
-test_that("are.connected works", {
+test_that("are_adjacent works", {
   library(igraph)
 
-  g <- graph.formula( A-B-C, B-D )
-  expect_that(are.connected(g, "A", "B"), is_true())
-  expect_that(are.connected(g, "B", "A"), is_true())
-  expect_that(are.connected(g, "A", "D"), is_false())
+  g <- graph_from_literal( A-B-C, B-D )
+  expect_that(are_adjacent(g, "A", "B"), is_true())
+  expect_that(are_adjacent(g, "B", "A"), is_true())
+  expect_that(are_adjacent(g, "A", "D"), is_false())
 
-  g2 <- graph( c(1,2, 2,3, 3,4), dir=FALSE )
-  expect_that(are.connected(g2, 1,2), is_true())
-  expect_that(are.connected(g2, 3,2), is_true())
-  expect_that(are.connected(g2, 4,1), is_false())
+  g2 <- graph( c(1,2, 2,3, 3,4), dir= FALSE )
+  expect_that(are_adjacent(g2, 1,2), is_true())
+  expect_that(are_adjacent(g2, 3,2), is_true())
+  expect_that(are_adjacent(g2, 4,1), is_false())
   
-  g3 <- graph.formula( A-+B-+C, B-+D )
-  expect_that(are.connected(g3, "A", "C"), is_false())
-  expect_that(are.connected(g3, "A", "B"), is_true())
-  expect_that(are.connected(g3, "B", "A"), is_false())
+  g3 <- graph_from_literal( A-+B-+C, B-+D )
+  expect_that(are_adjacent(g3, "A", "C"), is_false())
+  expect_that(are_adjacent(g3, "A", "B"), is_true())
+  expect_that(are_adjacent(g3, "B", "A"), is_false())
 })
 
 
diff --git a/inst/tests/test_arpack.R b/inst/tests/test_arpack.R
index 95c3318..96cae90 100644
--- a/inst/tests/test_arpack.R
+++ b/inst/tests/test_arpack.R
@@ -20,7 +20,7 @@ test_that("arpack works on the Laplacian of a star", {
   }
   
   r1 <- arpack(f, options=list(n=10, nev=1, ncv=3), sym=TRUE)
-  r2 <- eigen(graph.laplacian(graph.star(10, mode="undirected")))
+  r2 <- eigen(laplacian_matrix(make_star(10, mode="undirected")))
   
   correctSign <- function(x) { if (x[1]<0) { -x } else { x } }
   expect_that(r1$values, equals(r2$values[1]))
diff --git a/inst/tests/test_articulation.points.R b/inst/tests/test_articulation.points.R
index 4077d30..b00c6e7 100644
--- a/inst/tests/test_articulation.points.R
+++ b/inst/tests/test_articulation.points.R
@@ -1,14 +1,14 @@
 
-context("articulation.points")
+context("articulation_points")
 
-test_that("articulation.points works", {
+test_that("articulation_points works", {
   library(igraph)
 
-  g <- graph.full(5) + graph.full(5)
-  clu <- clusters(g)$membership
-  g <- add.edges(g, c(match(1,clu), match(2,clu)) )
+  g <- make_full_graph(5) + make_full_graph(5)
+  clu <- components(g)$membership
+  g <- add_edges(g, c(match(1,clu), match(2,clu)) )
 
-  ap <- articulation.points(g)
+  ap <- as.vector(articulation_points(g))
   deg <- degree(g)
   expect_that(sort(which(deg==max(deg))), equals(sort(ap)))
 })
diff --git a/inst/tests/test_as.directed.R b/inst/tests/test_as.directed.R
index d6e9b5f..1525fbf 100644
--- a/inst/tests/test_as.directed.R
+++ b/inst/tests/test_as.directed.R
@@ -4,7 +4,7 @@ context("as.directed")
 test_that("as.directed works", {
   library(igraph)
   
-  g <- erdos.renyi.game(100, 2/100)
+  g <- sample_gnp(100, 2/100)
   g2 <- as.directed(g, mode="mutual")
   g3 <- as.directed(g, mode="arbitrary")
 
@@ -17,7 +17,7 @@ test_that("as.directed works", {
 
 test_that("as.directed keeps attributes", {
   library(igraph)
-  g <- graph.formula( A-B-C, D-A, E )
+  g <- graph_from_literal( A-B-C, D-A, E )
   g$name <- "Small graph"
   g2 <- as.directed(g, mode="mutual")
   g3 <- as.directed(g, mode="arbitrary")
@@ -27,8 +27,8 @@ test_that("as.directed keeps attributes", {
   expect_that(V(g3)$name, equals(V(g)$name))
 
   E(g)$weight <- seq_len(ecount(g))
-  g4 <- as.directed(g, "mutual") ; df4 <- get.data.frame(g4)  
-  g5 <- as.directed(g, "arbitrary") ; df5 <- get.data.frame(g5)
+  g4 <- as.directed(g, "mutual") ; df4 <- as_data_frame(g4)  
+  g5 <- as.directed(g, "arbitrary") ; df5 <- as_data_frame(g5)
   expect_that(df4[order(df4[,1], df4[,2]),]$weight, equals(c(1,2,1,3,3,2)))
   expect_that(df5[order(df5[,1], df5[,2]),]$weight, equals(1:3))
 })
diff --git a/inst/tests/test_as.undirected.R b/inst/tests/test_as.undirected.R
index e101ae8..922e880 100644
--- a/inst/tests/test_as.undirected.R
+++ b/inst/tests/test_as.undirected.R
@@ -3,13 +3,13 @@ context("as.undirected")
 
 test_that("as.undirected keeps attributes", {
   library(igraph)
-  g <- graph.formula(A+-+B, A--+C, C+-+D)
+  g <- graph_from_literal(A+-+B, A--+C, C+-+D)
   g$name <- "Tiny graph"
   E(g)$weight <- seq_len(ecount(g))
 
-  g2 <- as.undirected(g, mode="collapse") ; df2 <- get.data.frame(g2)
-  g3 <- as.undirected(g, mode="each")     ; df3 <- get.data.frame(g3)
-  g4 <- as.undirected(g, mode="mutual")   ; df4 <- get.data.frame(g4)
+  g2 <- as.undirected(g, mode="collapse") ; df2 <- as_data_frame(g2)
+  g3 <- as.undirected(g, mode="each")     ; df3 <- as_data_frame(g3)
+  g4 <- as.undirected(g, mode="mutual")   ; df4 <- as_data_frame(g4)
 
   expect_that(g2$name, equals(g$name))
   expect_that(g3$name, equals(g$name))
diff --git a/inst/tests/test_assortativity.R b/inst/tests/test_assortativity.R
index 293b32c..88b3ea8 100644
--- a/inst/tests/test_assortativity.R
+++ b/inst/tests/test_assortativity.R
@@ -4,12 +4,12 @@ context("assortativity")
 test_that("assortativity works", {
   library(igraph)
   
-  g <- read.graph(f <- gzfile("celegansneural.gml.gz"), format="gml")
+  g <- read_graph(f <- gzfile("celegansneural.gml.gz"), format="gml")
 
   assR <- function(graph) { 
     indeg <- degree(graph, mode="in")
     outdeg <- degree(graph, mode="out")
-    el <- get.edgelist(graph, names=FALSE)
+    el <- as_edgelist(graph, names=FALSE)
     J <- outdeg[el[,1]]-1
     K <- indeg[el[,2]]-1
     num <- sum(J*K) - sum(J)*sum(K)/ecount(graph)
@@ -18,18 +18,18 @@ test_that("assortativity works", {
     num / sqrt(den1) / sqrt(den2)
   }
 
-  asd <- assortativity.degree(g)
+  asd <- assortativity_degree(g)
   as <- assortativity(g, degree(g, mode="out"), degree(g, mode="in"))
   as2 <- assR(g)
 
   expect_that(asd, equals(as))
   expect_that(asd, equals(as2))
 
-  asu <- assortativity.degree(simplify(as.undirected(g, mode="collapse")))
+  asu <- assortativity_degree(simplify(as.undirected(g, mode="collapse")))
   expect_that(asu, equals(-0.16319921031570466807))
 
-  p <- read.graph(f <- gzfile("power.gml.gz"), format="gml")
-  p.asd <- assortativity.degree(p)
+  p <- read_graph(f <- gzfile("power.gml.gz"), format="gml")
+  p.asd <- assortativity_degree(p)
   p.as <- assortativity(p, degree(p))
   p.as2 <- assR(as.directed(p, mode="mutual"))
 
@@ -40,11 +40,11 @@ test_that("assortativity works", {
 test_that("nominal assortativity works", {
   library(igraph)
   
-  o <- read.graph(f <- gzfile("football.gml.gz"), format="gml")
+  o <- read_graph(f <- gzfile("football.gml.gz"), format="gml")
   o <- simplify(o)
-  an <- assortativity.nominal(o, V(o)$value+1)
+  an <- assortativity_nominal(o, V(o)$value+1)
 
-  el <- get.edgelist(o, names=FALSE)
+  el <- as_edgelist(o, names=FALSE)
   etm <- matrix(0, nr=max(V(o)$value)+1, nc=max(V(o)$value)+1)
   for (e in 1:nrow(el)) {
     t1 <- V(o)$value[ el[e,1] ]+1
diff --git a/inst/tests/test_attributes.R b/inst/tests/test_attributes.R
index 88d9819..5859200 100644
--- a/inst/tests/test_attributes.R
+++ b/inst/tests/test_attributes.R
@@ -5,9 +5,9 @@ test_that("assigning and querying attributes work", {
   library(igraph)
 
   ## Create a small ring graph, assign attributes
-  ring <- graph.formula( A-B-C-D-E-F-G-A )
+  ring <- graph_from_literal( A-B-C-D-E-F-G-A )
   E(ring)$weight <- seq_len(ecount(ring))
-  
+
   ## Query attributes
   expect_that(V(ring)$name, equals(LETTERS[seq_len(vcount(ring))]))
   expect_that(E(ring)$weight, equals(seq_len(ecount(ring))))
@@ -17,21 +17,21 @@ test_that("brackering works", {
   library(igraph)
 
   g <- graph(c(1,2, 1,3, 3,4))
-  g <- set.vertex.attribute(g, name="weight", value=1:vcount(g))
-  g <- set.edge.attribute(g, name="weight", value=1:ecount(g))
-  g <- set.graph.attribute(g, name="name", "foo")
+  g <- set_vertex_attr(g, name="weight", value=1:vcount(g))
+  g <- set_edge_attr(g, name="weight", value=1:ecount(g))
+  g <- set_graph_attr(g, name="name", "foo")
 
-  graph2 <- set.vertex.attribute(g, name="weight",
+  graph2 <- set_vertex_attr(g, name="weight",
                                  value=rep(1, vcount(g)))
-  graph2 <- set.edge.attribute(g, name="weight",
+  graph2 <- set_edge_attr(g, name="weight",
                                value=rep(1, ecount(g)))
-  graph2 <- set.graph.attribute(g, name="name", "foobar")
+  graph2 <- set_graph_attr(g, name="name", "foobar")
 
-  expect_that(get.vertex.attribute(g, name="weight"),
+  expect_that(vertex_attr(g, name="weight"),
               equals(1:4))
-  expect_that(get.edge.attribute(g, name="weight"),
+  expect_that(edge_attr(g, name="weight"),
               equals(1:3))
-  expect_that(get.graph.attribute(g, name="name"), equals("foo"))
+  expect_that(graph_attr(g, name="name"), equals("foo"))
 })
 
 test_that("brackering works with a function", {
@@ -39,33 +39,33 @@ test_that("brackering works with a function", {
   library(testthat)
 
   g <- graph(c(1,2, 1,3, 3,4))
-  g <- set.vertex.attribute(g, name="weight", value=1:vcount(g))
-  g <- set.edge.attribute(g, name="weight", value=1:ecount(g))
-  g <- set.graph.attribute(g, name="name", "foo")
+  g <- set_vertex_attr(g, name="weight", value=1:vcount(g))
+  g <- set_edge_attr(g, name="weight", value=1:ecount(g))
+  g <- set_graph_attr(g, name="name", "foo")
 
   run.test <- function(graph) {
-    graph2 <- set.vertex.attribute(graph, name="weight",
+    graph2 <- set_vertex_attr(graph, name="weight",
                                    value=rep(1, vcount(graph)))
-    graph2 <- set.edge.attribute(graph, name="weight",
+    graph2 <- set_edge_attr(graph, name="weight",
                                    value=rep(1, ecount(graph)))
-    graph2 <- set.graph.attribute(graph, name="name", "foobar")
+    graph2 <- set_graph_attr(graph, name="name", "foobar")
   }
 
   g2 <- run.test(g)
-  expect_that(get.vertex.attribute(g, name="weight"),
+  expect_that(vertex_attr(g, name="weight"),
               equals(1:4))
-  expect_that(get.edge.attribute(g, name="weight"),
+  expect_that(edge_attr(g, name="weight"),
               equals(1:3))
-  expect_that(get.graph.attribute(g, name="name"), equals("foo"))
+  expect_that(graph_attr(g, name="name"), equals("foo"))
 })
 
 test_that("brackering works with shortcuts", {
   library(igraph)
 
   g <- graph(c(1,2, 1,3, 3,4))
-  g <- set.vertex.attribute(g, name="weight", value=1:vcount(g))
-  g <- set.edge.attribute(g, name="weight", value=1:ecount(g))
-  g <- set.graph.attribute(g, name="name", "foo")
+  g <- set_vertex_attr(g, name="weight", value=1:vcount(g))
+  g <- set_edge_attr(g, name="weight", value=1:ecount(g))
+  g <- set_graph_attr(g, name="name", "foo")
 
   run.test <- function(graph) {
     V(graph)$weight <- rep(1, vcount(graph))
@@ -74,13 +74,125 @@ test_that("brackering works with shortcuts", {
   }
 
   g2 <- run.test(g)
-  expect_that(get.vertex.attribute(g, name="weight"),
+  expect_that(vertex_attr(g, name="weight"),
               equals(1:4))
-  expect_that(get.edge.attribute(g, name="weight"),
+  expect_that(edge_attr(g, name="weight"),
               equals(1:3))
-  expect_that(get.graph.attribute(g, name="name"), equals("foo"))
+  expect_that(graph_attr(g, name="name"), equals("foo"))
 })
 
 ## TODO: subsetting
 
+test_that("we can query all attributes at once", {
+
+  g <- graph(c(1,2, 1,3, 2,4))
+
+  expect_equal(graph_attr(g), structure(list(), .Names = character(0)))
+  expect_equal(vertex_attr(g), list())
+  expect_equal(edge_attr(g), list())
+
+  g$name <- "toy"
+  g$layout <- cbind(1:4, 1:4)
+  V(g)$name <- letters[1:4]
+  V(g)$color <- rainbow(4)
+  E(g)$weight <- 1:3
+  E(g)$label <- LETTERS[1:3]
+
+  expect_equal(graph_attr(g), list(name = "toy", layout = cbind(1:4, 1:4)))
+  expect_equal(vertex_attr(g), list(name = letters[1:4], color = rainbow(4)))
+  expect_equal(edge_attr(g), list(weight = 1:3, label = LETTERS[1:3]))
+
+})
+
+test_that("we can query single attributes with the generic functions", {
+
+  g <- graph(c(1,2, 1,3, 2,4))
+
+  g$name <- "toy"
+  g$layout <- cbind(1:4, 1:4)
+  V(g)$name <- letters[1:4]
+  V(g)$color <- rainbow(4)
+  E(g)$weight <- 1:3
+  E(g)$label <- LETTERS[1:3]
+
+  expect_equal(graph_attr(g, "name"), "toy")
+  expect_equal(graph_attr(g, "layout"), cbind(1:4, 1:4))
+  expect_equal(vertex_attr(g, "name"), letters[1:4])
+  expect_equal(vertex_attr(g, "color"), rainbow(4))
+  expect_equal(edge_attr(g, "weight"), 1:3)
+  expect_equal(edge_attr(g, "label"), LETTERS[1:3])
+
+})
+
+test_that("we can query a subset of vertices", {
+
+  g <- graph(c(1,2, 1,3, 2,4))
+
+  V(g)$name <- letters[1:4]
+  V(g)$color <- as.list(rainbow(4))
+  E(g)$weight <- 1:3
+  E(g)$label <- as.list(LETTERS[1:3])
+
+  expect_equal(vertex_attr(g, "name", c(1,3)), letters[c(1,3)])
+  expect_equal(vertex_attr(g, "color", c("a", "c")),
+               as.list(rainbow(4))[c(1,3)])
+  expect_equal(edge_attr(g, "weight", 2:3), 2:3)
+  expect_equal(edge_attr(g, "label", 2:3), as.list(LETTERS[1:3])[2:3])
+
+})
+
+test_that("we can set all attributes at once", {
+
+  g <- graph(c(1,2, 1,3, 2,4))
+
+  g$name <- "toy"
+  g$layout <- cbind(1:4, 1:4)
+  V(g)$name <- letters[1:4]
+  V(g)$color <- as.list(rainbow(4))
+  E(g)$weight <- 1:3
+  E(g)$label <- as.list(LETTERS[1:3])
+
+  g2 <- graph(c(2,1, 3,1, 4,1))
+
+  graph_attr(g2) <- graph_attr(g)
+  expect_equal(graph_attr(g2), graph_attr(g))
+
+  vertex_attr(g2) <- vertex_attr(g)
+  expect_equal(vertex_attr(g2), vertex_attr(g))
+
+  edge_attr(g2) <- edge_attr(g)
+  expect_equal(edge_attr(g2), edge_attr(g))
+})
+
+test_that("we can set all attributes some vertices/edges", {
+
+  g <- graph(c(1,2, 1,3, 2,4))
 
+  V(g)$name <- letters[1:4]
+  V(g)$color <- as.list(rainbow(4))
+  E(g)$weight <- 1:3
+  E(g)$label <- as.list(LETTERS[1:3])
+
+  g2 <- graph(c(2,1, 3,1, 4,1, 2,5, 3,6))
+
+  vertex_attr(g2, index = c(1, 2, 4, 5)) <- vertex_attr(g)
+  expect_equal(vertex_attr(g2), list(name = c("a", "b", NA_character_,
+    "c", "d", NA_character_),color = list(rainbow(4)[1], rainbow(4)[2], NULL,
+    rainbow(4)[3], rainbow(4)[4], NULL)))
+
+  edge_attr(g2, index = c(1, 3, 5)) <- edge_attr(g)
+  expect_equal(edge_attr(g2), list(weight = c(1L, NA_integer_, 2L,
+    NA_integer_, 3L), label = list("A", NULL, "B", NULL, "C")))
+
+})
+
+test_that("cannot use vs/es from another graph", {
+
+  g <- graph.ring(10)
+  g2 <- g + 1
+  v <- V(g)[1:4]
+  expect_error(g2 - v, "Cannot use a vertex sequence from another graph")
+
+  e <- E(g)[1:2]
+  expect_error(g2 - e, "Cannot use an edge sequence from another graph")
+})
diff --git a/inst/tests/test_authority.score.R b/inst/tests/test_authority.score.R
index de5542d..6e3d868 100644
--- a/inst/tests/test_authority.score.R
+++ b/inst/tests/test_authority.score.R
@@ -1,5 +1,5 @@
 
-context("authority.score")
+context("authority_score")
 
 test_that("authority score works", {
   library(igraph)
@@ -10,36 +10,34 @@ test_that("authority score works", {
       if (x[1] < 0) { x <- -x       }
       x
     }
-    A <- get.adjacency(graph, sparse=FALSE)
+    A <- as_adj(graph, sparse=FALSE)
     if (as) { 
       s1 <- eigen(t(A) %*% A)$vectors[,1]
-      s2 <- authority.score(graph)$vector
+      s2 <- authority_score(graph)$vector
     } else {
       s1 <- eigen(A %*% t(A))$vectors[,1]
-      s2 <- hub.score(graph)$vector
+      s2 <- hub_score(graph)$vector
     }
     expect_that(mscale(s1), is_equivalent_to(mscale(s2)))
   }
 
-  g1 <- ba.game(100, m=10)
+  g1 <- sample_pa(100, m=10)
   ashs(g1)
   ashs(g1, as=FALSE)
 
-  g2 <- erdos.renyi.game(100, 2/100)
+  g2 <- sample_gnp(100, 2/100)
   ashs(g2)
   ashs(g2, as=FALSE)
 })
 
 test_that("authority scores of a ring are all one", {
   library(igraph)
-  g3 <- graph.ring(100)
-  expect_that(authority.score(g3)$vector, equals(rep(1, vcount(g3))))
-  expect_that(hub.score(g3)$vector, equals(rep(1, vcount(g3))))
+  g3 <- make_ring(100)
+  expect_that(authority_score(g3)$vector, equals(rep(1, vcount(g3))))
+  expect_that(hub_score(g3)$vector, equals(rep(1, vcount(g3))))
 })
 
-test_that("authority.score survives stress test", {
-  library(igraph)
-  library(Matrix)
+test_that("authority_score survives stress test", {
   set.seed(42)
 
   is.principal <- function(M, lambda) {
@@ -56,16 +54,16 @@ test_that("authority.score survives stress test", {
   }
 
   for (i in 1:100) {
-    G <- erdos.renyi.game(10, sample(1:20, 1), type="gnm")
-    as <- authority.score(G)
-    M <- get.adjacency(G)
+    G <- sample_gnm(10, sample(1:20, 1))
+    as <- authority_score(G)
+    M <- as_adj(G, sparse = FALSE)
     is.good(t(M) %*% M, as$vector, as$value)
   }
 
   for (i in 1:100) {
-    G <- erdos.renyi.game(10, sample(1:20, 1), type="gnm")
-    hs <- hub.score(G)
-    M <- get.adjacency(G)
+    G <- sample_gnm(10, sample(1:20, 1))
+    hs <- hub_score(G)
+    M <- as_adj(G, sparse = FALSE)
     is.good(M %*% t(M), hs$vector, hs$value)
   }
 })
diff --git a/inst/tests/test_average.path.length.R b/inst/tests/test_average.path.length.R
index e2c3030..5ac8f78 100644
--- a/inst/tests/test_average.path.length.R
+++ b/inst/tests/test_average.path.length.R
@@ -1,12 +1,12 @@
 
-context("average.path.length")
+context("mean_distance")
 
-test_that("average.path.length works", {
+test_that("mean_distance works", {
   library(igraph)
 
   apl <- function(graph) {
-    sp <- shortest.paths(graph, mode="out")
-    if (is.directed(graph)) {
+    sp <- distances(graph, mode="out")
+    if (is_directed(graph)) {
       diag(sp) <- NA
     } else {
       sp[lower.tri(sp, diag=TRUE)] <- NA
@@ -16,19 +16,19 @@ test_that("average.path.length works", {
   }
 
   giant.component <- function(graph, mode="weak") {
-    clu <- clusters(graph, mode=mode)
-    induced.subgraph(graph, which(clu$membership==which.max(clu$csize)))
+    clu <- components(graph, mode=mode)
+    induced_subgraph(graph, which(clu$membership==which.max(clu$csize)))
   }
   
-  g <- giant.component(erdos.renyi.game(100, 3/100))
-  expect_that(apl(g), equals(average.path.length(g)))
+  g <- giant.component(sample_gnp(100, 3/100))
+  expect_that(apl(g), equals(mean_distance(g)))
 
-  g <- giant.component(erdos.renyi.game(100, 6/100, dir=TRUE), mode="strong")
-  expect_that(apl(g), equals(average.path.length(g)))
+  g <- giant.component(sample_gnp(100, 6/100, dir=TRUE), mode="strong")
+  expect_that(apl(g), equals(mean_distance(g)))
 
-  g <- erdos.renyi.game(100, 2/100)
-  expect_that(apl(g), equals(average.path.length(g)))
+  g <- sample_gnp(100, 2/100)
+  expect_that(apl(g), equals(mean_distance(g)))
   
-  g <- erdos.renyi.game(100, 4/100, dir=TRUE)
-  expect_that(apl(g), equals(average.path.length(g)))
+  g <- sample_gnp(100, 4/100, dir=TRUE)
+  expect_that(apl(g), equals(mean_distance(g)))
 })
diff --git a/inst/tests/test_ba.game.R b/inst/tests/test_ba.game.R
index 30f2596..099ec3c 100644
--- a/inst/tests/test_ba.game.R
+++ b/inst/tests/test_ba.game.R
@@ -1,59 +1,59 @@
 
-context("ba.game")
+context("sample_pa")
 
-test_that("ba.game works", {
+test_that("sample_pa works", {
   library(igraph)
 
-  g <- ba.game(100, m=2)
+  g <- sample_pa(100, m=2)
   expect_that(ecount(g), equals(197))
   expect_that(vcount(g), equals(100))
-  expect_that(is.simple(g), is_true())
+  expect_that(is_simple(g), is_true())
 
-  g2 <- ba.game(100, m=2, algorithm="psumtree-multiple")
+  g2 <- sample_pa(100, m=2, algorithm="psumtree-multiple")
   expect_that(ecount(g2), equals(198))
   expect_that(vcount(g2), equals(100))
-  expect_that(is.simple(g2), is_false())
+  expect_that(is_simple(g2), is_false())
 
-  g3 <- ba.game(100, m=2, algorithm="bag")
+  g3 <- sample_pa(100, m=2, algorithm="bag")
   expect_that(ecount(g3), equals(198))
   expect_that(vcount(g3), equals(100))
-  expect_that(is.simple(g3), is_false())
+  expect_that(is_simple(g3), is_false())
 })
 
-test_that("ba.game can start from a graph", {
+test_that("sample_pa can start from a graph", {
   library(igraph)
   set.seed(1234)
   
-  g4 <- ba.game(10, m=1, algorithm="bag", start.graph=graph.empty(5))
+  g4 <- sample_pa(10, m=1, algorithm="bag", start.graph=make_empty_graph(5))
   expect_that(ecount(g4), equals(5))
   expect_that(vcount(g4), equals(10))
   expect_that(degree(g4), equals(c(2,0,0,0,1,2,1,1,2,1)))
 
-  g6 <- ba.game(10, m=1, algorithm="bag", start.graph=graph.star(10))
-  expect_that(graph.isomorphic(g6, graph.star(10)), is_true())
+  g6 <- sample_pa(10, m=1, algorithm="bag", start.graph=make_star(10))
+  expect_that(graph.isomorphic(g6, make_star(10)), is_true())
   
-  g7 <- ba.game(10, m=3, algorithm="psumtree-multiple",
-                start.graph=graph.empty(5))
+  g7 <- sample_pa(10, m=3, algorithm="psumtree-multiple",
+                start.graph=make_empty_graph(5))
   expect_that(degree(g7, mode="out"), equals(c(0,0,0,0,0, 3,3,3,3,3)))
 
-  g8 <- ba.game(10, m=3, algorithm="psumtree-multiple",
-                start.graph=graph.star(5))
+  g8 <- sample_pa(10, m=3, algorithm="psumtree-multiple",
+                start.graph=make_star(5))
   expect_that(degree(g8, mode="out"), equals(c(0,1,1,1,1, 3,3,3,3,3)))
-  expect_that(graph.isomorphic(induced.subgraph(g8, 1:5), graph.star(5)),
+  expect_that(graph.isomorphic(induced_subgraph(g8, 1:5), make_star(5)),
               is_true())
 
-  g9 <- ba.game(10, m=3, algorithm="psumtree-multiple",
-                start.graph=graph.star(10))
-  expect_that(graph.isomorphic(g9, graph.star(10)), is_true())
+  g9 <- sample_pa(10, m=3, algorithm="psumtree-multiple",
+                start.graph=make_star(10))
+  expect_that(graph.isomorphic(g9, make_star(10)), is_true())
 
-  g10 <- ba.game(10, m=3, start.graph=graph.empty(5))
+  g10 <- sample_pa(10, m=3, start.graph=make_empty_graph(5))
   expect_that(degree(g10, mode="out"), equals(c(0,0,0,0,0, 3,3,3,3,3)))
 
-  g11 <- ba.game(10, m=3, start.graph=graph.star(5))
+  g11 <- sample_pa(10, m=3, start.graph=make_star(5))
   expect_that(degree(g11, mode="out"), equals(c(0,1,1,1,1, 3,3,3,3,3)))
-  expect_that(graph.isomorphic(induced.subgraph(g11, 1:5), graph.star(5)),
+  expect_that(graph.isomorphic(induced_subgraph(g11, 1:5), make_star(5)),
               is_true())
   
-  g12 <- ba.game(10, m=3, start.graph=graph.star(10))
-  expect_that(graph.isomorphic(g12, graph.star(10)), is_true())
+  g12 <- sample_pa(10, m=3, start.graph=make_star(10))
+  expect_that(graph.isomorphic(g12, make_star(10)), is_true())
 })
diff --git a/inst/tests/test_betweenness.R b/inst/tests/test_betweenness.R
index 25d1c29..ba6c332 100644
--- a/inst/tests/test_betweenness.R
+++ b/inst/tests/test_betweenness.R
@@ -3,7 +3,7 @@ context("betweenness")
 
 test_that("betweenness works for kite graph", {
   library(igraph)
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
                         Beverly  - Andre:Diane:Ed:Garth,
                         Carol    - Andre:Diane:Fernando,
                         Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
@@ -52,7 +52,7 @@ test_that("weighted betweenness works", {
 test_that("normalization works well", {
   library(igraph)
 
-  g1 <- graph.formula( 0 +-+ 1 +-+ 2 )
+  g1 <- graph_from_literal( 0 +-+ 1 +-+ 2 )
 
   b11 <- betweenness(g1, normalized=TRUE, directed=FALSE)
   expect_that(b11, equals(c('0'=0, '1'=1, '2'=0)))
@@ -60,7 +60,7 @@ test_that("normalization works well", {
   b12 <- betweenness(g1, normalized=TRUE, directed=TRUE)
   expect_that(b12, equals(c('0'=0, '1'=1, '2'=0)))
 
-  g2 <- graph.formula( 0 --- 1 --- 2 )
+  g2 <- graph_from_literal( 0 --- 1 --- 2 )
 
   b2  <- betweenness(g2, normalized=TRUE)
   expect_that(b2, equals(c('0'=0, '1'=1, '2'=0)))
diff --git a/inst/tests/test_biconnected.components.R b/inst/tests/test_biconnected.components.R
index e704e40..ccc4920 100644
--- a/inst/tests/test_biconnected.components.R
+++ b/inst/tests/test_biconnected.components.R
@@ -1,23 +1,24 @@
 
-context("biconnected.components")
+context("biconnected_components")
 
-test_that("biconnected.components works", {
+test_that("biconnected_components works", {
   library(igraph)
 
-  g <- graph.full(5) + graph.full(5)
-  clu <- clusters(g)$membership
-  g <- add.edges(g, c(match(1,clu), match(2,clu)) )
+  g <- make_full_graph(5) + make_full_graph(5)
+  clu <- components(g)$membership
+  g <- add_edges(g, c(match(1,clu), match(2,clu)) )
 
   sortlist <- function(list) {
     list <- lapply(list, sort)
+    list <- lapply(list, as.vector)
     list[order(sapply(list, paste, collapse="x"))]
   }
     
-  bc <- biconnected.components(g)
+  bc <- biconnected_components(g)
   expect_that(bc$no, equals(3))
   expect_that(sortlist(bc$tree_edges), equals(list(c(11,15,18,20),
                                                    c(1,5,8,10), 21)))
   expect_that(sortlist(bc$component_edges), equals(list(11:20, 1:10, 21)))
   expect_that(sortlist(bc$components), equals(list(1:5, c(1,6), 6:10)))
-  expect_that(sort(bc$articulation_points), equals(c(1,6)))
+  expect_that(sort(as.vector(bc$articulation_points)), equals(c(1,6)))
 })
diff --git a/inst/tests/test_bipartite.projection.R b/inst/tests/test_bipartite.projection.R
index 55ab875..8dc1792 100644
--- a/inst/tests/test_bipartite.projection.R
+++ b/inst/tests/test_bipartite.projection.R
@@ -1,27 +1,27 @@
 
-context("bipartite.projection")
+context("bipartite_projection")
 
-test_that("bipartite.projection works", {
+test_that("bipartite_projection works", {
   library(igraph)
   set.seed(42)
 
-  g <- graph.full.bipartite(10,5)
-  proj <- bipartite.projection(g)
-  expect_that(graph.isomorphic(proj[[1]], graph.full(10)), is_true())
-  expect_that(graph.isomorphic(proj[[2]], graph.full(5)), is_true())
+  g <- make_full_bipartite_graph(10,5)
+  proj <- bipartite_projection(g)
+  expect_that(graph.isomorphic(proj[[1]], make_full_graph(10)), is_true())
+  expect_that(graph.isomorphic(proj[[2]], make_full_graph(5)), is_true())
 
   M <- matrix(0, nr=5, nc=3)
   rownames(M) <- c("Alice", "Bob", "Cecil", "Dan", "Ethel")
   colnames(M) <- c("Party", "Skiing", "Badminton")
   M[] <- sample(0:1, length(M), replace=TRUE)
   M
-  g2 <- graph.incidence(M)
+  g2 <- graph_from_incidence_matrix(M)
   expect_that(as.matrix(g2[1:5,6:8]), equals(M))
   expect_that(as.matrix(g2[1:5,1:5]), is_equivalent_to(matrix(0, 5, 5)))
   expect_that(as.matrix(g2[6:8,6:8]), is_equivalent_to(matrix(0, 3, 3)))  
     
   g2$name <- "Event network"
-  proj2 <- bipartite.projection(g2)
+  proj2 <- bipartite_projection(g2)
   expect_that(as.matrix(proj2[[1]][]),
               is_equivalent_to(cbind(c(0,2,0,2,2), c(2,0,1,2,2),
                                      c(0,1,0,0,0), c(2,2,0,0,2),
@@ -29,62 +29,62 @@ test_that("bipartite.projection works", {
   expect_that(as.matrix(proj2[[2]][]),
               is_equivalent_to(cbind(c(0,4,1), c(4,0,1), c(1,1,0))))
   
-  bs <- bipartite.projection.size(g2)
+  bs <- bipartite_projection_size(g2)
   expect_that(bs$vcount1, equals(vcount(proj2[[1]])))
   expect_that(bs$ecount1, equals(ecount(proj2[[1]])))
   expect_that(bs$vcount2, equals(vcount(proj2[[2]])))
   expect_that(bs$ecount2, equals(ecount(proj2[[2]])))
 })
 
-test_that("bipartite.projection can calculate only one projection", {
+test_that("bipartite_projection can calculate only one projection", {
   library(igraph)
   set.seed(42)
 
-  g <- bipartite.random.game(5, 10, p=.3)
-  proj <- bipartite.projection(g)
-  proj1 <- bipartite.projection(g, which="false")
-  proj2 <- bipartite.projection(g, which="true")
+  g <- sample_bipartite(5, 10, p=.3)
+  proj <- bipartite_projection(g)
+  proj1 <- bipartite_projection(g, which="false")
+  proj2 <- bipartite_projection(g, which="true")
 
   expect_that(graph.isomorphic(proj$proj1, proj1), is_true())
   expect_that(graph.isomorphic(proj$proj2, proj2), is_true())
   expect_that(vertex.attributes(proj$proj1), equals(vertex.attributes(proj1)))
   expect_that(vertex.attributes(proj$proj2), equals(vertex.attributes(proj2)))
-  expect_that(edge.attributes(proj$proj1), equals(edge.attributes(proj1)))
-  expect_that(edge.attributes(proj$proj2), equals(edge.attributes(proj2)))
+  expect_that(edge_attr(proj$proj1), equals(edge_attr(proj1)))
+  expect_that(edge_attr(proj$proj2), equals(edge_attr(proj2)))
 
 })
 
-test_that("bipartite.projection removes 'type' attribute if requested", {
+test_that("bipartite_projection removes 'type' attribute if requested", {
 
   library(igraph)
-  g <- graph.full.bipartite(10,5)
-  proj <- bipartite.projection(g)
-  proj1 <- bipartite.projection(g, which="true")
-  proj2 <- bipartite.projection(g, which="false")
-
-  proj3 <- bipartite.projection(g, remove.type=FALSE)
-  proj4 <- bipartite.projection(g, which="true", remove.type=FALSE)
-  proj5 <- bipartite.projection(g, which="false", remove.type=FALSE)
-
-  expect_that("type" %in% list.vertex.attributes(proj[[1]]), is_false())
-  expect_that("type" %in% list.vertex.attributes(proj[[2]]), is_false())
-  expect_that("type" %in% list.vertex.attributes(proj1), is_false())
-  expect_that("type" %in% list.vertex.attributes(proj2), is_false())
-
-  expect_that("type" %in% list.vertex.attributes(proj3[[1]]), is_true())
-  expect_that("type" %in% list.vertex.attributes(proj3[[2]]), is_true())
-  expect_that("type" %in% list.vertex.attributes(proj4), is_true())
-  expect_that("type" %in% list.vertex.attributes(proj5), is_true())
+  g <- make_full_bipartite_graph(10,5)
+  proj <- bipartite_projection(g)
+  proj1 <- bipartite_projection(g, which="true")
+  proj2 <- bipartite_projection(g, which="false")
+
+  proj3 <- bipartite_projection(g, remove.type=FALSE)
+  proj4 <- bipartite_projection(g, which="true", remove.type=FALSE)
+  proj5 <- bipartite_projection(g, which="false", remove.type=FALSE)
+
+  expect_that("type" %in% vertex_attr_names(proj[[1]]), is_false())
+  expect_that("type" %in% vertex_attr_names(proj[[2]]), is_false())
+  expect_that("type" %in% vertex_attr_names(proj1), is_false())
+  expect_that("type" %in% vertex_attr_names(proj2), is_false())
+
+  expect_that("type" %in% vertex_attr_names(proj3[[1]]), is_true())
+  expect_that("type" %in% vertex_attr_names(proj3[[2]]), is_true())
+  expect_that("type" %in% vertex_attr_names(proj4), is_true())
+  expect_that("type" %in% vertex_attr_names(proj5), is_true())
 })
 
-test_that("bipartite.projection breaks for non-bipartite graphs (#543)", {
+test_that("bipartite_projection breaks for non-bipartite graphs (#543)", {
 
   library(igraph)
-  g <- graph.formula(A-0, B-1, A-1, 0-1)
+  g <- graph_from_literal(A-0, B-1, A-1, 0-1)
   V(g)$type <- V(g)$name %in% LETTERS
 
-  expect_that(bipartite.projection.size(g),
+  expect_that(bipartite_projection_size(g),
           throws_error("Non-bipartite edge found in bipartite projection"))
-  expect_that(bipartite.projection(g),
+  expect_that(bipartite_projection(g),
           throws_error("Non-bipartite edge found in bipartite projection"))
 })
diff --git a/inst/tests/test_bipartite.random.game.R b/inst/tests/test_bipartite.random.game.R
index 2ee3d99..dceaacd 100644
--- a/inst/tests/test_bipartite.random.game.R
+++ b/inst/tests/test_bipartite.random.game.R
@@ -1,55 +1,55 @@
 
-context("bipartite.random.game")
+context("sample_bipartite")
 
-test_that("bipartite.random.game works", {
+test_that("sample_bipartite works", {
 
   library(igraph)
 
   set.seed(42)
-  g1 <- bipartite.random.game(10, 5, type="gnp", p=.1)
+  g1 <- sample_bipartite(10, 5, type="gnp", p=.1)
   expect_that(g1$name, equals("Bipartite Gnp random graph"))
   expect_that(vcount(g1), equals(15))
   expect_that(ecount(g1), equals(7))
-  expect_that(bipartite.mapping(g1)$res, is_true())
-  expect_that(is.directed(g1), is_false())
+  expect_that(bipartite_mapping(g1)$res, is_true())
+  expect_that(is_directed(g1), is_false())
 
-  g2 <- bipartite.random.game(10, 5, type="gnp", p=.1, directed=TRUE)
+  g2 <- sample_bipartite(10, 5, type="gnp", p=.1, directed=TRUE)
   expect_that(vcount(g2), equals(15))
   expect_that(ecount(g2), equals(6))
-  expect_that(bipartite.mapping(g2)$res, is_true())
-  expect_that(is.directed(g2), is_true())
+  expect_that(bipartite_mapping(g2)$res, is_true())
+  expect_that(is_directed(g2), is_true())
   expect_that(str(g2), prints_text("5->11"));
 
-  g3 <- bipartite.random.game(10, 5, type="gnp", p=.1, directed=TRUE, mode="in")
+  g3 <- sample_bipartite(10, 5, type="gnp", p=.1, directed=TRUE, mode="in")
   expect_that(str(g3), prints_text("11->3"));
 
-  g4 <- bipartite.random.game(10, 5, type="gnm", m=8)
+  g4 <- sample_bipartite(10, 5, type="gnm", m=8)
   expect_that(vcount(g4), equals(15))
   expect_that(ecount(g4), equals(8))
-  expect_that(bipartite.mapping(g4)$res, is_true())
-  expect_that(is.directed(g4), is_false())  
+  expect_that(bipartite_mapping(g4)$res, is_true())
+  expect_that(is_directed(g4), is_false())  
 
-  g5 <- bipartite.random.game(10, 5, type="gnm", m=8, directed=TRUE)
+  g5 <- sample_bipartite(10, 5, type="gnm", m=8, directed=TRUE)
   expect_that(vcount(g5), equals(15))
   expect_that(ecount(g5), equals(8))
-  expect_that(bipartite.mapping(g5)$res, is_true())
-  expect_that(is.directed(g5), is_true())
+  expect_that(bipartite_mapping(g5)$res, is_true())
+  expect_that(is_directed(g5), is_true())
   expect_that(str(g5), prints_text("5->12"))
 
-  g6 <- bipartite.random.game(10, 5, type="gnm", m=8, directed=TRUE, mode="in")
+  g6 <- sample_bipartite(10, 5, type="gnm", m=8, directed=TRUE, mode="in")
   expect_that(vcount(g6), equals(15))
   expect_that(ecount(g6), equals(8))
-  expect_that(bipartite.mapping(g6)$res, is_true())
-  expect_that(is.directed(g6), is_true())
+  expect_that(bipartite_mapping(g6)$res, is_true())
+  expect_that(is_directed(g6), is_true())
   expect_that(str(g6), prints_text("12->10"))
 
 #####
 
-  g7 <- bipartite.random.game(10, 5, type="gnp", p=0.9999, directed=TRUE,
+  g7 <- sample_bipartite(10, 5, type="gnp", p=0.9999, directed=TRUE,
                               mode="all")
   expect_that(ecount(g7), equals(100))
 
-  g8 <- bipartite.random.game(10, 5, type="gnm", m=99, directed=TRUE,
+  g8 <- sample_bipartite(10, 5, type="gnm", m=99, directed=TRUE,
                               mode="all")
   expect_that(ecount(g8), equals(99))
 
diff --git a/inst/tests/test_bonpow.R b/inst/tests/test_bonpow.R
index 2513c0e..b02642a 100644
--- a/inst/tests/test_bonpow.R
+++ b/inst/tests/test_bonpow.R
@@ -5,9 +5,9 @@ test_that("Power centrality works", {
   library(igraph)
 
   ## Generate some test data from Bonacich, 1987:
-  fig1 <- graph.formula( A -+ B -+ C:D )
+  fig1 <- graph_from_literal( A -+ B -+ C:D )
   fig1.bp <- lapply(seq(0, 0.8, by=0.2), function(x)
-                    round(bonpow(fig1, exponent=x), 2))
+                    round(power_centrality(fig1, exponent=x), 2))
   expect_that(fig1.bp, equals(list(c(A=0.89, B=1.79, C=0, D=0),
                                    c(A=1.15, B=1.64, C=0, D=0),
                                    c(A=1.34, B=1.49, C=0, D=0),
@@ -16,7 +16,7 @@ test_that("Power centrality works", {
 
   g.c <- graph( c(1,2,1,3,2,4,3,5), dir=FALSE)
   bp.c <- lapply(seq(-.5, .5, by=0.1), function(x)
-                 round(bonpow(g.c, exponent=x), 2)[c(1,2,4)])
+                 round(power_centrality(g.c, exponent=x), 2)[c(1,2,4)])
 
   expect_that(bp.c, equals(list(c(0.00, 1.58, 0.00), c(0.73, 1.45, 0.36),
                                 c(0.97, 1.34, 0.49), c(1.09, 1.27, 0.54),
@@ -27,7 +27,7 @@ test_that("Power centrality works", {
 
   g.d <- graph( c(1,2,1,3,1,4,2,5,3,6,4,7), dir=FALSE)
   bp.d <- lapply(seq(-.4, .4, by=0.1), function(x)
-                 round(bonpow(g.d, exponent=x), 2)[c(1,2,5)])
+                 round(power_centrality(g.d, exponent=x), 2)[c(1,2,5)])
   expect_that(bp.d, equals(list(c(1.62, 1.08, 0.54), c(1.62, 1.08, 0.54),
                                 c(1.62, 1.08, 0.54), c(1.62, 1.08, 0.54),
                                 c(1.62, 1.08, 0.54), c(1.62, 1.08, 0.54),
@@ -36,7 +36,7 @@ test_that("Power centrality works", {
 
   g.e <- graph( c(1,2,1,3,1,4,2,5,2,6,3,7,3,8,4,9,4,10), dir=FALSE)
   bp.e <- lapply(seq(-.4, .4, by=0.1), function(x)
-                 round(bonpow(g.e, exponent=x), 2)[c(1,2,5)])
+                 round(power_centrality(g.e, exponent=x), 2)[c(1,2,5)])
   expect_that(bp.e, equals(list(c(-1.00, 1.67, -0.33), c(0.36, 1.81, 0.12),
                                 c( 1.00, 1.67,  0.33), c(1.30, 1.55, 0.43),
                                 c( 1.46, 1.46,  0.49), c(1.57, 1.40, 0.52),
@@ -46,7 +46,7 @@ test_that("Power centrality works", {
   g.f <- graph( c(1,2,1,3,1,4,2,5,2,6,2,7,3,8,3,9,3,10,4,11,4,12,4,13),
                dir=FALSE)
   bp.f <- lapply(seq(-.4, .4, by=0.1), function(x)
-                 round(bonpow(g.f, exponent=x), 2)[c(1,2,5)])
+                 round(power_centrality(g.f, exponent=x), 2)[c(1,2,5)])
   expect_that(bp.f,
               equals(list(c(-1.72, 1.53, -0.57), c(-0.55, 2.03, -0.18),
                           c( 0.44, 2.05,  0.15), c( 1.01, 1.91,  0.34),
diff --git a/inst/tests/test_bug-1019624.R b/inst/tests/test_bug-1019624.R
index 5a7a5db..777e6a4 100644
--- a/inst/tests/test_bug-1019624.R
+++ b/inst/tests/test_bug-1019624.R
@@ -1,10 +1,10 @@
 
 context("Bug 1019624")
 
-test_that("weighted graph.adjacency works on integer matrices", {
+test_that("weighted graph_from_adjacency_matrix works on integer matrices", {
   library(igraph)
   data <- matrix(c(0,0,0,2, 0,0,0,0, 0,0,0,2, 0,1,0,0), 4)
-  g <- graph.adjacency(data, weighted=TRUE)
+  g <- graph_from_adjacency_matrix(data, weighted=TRUE)
   expect_that(as.matrix(g[]), is_equivalent_to(data))
 })
 
diff --git a/inst/tests/test_bug-1032819.R b/inst/tests/test_bug-1032819.R
index 3b6f60d..4c6bbe4 100644
--- a/inst/tests/test_bug-1032819.R
+++ b/inst/tests/test_bug-1032819.R
@@ -3,10 +3,10 @@ context("Bug 1032819")
 
 test_that("VF2 isomorphism considers colors", {
   library(igraph)
-  g <- graph.full(3)
-  path <- graph.ring(3, circular=F)
+  g <- make_full_graph(3)
+  path <- make_ring(3, circular=F)
   V(g)$color <- c(1,1,2)
   V(path)$color <- c(1,2,1)
-  n <- graph.count.subisomorphisms.vf2(g, path)
+  n <- count_subgraph_isomorphisms(path, g, method = "vf2")
   expect_that(n, equals(2))
 })
diff --git a/inst/tests/test_bug-1033045.R b/inst/tests/test_bug-1033045.R
index e7e6613..f0a64d4 100644
--- a/inst/tests/test_bug-1033045.R
+++ b/inst/tests/test_bug-1033045.R
@@ -3,8 +3,8 @@ context("Bug 1033045")
 
 test_that("Minimal s-t separators work", {
   library(igraph)
-  g <- graph.formula(a -- 1:3 -- 5 -- 2:4 -- b, 1 -- 2, 3 -- 4)
-  stsep <- minimal.st.separators(g)
-  ims <- sapply(stsep, is.minimal.separator, graph=g)
+  g <- graph_from_literal(a -- 1:3 -- 5 -- 2:4 -- b, 1 -- 2, 3 -- 4)
+  stsep <- min_st_separators(g)
+  ims <- sapply(stsep, is_min_separator, graph=g)
   expect_that(ims, equals(rep(TRUE, 9)))
 })
diff --git a/inst/tests/test_bug-1073705-indexing.R b/inst/tests/test_bug-1073705-indexing.R
index 0913b6a..7d9eaa9 100644
--- a/inst/tests/test_bug-1073705-indexing.R
+++ b/inst/tests/test_bug-1073705-indexing.R
@@ -4,18 +4,18 @@ context("Bug 1073705")
 test_that("Weighted indexing does not remove edges", {
   library(igraph)
 
-  g <- graph.ring(10)
+  g <- make_ring(10)
   g[1, 2, attr="weight"] <- 0
-  expect_that("weight" %in% list.edge.attributes(g), is_true())
+  expect_that("weight" %in% edge_attr_names(g), is_true())
   expect_that(E(g)$weight, equals(c(0, rep(NA, 9))))
 
-  el <- get.edgelist(g)
+  el <- as_edgelist(g)
   g[from=el[,1], to=el[,2], attr="sim"] <- rep(0:1, length=ecount(g))
-  expect_that("sim" %in% list.edge.attributes(g), is_true())
+  expect_that("sim" %in% edge_attr_names(g), is_true())
   expect_that(E(g)$sim, equals(rep(0:1, 5)))
 
   V(g)$name <- letters[seq_len(vcount(g))]
-  el <- get.edgelist(g)
+  el <- as_edgelist(g)
   g[from=el[,1], to=el[,2], attr="sim"] <- rep(1:0, length=ecount(g))
   expect_that(E(g)$sim, equals(rep(1:0, 5)))
 })
diff --git a/inst/tests/test_bug-1073800-clique.R b/inst/tests/test_bug-1073800-clique.R
index fadaea6..ad0c51e 100644
--- a/inst/tests/test_bug-1073800-clique.R
+++ b/inst/tests/test_bug-1073800-clique.R
@@ -3,8 +3,9 @@ context("Bug 1073800")
 
 test_that("Largest cliques is correct", {
   library(igraph)
+  unvs <- function(x) lapply(x, as.vector)
   adj <- matrix(1, nrow=11, ncol=11) - diag(11)
-  g <- graph.adjacency(adj)
-  lc <- suppressWarnings(largest.cliques(g))
-  expect_that(lc, equals(list(1:11)))
+  g <- graph_from_adjacency_matrix(adj)
+  lc <- suppressWarnings(largest_cliques(g))
+  expect_that(unvs(lc), equals(list(1:11)))
 })
diff --git a/inst/tests/test_callbacks.R b/inst/tests/test_callbacks.R
index fb350a0..13611ca 100644
--- a/inst/tests/test_callbacks.R
+++ b/inst/tests/test_callbacks.R
@@ -5,6 +5,6 @@ test_that("igraph calls from callbacks are not allowed", {
 
   library(igraph)
   f <- function(graph, data, extra) { vcount(graph) }
-  expect_that(graph.bfs(graph.ring(10), root=1, callback=f),
+  expect_that(bfs(make_ring(10), root=1, callback=f),
               throws_error("igraph callbacks cannot call igraph functions"))
 })
diff --git a/inst/tests/test_canonical.permutation.R b/inst/tests/test_canonical.permutation.R
index 09a6f86..4364d4e 100644
--- a/inst/tests/test_canonical.permutation.R
+++ b/inst/tests/test_canonical.permutation.R
@@ -1,21 +1,21 @@
 
-context("canonical.permutation")
+context("canonical_permutation")
 
-test_that("canonical.permutation works", {
+test_that("canonical_permutation works", {
   library(igraph)
 
-  g1 <- erdos.renyi.game(10, 20, type="gnm")
-  cp1 <- canonical.permutation(g1)
-  cf1 <- permute.vertices(g1, cp1$labeling)
+  g1 <- sample_gnm(10, 20)
+  cp1 <- canonical_permutation(g1)
+  cf1 <- permute(g1, cp1$labeling)
      
   ## Do the same with a random permutation of it
-  g2 <- permute.vertices(g1, sample(vcount(g1)))
-  cp2 <- canonical.permutation(g2)
-  cf2 <- permute.vertices(g2, cp2$labeling)
+  g2 <- permute(g1, sample(vcount(g1)))
+  cp2 <- canonical_permutation(g2)
+  cf2 <- permute(g2, cp2$labeling)
      
   ## Check that they are the same
-  el1 <- get.edgelist(cf1)
-  el2 <- get.edgelist(cf2)
+  el1 <- as_edgelist(cf1)
+  el2 <- as_edgelist(cf2)
   el1 <- el1[ order(el1[,1], el1[,2]), ]
   el2 <- el2[ order(el2[,1], el2[,2]), ]
 
diff --git a/inst/tests/test_cliques.R b/inst/tests/test_cliques.R
index 80f6864..609670e 100644
--- a/inst/tests/test_cliques.R
+++ b/inst/tests/test_cliques.R
@@ -6,21 +6,21 @@ test_that("cliques works", {
   set.seed(42)
 
   check.clique <- function(graph, vids) {
-    s <- induced.subgraph(graph, vids)
+    s <- induced_subgraph(graph, vids)
     ecount(s) == vcount(s) * (vcount(s)-1) / 2
   }
 
-  g <- erdos.renyi.game(100, 0.3)
-  expect_that(clique.number(g), equals(6))
+  g <- sample_gnp(100, 0.3)
+  expect_that(clique_num(g), equals(6))
   
   cl <- sapply(cliques(g, min=6), check.clique, graph=g)
-  lcl <- sapply(largest.cliques(g), check.clique, graph=g)
+  lcl <- sapply(largest_cliques(g), check.clique, graph=g)
   expect_that(cl, equals(lcl))
   expect_that(cl, equals(rep(TRUE, 17)))
   expect_that(lcl, equals(rep(TRUE, 17)))
 
   ## To have a bit less maximal cliques, about 100-200 usually
-  g <- erdos.renyi.game(100, 0.03)
-  expect_that(all(sapply(maximal.cliques(g), check.clique, graph=g)),
+  g <- sample_gnp(100, 0.03)
+  expect_that(all(sapply(max_cliques(g), check.clique, graph=g)),
               is_true())
 })
diff --git a/inst/tests/test_closeness.R b/inst/tests/test_closeness.R
index eca05ec..64fda70 100644
--- a/inst/tests/test_closeness.R
+++ b/inst/tests/test_closeness.R
@@ -4,16 +4,16 @@ context("closeness")
 test_that("closeness works", {
   library(igraph)
 
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
 
   clo <- closeness(kite) * (vcount(kite)-1)
   expect_that(round(sort(clo, decreasing=TRUE), 3),
@@ -30,19 +30,19 @@ test_that("closeness works", {
 test_that("closeness centralization works", {
 
   library(igraph)
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
 
   c1 <- closeness(kite, normalized=TRUE)
-  c2 <- centralization.closeness(kite)
+  c2 <- centr_clo(kite)
   expect_that(unname(c1), equals(c2$res))
   expect_that(c2$centralization, equals(0.270374931581828))
   expect_that(c2$theoretical_max, equals(4.23529411764706))
diff --git a/inst/tests/test_clusters.R b/inst/tests/test_clusters.R
index 1dcd056..36cb378 100644
--- a/inst/tests/test_clusters.R
+++ b/inst/tests/test_clusters.R
@@ -1,27 +1,53 @@
 
-context("clusters")
+context("components")
 
-test_that("clusters works", {
+test_that("components works", {
   library(igraph)
   set.seed(42)
   
   gc <- function(graph) {
-    cl <- clusters(graph)
-    induced.subgraph(graph, which(cl$membership==which.max(cl$csize)))
+    cl <- components(graph)
+    induced_subgraph(graph, which(cl$membership==which.max(cl$csize)))
   }
   
   rg <- function(n) {
-    gc(erdos.renyi.game(n, 1/n))
+    gc(sample_gnp(n, 1/n))
   }
   
   G <- lapply(1:30, function(x) rg(sample(100, 1)))
   Gsize <- sapply(G, vcount)
 
-  allg <- graph.disjoint.union(G)
-  clu <- clusters(allg)
+  allg <- disjoint_union(G)
+  clu <- components(allg)
 
   expect_that(as.numeric(table(clu$membership)), equals(clu$csize))
   expect_that(sort(clu$csize), equals(sort(Gsize)))
   expect_that(clu$no, equals(length(G)))
 })
 
+test_that("components names results", {
+  library(igraph)
+
+  g <- make_ring(10) + make_full_graph(5)
+  V(g)$name <- letters[1:15]
+
+  clu <- components(g)
+  expect_that(names(clu$membership), equals(letters[1:15]))
+})
+
+test_that("groups works", {
+  library(igraph)
+
+  g <- make_ring(10) + make_full_graph(5)
+  gr <- groups(components(g))
+
+  expect_that(gr, equals(structure(list(`1` = 1:10, `2` = 11:15), .Dim = 2L,
+                                   .Dimnames = list( c("1", "2")))))
+
+  V(g)$name <- letters[1:15]
+  gr <- groups(components(g))
+
+  expect_that(gr, equals(structure(list(`1` = letters[1:10],
+                                        `2` = letters[11:15]), .Dim = 2L,
+                                        .Dimnames = list(c("1", "2")))))
+})
diff --git a/inst/tests/test_communities.R b/inst/tests/test_communities.R
index c679ffc..0a57649 100644
--- a/inst/tests/test_communities.R
+++ b/inst/tests/test_communities.R
@@ -5,12 +5,12 @@ test_that("community detection functions work", {
   library(igraph)
   set.seed(42)
 
-  F <- list("edge.betweenness.community", "fastgreedy.community",
-            "label.propagation.community", "leading.eigenvector.community",
-            "multilevel.community", "optimal.community",
-            "spinglass.community", "walktrap.community")
+  F <- list("cluster_edge_betweenness", "cluster_fast_greedy",
+            "cluster_label_prop", "cluster_leading_eigen",
+            "cluster_louvain", "cluster_optimal",
+            "cluster_spinglass", "cluster_walktrap")
 
-  karate <- graph.famous("Zachary")
+  karate <- make_graph("Zachary")
 
   for (f in F) {
     f <- get(f)
@@ -26,11 +26,11 @@ test_that("community detection functions work", {
     expect_that(length(comm), equals(max(membership(comm))))
   }
 
-  fc <- fastgreedy.community(karate)
-  m1 <- modularity(karate, cutat(fc, no=1))
-  m2 <- modularity(karate, cutat(fc, no=2))
-  m3 <- modularity(karate, cutat(fc, no=3))
-  m4 <- modularity(karate, cutat(fc, no=4))
+  fc <- cluster_fast_greedy(karate)
+  m1 <- modularity(karate, cut_at(fc, no=1))
+  m2 <- modularity(karate, cut_at(fc, no=2))
+  m3 <- modularity(karate, cut_at(fc, no=3))
+  m4 <- modularity(karate, cut_at(fc, no=4))
   expect_that(m1, equals(0))
   expect_that(m2, equals(0.3717948718))
   expect_that(m3, equals(0.3806706114))
@@ -56,17 +56,37 @@ test_that("creating communities objects works", {
   library(igraph)
   set.seed(42)
 
-  karate <- graph.famous("Zachary")
+  karate <- make_graph("Zachary")
 
   membership <- sample(1:2, vcount(karate), replace=TRUE)
   mod <- modularity(karate, membership)
-  comm <- create.communities(algorithm="random", membership=membership,
-                             mod=mod, foo="bar")
-  print(comm)
+  comm <- make_clusters(algorithm="random", membership=membership,
+                             modularity = mod)
 
-  expect_that(membership(comm), equals(membership))
+  expect_that(as.vector(membership(comm)), equals(membership))
   expect_that(modularity(comm), equals(mod))
   expect_that(algorithm(comm), equals("random"))
-  expect_that(comm$foo, equals("bar"))
 
 })
+
+test_that("communities function works", {
+  library(igraph)
+  g <- make_graph("Zachary")
+  oc <- cluster_optimal(g)
+  gr <- communities(oc)
+  expect_that(gr, equals
+    (structure(list(`1` = c(1L, 2L, 3L, 4L, 8L, 12L, 13L, 14L, 18L,
+     20L, 22L), `2` = c(5L, 6L, 7L, 11L, 17L), `3` = c(9L, 10L, 15L,
+     16L, 19L, 21L, 23L, 27L, 30L, 31L, 33L, 34L), `4` = c(24L, 25L,
+     26L, 28L, 29L, 32L)), .Dim = 4L, .Dimnames = list(c("1", "2",
+     "3", "4")))))
+
+  g <- make_ring(5) + make_ring(5)
+  V(g)$name <- letters[1:10]
+  oc <- cluster_optimal(g)
+  gr <- communities(oc)
+  expect_that(gr, equals(structure(list(`1` = letters[1:5],
+                                        `2` = letters[6:10]),
+                                        .Dim = 2L,
+                                        .Dimnames = list(c("1", "2")))))
+})
diff --git a/inst/tests/test_constraint.R b/inst/tests/test_constraint.R
index 947ed46..844a6d1 100644
--- a/inst/tests/test_constraint.R
+++ b/inst/tests/test_constraint.R
@@ -5,11 +5,11 @@ test_that("constraint works", {
   library(igraph)
 
   constraint.orig <- function(graph, nodes=V(graph), attr=NULL) {
-    if (!is.igraph(graph)) {
+    if (!is_igraph(graph)) {
       stop("Not a graph object")
     }
     idx <- degree(graph) != 0
-    A <- get.adjacency(graph, attr=attr, sparse=FALSE)
+    A <- as_adj(graph, attr=attr, sparse=FALSE)
     A <- A[idx, idx]
     n <- sum(idx)
     
@@ -31,7 +31,7 @@ test_that("constraint works", {
     ci2[nodes]
   }
 
-  karate <- graph.famous("Zachary")
+  karate <- make_graph("Zachary")
 
   c1 <- constraint(karate)
   c2 <- constraint.orig(karate)
diff --git a/inst/tests/test_contract.vertices.R b/inst/tests/test_contract.vertices.R
index fba10e3..3cc6c8a 100644
--- a/inst/tests/test_contract.vertices.R
+++ b/inst/tests/test_contract.vertices.R
@@ -1,16 +1,16 @@
 
-context("contract.vertices")
+context("contract")
 
-test_that("contract.vertices works", {
+test_that("contract works", {
   library(igraph)
   set.seed(42)
 
-  g <- graph.ring(10)
+  g <- make_ring(10)
   g$name <- "Ring"
   V(g)$name <- letters[1:vcount(g)]
   E(g)$weight <- sample(ecount(g))
 
-  g2 <- contract.vertices(g, rep(1:5, each=2),
+  g2 <- contract(g, rep(1:5, each=2),
                           vertex.attr.comb=toString)
 
   ## graph and edge attributes are kept, vertex attributes are
diff --git a/inst/tests/test_correlated.R b/inst/tests/test_correlated.R
new file mode 100644
index 0000000..962276b
--- /dev/null
+++ b/inst/tests/test_correlated.R
@@ -0,0 +1,79 @@
+
+context("Correlated E-R random graphs")
+
+## Not very meaningful tests. They good for testing that the
+## functions run, but not much more
+
+test_that("sample_correlated_gnp works", {
+
+  library(igraph)
+  set.seed(42)
+
+  g <- erdos.renyi.game(10, .1)
+  g2 <- sample_correlated_gnp(g, corr=1, p=g$p, perm=NULL)
+  expect_that(g[], equals(g2[]))
+
+  g3 <- sample_correlated_gnp(g, corr=0, p=g$p, perm=NULL)
+  c3 <- cor(as.vector(g[]), as.vector(g3[]))
+  expect_that(abs(c3) < .3, is_true())
+
+})
+
+test_that("sample_correlated_gnp_pair works", {
+
+  library(igraph)
+  set.seed(42)
+
+  gp <- sample_correlated_gnp_pair(10, corr=.95, p=.1, perm=NULL)
+  expect_that(abs(ecount(gp[[1]]) - ecount(gp[[2]])) < 3, is_true())
+
+})
+
+## Some corner cases
+
+test_that("sample_correlated_gnp corner cases work", {
+
+  library(igraph)
+  set.seed(42)
+
+  is.full <- function(g) {
+    g2 <- graph.full(vcount(g), directed=is.directed(g))
+    graph.isomorphic(g, g2)
+  }
+
+  g <- erdos.renyi.game(10, .3)
+  g2 <- sample_correlated_gnp(g, corr=0.000001, p=.99999999)
+  expect_that(is.full(g2), is_true())
+
+  g3 <- sample_correlated_gnp(g, corr=0.000001, p=0.0000001)
+  expect_that(ecount(g3), equals(0))
+  expect_that(vcount(g3), equals(10))
+
+  gg <- erdos.renyi.game(10, .3, directed=TRUE)
+  gg2 <- sample_correlated_gnp(gg, corr=0.000001, p=.99999999)
+  expect_that(is.full(gg2), is_true())
+
+  gg3 <- sample_correlated_gnp(gg, corr=0.000001, p=0.0000001)
+  expect_that(ecount(gg3), equals(0))
+  expect_that(vcount(gg3), equals(10))
+
+})
+
+test_that("permutation works for sample_correlated_gnp", {
+
+  library(igraph)
+  set.seed(42)
+
+  g <- erdos.renyi.game(10, .3)
+  perm <- sample(vcount(g))
+  g2 <- sample_correlated_gnp(g, corr=.99999, p=.3, permutation=perm)
+  g <- permute.vertices(g, perm)
+  expect_that(g[], equals(g2[]))
+
+  g <- erdos.renyi.game(10, .3)
+  perm <- sample(vcount(g))
+  g2 <- sample_correlated_gnp(g, corr=1, p=.3, permutation=perm)
+  g <- permute.vertices(g, perm)
+  expect_that(g[], equals(g2[]))
+
+})
diff --git a/inst/tests/test_count.multiple.R b/inst/tests/test_count.multiple.R
index 3c8b041..e1bbf37 100644
--- a/inst/tests/test_count.multiple.R
+++ b/inst/tests/test_count.multiple.R
@@ -1,13 +1,13 @@
 
-context("count.multiple")
+context("count_multiple")
 
-test_that("count.multiple works", {
+test_that("count_multiple works", {
   library(igraph)
   set.seed(42)
 
   g <- barabasi.game(10, m=3, algorithm="bag")
-  im <- is.multiple(g)
-  cm <- count.multiple(g)
+  im <- which_multiple(g)
+  cm <- count_multiple(g)
   expect_that(im, equals(c(FALSE, TRUE, TRUE, FALSE, TRUE, TRUE,
                            FALSE, FALSE, FALSE, FALSE, FALSE, TRUE,
                            FALSE, FALSE, TRUE, FALSE, FALSE, TRUE,
@@ -15,20 +15,20 @@ test_that("count.multiple works", {
                            FALSE, FALSE, TRUE)))
   expect_that(cm, equals(c(3, 3, 3, 3, 3, 3, 1, 1, 1, 2, 1, 2, 1, 2,
                            2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 2)))
-  expect_that(count.multiple(simplify(g)),
+  expect_that(count_multiple(simplify(g)),
               equals(rep(1, ecount(simplify(g)))))
 
   
   ## Direction of the edge is important
-  expect_that(is.multiple(graph( c(1,2, 2,1) )), equals(c(FALSE, FALSE)))
-  expect_that(is.multiple(graph( c(1,2, 2,1), dir=FALSE )),
+  expect_that(which_multiple(graph( c(1,2, 2,1) )), equals(c(FALSE, FALSE)))
+  expect_that(which_multiple(graph( c(1,2, 2,1), dir=FALSE )),
               equals(c(FALSE, TRUE)))
 
   ## Remove multiple edges but keep multiplicity
   g <- barabasi.game(10, m=3, algorithm="bag")
   E(g)$weight <- 1
   g <- simplify(g)
-  expect_that(any(is.multiple(g)), is_false())
+  expect_that(any(which_multiple(g)), is_false())
   expect_that(E(g)$weight, equals(c(3, 2, 1, 2, 1, 3, 2, 1, 2, 1, 2,
                                     1, 1, 1, 1, 1, 1, 1)))
 
diff --git a/inst/tests/test_decompose.graph.R b/inst/tests/test_decompose.graph.R
index 63ffb7e..b26ea17 100644
--- a/inst/tests/test_decompose.graph.R
+++ b/inst/tests/test_decompose.graph.R
@@ -1,44 +1,44 @@
 
-context("decompose.graph")
+context("decompose")
 
-test_that("decompose.graph works", {
+test_that("decompose works", {
   library(igraph)
-  g <- erdos.renyi.game(1000, 1/1500)
-  G <- decompose.graph(g)
-  clu <- clusters(g)
+  g <- sample_gnp(1000, 1/1500)
+  G <- decompose(g)
+  clu <- components(g)
   Gsizes <- sapply(G, vcount)
   expect_that(sort(clu$csize), equals(sort(Gsizes)))
 })
 
-test_that("decompose.graph works for many components", {
+test_that("decompose works for many components", {
   library(igraph)
-  g <- graph.empty(50001)
-  tmp <- decompose.graph(g)
+  g <- make_empty_graph(50001)
+  tmp <- decompose(g)
   expect_that(1, equals(1))
 })
 
-test_that("decompose.graph works for many components and attributes", {
+test_that("decompose works for many components and attributes", {
   library(igraph)
-  g <- graph.empty(50001)
+  g <- make_empty_graph(50001)
   V(g)$name <- 1:vcount(g)
-  tmp <- decompose.graph(g)
+  tmp <- decompose(g)
   expect_that(1, equals(1))
 })
 
-test_that("decompose.graph keeps attributes", {
+test_that("decompose keeps attributes", {
   library(igraph)
-  g <- graph.ring(10) + graph.ring(5)
+  g <- make_ring(10) + make_ring(5)
   V(g)$name <- letters[1:(10+5)]
-  E(g)$name <- apply(get.edgelist(g), 1, paste, collapse="-")
-  d <- decompose.graph(g)
+  E(g)$name <- apply(as_edgelist(g), 1, paste, collapse="-")
+  d <- decompose(g)
   d <- d[order(sapply(d, vcount))]
 
   expect_that(length(d), equals(2))
   expect_that(sapply(d, vcount), equals(c(5,10)))
   expect_that(V(d[[1]])$name, equals(letters[1:5+10]))
   expect_that(V(d[[2]])$name, equals(letters[1:10]))
-  e1 <- apply(get.edgelist(d[[1]]), 1, paste, collapse="-")
-  e2 <- apply(get.edgelist(d[[2]]), 1, paste, collapse="-")
+  e1 <- apply(as_edgelist(d[[1]]), 1, paste, collapse="-")
+  e2 <- apply(as_edgelist(d[[2]]), 1, paste, collapse="-")
   expect_that(E(d[[1]])$name, equals(e1))
   expect_that(E(d[[2]])$name, equals(e2))
 })
diff --git a/inst/tests/test_degree.R b/inst/tests/test_degree.R
index 66969f6..68c0cab 100644
--- a/inst/tests/test_degree.R
+++ b/inst/tests/test_degree.R
@@ -4,17 +4,17 @@ context("degree")
 test_that("degree works", {
   library(igraph)
   
-  g <- erdos.renyi.game(100, 1/100)
+  g <- sample_gnp(100, 1/100)
   d <- degree(g)
-  el <- get.edgelist(g)
+  el <- as_edgelist(g)
   expect_that(as.numeric(table(el)), equals(d[d!=0]))
 
   expect_that(degree(g) / (vcount(g)-1), equals(degree(g, normalized=TRUE)))
 
-  g2 <- erdos.renyi.game(100, 2/100, dir=TRUE)
+  g2 <- sample_gnp(100, 2/100, dir=TRUE)
   din <- degree(g2, mode="in")
   dout <- degree(g2, mode="out")
-  el2 <- get.edgelist(g2)
+  el2 <- as_edgelist(g2)
   expect_that(as.numeric(table(el2[,1])), equals(dout[dout!=0]))
   expect_that(as.numeric(table(el2[,2])), equals(din[din!=0]))
 
diff --git a/inst/tests/test_degree.sequence.game.R b/inst/tests/test_degree.sequence.game.R
index dd96fee..ed2f7da 100644
--- a/inst/tests/test_degree.sequence.game.R
+++ b/inst/tests/test_degree.sequence.game.R
@@ -1,34 +1,34 @@
 
-context("degree.sequence.game")
+context("sample_degseq")
 
-test_that("degree.sequence.game works", {
+test_that("sample_degseq works", {
   library(igraph)
 
   gc <- function(graph) {
-    clu <- clusters(graph)
-    induced.subgraph(graph, which(clu$membership==which.max(clu$csize)))
+    clu <- components(graph)
+    induced_subgraph(graph, which(clu$membership==which.max(clu$csize)))
   }
 
-  g <- gc(erdos.renyi.game(1000, 2/1000))
+  g <- gc(sample_gnp(1000, 2/1000))
 
-  nG <- degree.sequence.game(degree(g), method="simple")
+  nG <- sample_degseq(degree(g), method="simple")
   expect_that(degree(nG), equals(degree(g)))
 
-  nG <- degree.sequence.game(degree(g), method="vl")
+  nG <- sample_degseq(degree(g), method="vl")
   expect_that(degree(nG), equals(degree(g)))
-  expect_that(is.connected(nG), is_true())
-  expect_that(is.simple(nG), is_true())
+  expect_that(is_connected(nG), is_true())
+  expect_that(is_simple(nG), is_true())
 
   #####
 
-  g <- erdos.renyi.game(1000, 1/1000)
+  g <- sample_gnp(1000, 1/1000)
 
-  nG <- degree.sequence.game(degree(g), method="simple")
+  nG <- sample_degseq(degree(g), method="simple")
   expect_that(degree(nG), equals(degree(g)))
 
-  g2 <- erdos.renyi.game(1000, 2/1000, dir=TRUE)
+  g2 <- sample_gnp(1000, 2/1000, dir=TRUE)
 
-  nG2 <- degree.sequence.game(degree(g, mode="out"),
+  nG2 <- sample_degseq(degree(g, mode="out"),
                               degree(g, mode="in"),
                               method="simple")
   expect_that(degree(nG, mode="out"), equals(degree(g, mode="out")))
diff --git a/inst/tests/test_delete.edges.R b/inst/tests/test_delete.edges.R
index 87cce72..bd9752b 100644
--- a/inst/tests/test_delete.edges.R
+++ b/inst/tests/test_delete.edges.R
@@ -1,10 +1,10 @@
 
-context("delete.edges")
+context("delete_edges")
 
-test_that("delete.edges works", {
+test_that("delete_edges works", {
   library(igraph)
-  g <- graph.formula(A:B:C - D:E:F, D-E-F)
-  g2 <- delete.edges(g, E(g, P=c("D", "E")))
+  g <- graph_from_literal(A:B:C - D:E:F, D-E-F)
+  g2 <- delete_edges(g, E(g, P=c("D", "E")))
   expect_that(as.matrix(g2[]),
               is_equivalent_to(cbind(c(0,0,0,1,1,1), c(0,0,0,1,1,1),
                                      c(0,0,0,1,1,1), c(1,1,1,0,0,0),
diff --git a/inst/tests/test_delete.vertices.R b/inst/tests/test_delete.vertices.R
index 007ec9a..2755b97 100644
--- a/inst/tests/test_delete.vertices.R
+++ b/inst/tests/test_delete.vertices.R
@@ -1,12 +1,12 @@
 
-context("delete.vertices")
+context("delete_vertices")
 
-test_that("delete.vertices works", {
+test_that("delete_vertices works", {
   library(igraph)
-  g <- graph.formula(A:B:C - D:E:F, D-E-F)
+  g <- graph_from_literal(A:B:C - D:E:F, D-E-F)
   
-  g2 <- delete.vertices(g, "A")
-  g3 <- delete.vertices(g, match("A", V(g)$name))
+  g2 <- delete_vertices(g, "A")
+  g3 <- delete_vertices(g, match("A", V(g)$name))
   
   expect_that(graph.isomorphic(g2, g3), is_true())
 })
diff --git a/inst/tests/test_diameter.R b/inst/tests/test_diameter.R
index 39f7df5..b3e49b2 100644
--- a/inst/tests/test_diameter.R
+++ b/inst/tests/test_diameter.R
@@ -6,38 +6,38 @@ test_that("diameter works", {
   library(igraph)
 
   gc <- function(graph) {
-    clu <- clusters(graph)
-    induced.subgraph(graph, which(clu$membership==which.max(clu$csize)))
+    clu <- components(graph)
+    induced_subgraph(graph, which(clu$membership==which.max(clu$csize)))
   }
 
 #### Undirected
   
-  g <- gc(erdos.renyi.game(30, 3/30))
-  sp <- shortest.paths(g)
+  g <- gc(sample_gnp(30, 3/30))
+  sp <- distances(g)
   expect_that(max(sp), equals(diameter(g)))
 
-  g <- gc(erdos.renyi.game(100, 1/100))
-  sp <- shortest.paths(g)
+  g <- gc(sample_gnp(100, 1/100))
+  sp <- distances(g)
   sp[sp==Inf] <- NA
   expect_that(max(sp, na.rm=TRUE), equals(diameter(g)))
 
 #### Directed
 
-  g <- erdos.renyi.game(30, 3/30, dir=TRUE)
-  sp <- shortest.paths(g, mode="out")
+  g <- sample_gnp(30, 3/30, dir=TRUE)
+  sp <- distances(g, mode="out")
   sp[sp==Inf] <- NA
   expect_that(max(sp, na.rm=TRUE), equals(diameter(g, unconnected=TRUE)))
 
 #### Weighted
 
   E(g)$weight <- sample(1:10, ecount(g), replace=TRUE)
-  sp <- shortest.paths(g, mode="out")
+  sp <- distances(g, mode="out")
   sp[sp==Inf] <- NA
   expect_that(max(sp, na.rm=TRUE), equals(diameter(g, unconnected=TRUE)))
 
 #### Bug #680538
 
-  g <- graph.tree(30, mode="undirected")
+  g <- make_tree(30, mode="undirected")
   E(g)$weight <- 2
   expect_that(diameter(g, unconnected=FALSE), equals(16))
 })
diff --git a/inst/tests/test_dimSelect.R b/inst/tests/test_dimSelect.R
new file mode 100644
index 0000000..d6d5352
--- /dev/null
+++ b/inst/tests/test_dimSelect.R
@@ -0,0 +1,33 @@
+
+context("Dimensionality selection")
+
+test_that("dimensionality selection works", {
+  library(igraph)
+  set.seed(42)
+
+  k <- graph.famous("zachary")
+  ev <- eigen(get.adjacency(k), only.values=TRUE)$values
+  kdim <- dim_select(ev)
+  expect_that(kdim, equals(4))
+
+  expect_that(dim_select(1:100), equals(50))
+
+  ## Some regression tests
+  expect_that(dim_select(runif(100)), equals(69))
+  expect_that(dim_select(runif(100)), equals(88))
+  expect_that(dim_select(runif(100)), equals(3))
+  expect_that(dim_select(runif(100)), equals(99))
+
+  ## Some more meaningful tests
+  x <- c(rnorm(50, mean=0, sd=1), rnorm(50, mean=5, sd=1))
+  expect_that(dim_select(x), equals(50))
+
+  x <- c(rnorm(10, mean=0, sd=1), rnorm(90, mean=2, sd=1))
+  expect_that(dim_select(x), equals(10))
+
+  x <- c(10, rnorm(99, mean=0, sd=1))
+  expect_that(dim_select(x), equals(1))
+
+  x <- c(rnorm(99, mean=0, sd=1), 10)
+  expect_that(dim_select(x), equals(99))
+})
diff --git a/inst/tests/test_dominator.tree.R b/inst/tests/test_dominator.tree.R
index 0456115..a83db4b 100644
--- a/inst/tests/test_dominator.tree.R
+++ b/inst/tests/test_dominator.tree.R
@@ -1,19 +1,19 @@
 
-context("dominator.tree")
+context("dominator_tree")
 
-test_that("dominator.tree works", {
+test_that("dominator_tree works", {
   library(igraph)
-  g <- graph.formula(R-+A:B:C, A-+D, B-+A:D:E, C-+F:G, D-+L,
-                     E-+H, F-+I, G-+I:J, H-+E:K, I-+K, J-+I,
-                     K-+I:R, L-+H)
-  dtree <- dominator.tree(g, root="R")
+  g <- graph_from_literal(R-+A:B:C, A-+D, B-+A:D:E, C-+F:G, D-+L,
+                 E-+H, F-+I, G-+I:J, H-+E:K, I-+K, J-+I,
+                 K-+I:R, L-+H)
+  dtree <- dominator_tree(g, root="R")
 
-  dtree$dom <- V(g)$name[ dtree$dom ]
+  dtree$dom <- V(g)$name[ as.vector(dtree$dom) ]
   dtree$leftout <- V(g)$name[ dtree$leftout ]
   expect_that(dtree$dom, equals(c("R", "R", "R", "R", "R", "C", "C",
                                   "D", "R", "R", "G", "R")))
   expect_that(dtree$leftout, equals(character()))
-  expect_that(get.edgelist(dtree$domtree),
+  expect_that(as_edgelist(dtree$domtree),
               equals(structure(c("R", "R", "R", "R", "R", "C", "C",
                                  "D", "R", "R", "G", "R", "A", "B",
                                  "C", "D", "E", "F", "G", "L", "H",
diff --git a/inst/tests/test_dot.product.game.R b/inst/tests/test_dot.product.game.R
new file mode 100644
index 0000000..bf00478
--- /dev/null
+++ b/inst/tests/test_dot.product.game.R
@@ -0,0 +1,46 @@
+
+context("Dot-product random graphs")
+
+test_that("Dot product rng works", {
+
+  library(igraph)
+  set.seed(42)
+  vecs <- cbind(c(0,1,1,1,0)/3, c(0,1,1,0,1)/3, c(1,1,1,1,0)/4,
+                c(0,1,1,1,0))
+
+  g <- sample_dot_product(vecs)
+  g0 <- graph.formula(1:2:3-4)
+  expect_that(g[], is_equivalent_to(g0[]))
+
+  g2 <- sample_dot_product(vecs, directed=TRUE)
+  g20 <- graph.formula(1:2:3:4, 1-+3, 1-+4, 3-+4, 4+-1, 4+-3)
+  expect_that(g[], is_equivalent_to(g20[]))
+
+  vecs <- replicate(5, rep(1/2, 4))
+  g <- sample_dot_product(vecs)
+  expect_that(g[], is_equivalent_to(graph.full(5)[]))
+
+  g2 <- sample_dot_product(vecs, directed=TRUE)
+  expect_that(g2[], is_equivalent_to(graph.full(5, directed=TRUE)[]))
+
+  vecs <- replicate(100, rep(sqrt(1/8), 4))
+  g <- sample_dot_product(vecs)
+  expect_that(ecount(g), equals(2454))
+
+  g2 <- sample_dot_product(vecs, directed=TRUE)
+  expect_that(ecount(g2), equals(4938))
+  
+})
+
+test_that("Dot product rng gives warnings", {
+
+  library(igraph)
+  vecs <- cbind(c(1,1,1)/3, -c(1,1,1)/3)
+  expect_that(g <- sample_dot_product(vecs),
+      gives_warning("Negative connection probability in dot-product graph"))
+
+  vecs <- cbind(c(1,1,1), c(1,1,1))
+  expect_that(g <- sample_dot_product(vecs),
+      gives_warning(paste(sep="", "Greater than 1 connection probability ",
+                          "in dot-product graph")))
+})
diff --git a/inst/tests/test_dyad.census.R b/inst/tests/test_dyad.census.R
index f558392..de1c1c9 100644
--- a/inst/tests/test_dyad.census.R
+++ b/inst/tests/test_dyad.census.R
@@ -1,13 +1,13 @@
 
-context("dyad.census")
+context("dyad_census")
 
-test_that("dyad.census works", {
+test_that("dyad_census works", {
   library(igraph)
-  ce <- simplify(read.graph(gzfile("celegansneural.gml.gz"), format="gml"))
-  dc <- dyad.census(ce)
+  ce <- simplify(read_graph(gzfile("celegansneural.gml.gz"), format="gml"))
+  dc <- dyad_census(ce)
 
   expect_that(dc, equals(list(mut=197, asym=1951, null=41808)))
-  expect_that(sum(is.mutual(ce)), equals(dc$mut * 2))
+  expect_that(sum(which_mutual(ce)), equals(dc$mut * 2))
   expect_that(ecount(as.undirected(ce, mode="collapse")) - dc$mut,
               equals(dc$asym))
   expect_that(sum(unlist(dc)), equals(vcount(ce) * (vcount(ce)-1) / 2))
diff --git a/inst/tests/test_edge.betweenness.R b/inst/tests/test_edge.betweenness.R
index 3dbcd77..c64d21d 100644
--- a/inst/tests/test_edge.betweenness.R
+++ b/inst/tests/test_edge.betweenness.R
@@ -1,22 +1,22 @@
 
-context("edge.betweenness")
+context("edge_betweenness")
 
-test_that("edge.betweenness works", {
+test_that("edge_betweenness works", {
   library(igraph)
 
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
 
   bet <- betweenness(kite)
-  ebet <- edge.betweenness(kite)
+  ebet <- edge_betweenness(kite)
 
   bet2 <- sapply(1:vcount(kite), function(x) {
     ae <- E(kite)[ adj(x) ]
@@ -30,7 +30,7 @@ test_that("edge.betweenness works", {
   E(kite)$weight <- sample(1:10, ecount(kite), replace=TRUE)
 
   bet <- betweenness(kite)
-  ebet <- edge.betweenness(kite)
+  ebet <- edge_betweenness(kite)
   bet2 <- sapply(1:vcount(kite), function(x) {
     ae <- E(kite)[ adj(x) ]
     (sum(ebet[ae])-vcount(kite)+1) / 2
diff --git a/inst/tests/test_edge.betweenness.community.R b/inst/tests/test_edge.betweenness.community.R
index d1b274f..377e9a5 100644
--- a/inst/tests/test_edge.betweenness.community.R
+++ b/inst/tests/test_edge.betweenness.community.R
@@ -1,17 +1,18 @@
 
-context("edge.betweenness.community")
+context("cluster_edge_betweenness")
 
-test_that("edge.betweenness.community works", {
+test_that("cluster_edge_betweenness works", {
   library(igraph)
 
-  g <- graph.famous("Zachary")
-  ebc <- edge.betweenness.community(g)
+  g <- make_graph("Zachary")
+  ebc <- cluster_edge_betweenness(g)
 
   expect_that(max(ebc$modularity), equals(modularity(g, ebc$membership)))
-  expect_that(membership(ebc), equals(c(1, 1, 2, 1, 3, 3, 3, 1, 4, 5,
-                                        3, 1, 1, 1, 4, 4, 3, 1, 4, 1,
-                                        4, 1, 4, 4, 2, 2, 4, 2, 2, 4,
-                                        4, 2, 4, 4)))
+  expect_that(as.vector(membership(ebc)),
+              equals(c(1, 1, 2, 1, 3, 3, 3, 1, 4, 5,
+                       3, 1, 1, 1, 4, 4, 3, 1, 4, 1,
+                       4, 1, 4, 4, 2, 2, 4, 2, 2, 4,
+                       4, 2, 4, 4)))
   expect_that(length(ebc), equals(5))
   expect_that(as.numeric(sizes(ebc)), equals(c(10, 6, 5, 12, 1)))
 
@@ -21,7 +22,7 @@ test_that("edge.betweenness.community works", {
               prints_text("2 branches.*15 members.*height 31"))
   expect_that(print(d[[2]]),
               prints_text("2 branches.*19 members.*height 32"))
-  m2 <- cutat(ebc, no=3)
+  m2 <- cut_at(ebc, no=3)
   expect_that(modularity(g, m2),
               equals(ebc$modularity[length(ebc$modularity)-2]))
 })
diff --git a/inst/tests/test_edge.connectivity.R b/inst/tests/test_edge.connectivity.R
index 7a4e0b2..4b4f11f 100644
--- a/inst/tests/test_edge.connectivity.R
+++ b/inst/tests/test_edge.connectivity.R
@@ -1,21 +1,21 @@
 
-context("edge.connectivity")
+context("edge_connectivity")
 
-test_that("edge.connectivity works", {
+test_that("edge_connectivity works", {
 
   library(igraph)
 
   gc <- function(graph) {
-    clu <- clusters(graph)
-    induced.subgraph(graph, which(clu$membership==which.max(clu$csize)))
+    clu <- components(graph)
+    induced_subgraph(graph, which(clu$membership==which.max(clu$csize)))
   }
 
-  g <- gc(erdos.renyi.game(30, 8/30))
-  ec <- edge.connectivity(g)
+  g <- gc(sample_gnp(30, 8/30))
+  ec <- edge_connectivity(g)
   ecST <- Inf
   for (j in 1:(vcount(g)-1)) {
     for (k in (j+1):vcount(g)) {
-      ec2 <- edge.connectivity(g, source=j, target=k)
+      ec2 <- edge_connectivity(g, source=j, target=k)
       if (ec2 < ecST) { ecST <- ec2 }
     } 
   }
@@ -23,20 +23,20 @@ test_that("edge.connectivity works", {
 
 ####
 
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
-
-  ec1 <- edge.connectivity(kite, source="Heather", target="Andre")
-  ec2 <- edge.connectivity(kite, source="Garth", target="Andre")
-  ec3 <- edge.connectivity(kite, source="Garth", target="Ike")
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
+
+  ec1 <- edge_connectivity(kite, source="Heather", target="Andre")
+  ec2 <- edge_connectivity(kite, source="Garth", target="Andre")
+  ec3 <- edge_connectivity(kite, source="Garth", target="Ike")
   expect_that(ec1, equals(2))
   expect_that(ec2, equals(4))
   expect_that(ec3, equals(1))
diff --git a/inst/tests/test_edgenames.R b/inst/tests/test_edgenames.R
index 04d0790..6f655f3 100644
--- a/inst/tests/test_edgenames.R
+++ b/inst/tests/test_edgenames.R
@@ -6,38 +6,38 @@ test_that("edge names work", {
   library(igraph) 
 
   ## named edges
-  igraph.options(print.edge.attributes = TRUE)
-  g <- graph.ring(10)
+  igraph_options(print.edge.attributes = TRUE)
+  g <- make_ring(10)
   E(g)$name <- letters[1:ecount(g)]
-  g2 <- delete.edges(g, c("b", "d", "e"))
-  expect_that(get.edgelist(g2),
+  g2 <- delete_edges(g, c("b", "d", "e"))
+  expect_that(as_edgelist(g2),
               equals(structure(c(1, 3, 6, 7, 8, 9, 1, 2, 4, 7, 8, 9,
                                  10, 10), .Dim = c(7L, 2L))))
 
   ## named vertices
-  g <- graph.ring(10)
+  g <- make_ring(10)
   V(g)$name <- letters[1:vcount(g)]
-  g3 <- delete.edges(g, c("a|b", "f|g", "c|b"))
-  expect_that(get.edgelist(g3),
+  g3 <- delete_edges(g, c("a|b", "f|g", "c|b"))
+  expect_that(as_edgelist(g3),
               equals(structure(c("c", "d", "e", "g", "h", "i", "a",
                                  "d", "e", "f", "h", "i", "j", "j"),
                                .Dim = c(7L, 2L))))
 
 
   ## no names at all, but select edges based on vertices
-  g <- graph.ring(10)
-  g4 <- delete.edges(g, c("1|2", "8|7", "1|10"))
-  expect_that(get.edgelist(g4),
+  g <- make_ring(10)
+  g4 <- delete_edges(g, c("1|2", "8|7", "1|10"))
+  expect_that(as_edgelist(g4),
               equals(structure(c(2, 3, 4, 5, 6, 8, 9, 3, 4, 5, 6, 7,
                                  9, 10), .Dim = c(7L, 2L))))
 
 
   ## mix edge names and vertex names
-  g <- graph.ring(10)
+  g <- make_ring(10)
   V(g)$name <- letters[1:vcount(g)]
   E(g)$name <- LETTERS[1:ecount(g)]
-  g5 <- delete.edges(g, c("a|b", "F", "j|i"))
-  expect_that(get.edgelist(g5),
+  g5 <- delete_edges(g, c("a|b", "F", "j|i"))
+  expect_that(as_edgelist(g5),
               equals(structure(c("b", "c", "d", "e", "g", "h", "a",
                                  "c", "d", "e", "f", "h", "i", "j"),
                                .Dim = c(7L, 2L))))
diff --git a/inst/tests/test_evcent.R b/inst/tests/test_evcent.R
index 2108068..7f6e9ea 100644
--- a/inst/tests/test_evcent.R
+++ b/inst/tests/test_evcent.R
@@ -1,21 +1,21 @@
 
-context("evcent")
+context("eigen_centrality")
 
-test_that("evcent works", {
+test_that("eigen_centrality works", {
 
   library(igraph)
 
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
-  evc <- round(evcent(kite)$vector, 3)
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
+  evc <- round(eigen_centrality(kite)$vector, 3)
   expect_that(evc, equals(structure(c(0.732, 0.732, 0.594, 1, 0.827,
                         0.594, 0.827, 0.407, 0.1, 0.023), .Names =
                         c("Andre", "Beverly", "Carol", "Diane",
@@ -38,9 +38,9 @@ test_that("evcent works", {
   }
 
   for (i in 1:1000) {
-    G <- erdos.renyi.game(10, sample(1:20, 1), type="gnm")
-    ev <- evcent(G)
-    expect_that(is.good(get.adjacency(G, sparse=FALSE), ev$vector,
+    G <- sample_gnm(10, sample(1:20, 1))
+    ev <- eigen_centrality(G)
+    expect_that(is.good(as_adj(G, sparse=FALSE), ev$vector,
                         ev$value), is_true())
   }
 })
diff --git a/inst/tests/test_fartherst.nodes.R b/inst/tests/test_fartherst.nodes.R
index b8dbc90..e7ecaf3 100644
--- a/inst/tests/test_fartherst.nodes.R
+++ b/inst/tests/test_fartherst.nodes.R
@@ -1,25 +1,27 @@
 
-context("farthest.nodes")
+context("farthest_vertices")
 
-test_that("farthest.nodes works", {
+test_that("farthest_vertices works", {
 
   library(igraph)
 
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
 
-  fn <- farthest.nodes(kite)
-  expect_that(fn, equals(c(1,10,4)))
+  fn <- farthest_vertices(kite)
+  fn$vertices <- as.vector(fn$vertices)
+  expect_that(fn, equals(list(vertices = c(1, 10), distance = 4)))
 
-  expect_that(shortest.paths(kite, v=fn[1], to=fn[2])[1], equals(fn[3]))
-  expect_that(diameter(kite), equals(fn[3]))
+  expect_that(distances(kite, v=fn$vertices[1], to=fn$vertices[2])[1],
+              equals(fn$distance))
+  expect_that(diameter(kite), equals(fn$distance))
 
 })
diff --git a/inst/tests/test_fastgreedy.community.R b/inst/tests/test_fastgreedy.community.R
index f5caac1..b9eb947 100644
--- a/inst/tests/test_fastgreedy.community.R
+++ b/inst/tests/test_fastgreedy.community.R
@@ -1,19 +1,20 @@
 
-context("fastgreedy.community")
+context("cluster_fast_greedy")
 
-test_that("fastgreedy.community works", {
+test_that("cluster_fast_greedy works", {
 
   library(igraph)
   set.seed(42)
 
-  g <- graph.famous("Zachary")
-  fc <- fastgreedy.community(g)
+  g <- make_graph("Zachary")
+  fc <- cluster_fast_greedy(g)
 
   expect_that(modularity(g, fc$membership), equals(max(fc$modularity)))
-  expect_that(membership(fc), equals(c(1, 3, 3, 3, 1, 1, 1, 3, 2, 3,
-                                       1, 1, 3, 3, 2, 2, 1, 3, 2, 1,
-                                       2, 3, 2, 2, 2, 2, 2, 2, 2, 2,
-                                       2, 2, 2, 2)))
+  expect_that(as.vector(membership(fc)),
+              equals(c(1, 3, 3, 3, 1, 1, 1, 3, 2, 3,
+                       1, 1, 3, 3, 2, 2, 1, 3, 2, 1,
+                       2, 3, 2, 2, 2, 2, 2, 2, 2, 2,
+                       2, 2, 2, 2)))
   expect_that(length(fc), equals(3))
   expect_that(as.numeric(sizes(fc)), equals(c(8, 17, 9)))
 
@@ -23,7 +24,7 @@ test_that("fastgreedy.community works", {
               prints_text("2 branches.*17 members.*height 32"))
   expect_that(print(d[[2]]),
               prints_text("2 branches.*17 members.*height 30"))
-  m2 <- cutat(fc, no=3)
+  m2 <- cut_at(fc, no=3)
   expect_that(modularity(g, m2),
               equals(fc$modularity[length(fc$modularity)-2]))
 })
diff --git a/inst/tests/test_forestfire.R b/inst/tests/test_forestfire.R
index 36094ab..3e7e1b1 100644
--- a/inst/tests/test_forestfire.R
+++ b/inst/tests/test_forestfire.R
@@ -1,7 +1,7 @@
 
-context("forest.fire.game")
+context("sample_forestfire")
 
-test_that("forest.fire.game works", {
+test_that("sample_forestfire works", {
   
   library(igraph)
   set.seed(42)
@@ -11,7 +11,7 @@ test_that("forest.fire.game works", {
                dense=c(0.38, 0.38/0.37))
 
   N <- 5000
-  G <- lapply(pars, function(x) forest.fire.game(N, fw=x[1], bw=x[2]))
+  G <- lapply(pars, function(x) sample_forestfire(N, fw=x[1], bw=x[2]))
   
   xv <- log(2:N)
   
diff --git a/inst/tests/test_get.adjacency.R b/inst/tests/test_get.adjacency.R
index a755868..1004f15 100644
--- a/inst/tests/test_get.adjacency.R
+++ b/inst/tests/test_get.adjacency.R
@@ -1,32 +1,32 @@
 
-context("get.adjacency")
+context("as_adj")
 
-test_that("get.adjacency works", {
+test_that("as_adj works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50, 1/50)
-  A <- get.adjacency(g, sparse=FALSE)
-  g2 <- graph.adjacency(A, mode="undirected")
+  g <- sample_gnp(50, 1/50)
+  A <- as_adj(g, sparse=FALSE)
+  g2 <- graph_from_adjacency_matrix(A, mode="undirected")
   expect_that(graph.isomorphic(g, g2), is_true())
 
 ###
 
-  A <- get.adjacency(g, sparse=TRUE)
-  g2 <- graph.adjacency(A, mode="undirected")
+  A <- as_adj(g, sparse=TRUE)
+  g2 <- graph_from_adjacency_matrix(A, mode="undirected")
   expect_that(graph.isomorphic(g, g2), is_true())
 
 ###
 
-  g <- erdos.renyi.game(50, 2/50, directed=TRUE)
-  A <- get.adjacency(g, sparse=FALSE)
-  g2 <- graph.adjacency(A)
+  g <- sample_gnp(50, 2/50, directed=TRUE)
+  A <- as_adj(g, sparse=FALSE)
+  g2 <- graph_from_adjacency_matrix(A)
   expect_that(graph.isomorphic(g, g2), is_true())
 
 ###
 
-  A <- get.adjacency(g, sparse=TRUE)
-  g2 <- graph.adjacency(A)
+  A <- as_adj(g, sparse=TRUE)
+  g2 <- graph_from_adjacency_matrix(A)
   expect_that(graph.isomorphic(g, g2), is_true())
 
 })
diff --git a/inst/tests/test_get.adjlist.R b/inst/tests/test_get.adjlist.R
index 132b1ed..e1122a6 100644
--- a/inst/tests/test_get.adjlist.R
+++ b/inst/tests/test_get.adjlist.R
@@ -1,13 +1,13 @@
 
-context("get.adjlist")
+context("as_adj_list")
 
-test_that("get.adjist works", {
+test_that("as_adj_list works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50, 2/50)
-  al <- get.adjlist(g)
-  g2 <- graph.adjlist(al, mode="all")
+  g <- sample_gnp(50, 2/50)
+  al <- as_adj_list(g)
+  g2 <- graph_from_adj_list(al, mode="all")
   expect_that(graph.isomorphic(g, g2), is_true())
   expect_that(graph.isomorphic.vf2(g, g2, vertex.color1=1:vcount(g),
                                    vertex.color2=1:vcount(g2))$iso,
@@ -15,25 +15,25 @@ test_that("get.adjist works", {
 
 ####
 
-  el <- get.adjedgelist(g)
+  el <- as_adj_edge_list(g)
   for (i in 1:vcount(g)) {
-    a <- as.numeric(E(g)[adj(i)])
-    expect_that(length(a), equals(length(el[[i]])))
-    expect_that(sort(el[[i]]), equals(sort(a)))
+    a <- E(g)[adj(i)]
+    expect_that(length(a), is_equivalent_to(length(el[[i]])))
+    expect_that(sort(el[[i]]), is_equivalent_to(sort(a)))
   }
 
-  g <- erdos.renyi.game(50, 4/50, directed=TRUE)
-  el1 <- get.adjedgelist(g, mode="out")
-  el2 <- get.adjedgelist(g, mode="in")
+  g <- sample_gnp(50, 4/50, directed=TRUE)
+  el1 <- as_adj_edge_list(g, mode="out")
+  el2 <- as_adj_edge_list(g, mode="in")
   for (i in 1:vcount(g)) {
-    a <- as.numeric(E(g)[from(i)])
-    expect_that(length(a), equals(length(el1[[i]])))
-    expect_that(sort(el1[[i]]), equals(sort(a)))
+    a <- E(g)[from(i)]
+    expect_that(length(a), is_equivalent_to(length(el1[[i]])))
+    expect_that(sort(el1[[i]]), is_equivalent_to(sort(a)))
   }
   for (i in 1:vcount(g)) {
-    a <- as.numeric(E(g)[to(i)])
-    expect_that(length(a), equals(length(el2[[i]])))
-    expect_that(sort(el2[[i]]), equals(sort(a)))
+    a <- E(g)[to(i)]
+    expect_that(length(a), is_equivalent_to(length(el2[[i]])))
+    expect_that(sort(el2[[i]]), is_equivalent_to(sort(a)))
   }
   
 })
diff --git a/inst/tests/test_get.all.shortest.paths.R b/inst/tests/test_get.all.shortest.paths.R
index 1f0dbdc..a615ab5 100644
--- a/inst/tests/test_get.all.shortest.paths.R
+++ b/inst/tests/test_get.all.shortest.paths.R
@@ -1,7 +1,7 @@
 
-context("get.all.shortest.paths")
+context("all_shortest_paths")
 
-test_that("get.all.shortest.paths works", {
+test_that("all_shortest_paths works", {
 
   library(igraph)
 
@@ -20,21 +20,22 @@ test_that("get.all.shortest.paths works", {
   edges <- as.data.frame(edges)
   edges[[3]] <- as.numeric(as.character(edges[[3]]))
 
-  g <- graph.data.frame(as.data.frame(edges))
+  g <- graph_from_data_frame(as.data.frame(edges))
 
   sortlist <- function(list) {
     list <- lapply(list, sort)
+    list <- lapply(list, as.vector)
     list[order(sapply(list, paste, collapse="!"))]
   }
 
-  sp1 <- get.all.shortest.paths(g, "s", "t", weights=NA)
+  sp1 <- all_shortest_paths(g, "s", "t", weights=NA)
 
   expect_that(sortlist(sp1$res),
               equals(list(c(1, 2, 7), c(1, 3, 7))))
   expect_that(sp1$nrgeo,
               equals(c(1,1,1,1,1,1,2)))
 
-  sp2 <- get.all.shortest.paths(g, "s", "t")
+  sp2 <- all_shortest_paths(g, "s", "t")
 
   expect_that(sortlist(sp2$res),
               equals(list(c(1, 2, 3, 4, 7), c(1, 2, 7), c(1, 3, 7))))
@@ -43,6 +44,6 @@ test_that("get.all.shortest.paths works", {
   ## TODO
 
   ## E(g)$weight <- E(g)$weight - 1
-  ## get.all.shortest.paths(g, "s", "t")
+  ## all_shortest_paths(g, "s", "t")
 
 })
diff --git a/inst/tests/test_get.diameter.R b/inst/tests/test_get.diameter.R
index b7e2d5d..ca4456b 100644
--- a/inst/tests/test_get.diameter.R
+++ b/inst/tests/test_get.diameter.R
@@ -1,22 +1,22 @@
 
-context("get.diameter")
+context("get_diameter")
 
-test_that("get.diameter works", {
+test_that("get_diameter works", {
 
   library(igraph)
 
-  g <- graph.ring(10)
+  g <- make_ring(10)
   E(g)$weight <- sample(seq_len(ecount(g)))
   d <- diameter(g)
-  gd <- get.diameter(g)
-  sp <- shortest.paths(g)
+  gd <- get_diameter(g)
+  sp <- distances(g)
 
   expect_that(d, equals(max(sp)))
   expect_that(sp[ gd[1], gd[length(gd)] ], equals(d))
 
   d <- diameter(g, weights=NA)
-  gd <- get.diameter(g, weights=NA)
-  sp <- shortest.paths(g, weights=NA)
+  gd <- get_diameter(g, weights=NA)
+  sp <- distances(g, weights=NA)
   
   expect_that(d, equals(max(sp)))
   length(gd) == d + 1
diff --git a/inst/tests/test_get.edge.R b/inst/tests/test_get.edge.R
index a2fc7af..141a88f 100644
--- a/inst/tests/test_get.edge.R
+++ b/inst/tests/test_get.edge.R
@@ -1,10 +1,10 @@
 
-context("get.edge")
+context("ends")
 
-test_that("get.edge works", {
+test_that("ends works", {
   library(igraph)
-  g <- erdos.renyi.game(100, 3/100)
-  edges <- unlist(lapply(seq_len(ecount(g)), get.edge, graph=g))
+  g <- sample_gnp(100, 3/100)
+  edges <- unlist(lapply(seq_len(ecount(g)), ends, graph=g))
   g2 <- graph(edges, dir=FALSE, n=vcount(g))
   expect_that(graph.isomorphic(g, g2), is_true())
 })
diff --git a/inst/tests/test_get.edgelist.R b/inst/tests/test_get.edgelist.R
index 7c361dc..3119dd6 100644
--- a/inst/tests/test_get.edgelist.R
+++ b/inst/tests/test_get.edgelist.R
@@ -1,10 +1,10 @@
 
-context("get.edgelist")
+context("edgelist")
 
-test_that("get.edgelist works", {
+test_that("as_edgelist works", {
   library(igraph)
-  g <- erdos.renyi.game(100, 3/100)
-  e <- get.edgelist(g)
+  g <- sample_gnp(100, 3/100)
+  e <- as_edgelist(g)
   g2 <- graph(t(e), n=vcount(g), dir=FALSE)
   expect_that(graph.isomorphic(g, g2), is_true())
 })
diff --git a/inst/tests/test_get.incidence.R b/inst/tests/test_get.incidence.R
index 954b1f0..c253e0a 100644
--- a/inst/tests/test_get.incidence.R
+++ b/inst/tests/test_get.incidence.R
@@ -1,21 +1,21 @@
 
-context("get.incidence")
+context("as_incidence_matrix")
 
-test_that("get.incidence works", {
+test_that("as_incidence_matrix works", {
 
   library(igraph)
 
   ## Dense
   I <- matrix(sample(0:1, 35, replace=TRUE, prob=c(3,1)), nc=5)
-  g <- graph.incidence(I)
-  I2 <- get.incidence(g)
+  g <- graph_from_incidence_matrix(I)
+  I2 <- as_incidence_matrix(g)
   expect_that(I, is_equivalent_to(I2))
   expect_that(rownames(I2), equals(as.character(1:7)))
   expect_that(colnames(I2), equals(as.character(8:12)))
 
   ## Sparse
 
-  I3 <- get.incidence(g, sparse=TRUE)
+  I3 <- as_incidence_matrix(g, sparse=TRUE)
   expect_that(as.matrix(I3), is_equivalent_to(I))
   expect_that(rownames(I3), equals(as.character(1:7)))
   expect_that(colnames(I3), equals(as.character(8:12)))
diff --git a/inst/tests/test_get.shortest.paths.R b/inst/tests/test_get.shortest.paths.R
index 14cce93..b0a962d 100644
--- a/inst/tests/test_get.shortest.paths.R
+++ b/inst/tests/test_get.shortest.paths.R
@@ -1,7 +1,7 @@
 
-context("get.shortest.paths")
+context("shortest_paths")
 
-test_that("get.shortest.paths works", {
+test_that("shortest_paths works", {
 
   library(igraph)
 
@@ -20,12 +20,12 @@ test_that("get.shortest.paths works", {
   edges <- as.data.frame(edges)
   edges[[3]] <- as.numeric(as.character(edges[[3]]))
 
-  g <- graph.data.frame(as.data.frame(edges))
+  g <- graph_from_data_frame(as.data.frame(edges))
 
-  all1 <- get.all.shortest.paths(g, "s", "t", weights=NA)$res
-  all2 <- get.all.shortest.paths(g, "s", "t")$res
+  all1 <- all_shortest_paths(g, "s", "t", weights=NA)$res
+  all2 <- all_shortest_paths(g, "s", "t")$res
 
-  s1 <- get.shortest.paths(g, "s", "t", weights=NA)
+  s1 <- shortest_paths(g, "s", "t", weights=NA)
   s2 <- get.shortest.paths(g, "s", "t")
 
   expect_that(s1$vpath %in% all1, is_true()) 
diff --git a/inst/tests/test_girth.R b/inst/tests/test_girth.R
index c52ea7d..b9ac7ac 100644
--- a/inst/tests/test_girth.R
+++ b/inst/tests/test_girth.R
@@ -6,15 +6,15 @@ test_that("girth works", {
   library(igraph)
 
   ## No circle in a tree
-  g <- graph.tree(1000, 3)
+  g <- make_tree(1000, 3)
   gi <- girth(g)
   expect_that(gi$girth, equals(0))
-  expect_that(gi$circle, equals(numeric()))
+  expect_that(as.vector(gi$circle), equals(numeric()))
 
   ## The worst case running time is for a ring
-  g <- graph.ring(100)
+  g <- make_ring(100)
   gi <- girth(g)
   expect_that(gi$girth, equals(100))
-  expect_that(sort(diff(gi$circle)), equals(c(-99, rep(1, 98))))
+  expect_that(sort(diff(as.vector(gi$circle))), equals(c(-99, rep(1, 98))))
 })
 
diff --git a/inst/tests/test_graph.adhesion.R b/inst/tests/test_graph.adhesion.R
index 48f1876..a34acad 100644
--- a/inst/tests/test_graph.adhesion.R
+++ b/inst/tests/test_graph.adhesion.R
@@ -1,41 +1,41 @@
 
-context("graph.adhesion")
+context("adhesion")
 
-test_that("graph.adhesion works", {
+test_that("adhesion works", {
 
   library(igraph)
 
-  g <- graph.famous("Zachary")
-  expect_that(graph.adhesion(g), equals(1))
-  expect_that(graph.cohesion(g), equals(1))
-
-  kite <- graph.formula(Andre    - Beverly:Carol:Diane:Fernando,
-                        Beverly  - Andre:Diane:Ed:Garth,
-                        Carol    - Andre:Diane:Fernando,
-                        Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
-                        Ed       - Beverly:Diane:Garth,
-                        Fernando - Andre:Carol:Diane:Garth:Heather,
-                        Garth    - Beverly:Diane:Ed:Fernando:Heather,
-                        Heather  - Fernando:Garth:Ike,
-                        Ike      - Heather:Jane,
-                        Jane     - Ike)
-
-  expect_that(graph.adhesion(kite), equals(1)) 
-  expect_that(graph.cohesion(kite), equals(1))
-
-  camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
-                        Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
-                        Holly   - Carol:Pat:Pam:Jennie:Bill,
-                        Bill    - Pauline:Michael:Lee:Holly,
-                        Pauline - Bill:Jennie:Ann,
-                        Jennie  - Holly:Michael:Lee:Ann:Pauline,
-                        Michael - Bill:Jennie:Ann:Lee:John,
-                        Ann     - Michael:Jennie:Pauline,
-                        Lee     - Michael:Bill:Jennie,
-                        Gery    - Pat:Steve:Russ:John,
-                        Russ    - Steve:Bert:Gery:John,
-                        John    - Gery:Russ:Michael)
-
-  expect_that(graph.adhesion(camp), equals(2))
-  expect_that(graph.cohesion(camp), equals(2))
+  g <- make_graph("Zachary")
+  expect_that(adhesion(g), equals(1))
+  expect_that(cohesion(g), equals(1))
+
+  kite <- graph_from_literal(Andre    - Beverly:Carol:Diane:Fernando,
+                    Beverly  - Andre:Diane:Ed:Garth,
+                    Carol    - Andre:Diane:Fernando,
+                    Diane    - Andre:Beverly:Carol:Ed:Fernando:Garth,
+                    Ed       - Beverly:Diane:Garth,
+                    Fernando - Andre:Carol:Diane:Garth:Heather,
+                    Garth    - Beverly:Diane:Ed:Fernando:Heather,
+                    Heather  - Fernando:Garth:Ike,
+                    Ike      - Heather:Jane,
+                    Jane     - Ike)
+
+  expect_that(adhesion(kite), equals(1)) 
+  expect_that(cohesion(kite), equals(1))
+
+  camp <- graph_from_literal(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
+                    Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
+                    Holly   - Carol:Pat:Pam:Jennie:Bill,
+                    Bill    - Pauline:Michael:Lee:Holly,
+                    Pauline - Bill:Jennie:Ann,
+                    Jennie  - Holly:Michael:Lee:Ann:Pauline,
+                    Michael - Bill:Jennie:Ann:Lee:John,
+                    Ann     - Michael:Jennie:Pauline,
+                    Lee     - Michael:Bill:Jennie,
+                    Gery    - Pat:Steve:Russ:John,
+                    Russ    - Steve:Bert:Gery:John,
+                    John    - Gery:Russ:Michael)
+
+  expect_that(adhesion(camp), equals(2))
+  expect_that(cohesion(camp), equals(2))
 })
diff --git a/inst/tests/test_graph.adjacency.R b/inst/tests/test_graph.adjacency.R
index 514c8f5..938e0ac 100644
--- a/inst/tests/test_graph.adjacency.R
+++ b/inst/tests/test_graph.adjacency.R
@@ -1,7 +1,7 @@
 
 context("graph.adjancency")
 
-test_that("graph.adjacency works", {
+test_that("graph_from_adjacency_matrix works", {
 
   library(igraph)
 
@@ -9,8 +9,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(0,1,0,1),
               c(1,0,0,1))
-  g1 <- graph.adjacency(M1)
-  el1 <- get.edgelist(g1)
+  g1 <- graph_from_adjacency_matrix(M1)
+  el1 <- as_edgelist(g1)
   expect_that(el1[order(el1[,1], el1[,2]),],
               equals(structure(c(1, 1, 2, 3, 3, 4, 4, 3, 4, 1, 2, 4,
                                  1, 4), .Dim = c(7L, 2L))))
@@ -19,8 +19,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,1),
               c(1,0,1,0))
-  g2 <- graph.adjacency(M2, mode="undirected")
-  el2 <- get.edgelist(g2)
+  g2 <- graph_from_adjacency_matrix(M2, mode="undirected")
+  el2 <- as_edgelist(g2)
   expect_that(el2[order(el2[,1], el2[,2]),],
               equals(structure(c(1, 1, 1, 3, 2, 3, 4, 4),
                                .Dim = c(4L, 2L))))
@@ -29,8 +29,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,0),
               c(1,0,1,0))
-  g3 <- graph.adjacency(M3, mode="min")
-  el3 <- get.edgelist(g3)
+  g3 <- graph_from_adjacency_matrix(M3, mode="min")
+  el3 <- as_edgelist(g3)
   expect_that(el3[order(el3[,1], el3[,2]),],
               equals(structure(c(1, 1, 1, 2, 3, 4), .Dim=c(3L, 2L))))
 
@@ -38,8 +38,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,0),
               c(1,0,1,0))
-  g4 <- graph.adjacency(M4, mode="max")
-  el4 <- get.edgelist(g4)
+  g4 <- graph_from_adjacency_matrix(M4, mode="max")
+  el4 <- as_edgelist(g4)
   expect_that(el4[order(el4[,1], el4[,2]),],
               equals(structure(c(1, 1, 1, 1, 3,
                                  2, 3, 4, 4, 4), .Dim=c(5L, 2L))))
@@ -48,8 +48,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,0),
               c(1,0,1,0))
-  g5 <- graph.adjacency(M5, mode="upper")
-  el5 <- get.edgelist(g5)
+  g5 <- graph_from_adjacency_matrix(M5, mode="upper")
+  el5 <- as_edgelist(g5)
   expect_that(el5[order(el5[,1], el5[,2]),],
               equals(structure(c(1, 1, 1, 1, 2, 3, 4, 4), .Dim=c(4L, 2L))))
 
@@ -57,8 +57,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,0),
               c(1,0,1,0))
-  g6 <- graph.adjacency(M6, mode="lower")
-  el6 <- get.edgelist(g6)
+  g6 <- graph_from_adjacency_matrix(M6, mode="lower")
+  el6 <- as_edgelist(g6)
   expect_that(el6[order(el6[,1], el6[,2]),],
               equals(structure(c(1, 1, 1, 3, 2, 3, 4, 4), .Dim=c(4L, 2L))))
 
@@ -66,8 +66,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,0),
               c(1,0,1,0))
-  g7 <- graph.adjacency(M7, mode="plus")
-  el7 <- get.edgelist(g7)
+  g7 <- graph_from_adjacency_matrix(M7, mode="plus")
+  el7 <- as_edgelist(g7)
   expect_that(el7[order(el7[,1], el7[,2]),],
               equals(structure(c(1, 1, 1, 1, 1, 1, 1, 3, 2, 2, 3, 3,
                                  4, 4, 4, 4), .Dim = c(8L, 2L))))
@@ -76,8 +76,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,0),
               c(1,0,2,0))
-  g8 <- graph.adjacency(M8, mode="directed", weighted=TRUE)
-  el8 <- cbind(get.edgelist(g8), E(g8)$weight)
+  g8 <- graph_from_adjacency_matrix(M8, mode="directed", weighted=TRUE)
+  el8 <- cbind(as_edgelist(g8), E(g8)$weight)
   expect_that(el8[order(el8[,1], el8[,2]),],
               equals(structure(c(1, 1, 1, 2, 3, 4, 4, 2, 3, 4, 1, 1,
                                  1, 3, 1, 1, 0.5, 1, 1, 1, 2), .Dim =
@@ -87,8 +87,8 @@ test_that("graph.adjacency works", {
               c(1,0,0,0),
               c(1,0,0,2),
               c(3,0,2,0))
-  g9 <- graph.adjacency(M9, mode="undirected", weighted=TRUE)
-  el9 <- cbind(get.edgelist(g9), E(g9)$weight)
+  g9 <- graph_from_adjacency_matrix(M9, mode="undirected", weighted=TRUE)
+  el9 <- cbind(as_edgelist(g9), E(g9)$weight)
   expect_that(el9[order(el9[,1], el9[,2]),],
               equals(structure(c(1, 1, 1, 3, 2, 3, 4, 4, 1, 1, 3, 2),
                                .Dim = c(4L, 3L))))
@@ -97,8 +97,8 @@ test_that("graph.adjacency works", {
                c(1,0,0,0),
                c(1,0,0,0),
                c(1,0,2,0))
-  g10 <- graph.adjacency(M10, mode="max", weighted=TRUE)
-  el10 <- cbind(get.edgelist(g10), E(g10)$weight)
+  g10 <- graph_from_adjacency_matrix(M10, mode="max", weighted=TRUE)
+  el10 <- cbind(as_edgelist(g10), E(g10)$weight)
   expect_that(el10[order(el10[,1], el10[,2]),],
               equals(structure(c(1, 1, 1, 3, 2, 3, 4, 4, 1, 1, 1, 2),
                                .Dim = c(4L, 3L))))
@@ -107,8 +107,8 @@ test_that("graph.adjacency works", {
                c(1,0,0,0),
                c(1,0,0,0),
                c(1,0,2,0))
-  g11 <- graph.adjacency(M11, mode="min", weighted=TRUE)
-  el11 <- cbind(get.edgelist(g11), E(g11)$weight)
+  g11 <- graph_from_adjacency_matrix(M11, mode="min", weighted=TRUE)
+  el11 <- cbind(as_edgelist(g11), E(g11)$weight)
   expect_that(el11[order(el11[,1], el11[,2]),],
               equals(structure(c(1, 1, 1, 2, 3, 4, 1, 1, 0.5), .Dim =
                                c(3L, 3L))))
@@ -117,8 +117,8 @@ test_that("graph.adjacency works", {
                c(1,0,0,0),
                c(1,0,0,0),
                c(1,0,2,0))
-  g12 <- graph.adjacency(M12, mode="lower", weighted=TRUE)
-  el12 <- cbind(get.edgelist(g12), E(g12)$weight)
+  g12 <- graph_from_adjacency_matrix(M12, mode="lower", weighted=TRUE)
+  el12 <- cbind(as_edgelist(g12), E(g12)$weight)
   expect_that(el12[order(el12[,1], el12[,2]),],
               equals(structure(c(1, 1, 1, 3, 2, 3, 4, 4, 1, 1, 1, 2),
                                .Dim = c(4L, 3L))))
@@ -127,8 +127,8 @@ test_that("graph.adjacency works", {
                c(1,0,0,0),
                c(1,0,0,0),
                c(1,0,2,0))
-  g13 <- graph.adjacency(M13, mode="upper", weighted=TRUE)
-  el13 <- cbind(get.edgelist(g13), E(g13)$weight)
+  g13 <- graph_from_adjacency_matrix(M13, mode="upper", weighted=TRUE)
+  el13 <- cbind(as_edgelist(g13), E(g13)$weight)
   expect_that(el13[order(el13[,1], el13[,2]),],
               equals(structure(c(1, 1, 1, 2, 3, 4, 1, 1, 0.5), .Dim =
                                c(3L, 3L))))
@@ -137,21 +137,21 @@ test_that("graph.adjacency works", {
                c(1,0,0,0),
                c(1,0,0,0),
                c(1,0,2,0))
-  g14 <- graph.adjacency(M14, mode="plus", weighted=TRUE)
-  el14 <- cbind(get.edgelist(g14), E(g14)$weight)
+  g14 <- graph_from_adjacency_matrix(M14, mode="plus", weighted=TRUE)
+  el14 <- cbind(as_edgelist(g14), E(g14)$weight)
   expect_that(el14[order(el14[,1], el14[,2]),],
               equals(structure(c(1, 1, 1, 3, 2, 3, 4, 4, 2, 2, 1.5,
                                  2), .Dim = c(4L, 3L))))
 
 })
 
-test_that("graph.adjacency 2 edge bug is fixed", {
+test_that("graph_from_adjacency_matrix 2 edge bug is fixed", {
 
   library(Matrix)
   library(igraph)
   A <- Matrix(0, 10, 10, sparse=TRUE)
   A[3,5] <- A[5,3] <- 1
-  g <- graph.adjacency(A, mode="undirected")
+  g <- graph_from_adjacency_matrix(A, mode="undirected")
   expect_that(g[], equals(A))
 
 })
@@ -161,7 +161,7 @@ test_that("graph.adjacenct empty graph bug is fixed", {
   library(Matrix)
   library(igraph)
   A <- Matrix(0, 10, 10, sparse=TRUE)
-  g <- graph.adjacency(A, mode="undirected")
+  g <- graph_from_adjacency_matrix(A, mode="undirected")
   expect_that(as.matrix(g[]), equals(as.matrix(A)))
 
 })
@@ -173,7 +173,7 @@ test_that("bug #554 is fixed", {
 
   M <- Matrix(0, 5, 5)
   M[1,2] <- M[2,1] <- M[3,4] <- M[4,3] <- 1
-  g <- graph.adjacency(M, mode="undirected", weighted=TRUE)
+  g <- graph_from_adjacency_matrix(M, mode="undirected", weighted=TRUE)
   expect_that(g[], equals(M))
 
 })
diff --git a/inst/tests/test_graph.adjlist.R b/inst/tests/test_graph.adjlist.R
index ae1e6e7..87c1e0a 100644
--- a/inst/tests/test_graph.adjlist.R
+++ b/inst/tests/test_graph.adjlist.R
@@ -1,19 +1,19 @@
 
-context("graph.adjlist")
+context("graph_from_adj_list")
 
-test_that("graph.adjlist works", {
+test_that("graph_from_adj_list works", {
 
   library(igraph)
   
-  g <- erdos.renyi.game(100, 3/100)
-  al <- get.adjlist(g)
-  g2 <- graph.adjlist(al, mode="all")
+  g <- sample_gnp(100, 3/100)
+  al <- as_adj_list(g)
+  g2 <- graph_from_adj_list(al, mode="all")
   expect_that(graph.isomorphic(g, g2), is_true())
 
   ##
   
-  g <- erdos.renyi.game(100, 3/100, dir=TRUE)
-  al <- get.adjlist(g, mode="out")
-  g2 <- graph.adjlist(al, mode="out")
+  g <- sample_gnp(100, 3/100, dir=TRUE)
+  al <- as_adj_list(g, mode="out")
+  g2 <- graph_from_adj_list(al, mode="out")
   expect_that(graph.isomorphic(g, g2), is_true())
 })
diff --git a/inst/tests/test_graph.bfs.R b/inst/tests/test_graph.bfs.R
index 7ce02a9..7299bc4 100644
--- a/inst/tests/test_graph.bfs.R
+++ b/inst/tests/test_graph.bfs.R
@@ -4,18 +4,18 @@ context("BFS")
 test_that("BFS works from multiple root vertices", {
 
   library(igraph)
-  g <- graph.ring(10) %du% graph.ring(10)
+  g <- make_ring(10) %du% make_ring(10)
 
-  expect_that(graph.bfs(g, 1)$order,
+  expect_that(as.vector(bfs(g, 1)$order),
               equals(c(1,2,10,3,9,4,8,5,7,6,11,12,20,13,19,14,18,15,17,16)))
   
-  expect_that(graph.bfs(g, 1, unreachable=FALSE)$order,
+  expect_that(as.vector(bfs(g, 1, unreachable=FALSE)$order),
               equals(c(1,2,10,3,9,4,8,5,7,6,rep(NaN, 10))))
 
-  expect_that(graph.bfs(g,c(1, 12), unreachable=FALSE)$order,
+  expect_that(as.vector(bfs(g,c(1, 12), unreachable=FALSE)$order),
               equals(c(1,2,10,3,9,4,8,5,7,6,12,11,13,20,14,19,15,18,16,17)))
 
-  expect_that(graph.bfs(g,c(12, 1, 15), unreachable=FALSE)$order,
+  expect_that(as.vector(bfs(g,c(12, 1, 15), unreachable=FALSE)$order),
               equals(c(12,11,13,20,14,19,15,18,16,17,1,2,10,3,9,4,8,5,7,6)))
 
 })
diff --git a/inst/tests/test_graph.bipartite.R b/inst/tests/test_graph.bipartite.R
index 5a31a9a..78746ca 100644
--- a/inst/tests/test_graph.bipartite.R
+++ b/inst/tests/test_graph.bipartite.R
@@ -1,18 +1,18 @@
 
-context("graph.bipartite")
+context("make_bipartite_graph")
 
-test_that("graph.bipartite works", {
+test_that("make_bipartite_graph works", {
   library(igraph)
 
   I <- matrix(sample(0:1, 35, replace=TRUE, prob=c(3,1)), nc=5)
-  g <- graph.incidence(I)
+  g <- graph_from_incidence_matrix(I)
 
   edges <- unlist(sapply(seq_len(nrow(I)), function(x) {
     w <- which(I[x,] != 0) + nrow(I)
     if (length(w)!=0) { as.vector(rbind(x, w)) } else { numeric() }
   }))
-  g2 <- graph.bipartite(seq_len(nrow(I)+ncol(I)) > nrow(I), edges)
-  I2 <- get.incidence(g2)
+  g2 <- make_bipartite_graph(seq_len(nrow(I)+ncol(I)) > nrow(I), edges)
+  I2 <- as_incidence_matrix(g2)
   
   expect_that(I2, is_equivalent_to(I))
 })
diff --git a/inst/tests/test_graph.complementer.R b/inst/tests/test_graph.complementer.R
index cd40c39..48a5d90 100644
--- a/inst/tests/test_graph.complementer.R
+++ b/inst/tests/test_graph.complementer.R
@@ -1,13 +1,13 @@
 
-context("graph.complementer")
+context("complementer")
 
-test_that("graph.complementer works", {
+test_that("complementer works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50, 3/50)
-  g2 <- graph.complementer(g)
-  g3 <- graph.complementer(g2)
+  g <- sample_gnp(50, 3/50)
+  g2 <- complementer(g)
+  g3 <- complementer(g2)
   expect_that(graph.isomorphic(g, g3), is_true())
   
 })
diff --git a/inst/tests/test_graph.compose.R b/inst/tests/test_graph.compose.R
index 35823b6..3328c25 100644
--- a/inst/tests/test_graph.compose.R
+++ b/inst/tests/test_graph.compose.R
@@ -1,15 +1,15 @@
 
-context("graph.compose")
+context("compose")
 
-test_that("graph.compose works", {
+test_that("compose works", {
 
   library(igraph)
 
-  g1 <- erdos.renyi.game(50, 3/50, directed=TRUE)
+  g1 <- sample_gnp(50, 3/50, directed=TRUE)
   gi <- graph( rep(1:vcount(g1), each=2), dir=TRUE )
 
-  g2 <- graph.compose(g1, gi)
-  g3 <- graph.compose(gi, g1)
+  g2 <- compose(g1, gi)
+  g3 <- compose(gi, g1)
 
   expect_that(graph.isomorphic(g1, g2), is_true())
   expect_that(graph.isomorphic(g1, g3), is_true())
diff --git a/inst/tests/test_graph.coreness.R b/inst/tests/test_graph.coreness.R
index 4b4b358..b3eb466 100644
--- a/inst/tests/test_graph.coreness.R
+++ b/inst/tests/test_graph.coreness.R
@@ -1,10 +1,10 @@
 
-context("graph.coreness")
+context("coreness")
 
-test_that("graph.coreness works", {
+test_that("coreness works", {
   library(igraph)
-  g <- graph.ring(10)
-  g <- add.edges(g, c(1,2, 2,3, 1,3))
-  gc <- graph.coreness(g)               
+  g <- make_ring(10)
+  g <- add_edges(g, c(1,2, 2,3, 1,3))
+  gc <- coreness(g)               
   expect_that(gc, equals(c(3,3,3,2,2,2,2,2,2,2)))
 })
diff --git a/inst/tests/test_graph.data.frame.R b/inst/tests/test_graph.data.frame.R
index f568562..ed3a4b5 100644
--- a/inst/tests/test_graph.data.frame.R
+++ b/inst/tests/test_graph.data.frame.R
@@ -1,9 +1,9 @@
 
-context("graph.data.frame")
+context("graph_from_data_frame")
 
-test_that("graph.data.frame works", {
+test_that("graph_from_data_frame works", {
 
-  library(igraph) ; igraph.options(print.full=TRUE)
+  library(igraph) ; igraph_options(print.full=TRUE)
 
   actors <- data.frame(name=c("Alice", "Bob", "Cecil", "David",
                          "Esmeralda"),
@@ -17,22 +17,22 @@ test_that("graph.data.frame works", {
                           same.dept=c(FALSE,FALSE,TRUE,FALSE,FALSE,TRUE),
                           friendship=c(4,5,5,2,1,1), advice=c(4,5,5,4,2,3),
                           stringsAsFactors=FALSE)
-  g <- graph.data.frame(relations, directed=TRUE, vertices=actors)
+  g <- graph_from_data_frame(relations, directed=TRUE, vertices=actors)
 
-  df <- get.data.frame(g, what="both")
+  df <- as_data_frame(g, what="both")
   expect_that(df$vertices, is_equivalent_to(actors))
   expect_that(df$edges, equals(relations))
 
 })
 
-test_that("graph.data.frame works on matrices", {
+test_that("graph_from_data_frame works on matrices", {
 
   library(igraph)
 
   el <- cbind(1:5,5:1,weight=1:5)
-  g <- graph.data.frame(el)
-  g <- remove.vertex.attribute(g, "name")
-  el2 <- get.data.frame(g)
+  g <- graph_from_data_frame(el)
+  g <- delete_vertex_attr(g, "name")
+  el2 <- as_data_frame(g)
   expect_that(as.data.frame(el), is_equivalent_to(el2))
 
 })
diff --git a/inst/tests/test_graph.de.bruijn.R b/inst/tests/test_graph.de.bruijn.R
index 99e757e..3376899 100644
--- a/inst/tests/test_graph.de.bruijn.R
+++ b/inst/tests/test_graph.de.bruijn.R
@@ -1,12 +1,12 @@
 
-context("graph.de.bruijn")
+context("make_de_bruijn_graph")
 
-test_that("graph.de.bruijn works", {
+test_that("make_de_bruijn_graph works", {
 
   library(igraph)
-  g <- graph.de.bruijn(2,1)
-  g2 <- graph.de.bruijn(2,2)
-  g3 <- line.graph(g)
+  g <- make_de_bruijn_graph(2,1)
+  g2 <- make_de_bruijn_graph(2,2)
+  g3 <- make_line_graph(g)
 
   expect_that(graph.isomorphic(g3, graph(c(1,1,3,1,1,2,3,2,2,3,
                                            4,3,2,4,4,4))), is_true())
diff --git a/inst/tests/test_graph.density.R b/inst/tests/test_graph.density.R
index 301c05c..5e421a5 100644
--- a/inst/tests/test_graph.density.R
+++ b/inst/tests/test_graph.density.R
@@ -1,19 +1,19 @@
 
-context("graph.density")
+context("edge_density")
 
-test_that("graph.density works", {
+test_that("edge_density works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50, 4/50)
-  gd <- graph.density(g)
+  g <- sample_gnp(50, 4/50)
+  gd <- edge_density(g)
   gd2 <- ecount(g) / vcount(g) / (vcount(g)-1) * 2
   expect_that(gd, equals(gd2))
 
 ####
 
-  g <- erdos.renyi.game(50, 4/50, dir=TRUE)
-  gd <- graph.density(g)
+  g <- sample_gnp(50, 4/50, dir=TRUE)
+  gd <- edge_density(g)
   gd2 <- ecount(g) / vcount(g) / (vcount(g)-1)
   expect_that(gd, equals(gd2))
 
diff --git a/inst/tests/test_graph.edgelist.R b/inst/tests/test_graph.edgelist.R
index 0c8c791..fa6b421 100644
--- a/inst/tests/test_graph.edgelist.R
+++ b/inst/tests/test_graph.edgelist.R
@@ -1,31 +1,31 @@
 
-context("graph.edgelist")
+context("graph_from_edgelist")
 
-test_that("graph.edgelist works", {
+test_that("graph_from_edgelist works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50, 5/50)
-  el <- get.edgelist(g)
-  g2 <- graph.edgelist(el, dir=FALSE)
+  g <- sample_gnp(50, 5/50)
+  el <- as_edgelist(g)
+  g2 <- graph_from_edgelist(el, dir=FALSE)
   expect_that(graph.isomorphic(g, g2), is_true())
 
 ####
 
-  g <- erdos.renyi.game(50, 5/50, dir=TRUE)
-  el <- get.edgelist(g)
-  g2 <- graph.edgelist(el, dir=TRUE)
+  g <- sample_gnp(50, 5/50, dir=TRUE)
+  el <- as_edgelist(g)
+  g2 <- graph_from_edgelist(el, dir=TRUE)
   expect_that(graph.isomorphic(g, g2), is_true())
 
 ####
 
-  g <- erdos.renyi.game(26, 5/26, dir=TRUE)
-  el <- get.edgelist(g)
+  g <- sample_gnp(26, 5/26, dir=TRUE)
+  el <- as_edgelist(g)
   n <- letters[1:26]
   names(n) <- 1:26
   mode(el) <- "character"
   el[] <- n[el]
-  g2 <- graph.edgelist(el, dir=TRUE)
+  g2 <- graph_from_edgelist(el, dir=TRUE)
   expect_that(graph.isomorphic(g, g2), is_true())
 
 })
diff --git a/inst/tests/test_graph.eigen.R b/inst/tests/test_graph.eigen.R
index e3cd6d6..51db7f5 100644
--- a/inst/tests/test_graph.eigen.R
+++ b/inst/tests/test_graph.eigen.R
@@ -1,7 +1,7 @@
 
 context("Eigenproblems")
 
-test_that("graph.eigen works for symmetric matrices", {
+test_that("spectrum works for symmetric matrices", {
   library(igraph)
   set.seed(42)
 
@@ -12,14 +12,14 @@ test_that("graph.eigen works for symmetric matrices", {
     })
   }
   
-  g <- erdos.renyi.game(50, 5/50)
-  e0 <- eigen(get.adjacency(g, sparse=FALSE))
+  g <- sample_gnp(50, 5/50)
+  e0 <- eigen(as_adj(g, sparse=FALSE))
 
-  e1 <- graph.eigen(g, which=list(howmany=4, pos="LA"))
+  e1 <- spectrum(g, which=list(howmany=4, pos="LA"))
   expect_that(e0$values[1:4], equals(e1$values))
   expect_that(std(e0$vectors[,1:4]), equals(std(e1$vectors)))
 
-  e2 <- graph.eigen(g, which=list(howmany=4, pos="SA"))
+  e2 <- spectrum(g, which=list(howmany=4, pos="SA"))
   expect_that(e0$values[50:47], equals(e2$values))
   expect_that(std(e0$vectors[,50:47]), equals(std(e2$vectors)))
 
diff --git a/inst/tests/test_graph.formula.R b/inst/tests/test_graph.formula.R
index 50d9452..9edfc2f 100644
--- a/inst/tests/test_graph.formula.R
+++ b/inst/tests/test_graph.formula.R
@@ -1,11 +1,11 @@
 
-context("graph.formula")
+context("graph_from_literal")
 
 test_that("simplify argument works", {
 
   library(igraph)
-  g1 <- graph.formula(1-1, 1-2, 1-2)
-  g2 <- graph.formula(1-1, 1-2, 1-2, simplify=FALSE)
+  g1 <- graph_from_literal(1-1, 1-2, 1-2)
+  g2 <- graph_from_literal(1-1, 1-2, 1-2, simplify=FALSE)
 
   expect_that(vcount(g1), equals(2))
   expect_that(ecount(g1), equals(1))
diff --git a/inst/tests/test_graph.isoclass.R b/inst/tests/test_graph.isoclass.R
index 569dec3..4014e43 100644
--- a/inst/tests/test_graph.isoclass.R
+++ b/inst/tests/test_graph.isoclass.R
@@ -1,16 +1,16 @@
 
-context("graph.isoclass")
+context("isomorphism_class")
 
-test_that("graph.isoclass works", {
+test_that("isomorphism_class works", {
 
   library(igraph)
 
-  g1 <- graph.isocreate(3, 10)
-  g2 <- graph.isocreate(3, 11)
-  expect_that(graph.isoclass(g1), equals(10))
-  expect_that(graph.isoclass(g2), equals(11))
+  g1 <- graph_from_isomorphism_class(3, 10)
+  g2 <- graph_from_isomorphism_class(3, 11)
+  expect_that(isomorphism_class(g1), equals(10))
+  expect_that(isomorphism_class(g2), equals(11))
 
-  g1 <- add.vertices(g1, 3)
+  g1 <- add_vertices(g1, 3)
   expect_that(graph.isoclass.subgraph(g1, 1:3), equals(10))
   expect_that(graph.isoclass.subgraph(g1 %du% g2, 1:3), equals(10))
   expect_that(graph.isoclass.subgraph(g1 %du% g2, 7:9), equals(11))
diff --git a/inst/tests/test_graph.kautz.R b/inst/tests/test_graph.kautz.R
index cf5dcb5..edcea77 100644
--- a/inst/tests/test_graph.kautz.R
+++ b/inst/tests/test_graph.kautz.R
@@ -1,14 +1,14 @@
 
-context("graph.kautz")
+context("make_kautz_graph")
 
-test_that("graph.kautz works", {
+test_that("make_kautz_graph works", {
   library(igraph)
-  g <- graph.kautz(2,3)
+  g <- make_kautz_graph(2,3)
   expect_that(g$name, equals("Kautz graph 2-3"))
   expect_that(g$m, equals(2))
   expect_that(g$n, equals(3))
 
-  el <- get.edgelist(g)
+  el <- as_edgelist(g)
   el <- el[order(el[,1], el[,2]),]
   expect_that(el, equals(
     structure(c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 
diff --git a/inst/tests/test_graph.knn.R b/inst/tests/test_graph.knn.R
index b9023e3..ec5371c 100644
--- a/inst/tests/test_graph.knn.R
+++ b/inst/tests/test_graph.knn.R
@@ -1,37 +1,37 @@
 
-context("graph.knn")
+context("knn")
 
-test_that("graph.knn works", {
+test_that("knn works", {
   library(igraph)
   set.seed(42)
 
   ## Some trivial ones
-  g <- graph.ring(10)
-  expect_that(graph.knn(g), equals(list(knn=rep(2,10), knnk=c(NaN, 2))))
+  g <- make_ring(10)
+  expect_that(knn(g), equals(list(knn=rep(2,10), knnk=c(NaN, 2))))
 
-  g2 <- graph.star(10)
-  expect_that(graph.knn(g2), equals(list(knn=c(1, rep(9,9)),
+  g2 <- make_star(10)
+  expect_that(knn(g2), equals(list(knn=c(1, rep(9,9)),
                                          knnk=c(9, rep(NaN, 7), 1))))
 
   ## A scale-free one, try to plot 'knnk'
-  g3 <- simplify(ba.game(1000, m=5))
-  r3 <- graph.knn(g3)
+  g3 <- simplify(sample_pa(1000, m=5))
+  r3 <- knn(g3)
   expect_that(r3$knn[43], equals(46))
   expect_that(r3$knn[1000], equals(192.4))
   expect_that(r3$knnk[100], equals(18.78))
   expect_that(length(r3$knnk), equals(359))
   
   ## A random graph
-  g4 <- random.graph.game(1000, p=5/1000)
-  r4 <- graph.knn(g4)
+  g4 <- sample_gnp(1000, p=5/1000)
+  r4 <- knn(g4)
   expect_that(r4$knn[1000], equals(20/3))
   expect_that(length(r4$knnk), equals(15))
   expect_that(r4$knnk[12], equals(19/3))
 
   ## A weighted graph
-  g5 <- graph.star(10)
+  g5 <- make_star(10)
   E(g5)$weight <- seq(ecount(g5))
-  r5 <- graph.knn(g5)
+  r5 <- knn(g5)
   expect_that(r5, equals(structure(list(knn = c(1, 45, 22.5, 15,
                                           11.25, 9, 7.5, 6.42857142857143,
                                           5.625, 5), knnk =
diff --git a/inst/tests/test_graph.maxflow.R b/inst/tests/test_graph.maxflow.R
index 7fa2921..f6d68d0 100644
--- a/inst/tests/test_graph.maxflow.R
+++ b/inst/tests/test_graph.maxflow.R
@@ -1,15 +1,15 @@
 
-context("graph.maxflow")
+context("max_flow")
 
-test_that("graph.maxflow works", {
+test_that("max_flow works", {
   library(igraph)
   E <- rbind( c(1,3,3), c(3,4,1), c(4,2,2), c(1,5,1), c(5,6,2), c(6,2,10))
   colnames(E) <- c("from", "to", "capacity")
-  g1 <- graph.data.frame(as.data.frame(E))
-  fl <- graph.maxflow(g1, source="1", target="2")
+  g1 <- graph_from_data_frame(as.data.frame(E))
+  fl <- max_flow(g1, source="1", target="2")
   expect_that(fl$value, equals(2))
-  expect_that(fl$flow, equals(rep(1, 6)))
-  expect_that(sort(fl$cut), equals(c(2,4)))
-  expect_that(sort(fl$partition1), equals(1:2))
-  expect_that(sort(fl$partition2), equals(3:6))
+  expect_that(as.vector(fl$flow), equals(rep(1, 6)))
+  expect_that(sort(as.vector(fl$cut)), equals(c(2,4)))
+  expect_that(sort(as.vector(fl$partition1)), equals(1:2))
+  expect_that(sort(as.vector(fl$partition2)), equals(3:6))
 })
diff --git a/inst/tests/test_graph.mincut.R b/inst/tests/test_graph.mincut.R
index 5e21a1a..654029e 100644
--- a/inst/tests/test_graph.mincut.R
+++ b/inst/tests/test_graph.mincut.R
@@ -1,17 +1,17 @@
 
-context("graph.mincut")
+context("min_cut")
 
-test_that("graph.mincut works", {
+test_that("min_cut works", {
 
   library(igraph)
 
   g2 <- graph( c(1,2,2,3,3,4, 1,6,6,5,5,4, 4,1) )
   E(g2)$capacity <- c(3,1,2, 10,1,3, 2)
-  mc <- graph.mincut(g2, value.only=FALSE)
+  mc <- min_cut(g2, value.only=FALSE)
 
   expect_that(mc$value, equals(1))
-  expect_that(mc$cut, equals(2))
-  expect_that(mc$partition1, equals(2))
-  expect_that(mc$partition2, equals(c(1,3:6)))
+  expect_that(as.vector(mc$cut), equals(2))
+  expect_that(as.vector(mc$partition1), equals(2))
+  expect_that(as.vector(mc$partition2), equals(c(1,3:6)))
 
 })
diff --git a/inst/tests/test_graph.subisomorphic.lad.R b/inst/tests/test_graph.subisomorphic.lad.R
index 26fb714..2c5b6e1 100644
--- a/inst/tests/test_graph.subisomorphic.lad.R
+++ b/inst/tests/test_graph.subisomorphic.lad.R
@@ -1,43 +1,26 @@
 
-context("graph.subisomorphic.lad")
+context("graph.subisomorphic, lad")
 
-test_that("graph.subisomorphic.lad works", {
+test_that("graph.subisomorphic, method = 'lad' works", {
 
   library(igraph)
 
-  pattern <- graph.formula(1:2:3:4:5,
-                           1 - 2:5, 2 - 1:5:3, 3 - 2:4, 4 - 3:5, 5 - 4:2:1)
-  target <- graph.formula(1:2:3:4:5:6:7:8:9,
-                          1 - 2:5:7, 2 - 1:5:3, 3 - 2:4, 4 - 3:5:6:8:9,
-                          5 - 1:2:4:6:7, 6 - 7:5:4:9, 7 - 1:5:6,
-                          8 - 4:9, 9 - 6:4:8)
+  pattern <- graph_from_literal(1:2:3:4:5,
+                       1 - 2:5, 2 - 1:5:3, 3 - 2:4, 4 - 3:5, 5 - 4:2:1)
+  target <- graph_from_literal(1:2:3:4:5:6:7:8:9,
+                      1 - 2:5:7, 2 - 1:5:3, 3 - 2:4, 4 - 3:5:6:8:9,
+                      5 - 1:2:4:6:7, 6 - 7:5:4:9, 7 - 1:5:6,
+                      8 - 4:9, 9 - 6:4:8)
   domains <- list(`1` = c(1,3,9), `2` = c(5,6,7,8), `3` = c(2,4,6,7,8,9),
                   `4` = c(1,3,9), `5` = c(2,4,8,9))
-  i1 <- graph.subisomorphic.lad(pattern, target, all.maps=TRUE)
-  i2 <- graph.subisomorphic.lad(pattern, target, induced=TRUE,
-                                all.maps=TRUE)
-  i3 <- graph.subisomorphic.lad(pattern, target, domains=domains,
-                                all.maps=TRUE)
+  i1 <- subgraph_isomorphic(pattern, target, method = "lad")
+  i2 <- subgraph_isomorphic(pattern, target, induced=TRUE, method = "lad")
+  i3 <- subgraph_isomorphic(pattern, target, domains=domains,
+                            method = "lad")
 
-  expect_that(i1$iso, is_true())
-  expect_that(i2, equals(
-    structure(list(iso = TRUE, map = structure(c(1, 2, 3, 4, 5),
-                                 .Names = c("1", "2", "3", "4", "5")),
-                   maps = list(structure(c(1, 2, 3, 4, 5),
-                     .Names = c("1", "2", "3", "4", "5")),
-                     structure(c(6, 4, 3, 2, 5),
-                               .Names = c("6", "4", "3", "2", "5")),
-                     structure(c(6, 5, 2, 3, 4),
-                               .Names = c("6", "5", "2", "3", "4")),
-                     structure(c(1, 5, 4, 3, 2),
-                               .Names = c("1", "5", "4", "3", "2")))),
-              .Names = c("iso", "map", "maps")) ))
-  expect_that(i3, equals(
-    structure(list(iso = TRUE, map = structure(c(1, 5, 4, 3, 2),
-                                 .Names = c("1", "5", "4", "3", "2")),
-                   maps = list(structure(c(1, 5, 4, 3, 2),
-                     .Names = c("1", "5", "4", "3", "2")))),
-              .Names = c("iso", "map", "maps")) ))
+  expect_that(i1, is_true())
+  expect_that(i2, is_true())
+  expect_that(i3, is_true())
 
 })
 
@@ -48,23 +31,23 @@ test_that("LAD stress test", {
   N <- 100
   
   for (i in 1:N) {
-    target <- erdos.renyi.game(20, .5)
+    target <- sample_gnp(20, .5)
     pn <- sample(4:18, 1)
-    pattern <- induced.subgraph(target, sample(vcount(target), pn))
-    iso <- graph.subisomorphic.lad(pattern, target, induced=TRUE,
-                                   all.maps=FALSE)
-    expect_that(iso$iso, is_true())
+    pattern <- induced_subgraph(target, sample(vcount(target), pn))
+    iso <- subgraph_isomorphic(pattern, target, induced=TRUE,
+                               method = "lad")
+    expect_that(iso, is_true())
   }
 
   set.seed(42)
   
   for (i in 1:N) {
-    target <- erdos.renyi.game(20, 1/20)
+    target <- sample_gnp(20, 1/20)
     pn <- sample(5:18, 1)
-    pattern <- erdos.renyi.game(pn, .6)
-    iso <- graph.subisomorphic.lad(pattern, target, induced=TRUE,
-                                   all.maps=FALSE)
-    expect_that(iso$iso, is_false())
+    pattern <- sample_gnp(pn, .6)
+    iso <- subgraph_isomorphic(pattern, target, induced=TRUE,
+                               method = "lad")
+    expect_that(iso, is_false())
   }
 
 })
diff --git a/inst/tests/test_graph.subisomorphic.vf2.R b/inst/tests/test_graph.subisomorphic.vf2.R
index 6719873..2308258 100644
--- a/inst/tests/test_graph.subisomorphic.vf2.R
+++ b/inst/tests/test_graph.subisomorphic.vf2.R
@@ -6,8 +6,8 @@ test_that("graph.subisomorphic.vf2 works", {
   library(igraph)
   set.seed(42)
 
-  g1 <- erdos.renyi.game(20,6/20)
-  g2 <- erdos.renyi.game(20,6/20)
+  g1 <- sample_gnp(20,6/20)
+  g2 <- sample_gnp(20,6/20)
   g <- g1 %du% g2
 
   ig1 <- graph.subisomorphic.vf2(g, g1)
diff --git a/inst/tests/test_graphNEL.R b/inst/tests/test_graphNEL.R
index ff7cbca..adc6f40 100644
--- a/inst/tests/test_graphNEL.R
+++ b/inst/tests/test_graphNEL.R
@@ -6,9 +6,9 @@ test_that("graphNEL conversion works", {
   library(igraph)
   library(graph, warn.conflicts=FALSE)
 
-  g <- erdos.renyi.game(100, 5/100)
-  N <- igraph.to.graphNEL(g)
-  g2 <- igraph.from.graphNEL(N)
+  g <- sample_gnp(100, 5/100)
+  N <- as_graphnel(g)
+  g2 <- graph_from_graphnel(N)
   gi <- graph.isomorphic.vf2(g, g2)
   expect_that(gi$iso, is_true())
   expect_that(gi$map12, equals(1:vcount(g)))
@@ -20,13 +20,13 @@ test_that("graphNEL conversion works", {
   E(g)$weight <- sample(1:10, ecount(g), replace=TRUE)
   g$name <- "Foobar"
 
-  N <- igraph.to.graphNEL(g)
-  g2 <- igraph.from.graphNEL(N)
+  N <- as_graphnel(g)
+  g2 <- graph_from_graphnel(N)
   expect_that(graph.isomorphic(g, g2), is_true())
   expect_that(V(g)$name, equals(V(g2)$name))
 
-  A <- get.adjacency(g, attr="weight", sparse=FALSE)
-  A2 <- get.adjacency(g2, attr="weight", sparse=FALSE)
+  A <- as_adj(g, attr="weight", sparse=FALSE)
+  A2 <- as_adj(g2, attr="weight", sparse=FALSE)
   expect_that(A, equals(A))
   expect_that(g$name, equals(g2$name))
 
diff --git a/inst/tests/test_graphlets.R b/inst/tests/test_graphlets.R
index cce3f6c..e2bc82b 100644
--- a/inst/tests/test_graphlets.R
+++ b/inst/tests/test_graphlets.R
@@ -4,11 +4,11 @@ context("Graphlets")
 test_that("Getting subcliques works", {
   library(igraph)
   set.seed(42*42)
-  g <- erdos.renyi.game(10, 4/10)
+  g <- sample_gnp(10, 4/10)
   E(g)$weight <- as.double(sample(1:10, ecount(g), replace=TRUE))
   ids <- 1:vcount(g)
 
-  cl <- maximal.cliques(g)
+  cl <- max_cliques(g)
   cl <- lapply(cl, "-", 1)[c(9, 2, 3, 10, 5, 7, 6, 1, 4, 8)]
 
   res <- .Call("R_igraph_subclique_next", g, E(g)$weight, ids, cl,
@@ -43,19 +43,19 @@ sortgl <- function(x) {
 test_that("Graphlets work for some simple graphs", {
   library(igraph)
 
-  g <- graph.full(5)
+  g <- make_full_graph(5)
   E(g)$weight <- 1
-  gl <- graphlets.candidate.basis(g)
+  gl <- graphlet_basis(g)
 
   expect_that(names(gl), equals(c("cliques", "thresholds")))
   expect_that(length(gl$cliques), equals(1))
   expect_that(sort(gl$cliques[[1]]), equals(1:vcount(g)))
   expect_that(gl$thresholds, equals(1))
 
-  g2 <- graph.full(5)
+  g2 <- make_full_graph(5)
   E(g2)$weight <- 1
   E(g2)[1%--%2]$weight <- 2
-  gl2 <- sortgl(graphlets.candidate.basis(g2))
+  gl2 <- sortgl(graphlet_basis(g2))
 
   expect_that(gl2, equals(list(cliques=list(1:2, 1:5), thresholds=c(2,1))))
 })
@@ -66,8 +66,8 @@ test_that("Graphlets filtering works", {
                    to    =c("B", "C", "C", "D", "E", "D", "E", "E"),
                    weight=c( 8 ,  8 ,  8 ,  5 ,  5 ,  5 ,  5 ,  5 ))
 
-  g <- graph.data.frame(gt, directed=FALSE, vertices=data.frame(LETTERS[1:5]))
-  gl <- sortgl(graphlets.candidate.basis(g))
+  g <- graph_from_data_frame(gt, directed=FALSE, vertices=data.frame(LETTERS[1:5]))
+  gl <- sortgl(graphlet_basis(g))
 
   expect_that(gl$cliques, equals(list(1:3, 2:5)))
   expect_that(gl$thresholds, equals(c(8, 5)))
@@ -75,18 +75,20 @@ test_that("Graphlets filtering works", {
 
 ## Naive version of graphlets
 
+unvs <- function(x) lapply(x, as.vector)
+
 threshold.net <- function(graph, level) {
   N <- vcount(graph)
-  graph.t <- delete.edges(graph, which(E(graph)$weight < level))
+  graph.t <- delete_edges(graph, which(E(graph)$weight < level))
 
-  clqt <- maximal.cliques(graph.t)
+  clqt <- unvs(max_cliques(graph.t))
   clqt <- lapply(clqt, sort)
   clqt[order(sapply(clqt, length), decreasing=TRUE)]
 }
 
 graphlets.old <- function(graph) {
 
-  if (!is.weighted(graph)) { stop("Graph not weighted") }
+  if (!is_weighted(graph)) { stop("Graph not weighted") }
   if (min(E(graph)$weight) <= 0 || !is.finite(E(graph)$weight)) {
     stop("Edge weights must be non-negative and finite")
   }
@@ -114,13 +116,13 @@ graphlets.old <- function(graph) {
 test_that("Graphlets work for a bigger graph", {
   library(igraph)
   set.seed(42)
-  g <- graph.famous("zachary")
+  g <- make_graph("zachary")
   E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
 
-  gl <- graphlets.candidate.basis(g)
+  gl <- graphlet_basis(g)
   gl2 <- graphlets.old(g)
 
-  glo <- sort(sapply(gl$cliques, paste, collapse="-"))
+  glo <- sort(sapply(unvs(gl$cliques), paste, collapse="-"))
   gl2o <- sort(sapply(gl2, paste, collapse="-"))
 
   expect_that(glo, equals(gl2o))
@@ -128,7 +130,7 @@ test_that("Graphlets work for a bigger graph", {
 
 graphlets.project.old <- function(graph, cliques, iter, Mu=NULL) {
 
-  if (!is.weighted(graph)) { stop("Graph not weighted") }
+  if (!is_weighted(graph)) { stop("Graph not weighted") }
   if (min(E(graph)$weight) <= 0 || !is.finite(E(graph)$weight)) {
     stop("Edge weights must be non-negative and finite")
   }
@@ -149,7 +151,7 @@ graphlets.project.old <- function(graph, cliques, iter, Mu=NULL) {
 
   ## Create edge-clique list from this, it is useful to have the edge list
   ## of the graph at hand
-  el <- get.edgelist(graph, names=FALSE)
+  el <- as_edgelist(graph, names=FALSE)
   ecl <- vector(length=ecount(graph), mode="list")
   for (i in 1:ecount(graph)) {
     edge <- el[i,]
@@ -194,12 +196,13 @@ test_that("Graphlet projection works", {
   D1[1:3, 1:3] <- 2
   D2[3:5, 3:5] <- 3
   D3[2:5, 2:5] <- 1
-  g <- graph.adjacency(D1 + D2 + D3, mode="undirected", weighted=TRUE)
+  g <- graph_from_adjacency_matrix(D1 + D2 + D3, mode="undirected", weighted=TRUE)
   g <- simplify(g)
 
-  gl <- graphlets.candidate.basis(g)
+  gl <- graphlet_basis(g)
   glp <- graphlets(g)
   glp2 <- graphlets.project.old(g, cliques=gl$cliques, iter=1000)
 
+  glp$cliques <- unvs(glp$cliques)
   expect_that(glp, equals(glp2))
 })
diff --git a/inst/tests/test_hrg.R b/inst/tests/test_hrg.R
index 3f0597e..336257d 100644
--- a/inst/tests/test_hrg.R
+++ b/inst/tests/test_hrg.R
@@ -5,9 +5,9 @@ test_that("Starting from state works (#225)", {
   library(igraph)
   set.seed(42)
   
-  g <- erdos.renyi.game(10, p=1/2) + erdos.renyi.game(10, p=1/2)
-  hrg <- hrg.fit(g)
-  hrg2 <- hrg.fit(g, hrg=hrg, start=TRUE, steps=1)
+  g <- sample_gnp(10, p=1/2) + sample_gnp(10, p=1/2)
+  hrg <- fit_hrg(g)
+  hrg2 <- fit_hrg(g, hrg=hrg, start=TRUE, steps=1)
   expect_that(hrg2, is_equivalent_to(hrg))
   
 })
diff --git a/inst/tests/test_hsbm.R b/inst/tests/test_hsbm.R
new file mode 100644
index 0000000..d25a3ab
--- /dev/null
+++ b/inst/tests/test_hsbm.R
@@ -0,0 +1,113 @@
+
+context("Hierarchical stochastic block models")
+
+test_that("HSBM works", {
+  library(igraph)
+  set.seed(42)
+
+  C <- matrix(c(1  , 1/2,   0,
+                1/2,   0, 1/2,
+                0  , 1/2, 1/2), nrow=3)
+                
+  g <- sample_hierarchical_sbm(100, 10, rho=c(3,3,4)/10, C=C, p=0)
+  expect_that(ecount(g), equals(172))
+  expect_that(vcount(g), equals(100))
+  expect_that(is.directed(g), is_false())
+
+  set.seed(42)
+
+  g2 <- sample_hierarchical_sbm(100, 10, rho=c(3,3,4)/10, C=C, p=1)
+  expect_that(ecount(g2), equals(ecount(g) + 10 * 9 * (90 + 10) / 2))
+  expect_that(vcount(g2), equals(100))
+  expect_that(is.simple(g2), is_true())
+
+  set.seed(42)
+  
+  g3 <- sample_hierarchical_sbm(100, 10, rho=c(3,3,4)/10, C=C, p=1e-15)
+  expect_that(ecount(g3), equals(ecount(g)))
+  expect_that(vcount(g3), equals(100))
+  expect_that(is.simple(g3), is_true())
+
+  set.seed(42)
+  
+  g4 <- sample_hierarchical_sbm(100, 10, rho=c(3,3,4)/10, C=C, p=1-1e-15)
+  expect_that(ecount(g4), equals(ecount(g2)))
+  expect_that(vcount(g4), equals(100))
+  expect_that(is.simple(g4), is_true())
+
+})
+
+test_that("HSBM with 1 cluster per block works", {
+  library(igraph)
+  res <- Matrix(0, nrow=10, ncol=10)
+  res[6:10, 1:5] <- res[1:5, 6:10] <- 1
+  g <- sample_hierarchical_sbm(10, 5, rho=1, C=matrix(0), p=1)
+  expect_that(g[], equals(res))
+})
+
+test_that("HSBM with list arguments works", {
+  library(igraph)
+
+  b <- 5
+  C <- matrix(c(1  , 1/2,   0,
+                1/2,   0, 1/2,
+                0  , 1/2, 1/2), nrow=3)
+  m <- 10
+  rho <- c(3,3,4)/10
+
+  set.seed(42)
+  g <- sample_hierarchical_sbm(b*m, m, rho=rho, C=C, p=0)
+
+  set.seed(42)
+  g2 <- sample_hierarchical_sbm(b*m, rep(m, b), rho=rho, C=C, p=0)
+  expect_that(g[], equals(g2[]))
+
+  set.seed(42)
+  g3 <- sample_hierarchical_sbm(b*m, m, rho=replicate(b, rho, simplify=FALSE), C=C, p=0)
+  expect_that(g[], equals(g3[]))
+
+  set.seed(42)
+  g4 <- sample_hierarchical_sbm(b*m, m, rho=rho, C=replicate(b, C, simplify=FALSE), p=0)
+  expect_that(g[], equals(g4[]))
+
+  expect_that(sample_hierarchical_sbm(b*m, rep(m, b), rho=list(rho, rho), C=C, p=0),
+              throws_error("Lengths of `m', `rho' and `C' must match"))
+
+  ###
+
+  n <- function(x) x/sum(x)
+  
+  rho1 <- n(c(1,2))
+  C1 <- matrix(0, nrow=2, ncol=2)
+  rho2 <- n(c(3,3,4))
+  C2 <- matrix(0, nrow=3, ncol=3)
+  rho3 <- 1
+  C3 <- matrix(0)
+  rho4 <- n(c(2,1))
+  C4 <- matrix(0, nrow=2, ncol=2)
+
+  gg1 <- sample_hierarchical_sbm(21, m=c(3, 10, 5, 3), rho=list(rho1, rho2, rho3, rho4),
+                   C=list(C1, C2, C3, C4), p=1)
+  expect_that(is.simple(gg1), is_true())
+
+  set.seed(42)
+  gg11 <- sample_hierarchical_sbm(21, m=c(3, 10, 5, 3), rho=list(rho1, rho2, rho3, rho4),
+                    C=list(C1, C2, C3, C4), p=1-1e-10)
+  expect_that(gg1[], equals(gg11[]))
+
+  rho1 <- n(c(1,2))
+  C1 <- matrix(1, nrow=2, ncol=2)
+  rho2 <- n(c(3,3,4))
+  C2 <- matrix(1, nrow=3, ncol=3)
+  rho3 <- 1
+  C3 <- matrix(1)
+  rho4 <- n(c(2,1))
+  C4 <- matrix(1, nrow=2, ncol=2)
+  gg2 <- sample_hierarchical_sbm(21, m=c(3, 10, 5, 3), rho=list(rho1, rho2, rho3, rho4),
+                   C=list(C1, C2, C3, C4), p=0)
+  expect_that(is.simple(gg2), is_true())
+
+  gg22 <- sample_hierarchical_sbm(21, m=c(3, 10, 5, 3), rho=list(rho1, rho2, rho3, rho4),
+                   C=list(C1, C2, C3, C4), p=1)
+  expect_that(gg1[] + gg2[], equals(gg22[]))
+})
diff --git a/inst/tests/test_igraph.options.R b/inst/tests/test_igraph.options.R
index b52604e..210ad57 100644
--- a/inst/tests/test_igraph.options.R
+++ b/inst/tests/test_igraph.options.R
@@ -1,14 +1,14 @@
 
-context("igraph.options")
+context("igraph_options")
 
-test_that("igraph.options works", {
+test_that("igraph_options works", {
 
   library(igraph)
 
-  igraph.options(verbose=TRUE)
-  expect_that(getIgraphOpt("verbose"), is_true())
+  igraph_options(verbose=TRUE)
+  expect_that(igraph_opt("verbose"), is_true())
   
-  igraph.options(verbose=FALSE)
-  expect_that(getIgraphOpt("verbose"), is_false())
+  igraph_options(verbose=FALSE)
+  expect_that(igraph_opt("verbose"), is_false())
 
 })
diff --git a/inst/tests/test_independent.vertex.sets.R b/inst/tests/test_independent.vertex.sets.R
index 4948a12..5ac1393 100644
--- a/inst/tests/test_independent.vertex.sets.R
+++ b/inst/tests/test_independent.vertex.sets.R
@@ -1,14 +1,14 @@
 
-context("independent.vertex.sets")
+context("ivs")
 
-test_that("independent.vetex.sets works", {
+test_that("ivs works", {
 
   library(igraph)
   
-  g <- erdos.renyi.game(50, 0.8)
-  ivs <- independent.vertex.sets(g, min=independence.number(g))
+  g <- sample_gnp(50, 0.8)
+  ivs <- ivs(g, min=ivs_size(g))
   ec <- sapply(seq_along(ivs), function(x)
-               ecount(induced.subgraph(g, ivs[[x]])))
+               ecount(induced_subgraph(g, ivs[[x]])))
   expect_that(unique(ec), equals(0))
   
 })
diff --git a/inst/tests/test_indexing.R b/inst/tests/test_indexing.R
index 272c574..2431cc1 100644
--- a/inst/tests/test_indexing.R
+++ b/inst/tests/test_indexing.R
@@ -14,7 +14,7 @@ am <- function(x) {
 library(igraph)
 library(Matrix, quietly=TRUE, warn.conflicts=FALSE)
 
-g <- graph.tree(20)
+g <- make_tree(20)
 
 test_that("[ indexing works", {
   
@@ -68,7 +68,7 @@ test_that("[ indexing works with negative indices", {
   expect_that(as.matrix(g[2:3,-1]), equals(nres))
 })
 
-el <- get.edgelist(g, names=FALSE)
+el <- as_edgelist(g, names=FALSE)
 E(g)$weight <- el[,1] * el[,2]
 
 test_that("[ indexing works with weighted graphs", {
@@ -101,40 +101,49 @@ test_that("[ indexing works with weighted graphs and symbolic names",
 test_that("[[ indexing works", {
 
   ## Adjacent vertices
-  expect_that(g[[1, ]], equals(list(a=2:3)))
-  expect_that(g[[, 2]], equals(list(b=1)))
-  expect_that(g[[, 2, directed=FALSE]], equals(list(b=c(1,4,5))))
-  expect_that(g[[2, directed=FALSE]], equals(list(b=c(1,4,5))))
-
-  expect_that(g[[1:3, ]], equals(list(a=2:3, b=4:5, c=6:7)))
-  expect_that(g[[, 1:3]], equals(list(a=numeric(), b=1, c=1)))
+  expect_that(g[[1, ]], is_equivalent_to(list(a=V(g)[2:3])))
+  expect_that(g[[, 2]], is_equivalent_to(list(b=V(g)[1])))
+  expect_that(g[[, 2, directed=FALSE]],
+              is_equivalent_to(list(b=V(g)[c(1,4,5)])))
+  expect_that(g[[2, directed=FALSE]],
+              is_equivalent_to(list(b=V(g)[c(1,4,5)])))
+
+  expect_that(g[[1:3, ]], is_equivalent_to(list(a=V(g)[2:3], b=V(g)[4:5],
+                                                c=V(g)[6:7])))
+  expect_that(g[[, 1:3]], is_equivalent_to(list(a=V(g)[numeric()],
+                                                b=V(g)[1], c=V(g)[1])))
 })
 
 test_that("[[ indexing works with symbolic names", {
   
   ## Same with vertex names
-  expect_that(g[['a', ]], equals(list(a=2:3)))
-  expect_that(g[[, 'b']], equals(list(b=1)))
-  expect_that(g[[, 'b', directed=FALSE]], equals(list(b=c(1,4,5))))
-  expect_that(g[['b', directed=FALSE]], equals(list(b=c(1,4,5))))
-
-  expect_that(g[[letters[1:3],]], equals(list(a=2:3, b=4:5, c=6:7)))
-  expect_that(g[[, letters[1:3]]], equals(list(a=numeric(), b=1, c=1)))
+  expect_that(g[['a', ]], is_equivalent_to(list(a=V(g)[2:3])))
+  expect_that(g[[, 'b']], is_equivalent_to(list(b=V(g)[1])))
+  expect_that(g[[, 'b', directed=FALSE]],
+              is_equivalent_to(list(b=V(g)[c(1,4,5)])))
+  expect_that(g[['b', directed=FALSE]],
+              is_equivalent_to(list(b=V(g)[c(1,4,5)])))
+
+  expect_that(g[[letters[1:3],]],
+    is_equivalent_to(list(a=V(g)[2:3], b=V(g)[4:5], c=V(g)[6:7])))
+  expect_that(g[[, letters[1:3]]],
+    is_equivalent_to(list(a=V(g)[numeric()], b=V(g)[1], c=V(g)[1])))
 })
 
 test_that("[[ indexing works with logical vectors", {
 
   ## Logical vectors
-  expect_that(g[[degree(g,mode="in")==0,]], equals(list(a=2:3)))
+  expect_that(g[[degree(g,mode="in")==0,]],
+              is_equivalent_to(list(a=V(g)[2:3])))
 })
 
 test_that("[[ indexing works with filtering on both ends", {
 
   ## Filtering on both ends
-  expect_that(g[[1:10, 1:10]], equals(list(a=2:3, b=4:5, c=6:7, d=8:9,
-                                           e=10, f=numeric(),
-                                           g=numeric(), h=numeric(),
-                                           i=numeric(), j=numeric())))
+  expect_that(g[[1:10, 1:10]],
+    is_equivalent_to(list(a=V(g)[2:3], b=V(g)[4:5], c=V(g)[6:7], d=V(g)[8:9],
+      e=V(g)[10], f=V(g)[numeric()], g=V(g)[numeric()], h=V(g)[numeric()],
+                          i=V(g)[numeric()], j=V(g)[numeric()])))
 })
 
 ################################################################
@@ -172,35 +181,41 @@ test_that("[ can query edge ids with symbolic names", {
 test_that("[[ can query incident edges", {
   
   ## Incident edges of vertices
-  expect_that(g[[1, , edges=TRUE]], equals(list(a=1:2)))
-  expect_that(g[[, 2, edges=TRUE]], equals(list(b=1)))
+  expect_that(g[[1, , edges=TRUE]], is_equivalent_to(list(a=E(g)[1:2])))
+  expect_that(g[[, 2, edges=TRUE]], is_equivalent_to(list(b=E(g)[1])))
   expect_that(g[[, 2, directed=FALSE, edges=TRUE]],
-              equals(list(b=c(3,4,1))))
-  expect_that(g[[2, directed=FALSE, edges=TRUE]], equals(list(b=c(3,4,1))))
-
-  expect_that(g[[1:3, , edges=TRUE]], equals(list(a=1:2, b=3:4, c=5:6)))
-  expect_that(g[[, 1:3, edges=TRUE]], equals(list(a=numeric(), b=1, c=2)))
+              is_equivalent_to(list(b=E(g)[c(3,4,1)])))
+  expect_that(g[[2, directed=FALSE, edges=TRUE]],
+              is_equivalent_to(list(b=E(g)[c(3,4,1)])))
+
+  expect_that(g[[1:3, , edges=TRUE]],
+              is_equivalent_to(list(a=E(g)[1:2], b=E(g)[3:4], c=E(g)[5:6])))
+  expect_that(g[[, 1:3, edges=TRUE]],
+              is_equivalent_to(list(a=E(g)[numeric()], b=E(g)[1], c=E(g)[2])))
 })
 
 test_that("[[ queries edges with vertex names", {
   
   ## Same with vertex names
-  expect_that(g[['a', , edges=TRUE]], equals(list(a=1:2)))
-  expect_that(g[[, 'b', edges=TRUE]], equals(list(b=1)))
+  expect_that(g[['a', , edges=TRUE]],
+              is_equivalent_to(list(a=E(g)[1:2])))
+  expect_that(g[[, 'b', edges=TRUE]],
+              is_equivalent_to(list(b=E(g)[1])))
   expect_that(g[[, 'b', directed=FALSE, edges=TRUE]],
-              equals(list(b=c(3,4,1))))
+              is_equivalent_to(list(b=E(g)[c(3,4,1)])))
   expect_that(g[['b', directed=FALSE, edges=TRUE]],
-              equals(list(b=c(3,4,1))))
+              is_equivalent_to(list(b=E(g)[c(3,4,1)])))
 
   expect_that(g[[letters[1:3],, edges=TRUE]],
-              equals(list(a=1:2, b=3:4, c=5:6)))
+              is_equivalent_to(list(a=E(g)[1:2], b=E(g)[3:4], c=E(g)[5:6])))
   expect_that(g[[, letters[1:3], edges=TRUE]],
-              equals(list(a=numeric(), b=1, c=2)))
+              is_equivalent_to(list(a=E(g)[numeric()], b=E(g)[1], c=E(g)[2])))
 
   ## Filtering on both ends
   expect_that(g[[1:10, 1:10, edges=TRUE]],
-              equals(list(1:2, 3:4, 5:6, 7:8, 9, numeric(), numeric(),
-                          numeric(), numeric(), numeric())))
+    is_equivalent_to(list(E(g)[1:2], E(g)[3:4], E(g)[5:6], E(g)[7:8],
+                          E(g)[9], E(g)[numeric()], E(g)[numeric()],
+                          E(g)[numeric()], E(g)[numeric()], E(g)[numeric()])))
 })
 
 #################################################################
@@ -208,7 +223,7 @@ test_that("[[ queries edges with vertex names", {
 test_that("[ handles from and to properly", {
   
   ## from & to
-  g <- graph.tree(20)
+  g <- make_tree(20)
   expect_that(g[from=c(1,2,2,3), to=c(3,4,8,7)], equals(c(1,1,0,1)))
 
   V(g)$name <- letters[1:20]
@@ -224,3 +239,25 @@ test_that("[ handles from and to properly", {
               
 
 })
+
+test_that("[[ works with from and to", {
+
+  g <- make_tree(20)
+
+  expect_equivalent(g[[1, ]], g[[from = 1]])
+  expect_equivalent(g[[, 1]], g[[to = 1]])
+  expect_equivalent(g[[1:5, 4:10]], g[[from = 1:5, to = 4:10]])
+
+  expect_error(g[[1, from = 1]], "Cannot give both")
+  expect_error(g[[, 2, to = 10]], "Cannot give both")
+})
+
+test_that("[[ returns vertex and edges sequences", {
+
+  g <- make_tree(20)
+  expect_true(is_igraph_vs(g[[1]][[1]]))
+  expect_true(is_igraph_es(g[[1, edges = TRUE]][[1]]))
+  expect_true(is_igraph_vs(g[[1:3, 2:6]][[1]]))
+  expect_true(is_igraph_es(g[[1:3, 2:6, edges = TRUE]][[1]]))
+
+})
diff --git a/inst/tests/test_indexing2.R b/inst/tests/test_indexing2.R
index 0463e50..9549d30 100644
--- a/inst/tests/test_indexing2.R
+++ b/inst/tests/test_indexing2.R
@@ -11,7 +11,7 @@ am <- function(x) {
 
 test_that("[ can add and delete edges", {
 
-  g <- graph.empty(10) ;  A <- matrix(0, 10, 10)
+  g <- make_empty_graph(10) ;  A <- matrix(0, 10, 10)
 
   A[1,2] <- g[1,2] <- TRUE
   expect_that(am(g[]), equals(A))
@@ -25,15 +25,15 @@ test_that("[ can add and delete edges", {
   A[1,2] <- g[1,2] <- FALSE
   expect_that(am(g[]), equals(A))
 
-  g <- graph.empty(10) ; A <- matrix(0, 10, 10)
+  g <- make_empty_graph(10) ; A <- matrix(0, 10, 10)
   A[-1,1] <- g[-1,1] <- 1
   expect_that(am(g[]), equals(A))
 })
 
 test_that("[ can set weights and delete weighted edges", {
 
-  g <- graph.empty(10) ; A <- matrix(0, 10, 10)
-  g <- set.edge.attribute(g, "weight", c(), 1)
+  g <- make_empty_graph(10) ; A <- matrix(0, 10, 10)
+  g <- set_edge_attr(g, "weight", c(), 1)
   A[1,2] <- g[1,2] <- 1
   expect_that(am(g[]), equals(A))
   
@@ -52,7 +52,7 @@ test_that("[ can set weights and delete weighted edges", {
 
 test_that("[ can add edges and ste weights via vertex names", {
 
-  g <- graph.empty(10) ; A <- matrix(0, 10, 10)
+  g <- make_empty_graph(10) ; A <- matrix(0, 10, 10)
   V(g)$name <- letters[1:vcount(g)]
   rownames(A) <- colnames(A) <- letters[1:vcount(g)]
 
@@ -71,7 +71,7 @@ test_that("[ can add edges and ste weights via vertex names", {
 
 test_that("[ and the from-to notation", {
 
-  g <- graph.empty(10) ; A <- matrix(0, 10, 10)
+  g <- make_empty_graph(10) ; A <- matrix(0, 10, 10)
   V(g)$name <- letters[1:vcount(g)]
   rownames(A) <- colnames(A) <- letters[1:vcount(g)]
 
@@ -90,7 +90,7 @@ test_that("[ and the from-to notation", {
 
 test_that("[ and from-to with multiple values", {
 
-  g <- graph.empty(10) ; A <- matrix(0, 10, 10)
+  g <- make_empty_graph(10) ; A <- matrix(0, 10, 10)
   V(g)$name <- letters[1:vcount(g)]
   rownames(A) <- colnames(A) <- letters[1:vcount(g)]
 
diff --git a/inst/tests/test_indexing3.R b/inst/tests/test_indexing3.R
new file mode 100644
index 0000000..e9b0980
--- /dev/null
+++ b/inst/tests/test_indexing3.R
@@ -0,0 +1,10 @@
+
+context("Indexing")
+
+test_that("Indexing multi-graphs as adjacency list", {
+
+  g <- make_graph(~ A -+ B:C, A -+ B:C:D, simplify = FALSE)
+  e <- g[['A', 'B', edges = TRUE]]
+
+  expect_equal(sort(e[[1]]), E(g)[1,3])
+})
diff --git a/inst/tests/test_is.bipartite.R b/inst/tests/test_is.bipartite.R
index 1b1c39f..d2169ca 100644
--- a/inst/tests/test_is.bipartite.R
+++ b/inst/tests/test_is.bipartite.R
@@ -1,17 +1,17 @@
 
-context("is.bipartite")
+context("is_bipartite")
 
-test_that("is.bipartite works", {
+test_that("is_bipartite works", {
 
   library(igraph)
 
   I <- matrix(sample(0:1, 35, replace=TRUE, prob=c(3,1)), nc=5)
-  g <- graph.incidence(I)
-  expect_that(bipartite.mapping(g)$res, is_true())
+  g <- graph_from_incidence_matrix(I)
+  expect_that(bipartite_mapping(g)$res, is_true())
 
   set.seed(42)
   I <- matrix(sample(0:1, 35, replace=TRUE, prob=c(3,1)), nc=5)
-  g <- graph.incidence(I)
-  expect_that(bipartite.mapping(g),
+  g <- graph_from_incidence_matrix(I)
+  expect_that(bipartite_mapping(g),
               equals(list(res=TRUE, type=c(rep(FALSE, 7), rep(TRUE, 5)))))
 })
diff --git a/inst/tests/test_is.chordal.R b/inst/tests/test_is.chordal.R
index 2c7caa9..8d501be 100644
--- a/inst/tests/test_is.chordal.R
+++ b/inst/tests/test_is.chordal.R
@@ -1,33 +1,36 @@
 
-context("is.chordal")
+context("is_chordal")
 
-test_that("is.chordal works", {
+test_that("is_chordal works", {
 
   library(igraph)
 
   ## The examples from the Tarjan-Yannakakis paper
-  g1 <- graph.formula(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
-                      E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
-                      I-A:H)
+  g1 <- graph_from_literal(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
+                  E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
+                  I-A:H)
 
-  mc <- maximum.cardinality.search(g1)
+  mc <- max_cardinality(g1)
+  mc$alpha <- as.vector(mc$alpha)
   expect_that(mc, equals(list(alpha=c(9,4,6,8,3,5,7,2,1),
                               alpham1=c(9,8,5,2,6,3,7,4,1))))
 
-  ic <- is.chordal(g1, fillin=TRUE)
+  ic <- is_chordal(g1, fillin=TRUE)
   expect_that(ic$chordal, equals(FALSE))
   expect_that(unique(sort(ic$fillin)), equals(c(1,2,5,6,7,8)))
   expect_that(ic$newgraph, equals(NULL))
 
-  g2 <- graph.formula(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
-                      E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
-                      I-G:H:J, J-H:I)
+  g2 <- graph_from_literal(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
+                  E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
+                  I-G:H:J, J-H:I)
 
-  mc2 <- maximum.cardinality.search(g2)
+  mc2 <- max_cardinality(g2)
+  mc2$alpha <- as.vector(mc2$alpha)
+  mc2$alpham1 <- as.vector(mc2$alpham1)
   expect_that(mc2, equals(list(alpha=c(10,8,9,6,7,5,4,2,3,1),
                                alpham1=c(10,8,9,7,6,4,5,2,3,1))))
   
-  ic2 <- is.chordal(g2, fillin=TRUE)
+  ic2 <- is_chordal(g2, fillin=TRUE)
   expect_that(ic2, equals(list(chordal=TRUE, fillin=numeric(),
                                newgraph=NULL)))
 })
diff --git a/inst/tests/test_iterators.R b/inst/tests/test_iterators.R
index fed35dd..39373fc 100644
--- a/inst/tests/test_iterators.R
+++ b/inst/tests/test_iterators.R
@@ -6,7 +6,7 @@ test_that("iterators work", {
   library(igraph)
 
   ## Create a small ring graph, assign attributes
-  ring <- graph.formula( A-B-C-D-E-F-G-A )
+  ring <- graph_from_literal( A-B-C-D-E-F-G-A )
   E(ring)$weight <- seq_len(ecount(ring))
 
   ## Selection based on attributes
@@ -20,7 +20,7 @@ test_that("iterators work", {
 test_that("complex attributes work", {
   library(igraph)
 
-  g <- graph.ring(10)
+  g <- make_ring(10)
   foo <- lapply(1:vcount(g), seq, from=1)
   V(g)$foo <- foo
 
@@ -42,3 +42,39 @@ test_that("complex attributes work", {
   expect_that(V(g)[5]$foo, equals(list(c(0,0,0,4,5))))
 
 })
+
+test_that("we got rid of confusing indexing by numbers", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+  E(g)$weight <- seq(ecount(g))
+
+  expect_equal(as.vector(V(g)[6:10][1:5]), 6:10)
+  expect_equal(as.vector(E(g)[6:10][1:5]), 6:10)
+
+})
+
+test_that("selecting edges using vertex names works", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+
+  e1 <- E(g)[c('a|b', 'c|d')]
+  expect_equal(as.vector(e1), c(1,3))
+
+})
+
+test_that("indexing with characters work as expected", {
+
+  g <- make_ring(10)
+  V(g)$name <- letters[1:10]
+  E(g)$name <- LETTERS[1:10]
+
+  expect_equal(as.vector(V(g)[letters[3:6]]), 3:6)
+  expect_equal(as.vector(E(g)[LETTERS[4:7]]), 4:7)
+  ## expect_equal(as.vector(E(g)[c('a|b', 'c|d')]), c(1,3))
+
+  expect_error(V(g)[1:5]['h'], 'Unknown vertex selected')
+  expect_error(E(g)[1:5]['H'], 'Unknown edge selected')
+  expect_error(E(g)[6:9]['a|b'], 'Unknown edge selected')
+})
diff --git a/inst/tests/test_label.propagation.community.R b/inst/tests/test_label.propagation.community.R
index e8c1fad..7dc27b4 100644
--- a/inst/tests/test_label.propagation.community.R
+++ b/inst/tests/test_label.propagation.community.R
@@ -1,15 +1,15 @@
 
-context("label.propagation.community")
+context("cluster_label_prop")
 
 test_that("label.probagation.community works", {
 
   library(igraph)
 
-  g <- graph.famous("Zachary")
+  g <- make_graph("Zachary")
   set.seed(42)
-  lpc <- label.propagation.community(g)
+  lpc <- cluster_label_prop(g)
   expect_that(lpc$modularity, equals(modularity(g, lpc$membership)))
-  expect_that(membership(lpc),
+  expect_that(as.vector(membership(lpc)),
               equals(c(1, 1, 2, 1, 3, 3, 3, 1, 2, 2, 3, 1, 1, 1, 2, 2,
                        3, 1, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
                        2, 2)))
diff --git a/inst/tests/test_laplacian.spectral.embedding.R b/inst/tests/test_laplacian.spectral.embedding.R
new file mode 100644
index 0000000..caf5303
--- /dev/null
+++ b/inst/tests/test_laplacian.spectral.embedding.R
@@ -0,0 +1,442 @@
+
+context("Spectral embedding of the Laplacian")
+
+std <- function(x) {
+  x <- zapsmall(x)
+  apply(x, 2, function(col) {
+    if (any(col < 0) && col[which(col != 0)[1]] < 0) { -col } else { col }
+  })
+}
+
+mag_order <- function(x) {
+  order(abs(x), sign(x), decreasing=TRUE)
+}
+
+mag_sort <- function(x) {
+  x[mag_order(x)]
+}
+
+test_that("Undirected, unweighted, D-A case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+
+  no <- 3
+  A <- diag(degree(g)) - g[]
+  ss <- eigen(A)
+
+  D <- ss$values
+  U <- ss$vectors
+  X <- std(ss$vectors %*% sqrt(diag(ss$values)))
+  Y <- std(ss$vectors %*% sqrt(diag(ss$values)))
+
+  ## LA
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="D-A",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="D-A",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(D[1:no]))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+
+  ## LM
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="D-A",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="D-A",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,mag_order(D)][,1:no])))
+  expect_that(as_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(D)][,1:no])))
+
+  ## SA
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="D-A",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="D-A",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+
+})
+
+test_that("Undirected, unweighted, DAD case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+
+  no <- 3
+  D12 <- diag(1/sqrt(degree(g)))
+  A <- D12 %*% g[] %*% D12
+  ss <- eigen(A)
+
+  D <- ss$values
+  U <- ss$vectors
+  X <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+  Y <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+
+  ## LA
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="DAD",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(abs(D[1:no])))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+
+  ## LM
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="DAD",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,mag_order(D)][,1:no])))
+  expect_that(as_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(D)][,1:no])))
+
+  ## SA
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="DAD",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+})
+
+test_that("Undirected, unweighted, I-DAD case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+
+  no <- 3
+  D12 <- diag(1/sqrt(degree(g)))
+  A <- diag(vcount(g)) - D12 %*% g[] %*% D12
+  ss <- eigen(A)
+
+  D <- ss$values
+  U <- ss$vectors
+  X <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+  Y <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+
+  ## LA
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="I-DAD",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="I-DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(abs(D[1:no])))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+
+  ## LM
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="I-DAD",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="I-DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,mag_order(D)][,1:no])))
+  expect_that(as_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(D)][,1:no])))
+
+  ## SA
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="I-DAD",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="I-DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+})
+
+test_that("Undirected, weighted, D-A case works", {
+  library(igraph)
+  set.seed(42*42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+  E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
+
+  no <- 3
+  A <- diag(graph.strength(g)) - g[]
+  ss <- eigen(A)
+
+  D <- ss$values
+  U <- ss$vectors
+  X <- std(ss$vectors %*% sqrt(diag(abs(D))))
+  Y <- std(ss$vectors %*% sqrt(diag(abs(D))))
+
+  ## LA
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="D-A",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="D-A",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(abs(D[1:no])))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+
+  ## LM
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="D-A",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="D-A",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,mag_order(D)][,1:no])))
+  expect_that(as_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(D)][,1:no])))
+
+  ## SA
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="D-A",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="D-A",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(X[,vcount(g)-1:no+1],
+                                   tolerance=.Machine$double.eps ^ 0.25))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+
+})
+
+test_that("Undirected, unweighted, DAD case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+
+  no <- 3
+  D12 <- diag(1/sqrt(degree(g)))
+  A <- D12 %*% g[] %*% D12
+  ss <- eigen(A)
+
+  D <- ss$values
+  U <- ss$vectors
+  X <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+  Y <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+
+  ## LA
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="DAD",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(abs(D[1:no])))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+
+  ## LM
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="DAD",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,mag_order(D)][,1:no])))
+  expect_that(as_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(D)][,1:no])))
+
+  ## SA
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="DAD",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+})
+
+test_that("Undirected, unweighted, I-DAD case works", {
+  library(igraph)
+  set.seed(42)
+  g <- random.graph.game(10, 20, type="gnm", directed=FALSE)
+
+  no <- 3
+  D12 <- diag(1/sqrt(degree(g)))
+  A <- diag(vcount(g)) - D12 %*% g[] %*% D12
+  ss <- eigen(A)
+
+  D <- ss$values
+  U <- ss$vectors
+  X <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+  Y <- std(ss$vectors %*% sqrt(diag(abs(ss$values))))
+
+  ## LA
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="I-DAD",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="I-DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(abs(D[1:no])))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+
+  ## LM
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="I-DAD",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="I-DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,mag_order(D)][,1:no])))
+  expect_that(as_lm$D, equals(mag_sort(D)[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,mag_order(D)][,1:no])))
+
+  ## SA
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="I-DAD",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="I-DAD",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+})
+
+test_that("Directed, unweighted, OAP case works", {
+  library(igraph)
+  set.seed(42*42)
+  g <- random.graph.game(10, 30, type="gnm", directed=TRUE)
+
+  no <- 3
+  O12 <- diag(1/sqrt(degree(g, mode="out")))
+  P12 <- diag(1/sqrt(degree(g, mode="in")))
+  A <- O12 %*% g[] %*% P12
+  ss <- svd(A)
+
+  D <- ss$d
+  U <- ss$u
+  V <- ss$v
+  X <- std(ss$u %*% sqrt(diag(ss$d)))
+  Y <- std(ss$v %*% sqrt(diag(ss$d)))
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="OAP",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="OAP",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(D[1:no]))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(std(au_la$Y), equals(std(Y[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+  expect_that(std(as_la$Y), equals(std(V[,1:no])))
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="OAP",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="OAP",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(D[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,1:no])))
+  expect_that(std(au_lm$Y), equals(std(Y[,1:no])))
+  expect_that(as_lm$D, equals(D[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,1:no])))
+  expect_that(std(as_lm$Y), equals(std(V[,1:no])))
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="OAP",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="OAP",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(std(au_sa$Y), equals(std(Y[,vcount(g)-1:no+1]),
+                            tolerance=sqrt(sqrt(.Machine$double.eps))))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+  expect_that(std(as_sa$Y), equals(std(V[,vcount(g)-1:no+1])))
+})
+
+test_that("Directed, weighted case works", {
+  library(igraph)
+  set.seed(42*42)
+  g <- random.graph.game(10, 30, type="gnm", directed=TRUE)
+  E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
+
+  no <- 3
+  O12 <- diag(1/sqrt(graph.strength(g, mode="out")))
+  P12 <- diag(1/sqrt(graph.strength(g, mode="in")))
+  A <- O12 %*% g[] %*% P12
+  ss <- svd(A)
+
+  D <- ss$d
+  U <- ss$u
+  V <- ss$v
+  X <- std(ss$u %*% sqrt(diag(ss$d)))
+  Y <- std(ss$v %*% sqrt(diag(ss$d)))
+
+  au_la <- embed_laplacian_matrix(g, no=no, which="la", type="OAP",
+                                        scaled=TRUE)
+  as_la <- embed_laplacian_matrix(g, no=no, which="la", type="OAP",
+                                        scaled=FALSE)
+
+  expect_that(au_la$D, equals(D[1:no]))
+  expect_that(std(au_la$X), equals(std(X[,1:no])))
+  expect_that(std(au_la$Y), equals(std(Y[,1:no])))
+  expect_that(as_la$D, equals(D[1:no]))
+  expect_that(std(as_la$X), equals(std(U[,1:no])))
+  expect_that(std(as_la$Y), equals(std(V[,1:no])))
+
+  au_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="OAP",
+                                        scaled=TRUE)
+  as_lm <- embed_laplacian_matrix(g, no=no, which="lm", type="OAP",
+                                        scaled=FALSE)
+
+  expect_that(au_lm$D, equals(D[1:no]))
+  expect_that(std(au_lm$X), equals(std(X[,1:no])))
+  expect_that(std(au_lm$Y), equals(std(Y[,1:no])))
+  expect_that(as_lm$D, equals(D[1:no]))
+  expect_that(std(as_lm$X), equals(std(U[,1:no])))
+  expect_that(std(as_lm$Y), equals(std(V[,1:no])))
+
+  au_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="OAP",
+                                        scaled=TRUE)
+  as_sa <- embed_laplacian_matrix(g, no=no, which="sa", type="OAP",
+                                        scaled=FALSE)
+
+  expect_that(au_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(au_sa$X), equals(std(X[,vcount(g)-1:no+1])))
+  expect_that(std(au_sa$Y), equals(std(Y[,vcount(g)-1:no+1]),
+                            tolerance=sqrt(sqrt(.Machine$double.eps))))
+  expect_that(as_sa$D, equals(D[vcount(g)-1:no+1]))
+  expect_that(std(as_sa$X), equals(std(U[,vcount(g)-1:no+1])))
+  expect_that(std(as_sa$Y), equals(std(V[,vcount(g)-1:no+1])))
+})
diff --git a/inst/tests/test_largest.cliques.R b/inst/tests/test_largest.cliques.R
index 94713c5..3a48a93 100644
--- a/inst/tests/test_largest.cliques.R
+++ b/inst/tests/test_largest.cliques.R
@@ -1,16 +1,16 @@
 
-context("largest.cliques")
+context("largest_cliques")
 
-test_that("largest.cliques works", {
+test_that("largest_cliques works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50,20/50)
-  lc <- largest.cliques(g)
+  g <- sample_gnp(50,20/50)
+  lc <- largest_cliques(g)
 
   ## TODO: this only checks that these are cliques
   expect_that(unique(sapply(lc, function(x)
-                            graph.density(induced.subgraph(g, x)))),
+    edge_density(induced_subgraph(g, x)))),
               equals(1))
 
 })
diff --git a/inst/tests/test_largest.independent.vertex.sets.R b/inst/tests/test_largest.independent.vertex.sets.R
index 88e6370..11d97bd 100644
--- a/inst/tests/test_largest.independent.vertex.sets.R
+++ b/inst/tests/test_largest.independent.vertex.sets.R
@@ -1,17 +1,17 @@
 
-context("largest.independent.vertex.sets")
+context("largest_ivs")
 
-test_that("largest.independent.vertex.sets works", {
+test_that("largest_ivs works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(50, 0.8)
-  livs <- largest.independent.vertex.sets(g)
+  g <- sample_gnp(50, 0.8)
+  livs <- largest_ivs(g)
   expect_that(unique(sapply(livs, length)),
-              equals(independence.number(g)))
+              equals(ivs_size(g)))
 
   ec <- sapply(seq_along(livs), function(x)
-               ecount(induced.subgraph(g, livs[[x]])))
+               ecount(induced_subgraph(g, livs[[x]])))
   expect_that(unique(ec), equals(0))
 
   ## TODO: check that they are largest
diff --git a/inst/tests/test_layout.fr.R b/inst/tests/test_layout.fr.R
new file mode 100644
index 0000000..9b8b988
--- /dev/null
+++ b/inst/tests/test_layout.fr.R
@@ -0,0 +1,25 @@
+
+context("Fruchterman-Reingold layout")
+
+test_that("", {
+
+  library(igraph)
+  set.seed(42)
+  g <- make_ring(10)
+  l <- layout_with_fr(g, niter=50, start.temp=sqrt(10)/10)
+  if (.Machine$sizeof.pointer == 4) {
+    expect_that(sum(l), equals(10.794223604849))
+  } else {
+    expect_that(sum(l), equals(10.7943032688805))
+  }
+
+  set.seed(42)
+  g <- make_star(30)
+  l <- layout_with_fr(g, niter=500, dim=3, start.temp=20)
+  if (.Machine$sizeof.pointer == 4) {
+    expect_that(sum(l), equals(1004.00737470853))
+  } else {
+    expect_that(sum(l), equals(941.472420651506))
+  }
+
+})
diff --git a/inst/tests/test_layout.gem.R b/inst/tests/test_layout.gem.R
new file mode 100644
index 0000000..e9dab24
--- /dev/null
+++ b/inst/tests/test_layout.gem.R
@@ -0,0 +1,12 @@
+
+context("GEM layout")
+
+test_that("GEM layout works", {
+
+  set.seed(42)
+  l <- cbind(1:10, rep(2:3, each=5))
+  g <- make_ring(10)
+  l2 <- layout_with_gem(g, coords=l, maxiter=1)
+  test_that(l[1:9,], equals(l2[1:9,]))  
+  
+})
diff --git a/inst/tests/test_layout.kk.R b/inst/tests/test_layout.kk.R
new file mode 100644
index 0000000..5b94e46
--- /dev/null
+++ b/inst/tests/test_layout.kk.R
@@ -0,0 +1,53 @@
+
+context("Kamada-Kawai layouts")
+
+test_that("Kamada-Kawai layout generator works", {
+
+  library(igraph)
+  g <- make_ring(10)
+  l <- layout_with_kk(g, maxiter=50)
+  if (Sys.info()["sysname"] == "Darwin") {
+    expect_that(sum(l), equals(-1.13071769106689))
+  } else if (Sys.info()["sysname"] == "Linux" &&
+             Sys.info()["machine"] == "x86_64") {
+    expect_that(sum(l), equals(-6.77278645472984e-05))
+  } else if (Sys.info()["sysname"] == "Linux" &&
+             Sys.info()["machine"] == "i686") {
+    expect_that(sum(l), equals(0.914809637353466))
+  }
+
+  g <- make_star(30)
+  l <- layout_with_kk(g, maxiter=500)
+  if (Sys.info()["sysname"] == "Darwin") {
+    expect_that(sum(l), equals(-85.6883999492408))
+  } else if (Sys.info()["sysname"] == "Linux" &&
+             Sys.info()["machine"] == "x86_64") {
+    expect_that(sum(l), equals(-86.1405864709501))
+  } else if (Sys.info()["sysname"] == "Linux" &&
+             Sys.info()["machine"] == "i686") {
+    expect_that(sum(l), equals(-85.142223229617))
+  }
+
+  g <- make_ring(10)
+  E(g)$weight <- rep(1:2, length.out=ecount(g))
+  l <- layout_with_kk(g, maxiter=500)
+  if (Sys.info()["sysname"] == "Darwin") {
+    expect_that(sum(l), equals(1.61069099387368))
+  } else if (Sys.info()["sysname"] == "Linux" &&
+             Sys.info()["machine"] == "x86_64") {
+    expect_that(sum(l), equals(-1.83036635516248))
+  } else if (Sys.info()["sysname"] == "Linux" &&
+             Sys.info()["machine"] == "i686") {
+    expect_that(sum(l), equals(0.0631144692360025))
+  }
+  
+})
+
+test_that("3D Kamada-Kawai layout generator works", {
+
+  library(igraph)
+  g <- make_star(30)
+  l <- layout_with_kk(g, maxiter=5000, dim=3)
+  expect_that(sum(l), equals(61.0559727551764))
+
+})
diff --git a/inst/tests/test_layout.mds.R b/inst/tests/test_layout.mds.R
index 19977ae..6c77930 100644
--- a/inst/tests/test_layout.mds.R
+++ b/inst/tests/test_layout.mds.R
@@ -1,16 +1,16 @@
 
-context("layout.mds")
+context("layout_with_mds")
 
-test_that("layout.mds works", {
+test_that("layout_with_mds works", {
 
   library(igraph)
 
   ## A tree
 
-  g <- graph.tree(10, 2, "undirected")
+  g <- make_tree(10, 2, "undirected")
 
   mymds <- function(g) { 
-    sp <- shortest.paths(g)
+    sp <- distances(g)
     sp <- sp * sp
     sp <- sp - rowMeans(sp) - rep(rowMeans(sp), each=nrow(sp)) + mean(sp)
     sp <- sp / -2
@@ -19,21 +19,21 @@ test_that("layout.mds works", {
     ei$vectors[,1:2] * rep(va, each=nrow(sp))
   }
 
-  expect_that(mymds(g), equals(layout.mds(g)))
+  expect_that(mymds(g), equals(layout_with_mds(g)))
 
   ## plot(g, layout=ll)
 
   ## A graph with multiple components, just test that it runs
 
   set.seed(42)
-  g <- graph.ring(10) + graph.ring(3)
-  expect_that(ncol(layout.mds(g)), equals(2))
+  g <- make_ring(10) + make_ring(3)
+  expect_that(ncol(layout_with_mds(g)), equals(2))
   
   ## Small stress test
 
   for (i in 1:10) {
-    g <- erdos.renyi.game(100, 2/100)
-    l <- layout.mds(g)
+    g <- sample_gnp(100, 2/100)
+    l <- layout_with_mds(g)
     expect_that(ncol(l), equals(2))
   }
 
diff --git a/inst/tests/test_layout.merge.R b/inst/tests/test_layout.merge.R
index 5b21c3f..b3fe36b 100644
--- a/inst/tests/test_layout.merge.R
+++ b/inst/tests/test_layout.merge.R
@@ -1,16 +1,16 @@
 
-context("layout.merge")
+context("merge_coords")
 
-test_that("layout.merge works", {
+test_that("merge_coords works", {
 
   library(igraph)
   set.seed(42)
 
-  g <- list(graph.ring(10), graph.ring(5))
-  l <- lapply(g, layout.mds)
+  g <- list(make_ring(10), make_ring(5))
+  l <- lapply(g, layout_with_mds)
   l
 
-  lm <- layout.merge(g, l)
+  lm <- merge_coords(g, l)
   expect_that(is.matrix(lm), is_true())
   expect_that(ncol(lm), equals(2))
   expect_that(nrow(lm), equals(sum(sapply(g, vcount))))
@@ -19,8 +19,8 @@ test_that("layout.merge works", {
 
   ## Stress test
   for (i in 1:10) {
-    g <- erdos.renyi.game(100, 2/100)
-    l <- layout.mds(g)
+    g <- sample_gnp(100, 2/100)
+    l <- layout_with_mds(g)
     expect_that(dim(l), equals(c(vcount(g), 2)))
   }
 
diff --git a/inst/tests/test_leading.eigenvector.community.R b/inst/tests/test_leading.eigenvector.community.R
index 1cb5988..a8a4b3f 100644
--- a/inst/tests/test_leading.eigenvector.community.R
+++ b/inst/tests/test_leading.eigenvector.community.R
@@ -1,7 +1,7 @@
 
-context("leading.eigenvector.community")
+context("cluster_leading_eigen")
 
-test_that("leading.eigenvector.community works", {
+test_that("cluster_leading_eigen works", {
 
   library(igraph)
 
@@ -20,13 +20,14 @@ test_that("leading.eigenvector.community works", {
       ev$vectors <- -ev$vectors
     }
     expect_that(ev$vectors[,1], equals(vector))
+    0
   }
 
-  g <- graph.famous("Zachary")
-  lc <- leading.eigenvector.community(g, callback=f)
+  g <- make_graph("Zachary")
+  lc <- cluster_leading_eigen(g, callback=f)
   
   expect_that(lc$modularity, equals(modularity(g, lc$membership)))
-  expect_that(membership(lc),
+  expect_that(as.vector(membership(lc)),
               equals(c(1, 3, 3, 3, 1, 1, 1, 3, 2, 2, 1, 1, 3, 3, 2, 2,
                        1, 3, 2, 3, 2, 3, 2, 4, 4, 4, 2, 4, 4, 2, 2, 4,
                        2, 2)))
@@ -51,21 +52,23 @@ test_that("leading.eigenvector.community works", {
     BG <- B-diag(rowSums(B))
     
     expect_that(M, equals(BG))
+    0
   }
 
-  g <- graph.famous("Zachary")
-  A <- get.adjacency(g, sparse=FALSE)
+  g <- make_graph("Zachary")
+  A <- as_adj(g, sparse=FALSE)
   ec <- ecount(g)
   deg <- degree(g)
-  lc <- leading.eigenvector.community(g, callback=f)
+  lc <- cluster_leading_eigen(g, callback=f)
 
   ## Stress-test
 
   for (i in 1:100) {
-    g <- erdos.renyi.game(20, sample(5:40, 1), type="gnm")
-    lec1 <- leading.eigenvector.community(g)
-    lec2 <- leading.eigenvector.community(g)
-    expect_that(membership(lec1), equals(membership(lec2)))
+    g <- sample_gnm(20, sample(5:40, 1))
+    lec1 <- cluster_leading_eigen(g)
+    lec2 <- cluster_leading_eigen(g)
+    expect_that(as.vector(membership(lec1)),
+                equals(as.vector(membership(lec2))))
   }
 
 })
diff --git a/inst/tests/test_maximal_cliques.R b/inst/tests/test_maximal_cliques.R
index 628e771..bf0d928 100644
--- a/inst/tests/test_maximal_cliques.R
+++ b/inst/tests/test_maximal_cliques.R
@@ -8,6 +8,8 @@ mysort <- function(x) {
   x[order(xl, xc)]
 }
 
+unvs <- function(x) lapply(x, as.vector)
+
 bk4 <- function(graph, min=0, max=Inf) {
 
   Gamma <- function(v) { neighbors(graph, v) }
@@ -59,7 +61,7 @@ bk4 <- function(graph, min=0, max=Inf) {
   }
 
   res <- list()
-  cord <- order(graph.coreness(graph))
+  cord <- order(coreness(graph))
   for (v in seq_along(cord)) {
     if (v != length(cord)) {
       P <- intersect(Gamma(cord[v]), cord[(v+1):length(cord)])
@@ -75,7 +77,7 @@ bk4 <- function(graph, min=0, max=Inf) {
                XS=length(P)+1, XE=length(P)+length(X))
     res <- c(res, bkpivot(PX, cord[v]))
   }
-  res    
+  lapply(res, as.integer)
 }
 
 #################################################################
@@ -83,16 +85,16 @@ bk4 <- function(graph, min=0, max=Inf) {
 test_that("Maximal cliques work", {
   library(igraph)
   set.seed(42)
-  G <- erdos.renyi.game(1000, 1000, type="gnm")
-  cli <- graph.full(10)
+  G <- sample_gnm(1000, 1000)
+  cli <- make_full_graph(10)
   for (i in 1:10) {
-    G <- permute.vertices(G, sample(vcount(G)))
+    G <- permute(G, sample(vcount(G)))
     G <- G %u% cli
   }
   G <- simplify(G)
 
   cl1 <- mysort(bk4(G, min=3))
-  cl2 <- mysort(maximal.cliques(G, min=3))
+  cl2 <- mysort(unvs(max_cliques(G, min=3)))
 
   expect_that(cl1, is_identical_to(cl2))
 })
@@ -100,12 +102,12 @@ test_that("Maximal cliques work", {
 test_that("Maximal cliques work for subsets", {
   library(igraph)
   set.seed(42)
-  G <- erdos.renyi.game(100, .5)
+  G <- sample_gnp(100, .5)
 
-  cl1  <- mysort(maximal.cliques(G, min=8))
+  cl1  <- mysort(unvs(max_cliques(G, min=8)))
 
-  c1 <- maximal.cliques(G, min=8, subset=1:13)
-  c2 <- maximal.cliques(G, min=8, subset=14:100)
+  c1 <- unvs(max_cliques(G, min=8, subset=1:13))
+  c2 <- unvs(max_cliques(G, min=8, subset=14:100))
   cl2 <- mysort(c(c1, c2))
   
   expect_that(cl1, is_identical_to(cl2))
@@ -114,12 +116,12 @@ test_that("Maximal cliques work for subsets", {
 test_that("Counting maximal cliques works", {
   library(igraph)
   set.seed(42)
-  G <- erdos.renyi.game(100, .5)
+  G <- sample_gnp(100, .5)
 
-  cl1  <- maximal.cliques.count(G, min=8)
+  cl1  <- count_max_cliques(G, min=8)
           
-  c1 <- maximal.cliques.count(G, min=8, subset=1:13)
-  c2 <- maximal.cliques.count(G, min=8, subset=14:100)
+  c1 <- count_max_cliques(G, min=8, subset=1:13)
+  c2 <- count_max_cliques(G, min=8, subset=14:100)
   cl2 <- c1+c2
   
   expect_that(cl1, is_identical_to(cl2))
diff --git a/inst/tests/test_minimal.st.separators.R b/inst/tests/test_minimal.st.separators.R
index e615de3..0f9c7e8 100644
--- a/inst/tests/test_minimal.st.separators.R
+++ b/inst/tests/test_minimal.st.separators.R
@@ -1,12 +1,12 @@
 
-context("minimal.st.separators")
+context("min_st_separators")
 
-test_that("minimal.st.separators works", {
+test_that("min_st_separators works", {
 
   library(igraph)
-  g <- graph.famous("Zachary")
-  msts <- minimal.st.separators(g)
-  is <- sapply(msts, is.separator, graph=g)
+  g <- make_graph("Zachary")
+  msts <- min_st_separators(g)
+  is <- sapply(msts, is_separator, graph=g)
   expect_that(unique(is), equals(TRUE))
 
   ## TODO: check that it is minimal
diff --git a/inst/tests/test_minimum.size.separators.R b/inst/tests/test_minimum.size.separators.R
index 002ad5f..f59ab6e 100644
--- a/inst/tests/test_minimum.size.separators.R
+++ b/inst/tests/test_minimum.size.separators.R
@@ -1,24 +1,24 @@
 
-context("minimum.size.separators")
+context("min_separators")
 
-test_that("minimum.size.separators works", {
+test_that("min_separators works", {
 
   library(igraph)
 
-  camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
-                        Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
-                        Holly   - Carol:Pat:Pam:Jennie:Bill,
-                        Bill    - Pauline:Michael:Lee:Holly,
-                        Pauline - Bill:Jennie:Ann,
-                        Jennie  - Holly:Michael:Lee:Ann:Pauline,
-                        Michael - Bill:Jennie:Ann:Lee:John,
-                        Ann     - Michael:Jennie:Pauline,
-                        Lee     - Michael:Bill:Jennie,
-                        Gery    - Pat:Steve:Russ:John,
-                        Russ    - Steve:Bert:Gery:John,
-                        John    - Gery:Russ:Michael)
+  camp <- graph_from_literal(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
+                    Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
+                    Holly   - Carol:Pat:Pam:Jennie:Bill,
+                    Bill    - Pauline:Michael:Lee:Holly,
+                    Pauline - Bill:Jennie:Ann,
+                    Jennie  - Holly:Michael:Lee:Ann:Pauline,
+                    Michael - Bill:Jennie:Ann:Lee:John,
+                    Ann     - Michael:Jennie:Pauline,
+                    Lee     - Michael:Bill:Jennie,
+                    Gery    - Pat:Steve:Russ:John,
+                    Russ    - Steve:Bert:Gery:John,
+                    John    - Gery:Russ:Michael)
   camp <- simplify(camp)
-  sep <- lapply(minimum.size.separators(camp), function(x) V(camp)[x])
-  expect_that(all(sapply(sep, is.minimal.separator, graph=camp)), is_true())
+  sep <- min_separators(camp)
+  expect_that(all(sapply(sep, is_min_separator, graph=camp)), is_true())
 
 })
diff --git a/inst/tests/test_modularity_matrix.R b/inst/tests/test_modularity_matrix.R
index e1d1efa..f126720 100644
--- a/inst/tests/test_modularity_matrix.R
+++ b/inst/tests/test_modularity_matrix.R
@@ -1,20 +1,20 @@
 
-context("mod.matrix")
+context("modularity_matrix")
 
-test_that("mod.matrix works", {
+test_that("modularity_matrix works", {
 
   library(igraph)
 
-  kar <- graph.famous("zachary")
+  kar <- make_graph("zachary")
 
-  fc <- fastgreedy.community(kar)
+  fc <- cluster_fast_greedy(kar)
 
   m1 <- modularity(kar, membership(fc))
   m2 <- modularity(kar, membership(fc), weights=rep(1, ecount(kar)))
   expect_that(m1, equals(m2))
   
-  B1 <- mod.matrix(kar, membership(fc))
-  B2 <- mod.matrix(kar, membership(fc), weights=rep(1, ecount(kar)))
+  B1 <- modularity_matrix(kar, membership(fc))
+  B2 <- modularity_matrix(kar, membership(fc), weights=rep(1, ecount(kar)))
 
   expect_that(B1, equals(B2))
 
diff --git a/inst/tests/test_motifs.R b/inst/tests/test_motifs.R
index f42a773..90a1e31 100644
--- a/inst/tests/test_motifs.R
+++ b/inst/tests/test_motifs.R
@@ -6,20 +6,20 @@ test_that("motif finding works", {
   library(igraph)
   set.seed(123)
 
-  b <- erdos.renyi.game(10000, 4/10000, directed=TRUE)
+  b <- sample_gnp(10000, 4/10000, directed=TRUE)
 
-  mno <- graph.motifs.no(b)
+  mno <- count_motifs(b)
 
-  mno0 <- graph.motifs.no(b, cut.prob=c(1/3, 0, 0))
-  mno1 <- graph.motifs.no(b, cut.prob=c(0, 0, 1/3))
-  mno2 <- graph.motifs.no(b, cut.prob=c(0, 1/3, 0))
+  mno0 <- count_motifs(b, cut.prob=c(1/3, 0, 0))
+  mno1 <- count_motifs(b, cut.prob=c(0, 0, 1/3))
+  mno2 <- count_motifs(b, cut.prob=c(0, 1/3, 0))
   expect_that(c(mno0/mno, mno1/mno, mno2/mno),
               equals(c(0.654821903845065, 0.666289144345659,
                        0.668393831285275)))
 
-  mno3 <- graph.motifs.no(b, cut.prob=c(0, 1/3, 1/3))
-  mno4 <- graph.motifs.no(b, cut.prob=c(1/3, 0, 1/3))
-  mno5 <- graph.motifs.no(b, cut.prob=c(1/3, 1/3, 0))
+  mno3 <- count_motifs(b, cut.prob=c(0, 1/3, 1/3))
+  mno4 <- count_motifs(b, cut.prob=c(1/3, 0, 1/3))
+  mno5 <- count_motifs(b, cut.prob=c(1/3, 1/3, 0))
   expect_that(c(mno3/mno, mno4/mno, mno5/mno),
               equals(c(0.443959957465819, 0.441952797125797,
                        0.446004870037941) ))
@@ -27,13 +27,13 @@ test_that("motif finding works", {
 ######################
 
   set.seed(123)
-  b <- erdos.renyi.game(10000, 4/10000, directed=TRUE)
+  b <- sample_gnp(10000, 4/10000, directed=TRUE)
 
-  m <- graph.motifs(b)
+  m <- motifs(b)
 
-  m0 <- graph.motifs(b, cut.prob=c(1/3, 0, 0))
-  m1 <- graph.motifs(b, cut.prob=c(0, 1/3, 0))
-  m2 <- graph.motifs(b, cut.prob=c(0, 0, 1/3))
+  m0 <- motifs(b, cut.prob=c(1/3, 0, 0))
+  m1 <- motifs(b, cut.prob=c(0, 1/3, 0))
+  m2 <- motifs(b, cut.prob=c(0, 0, 1/3))
   expect_that(m0/m, equals(c(NA, NA, 0.653972107372707, NA,
                              0.653993015279859, 0.612244897959184,
                              0.657514670174019, 0.63013698630137, NaN,
@@ -50,9 +50,9 @@ test_that("motif finding works", {
                              NaN, 0.753846153846154, NaN,
                              0.565217391304348, NaN, NaN, NaN, NaN) ))
 
-  m3 <- graph.motifs(b, cut.prob=c(0, 1/3, 1/3))
-  m4 <- graph.motifs(b, cut.prob=c(1/3, 1/3, 0))
-  m5 <- graph.motifs(b, cut.prob=c(1/3, 1/3, 0))
+  m3 <- motifs(b, cut.prob=c(0, 1/3, 1/3))
+  m4 <- motifs(b, cut.prob=c(1/3, 1/3, 0))
+  m5 <- motifs(b, cut.prob=c(1/3, 1/3, 0))
   expect_that(m3/m, equals(c(NA, NA, 0.445611905574732, NA,
                              0.442789875290769, 0.448979591836735,
                              0.444695973290166, 0.424657534246575,
diff --git a/inst/tests/test_multilevel.community.R b/inst/tests/test_multilevel.community.R
index b12f564..0294594 100644
--- a/inst/tests/test_multilevel.community.R
+++ b/inst/tests/test_multilevel.community.R
@@ -1,14 +1,14 @@
 
-context("multilevel.community")
+context("cluster_louvain")
 
-test_that("multilevel.community works", {
+test_that("cluster_louvain works", {
 
   library(igraph)
 
-  g <- graph.famous("Zachary")
-  mc <- multilevel.community(g)
+  g <- make_graph("Zachary")
+  mc <- cluster_louvain(g)
   
-  expect_that(membership(mc),
+  expect_that(as.vector(membership(mc)),
               equals(c(2, 2, 2, 2, 1, 1, 1, 2, 4, 2, 1, 2, 2, 2, 4, 4,
                        1, 2, 4, 2, 4, 2, 4, 3, 3, 3, 4, 3, 3, 4, 4, 3,
                        4, 4) ))
diff --git a/inst/tests/test_neighborhood.R b/inst/tests/test_neighborhood.R
index c877371..378fc99 100644
--- a/inst/tests/test_neighborhood.R
+++ b/inst/tests/test_neighborhood.R
@@ -1,42 +1,74 @@
 
-context("neighborhood")
+context("ego")
 
-test_that("neighborhood works", {
+test_that("ego works", {
 
   library(igraph)
 
   neig <- function(graph, order, vertices) {
-    sp <- shortest.paths(graph)
+    sp <- distances(graph)
     v <- unique(unlist(lapply(vertices, function(x) {
       w <- which(sp[x,] <= order)
     })))
-    induced.subgraph(graph, c(v,vertices))
+    induced_subgraph(graph, c(v,vertices))
   }
 
-  g <- erdos.renyi.game(50, 5/50)
+  g <- sample_gnp(50, 5/50)
 
   v <- sample(vcount(g), 1)
-  g1 <- graph.neighborhood(g, 2, v)[[1]]
+  g1 <- make_ego_graph(g, 2, v)[[1]]
   g2 <- neig(g, 2, v)
   expect_that(graph.isomorphic(g1, g2), is_true())
 
 #########
 
   nei <- function(graph, order, vertices) {
-    sp <- shortest.paths(graph)
+    sp <- distances(graph)
     v <- unique(unlist(lapply(vertices, function(x) {
       w <- which(sp[x,] <= order)
     })))
     v
   }
 
-  v1 <- neighborhood(g, 2, v)[[1]]
+  v1 <- ego(g, 2, v)[[1]]
   v2 <- nei(g, 2, v)
-  expect_that(sort(v1), equals(sort(v2))) 
+  expect_that(as.vector(sort(v1)), equals(sort(v2)))
 
 #########
 
-  s <- neighborhood.size(g, 2, v)[[1]]
+  s <- ego_size(g, 2, v)[[1]]
   expect_that(s, equals(length(v1)))
 
 })
+
+test_that("mindist works", {
+
+  library(igraph)
+  g <- make_ring(10)
+  expect_that(ego_size(g, order=2, mindist=0), equals(rep(5, 10)))
+  expect_that(ego_size(g, order=2, mindist=1), equals(rep(4, 10)))
+  expect_that(ego_size(g, order=2, mindist=2), equals(rep(2, 10)))
+
+  unvs <- function(x) lapply(x, as.vector)
+
+  n0 <- unvs(ego(g, order=2, 5:6, mindist=0))
+  n1 <- unvs(ego(g, order=2, 5:6, mindist=1))
+  n2 <- unvs(ego(g, order=2, 5:6, mindist=2))
+
+  expect_that(lapply(n0, sort), equals(list(3:7, 4:8)))
+  expect_that(lapply(n1, sort), equals(list(c(3,4,6,7), c(4,5,7,8))))
+  expect_that(lapply(n2, sort), equals(list(c(3,7), c(4,8))))
+
+  ng0 <- make_ego_graph(g, order=2, 5:6, mindist=0)
+  ng1 <- make_ego_graph(g, order=2, 5:6, mindist=1)
+  ng2 <- make_ego_graph(g, order=2, 5:6, mindist=2)
+
+  expect_that(sapply(ng0, vcount), equals(c(5,5)))
+  expect_that(sapply(ng1, vcount), equals(c(4,4)))
+  expect_that(sapply(ng2, vcount), equals(c(2,2)))
+
+  expect_that(sapply(ng0, ecount), equals(c(4,4)))
+  expect_that(sapply(ng1, ecount), equals(c(2,2)))
+  expect_that(sapply(ng2, ecount), equals(c(0,0)))
+
+})
diff --git a/inst/tests/test_neighbors.R b/inst/tests/test_neighbors.R
index 892c21f..772b67b 100644
--- a/inst/tests/test_neighbors.R
+++ b/inst/tests/test_neighbors.R
@@ -5,11 +5,11 @@ test_that("neighbors works", {
 
   library(igraph)
 
-  g <- erdos.renyi.game(100, 20/100)
-  al <- get.adjlist(g, mode="all")
+  g <- sample_gnp(100, 20/100)
+  al <- as_adj_list(g, mode="all")
   for (i in 1:length(al)) {
     n <- neighbors(g, i, mode="out")
-    expect_that(sort(n), equals(al[[i]]))
+    expect_that(sort(n), is_equivalent_to(al[[i]]))
   }
 
 })
diff --git a/inst/tests/test_operators.R b/inst/tests/test_operators.R
index de710eb..4c54419 100644
--- a/inst/tests/test_operators.R
+++ b/inst/tests/test_operators.R
@@ -7,41 +7,56 @@ test_that("operators work", {
 
   o <- function(x) x[order(x[,1], x[,2]),]
 
-  g1 <- graph.ring(10)
-  g2 <- graph.star(11, center=11, mode="undirected")
-  gu <- graph.union(g1, g2)
+  g1 <- make_ring(10)
+  g2 <- make_star(11, center=11, mode="undirected")
+  gu <- union(g1, g2)
   expect_that(vcount(gu), equals(11))
   expect_that(ecount(gu), equals(20))
-  expect_that(o(rbind(get.edgelist(g1), get.edgelist(g2))),
-              equals(o(get.edgelist(gu))))
+  expect_that(o(rbind(as_edgelist(g1), as_edgelist(g2))),
+              equals(o(as_edgelist(gu))))
 
-  gdu <- graph.disjoint.union(g1, g2)
-  expect_that(o(get.edgelist(gdu)),
-              equals(o(rbind(get.edgelist(g1),
-                             get.edgelist(g2)+vcount(g1)))))
+  gdu <- disjoint_union(g1, g2)
+  expect_that(o(as_edgelist(gdu)),
+              equals(o(rbind(as_edgelist(g1),
+                             as_edgelist(g2)+vcount(g1)))))
 
 ####
 
-  expect_that(graph.isomorphic(graph.difference(gu, g1), g2), is_true())
+  expect_that(graph.isomorphic(difference(gu, g1), g2), is_true())
 
 ####
 
-  expect_that(graph.isomorphic(graph.intersection(gu, g2), g2), is_true())
+  expect_that(graph.isomorphic(intersection(gu, g2), g2), is_true())
 
-  expect_that(graph.isomorphic(graph.intersection(gu, g1,
+  expect_that(graph.isomorphic(intersection(gu, g1,
                                                   keep.all.vertices=FALSE),
                                g1),is_true())
 
 ####
 
-  expect_that(graph.complementer(graph.complementer(g2)),
-              equals(g2))
+  x <- complementer(complementer(g2))
+  expect_true(identical_graphs(x, g2))
 
 ####
 
-  gc <- graph.compose(gu, g1)
+  gc <- compose(gu, g1)
   expect_that(vcount(gc), equals(11))
   expect_that(ecount(gc), equals(60))
   expect_that(diameter(gc), equals(2))
   
 })
+
+test_that("Union of directed named graphs", {
+
+  graphs <- list(
+    make_graph( ~1:2:3:4:5, 1-+2, 1-+3, 2-+3, 2-+4, 3-+4, 1-+5, 3-+5),
+    make_graph( ~1:2:3:4:5, 2-+3, 1-+4, 2-+4, 3-+4, 2-+5, 3-+5),
+    make_graph( ~1:2:3:4:5, 1-+2, 1-+3, 2-+4, 3-+4, 1-+5, 4-+5)
+  )
+
+  gg <- graph.union(graphs)
+
+  expect_equal(vcount(gg), 5)
+  expect_equal(ecount(gg), 10)
+
+})
diff --git a/inst/tests/test_operators3.R b/inst/tests/test_operators3.R
index b486134..6fe789b 100644
--- a/inst/tests/test_operators3.R
+++ b/inst/tests/test_operators3.R
@@ -5,35 +5,35 @@ test_that("infix operators work", {
 
   library(igraph)
 
-  g <- graph.ring(10)
+  g <- make_ring(10)
   V(g)$name <- letters[1:10]
   E(g)$name <- LETTERS[1:10]
 
   g <- g - c("a", "b")
   expect_that(vcount(g), equals(8))
   expect_that(ecount(g), equals(7))
-  expect_that(graph.isomorphic(g, graph.lattice(8)), is_true())
+  expect_that(graph.isomorphic(g, make_lattice(8)), is_true())
 
   g <- g - edge("e|f")
-  expect_that(graph.isomorphic(g, graph.lattice(5) + graph.lattice(3)),
+  expect_that(graph.isomorphic(g, make_lattice(5) + make_lattice(3)),
               is_true())
 
   g <- g - edge("H")
-  expect_that(graph.isomorphic(g, graph.formula(a-b-c, d-e-f, g-h)),
+  expect_that(graph.isomorphic(g, graph_from_literal(a-b-c, d-e-f, g-h)),
               is_true())
 
-  g <- graph.ring(10)
+  g <- make_ring(10)
   V(g)$name <- letters[1:10]
 
   g <- g - path("a", "b", "c", "d")
-  expect_that(graph.isomorphic(g, graph.lattice(8) + 2), is_true())
+  expect_that(graph.isomorphic(g, make_lattice(8) + 2), is_true())
 
   expect_that(graph.isomorphic(g - V(g)[c('d', 'g')],
-                               graph.lattice(4) + graph.lattice(2) + 2),
+                               make_lattice(4) + make_lattice(2) + 2),
               is_true())
 
   expect_that(graph.isomorphic(g - E(g)['f' %--% 'g'],
-                               graph.lattice(5) + graph.lattice(3) + 2),
+                               make_lattice(5) + make_lattice(3) + 2),
               is_true())
 
 })
diff --git a/inst/tests/test_operators4.R b/inst/tests/test_operators4.R
index 0bc04e0..898af8d 100644
--- a/inst/tests/test_operators4.R
+++ b/inst/tests/test_operators4.R
@@ -6,7 +6,7 @@ test_that("disjoint union works for named graphs", {
 
   library(igraph)
 
-  g1 <- g2 <- graph.ring(10)
+  g1 <- g2 <- make_ring(10)
   g1$foo <- "bar"
   V(g1)$name <- letters[ 1:10]
   V(g2)$name <- letters[11:20]
@@ -19,14 +19,14 @@ test_that("disjoint union works for named graphs", {
   E(g1)$b1 <- 1:10
   E(g2)$b2 <- 11:20
   
-  g <- graph.disjoint.union(g1, g2)
+  g <- disjoint_union(g1, g2)
 
-  expect_that(sort(list.graph.attributes(g)),
+  expect_that(sort(graph_attr_names(g)),
               equals(c("circular_1", "circular_2", "foo", "mutual_1",
                        "mutual_2", "name_1", "name_2")))
-  expect_that(sort(list.vertex.attributes(g)),
+  expect_that(sort(vertex_attr_names(g)),
               equals(c("a1", "a2", "name")))
-  expect_that(sort(list.edge.attributes(g)),
+  expect_that(sort(edge_attr_names(g)),
               equals(c("b1", "b2", "weight")))
 
   expect_that(V(g)$name, equals(letters[1:20]))
@@ -43,10 +43,10 @@ test_that("disjoint union gives warning for non-unique vertex names", {
 
   library(igraph)
 
-  g1 <- graph.ring(5); V(g1)$name <- letters[1:5]
-  g2 <- graph.ring(5); V(g2)$name <- letters[5:9]
+  g1 <- make_ring(5); V(g1)$name <- letters[1:5]
+  g2 <- make_ring(5); V(g2)$name <- letters[5:9]
   
-  expect_that(graph.disjoint.union(g1, g2),
+  expect_that(disjoint_union(g1, g2),
               gives_warning("Duplicate vertex names in disjoint union"))
 })
   
@@ -55,8 +55,8 @@ test_that("union of unnamed graphs works", {
 
   library(igraph)
 
-  g1 <- graph.ring(10)
-  g2 <- graph.ring(13)
+  g1 <- make_ring(10)
+  g2 <- make_ring(13)
   g1$foo <- "bar"
   E(g1)$weight <- 1:10
   E(g2)$weight <- 13:1
@@ -69,17 +69,17 @@ test_that("union of unnamed graphs works", {
   
   g <- graph.union(g1, g2)
 
-  expect_that(sort(list.graph.attributes(g)),
+  expect_that(sort(graph_attr_names(g)),
               equals(c("circular_1", "circular_2", "foo", "mutual_1",
                        "mutual_2", "name_1", "name_2")))
-  expect_that(sort(list.vertex.attributes(g)),
+  expect_that(sort(vertex_attr_names(g)),
               equals(c("a1", "a2")))
-  expect_that(sort(list.edge.attributes(g)),
+  expect_that(sort(edge_attr_names(g)),
               equals(c("b1", "b2", "weight_1", "weight_2")))
 
-  df1 <- get.data.frame(g)
+  df1 <- as_data_frame(g)
   df1 <- df1[ order(df1$from, df1$to), c(1,2,3,5,4,6)]
-  df2 <- merge(get.data.frame(g1), get.data.frame(g2),
+  df2 <- merge(as_data_frame(g1), as_data_frame(g2),
                by=c("from", "to"), all=TRUE)
   rownames(df1) <- seq_len(nrow(df1))
   colnames(df2) <- c("from", "to", "weight_1", "b1", "weight_2", "b2")
@@ -91,8 +91,8 @@ test_that("union of named graphs works", {
 
   library(igraph)
 
-  g1 <- graph.ring(10)
-  g2 <- graph.ring(13)
+  g1 <- make_ring(10)
+  g2 <- make_ring(13)
   V(g1)$name <- letters[seq_len(vcount(g1))]
   V(g2)$name <- letters[seq_len(vcount(g2))]
 
@@ -108,15 +108,15 @@ test_that("union of named graphs works", {
 
   g <- graph.union(g1, g2)
 
-  expect_that(sort(list.graph.attributes(g)),
+  expect_that(sort(graph_attr_names(g)),
               equals(c("circular_1", "circular_2", "foo",
                        "mutual_1", "mutual_2", "name_1", "name_2")))
-  expect_that(sort(list.vertex.attributes(g)),
+  expect_that(sort(vertex_attr_names(g)),
               equals(c("a1", "a2", "name")))
-  expect_that(sort(list.edge.attributes(g)),
+  expect_that(sort(edge_attr_names(g)),
               equals(c("b1", "b2", "weight_1", "weight_2")))
   
-  df1 <- get.data.frame(g, what="both")
+  df1 <- as_data_frame(g, what="both")
 
   g.v <- read.table(stringsAsFactors=FALSE, textConnection("
   a1 a2 name
@@ -162,8 +162,8 @@ test_that("intersection of named graphs works", {
 
   library(igraph)
 
-  g1 <- graph.ring(10)
-  g2 <- graph.ring(13)
+  g1 <- make_ring(10)
+  g2 <- make_ring(13)
   V(g1)$name <- letters[V(g1)]
   V(g2)$name <- letters[V(g2)]
 
@@ -177,17 +177,17 @@ test_that("intersection of named graphs works", {
   E(g1)$b1 <- letters[1:10]
   E(g2)$b2 <- letters[11:23]
 
-  g <- graph.intersection(g1, g2, keep.all.vertices=FALSE)
+  g <- intersection(g1, g2, keep.all.vertices=FALSE)
 
-  expect_that(sort(list.graph.attributes(g)),
+  expect_that(sort(graph_attr_names(g)),
               equals(c("circular_1", "circular_2", "foo", "mutual_1",
                        "mutual_2", "name_1", "name_2")))
-  expect_that(sort(list.vertex.attributes(g)),
+  expect_that(sort(vertex_attr_names(g)),
               equals(c("a1", "a2", "name")))
-  expect_that(sort(list.edge.attributes(g)),
+  expect_that(sort(edge_attr_names(g)),
               equals(c("b1", "b2", "weight_1", "weight_2")))
 
-  df1 <- get.data.frame(g, what="both")
+  df1 <- as_data_frame(g, what="both")
 
   g.e <- read.table(stringsAsFactors=FALSE, textConnection("
   from to weight_1 weight_2 b1 b2
@@ -219,9 +219,9 @@ j 10 20    j
 "))
   expect_that(df1$vertices, equals(g.v))
 
-  gg <- graph.intersection(g1, g2, keep.all.vertices=TRUE)
+  gg <- intersection(g1, g2, keep.all.vertices=TRUE)
 
-  df2 <- get.data.frame(gg, what="both")
+  df2 <- as_data_frame(gg, what="both")
 
   rownames(df2$edges) <- rownames(df2$edges)
   expect_that(df2$edges, equals(g.e))
@@ -249,16 +249,16 @@ test_that("difference of named graphs works", {
 
   library(igraph)
 
-  g1 <- graph.ring(10)
-  g2 <- graph.star(11, center=11, mode="undirected")
+  g1 <- make_ring(10)
+  g2 <- make_star(11, center=11, mode="undirected")
   V(g1)$name <- letters[1:10]
   V(g2)$name <- letters[1:11]
   g <- g1 %u% g2
 
-  sg <- graph.ring(4)
+  sg <- make_ring(4)
   V(sg)$name <- letters[c(1,2,3,11)]
 
-  df1 <- get.data.frame(g - sg, what="both")
+  df1 <- as_data_frame(g - sg, what="both")
 
   t1.e <- read.table(stringsAsFactors=FALSE,
                                            textConnection("
@@ -297,8 +297,8 @@ test_that("compose works for named graphs", {
 
   library(igraph)
 
-  g1 <- graph.formula( A-B:D:E, B-C:D, C-D, D-E )
-  g2 <- graph.formula( A-B-E-A )
+  g1 <- graph_from_literal( A-B:D:E, B-C:D, C-D, D-E )
+  g2 <- graph_from_literal( A-B-E-A )
 
   V(g1)$bar1 <- seq_len(vcount(g1))
   V(g2)$bar2 <- seq_len(vcount(g2))
@@ -310,8 +310,8 @@ test_that("compose works for named graphs", {
   E(g1)$foo <- letters[seq_len(ecount(g1))]
   E(g2)$foo <- letters[seq_len(ecount(g2))]
 
-  g <- graph.compose(g1, g2)
-  df <- get.data.frame(g, what="both")
+  g <- compose(g1, g2)
+  df <- as_data_frame(g, what="both")
 
   df.v <- read.table(stringsAsFactors=FALSE, textConnection("
   bar1 foo_1 foo_2 bar2 name
@@ -351,21 +351,21 @@ test_that("intersection of non-named graphs keeps attributes properly", {
   library(igraph)
   set.seed(42)
 
-  g <- erdos.renyi.game(10, 1/2)
-  g2 <- erdos.renyi.game(10, 1/2)
+  g <- sample_gnp(10, 1/2)
+  g2 <- sample_gnp(10, 1/2)
   E(g)$weight <- sample(ecount(g))
   E(g2)$weight <- sample(ecount(g2))
 
-  gi <- graph.intersection(g, g2)
+  gi <- intersection(g, g2)
 
   rn <- function(D) {
     rownames(D) <- paste(D[,1], D[,2], sep="-")
     D
   }
 
-  df <- rn(get.data.frame(g))
-  df2 <- rn(get.data.frame(g2))
-  dfi <- rn(get.data.frame(gi))
+  df <- rn(as_data_frame(g))
+  df2 <- rn(as_data_frame(g2))
+  dfi <- rn(as_data_frame(gi))
 
   expect_that(df[rownames(dfi), ], is_equivalent_to(dfi[, 1:3]))
   expect_that(df2[rownames(dfi), ], is_equivalent_to(dfi[, c(1,2,4)]))
@@ -376,8 +376,8 @@ test_that("union of non-named graphs keeps attributes properly", {
   library(igraph)
   set.seed(42)
 
-  g <- erdos.renyi.game(10, 1/2)
-  g2 <- erdos.renyi.game(10, 1/2)
+  g <- sample_gnp(10, 1/2)
+  g2 <- sample_gnp(10, 1/2)
   E(g)$weight <- sample(ecount(g))
   E(g2)$weight <- sample(ecount(g2))
 
@@ -388,9 +388,9 @@ test_that("union of non-named graphs keeps attributes properly", {
     D
   }
 
-  df <- rn(get.data.frame(g))
-  df2 <- rn(get.data.frame(g2))
-  dfu <- rn(get.data.frame(gu))
+  df <- rn(as_data_frame(g))
+  df2 <- rn(as_data_frame(g2))
+  dfu <- rn(as_data_frame(gu))
 
   expect_that(dfu[rownames(df), 1:3], is_equivalent_to(df))
   expect_that(dfu[rownames(df2), c(1,2,4)], is_equivalent_to(df2))
diff --git a/inst/tests/test_optimal.community.R b/inst/tests/test_optimal.community.R
index e756536..1b8901f 100644
--- a/inst/tests/test_optimal.community.R
+++ b/inst/tests/test_optimal.community.R
@@ -1,13 +1,13 @@
 
-context("optimal.community")
+context("cluster_optimal")
 
-test_that("optimal.community works", {
+test_that("cluster_optimal works", {
 
   library(igraph)
-  g <- graph.famous("Zachary")
-  oc <- optimal.community(g)
+  g <- make_graph("Zachary")
+  oc <- cluster_optimal(g)
 
-  expect_that(membership(oc),
+  expect_that(as.vector(membership(oc)),
               equals(c(1, 1, 1, 1, 2, 2, 2, 1, 3, 3, 2, 1, 1, 1, 3, 3,
                        2, 1, 3, 1, 3, 1, 3, 4, 4, 4, 3, 4, 4, 3, 3, 4,
                        3, 3) ))
@@ -20,13 +20,13 @@ test_that("optimal.community works", {
 
 })
 
-test_that("weighted optimal.community works", {
+test_that("weighted cluster_optimal works", {
 
   library(igraph)
   set.seed(42)
-  g <- graph.full(5) + graph.ring(5)
+  g <- make_full_graph(5) + make_ring(5)
   E(g)$weight <- sample(1:2, ecount(g), replace=TRUE)
 
-  oc <- optimal.community(g)
+  oc <- cluster_optimal(g)
   expect_that(modularity(oc), equals(0.4032))
 })
diff --git a/inst/tests/test_pajek.R b/inst/tests/test_pajek.R
index fee7efd..73cead6 100644
--- a/inst/tests/test_pajek.R
+++ b/inst/tests/test_pajek.R
@@ -5,11 +5,11 @@ test_that("writing Pajek files works", {
 
   library(igraph)
 
-  g <- graph.ring(9)
+  g <- make_ring(9)
   V(g)$color <- c("red", "green", "yellow")
 
   tc <- rawConnection(raw(0), "w")
-  write.graph(g, format="pajek", file=tc)
+  write_graph(g, format="pajek", file=tc)
   out <- rawToChar(rawConnectionValue(tc))
   close(tc)
 
diff --git a/inst/tests/test_print.R b/inst/tests/test_print.R
index fdf7b2b..476191e 100644
--- a/inst/tests/test_print.R
+++ b/inst/tests/test_print.R
@@ -4,10 +4,10 @@ context("print.igraph")
 test_that("print.igraph works", {
 
   library(igraph)
-  igraph.options(print.full=TRUE)
+  igraph_options(print.full=TRUE)
   options(width=76)
 
-  g <- graph.ring(5)
+  g <- make_ring(5)
   expect_that(summary(g), prints_text("attr:.* name[ ]*[(]g/c[)]"))
   expect_that(g, prints_text("attr:.* name[ ]*[(]g/c[)]"))
   expect_that(g, prints_text("1--2"))
@@ -26,27 +26,34 @@ test_that("print.igraph works", {
   expect_that(print(g, e=T), prints_text("edges [(]vertex names[)] and"))
 
   set.seed(42)
-  g2 <- erdos.renyi.game(13, p=0.6, directed=TRUE)
+  g2 <- sample_gnp(13, p=0.6, directed=TRUE)
   expect_that(g2, prints_text("1 ->"))
 
-  g3 <- erdos.renyi.game(20, p=0.8)
+  g3 <- sample_gnp(20, p=0.8)
   expect_that(g3, prints_text("1 --"))
 
-  g4 <- graph.star(100)
+  g4 <- make_star(100)
   expect_that(g4, prints_text("2->1"))
 
-  g5 <- graph.star(100, mode="out")
+  g5 <- make_star(100, mode="out")
   expect_that(g5, prints_text("1->"))
 
-  g6 <- ba.game(100, m=6, directed=FALSE)
+  g6 <- sample_pa(100, m=6, directed=FALSE)
   expect_that(g6, prints_text("     "))
 
-  kite <- graph.empty(directed=FALSE) + LETTERS[1:10]
+  kite <- make_empty_graph(directed=FALSE) + LETTERS[1:10]
   kite <- kite + edges('A','B','A','C','A','D','A','F',
                        'B','D','B','E','B','G', 'C','D','C','F', 
                        'D','E','D','F','D','G', 'E','G', 
                        'F','G','F','H', 'G','H', 'H','I','I','J')
   expect_that(kite, prints_text("A -- "))
               
-  igraph.options(print.full=FALSE)
+  igraph_options(print.full=FALSE)
+})
+
+test_that("print.igraph.es uses vertex names", {
+
+  g <- make_directed_graph(c("A", "B"))
+  expect_output(print(E(g)), "A\\s*->\\s*B")
+
 })
diff --git a/inst/tests/test_sample.R b/inst/tests/test_sample.R
new file mode 100644
index 0000000..14705da
--- /dev/null
+++ b/inst/tests/test_sample.R
@@ -0,0 +1,29 @@
+
+context("Various samplers")
+
+test_that("Sampling from a Dirichlet works", {
+
+  library(igraph)
+  set.seed(42)
+  sd <- sample_dirichlet(100, alpha=c(1, 1, 1))
+  expect_that(dim(sd), equals(c(3, 100)))
+  expect_that(colSums(sd), equals(rep(1, 100)))
+  expect_that(mean(sd), equals(1/3))
+  expect_that(sd(sd), equals(0.248901845755354))
+
+  ## Corner cases
+  sd1 <- sample_dirichlet(1, alpha=c(2, 2, 2))
+  expect_that(dim(sd1), equals(c(3, 1)))
+  sd0 <- sample_dirichlet(0, alpha=c(3, 3, 3))
+  expect_that(dim(sd0), equals(c(3, 0)))
+
+  ## Errors
+  expect_that(sample_dirichlet(-1, alpha=c(1,1,1,1)),
+              throws_error("should be non-negative"))
+  expect_that(sample_dirichlet(5, alpha=c(1)),
+              throws_error("must have at least two entries"))
+  expect_that(sample_dirichlet(5, alpha=c(0, 1, 1)),
+              throws_error("must be positive"))
+  expect_that(sample_dirichlet(5, alpha=c(1, -1, -1)),
+              throws_error("must be positive"))
+})
diff --git a/inst/tests/test_sbm.game.R b/inst/tests/test_sbm.game.R
index 3b292d0..7e4861e 100644
--- a/inst/tests/test_sbm.game.R
+++ b/inst/tests/test_sbm.game.R
@@ -6,24 +6,24 @@ test_that("Generating stochastic block models works", {
   library(igraph)
   pm <- matrix(1, nrow=2, ncol=2)
   bs <- c(4,6)
-  g1 <- sbm.game(10, pref.matrix=pm, block.sizes=bs,
+  g1 <- sample_sbm(10, pref.matrix=pm, block.sizes=bs,
                  directed=FALSE, loops=FALSE)
-  expect_that(graph.isomorphic(g1, graph.full(10, directed=FALSE, loops=FALSE)),
+  expect_that(graph.isomorphic(g1, make_full_graph(10, directed=FALSE, loops=FALSE)),
               is_true())
 
-  g2 <- sbm.game(10, pref.matrix=pm, block.sizes=bs,
+  g2 <- sample_sbm(10, pref.matrix=pm, block.sizes=bs,
                 directed=FALSE, loops=TRUE)
-  g2x <- graph.full(10, directed=FALSE, loops=TRUE)
+  g2x <- make_full_graph(10, directed=FALSE, loops=TRUE)
   expect_that(g2[sparse=FALSE], equals(g2x[sparse=FALSE]))
 
-  g3 <- sbm.game(10, pref.matrix=pm, block.sizes=bs,
+  g3 <- sample_sbm(10, pref.matrix=pm, block.sizes=bs,
                  directed=TRUE, loops=FALSE)
-  g3x <- graph.full(10, directed=TRUE, loops=FALSE)
+  g3x <- make_full_graph(10, directed=TRUE, loops=FALSE)
   expect_that(g3[sparse=FALSE], equals(g3x[sparse=FALSE]))
 
-  g4 <- sbm.game(10, pref.matrix=pm, block.sizes=bs,
+  g4 <- sample_sbm(10, pref.matrix=pm, block.sizes=bs,
                  directed=TRUE, loops=TRUE)
-  g4x <- graph.full(10, directed=TRUE, loops=TRUE)
+  g4x <- make_full_graph(10, directed=TRUE, loops=TRUE)
   expect_that(g4[sparse=FALSE], equals(g4x[sparse=FALSE]))
   
 })
diff --git a/inst/tests/test_scan.R b/inst/tests/test_scan.R
new file mode 100644
index 0000000..ba31d1f
--- /dev/null
+++ b/inst/tests/test_scan.R
@@ -0,0 +1,188 @@
+
+context("Local scan statistics")
+
+library(igraph)
+require(digest)
+
+set.seed(12345)
+n <- 10^3
+p <- 0.1
+g <- erdos.renyi.game(n,p)
+E(g)$weight = sample(ecount(g))
+gp <- erdos.renyi.game(n,p)
+E(gp)$weight = sample(ecount(gp))
+
+test_that("General scan-stat works, US, scan-0, unweighted", {
+  s1 <- local_scan(g, k=0)
+  expect_that(digest(s1), equals("659ffaaf303742f0806a79b8ff3d88b3"))
+})
+
+test_that("General scan-stat works, US, scan-0, weighted", {
+  s1 <- local_scan(g, k=0, weighted=TRUE)
+  expect_that(digest(s1), equals("0f8d7ac831389cea04e0bfc5e2510c73"))
+})
+
+
+test_that("General scan-stat works, US, scan-1, unweighted", {
+  s1 <- local_scan(g)
+  expect_that(digest(s1), equals("df0fd77489f70cc47f682dc31d9f52f5"))
+})
+
+test_that("General scan-stat works, US, scan-1, weighted", {
+  s1 <- local_scan(g, k=1, weighted=TRUE)
+  expect_that(digest(s1), equals("af720916ae4b49881745d2dcdd614401"))
+})
+
+test_that("General scan-stat works, US, scan-2, unweighted", {
+  s1 <- local_scan(g, k=2)
+  expect_that(digest(s1), equals("6f47f47abde25d00d615dd56826cca5a"))
+})
+
+test_that("General scan-stat works, US, scan-2, weighted", {
+  s1 <- local_scan(g, k=2, weighted=TRUE)
+  expect_that(digest(s1), equals("e02e9d58168ee5d53850497f6d4c76b0"))
+})
+
+test_that("General scan-stat works, THEM, scan-0, unweighted", {
+  s1 <- local_scan(g, gp, k=0)
+  expect_that(digest(s1), equals("f584f7d287f8f89f5f7882165ca41b8c"))
+})
+
+test_that("General scan-stat works, THEM, scan-0, weighted", {
+  s1 <- local_scan(g, gp, k=0, weighted=TRUE)
+  expect_that(digest(s1), equals("213db8e7517d1e6406da3dbd55281ed1"))
+})
+
+test_that("General scan-stat works, THEM, scan-1, unweighted", {
+  s1 <- local_scan(g, gp, k=1)
+  expect_that(digest(s1), equals("e9ca740ebba2fd1db4abe939954b2638"))
+})
+
+test_that("General scan-stat works, THEM, scan-1, weighted", {
+  s1 <- local_scan(g, gp, k=1, weighted=TRUE)
+  expect_that(digest(s1), equals("a98e9a03eda7feaae8524dc9348ad74b"))
+})
+
+test_that("General scan-stat works, THEM, scan-2, unweighted", {
+  s1 <- local_scan(g, gp, k=2)
+  expect_that(digest(s1), equals("a3237a9a55e9d86ab471c81a291eb03b"))
+})
+
+test_that("General scan-stat works, THEM, scan-2, weighted", {
+  s1 <- local_scan(g, gp, k=2, weighted=TRUE)
+  expect_that(digest(s1), equals("995d0b6a952834ff6e534efc2cfb917b"))
+})
+
+test_that("Neighborhoods work for us", {
+  nei <- neighborhood(g, order=1)
+  s1 <- local_scan(g, neighborhoods=nei)
+  expect_that(digest(s1), equals("df0fd77489f70cc47f682dc31d9f52f5"))
+  s1 <- local_scan(g, k=1, weighted=TRUE, neighborhoods=nei)
+  expect_that(digest(s1), equals("af720916ae4b49881745d2dcdd614401"))
+
+  nei <- neighborhood(g, order=2)
+  s1 <- local_scan(g, k=2, neighborhoods=nei)
+  expect_that(digest(s1), equals("6f47f47abde25d00d615dd56826cca5a"))
+  s1 <- local_scan(g, k=2, weighted=TRUE, neighborhoods=nei)
+  expect_that(digest(s1), equals("e02e9d58168ee5d53850497f6d4c76b0"))
+
+})
+
+test_that("Neighborhoods work for them", {
+
+  nei <- neighborhood(g, order=1)
+  s1 <- local_scan(g, gp, k=1, neighborhoods=nei)
+  expect_that(digest(s1), equals("e9ca740ebba2fd1db4abe939954b2638"))
+  s1 <- local_scan(g, gp, k=1, weighted=TRUE, neighborhoods=nei)
+  expect_that(digest(s1), equals("a98e9a03eda7feaae8524dc9348ad74b"))
+
+  nei <- neighborhood(g, order=2)
+  s1 <- local_scan(g, gp, k=2, neighborhoods=nei)
+  expect_that(digest(s1), equals("a3237a9a55e9d86ab471c81a291eb03b"))
+  s1 <- local_scan(g, gp, k=2, weighted=TRUE, neighborhoods=nei)
+  expect_that(digest(s1), equals("995d0b6a952834ff6e534efc2cfb917b"))
+
+})
+
+set.seed(42)
+n <- 10^3
+p <- 0.1
+g <- erdos.renyi.game(n, p, directed=TRUE)
+E(g)$weight = sample(ecount(g))
+gp <- erdos.renyi.game(n, p)
+E(gp)$weight = sample(ecount(gp))
+
+## US, scan-0, unweighted, directed
+## TODO
+
+test_that("General scan-stat works, US, scan-1, unweighted, directed", {
+
+  s1o <- local_scan(g, k=1, weighted=FALSE, mode="out")
+  expect_that(digest(s1o), equals("ac463c21b2b6bc91abf82f0141a4a7d4"))
+
+  s1i <- local_scan(g, k=1, weighted=FALSE, mode="in")
+  expect_that(digest(s1i), equals("13fdaaeec54118e217821b56d8c3ff03"))
+
+})
+
+test_that("General scan-stat works, US, scan-1, weighted, directed", {
+
+  s1o <- local_scan(g, k=1, weighted=TRUE, mode="out")
+  expect_that(digest(s1o), equals("da8e14f2ba63efc74b5fd7b9d8f79bbc"))
+
+  s1i <- local_scan(g, k=1, weighted=TRUE, mode="in")
+  expect_that(digest(s1i), equals("f5f07eebb907ae0a244195a20971be11"))
+
+})
+
+## US, scan-2, unweighted, directed
+## TODO
+
+test_that("Issue 18 is resolved", {
+
+  library(igraph)
+  g <- graph(c(1,2,2,1, 1,3,3,1, 2,4, 3,4, 3,5,5,3, 4,5,5,4))
+  expect_that(local_scan(g, mode="all"), equals(c(4, 3, 7, 6, 5)))
+  expect_that(local_scan(g, mode="out"), equals(c(4, 3, 7, 2, 5)))
+  expect_that(local_scan(g, mode="in"), equals(c(4, 2, 4, 6, 5)))
+})
+
+test_that("Issue 18 is really resolved", {
+  library(igraph)
+  el <- c(1, 5, 1, 7, 2, 5, 2, 7, 2, 10, 2, 13, 2, 18, 3, 5, 3, 10, 3, 
+          13, 4, 5, 4, 10, 5, 7, 5, 10, 5, 13, 5, 18, 6, 3, 6, 5, 6, 7, 
+          6, 13, 7, 5, 8, 5, 8, 10, 8, 18, 9, 3, 9, 5, 9, 7, 9, 10, 11, 
+          5, 12, 5, 12, 7, 14, 5, 14, 7, 14, 13, 14, 18, 15, 5, 15, 13, 
+          15, 18, 16, 5, 16, 10, 16, 13, 16, 18, 17, 5)
+  
+  g <- graph(el)
+
+  sc1 <- sapply(graph.neighborhood(g, order=1, mode="all"), ecount)
+  sc2 <- local_scan(graph.us=g, mode="all", k=1)
+  expect_that(sc1, equals(sc2))
+
+  g2 <- induced.subgraph(g, 5:8)
+  sc21 <- sapply(graph.neighborhood(g2, order=1, mode="all"), ecount)
+  sc22 <- local_scan(graph.us=g2, mode="all", k=1)
+  expect_that(sc21, equals(sc22))
+})
+
+test_that("Issue 20 is resolved", {
+
+  library(igraph)
+  set.seed(12345)
+  g1 <- erdos.renyi.game(n=20, p=0.1, directed=TRUE)
+  g2 <- erdos.renyi.game(n=20, p=0.1, directed=TRUE)
+  ls <- local_scan(g2, g1, k=1, mode="all")
+  correct <- c(4, 1, 2, 1, 1, 8, 1, 2, 0, 5, 2, 3, 3, 4, 5, 3, 5, 4, 2, 1)
+  expect_that(ls, equals(correct))
+})
+
+test_that("FUN argument works, #32", {
+  library(igraph)
+  r1 <- local_scan(graph.ring(10), k=1, FUN="ecount")
+  r2 <- local_scan(graph.ring(10), k=1, FUN=ecount)
+  expect_that(r1, equals(rep(2, 10)))
+  expect_that(r2, equals(rep(2, 10)))
+})
+
diff --git a/inst/tests/test_scg.R b/inst/tests/test_scg.R
index f4a7546..7906c3b 100644
--- a/inst/tests/test_scg.R
+++ b/inst/tests/test_scg.R
@@ -7,9 +7,9 @@ test_that("SCG functions work", {
 
   library(igraph)
 
-  tree <- graph.tree(10, 3, "undirected")
-  treeM <- get.adjacency(tree, sparse=TRUE)
-  treeM2 <- get.adjacency(tree, sparse=FALSE)
+  tree <- make_tree(10, 3, "undirected")
+  treeM <- as_adj(tree, sparse=TRUE)
+  treeM2 <- as_adj(tree, sparse=FALSE)
 
   args <- list(ev=1, nt=3, mtype="symmetric", algo="exact_scg",
                semproj=TRUE, epairs=TRUE)
diff --git a/inst/tests/test_sdf.R b/inst/tests/test_sdf.R
index 0f2c5ed..38b0862 100644
--- a/inst/tests/test_sdf.R
+++ b/inst/tests/test_sdf.R
@@ -5,7 +5,12 @@ test_that("sdf works", {
 
   library(igraph)
 
-  sdf <- igraph:::sdf(id=1:10, color="black")
+  sdf <- igraph:::sdf
+  `[.igraphSDF` <- igraph:::`[.igraphSDF`
+  `[<-.igraphSDF` <- igraph:::`[<-.igraphSDF`
+  as.data.frame.igraphSDF <- igraph:::as.data.frame.igraphSDF
+  
+  sdf <- sdf(id=1:10, color="black")
   expect_that(as.data.frame(sdf),
               equals(data.frame(id=1:10, color="black")))
 
diff --git a/inst/tests/test_sgm.R b/inst/tests/test_sgm.R
new file mode 100644
index 0000000..577c2f9
--- /dev/null
+++ b/inst/tests/test_sgm.R
@@ -0,0 +1,48 @@
+
+context("Seeded graph matching")
+
+test_that("SGM works", {
+  library(igraph)
+  set.seed(42)
+
+  vc <- 10
+  nos <- 3
+  
+  g1 <- erdos.renyi.game(vc, .5)
+  randperm <- c(1:nos, nos + sample(vc-nos))
+  g2 <- sample_correlated_gnp(g1, corr=.7, p=g1$p, perm=randperm)
+  P  <-match_vertices (g1[], g2[], m=nos, start=matrix(1/(vc-nos), vc-nos, vc-nos),
+            iteration=20)
+
+  expect_that(c(1:nos, P$corr[,2]), equals(randperm))
+  expect_that(apply(P$P != 0, 1, which), equals(randperm))
+  expect_that(apply(P$D != 0, 1, which),
+              equals(randperm[(nos+1):vc] - nos))
+
+  ## Slightly bigger
+  set.seed(42)
+
+  vc <- 100
+  nos <- 10
+
+  g1 <- erdos.renyi.game(vc, .1);
+  perm <- c(1:nos, sample(vc-nos)+nos)
+  g2 <- sample_correlated_gnp(g1, corr=1, p=g1$p, perm=perm)
+
+  P <- match_vertices(g1[], g2[], m=nos, start=matrix(1/(vc-nos), vc-nos, vc-nos),
+           iteration=20)
+
+  test_that(P$corr[,2], equals(perm[(nos+1):vc]))
+  expect_that(apply(P$P != 0, 1, which), equals(perm))
+  expect_that(apply(P$D != 0, 1, which),
+              equals(perm[(nos+1):vc] - nos))
+})
+
+test_that("LSAP does not change input matrix", {
+
+  x <- matrix(c(5, 1, 4, 3, 5, 2, 2, 4, 4), nrow = 3)
+  solve_LSAP(x)
+
+  expect_equal(x, matrix(c(5, 1, 4, 3, 5, 2, 2, 4, 4), nrow = 3))
+  
+})
diff --git a/inst/tests/test_sir.R b/inst/tests/test_sir.R
index 6442ba9..9c34453 100644
--- a/inst/tests/test_sir.R
+++ b/inst/tests/test_sir.R
@@ -7,7 +7,7 @@ test_that("SIR works", {
   library(digest)
   library(igraph)
 
-  g <- erdos.renyi.game(50, 50, type="gnm")
+  g <- sample_gnm(50, 50)
   res <- sir(g, beta=5, gamma=1, no.sim=10)
   if (.Machine$sizeof.pointer == 4) {
     expect_that(digest(res), equals("b73a8ad03b832b3543f2f03d07330398"))
diff --git a/inst/tests/test_sphere.R b/inst/tests/test_sphere.R
new file mode 100644
index 0000000..77dac22
--- /dev/null
+++ b/inst/tests/test_sphere.R
@@ -0,0 +1,40 @@
+
+context("Sampling points from a sphere")
+
+test_that("Sampling sphere surface works", {
+
+  library(igraph)
+  library(digest)
+  
+  set.seed(42)
+  s1 <- sample_sphere_surface(4, 100, positive=FALSE)
+  expect_that(colSums(s1^2), equals(rep(1, 100)))
+
+  s2 <- sample_sphere_surface(3, 100, radius=2, positive=FALSE)
+  expect_that(sqrt(colSums(s2^2)), equals(rep(2, 100)))
+
+  s3 <- sample_sphere_surface(2, 100, radius=1/2, positive=TRUE)
+  expect_that(sqrt(colSums(s3^2)), equals(rep(1/2, 100)))
+  expect_that(all(s3 >= 0), is_true())
+  expect_that(digest(s3), equals("b86e4a0dc877e3540fb8a88b4be6a781"))
+  
+})
+
+test_that("Sampling sphere volume works", {
+
+  library(igraph)
+  library(digest)
+  
+  set.seed(42)
+  s1 <- sample_sphere_volume(4, 10000, positive=FALSE)
+  expect_that(all(colSums(s1^2) < 1), is_true())
+
+  s2 <- sample_sphere_volume(3, 100, radius=2, positive=FALSE)
+  expect_that(all(sqrt(colSums(s2^2)) < 2), is_true())
+
+  s3 <- sample_sphere_volume(2, 100, radius=1/2, positive=TRUE)
+  expect_that(all(sqrt(colSums(s3^2)) < 1/2), is_true())
+  expect_that(all(s3 >= 0), is_true())
+  expect_that(digest(s3), equals("9fa27a0edba7bbb1787d507cbbbf84b7"))
+  
+})
diff --git a/inst/tests/test_transitivity.R b/inst/tests/test_transitivity.R
index 23417c0..267e527 100644
--- a/inst/tests/test_transitivity.R
+++ b/inst/tests/test_transitivity.R
@@ -4,7 +4,7 @@ context("transitivity")
 test_that("transitivity works", {
   library(igraph)
   set.seed(42)
-  g <- erdos.renyi.game(100, p=10/100)
+  g <- sample_gnp(100, p=10/100)
 
   t1 <- transitivity(g, type="global")
   expect_that(t1, equals(0.10483870967741935887))
@@ -21,3 +21,13 @@ test_that("transitivity works", {
   expect_that(summary(t3), equals(est3))
   expect_that(summary(t33), equals(est3))
 })
+
+test_that("no integer overflow", {
+
+  library(igraph)
+  set.seed(42)
+  g <- graph.star(80000, mode="undirected") + edges(sample(2:1000), 100)
+  mtr <- min(transitivity(g, type="local"), na.rm=TRUE)
+  expect_true(mtr > 0)
+
+})
diff --git a/inst/tests/test_triangles.R b/inst/tests/test_triangles.R
new file mode 100644
index 0000000..87f112f
--- /dev/null
+++ b/inst/tests/test_triangles.R
@@ -0,0 +1,39 @@
+
+context("Triangles")
+
+test_that("Listing triangles works", {
+
+  triangles <- function(...) as.vector(igraph::triangles(...))
+
+  g1 <- make_empty_graph(directed=TRUE)
+  g2 <- make_empty_graph(directed=FALSE)
+  expect_that(triangles(g1), equals(numeric()))
+  expect_that(triangles(g2), equals(numeric()))
+
+  g3 <- make_empty_graph(n=1, directed=TRUE)
+  g4 <- make_empty_graph(n=1, directed=FALSE)
+  expect_that(triangles(g3), equals(numeric()))
+  expect_that(triangles(g4), equals(numeric()))
+
+  g5 <- make_empty_graph(n=100, directed=TRUE)
+  g6 <- make_empty_graph(n=100, directed=FALSE)
+  expect_that(triangles(g5), equals(numeric()))
+  expect_that(triangles(g6), equals(numeric()))
+  
+  g7 <- make_ring(3, directed=FALSE)
+  g8 <- make_ring(3, directed=TRUE)
+  g9 <- graph_from_literal(A-+B:C, B-+C)
+  expect_that(sort(triangles(g7)), equals(1:3))
+  expect_that(sort(triangles(g8)), equals(1:3))
+  expect_that(sort(triangles(g9)), equals(1:3))
+
+  g10 <- make_full_graph(5, directed=FALSE)
+  g11 <- make_full_graph(5, directed=TRUE)
+  r10 <- c(1L, 2L, 5L, 1L, 2L, 3L, 1L, 2L, 4L, 1L, 3L, 5L, 1L, 3L, 4L, 
+           1L, 4L, 5L, 2L, 3L, 5L, 2L, 3L, 4L, 2L, 4L, 5L, 3L, 4L, 5L)
+  r11 <- c(1L, 2L, 5L, 1L, 2L, 4L, 1L, 2L, 3L, 1L, 3L, 5L, 1L, 3L, 4L, 
+           1L, 4L, 5L, 2L, 4L, 5L, 2L, 3L, 5L, 2L, 3L, 4L, 3L, 4L, 5L)
+  expect_that(triangles(g10), equals(r10))
+  expect_that(triangles(g11), equals(r11))
+
+})
diff --git a/inst/tests/test_unfold.tree.R b/inst/tests/test_unfold.tree.R
index 81f4b79..faf03d5 100644
--- a/inst/tests/test_unfold.tree.R
+++ b/inst/tests/test_unfold.tree.R
@@ -1,13 +1,13 @@
 
-context("unfold.tree")
+context("unfold_tree")
 
-test_that("unfold.tree works", {
+test_that("unfold_tree works", {
   
   library(igraph)
   
-  g <- graph.tree(7, 2)
-  g <- add.edges(g, c(2,7, 1,4))
-  g2 <- unfold.tree(g, roots=1)
+  g <- make_tree(7, 2)
+  g <- add_edges(g, c(2,7, 1,4))
+  g2 <- unfold_tree(g, roots=1)
   expect_that(graph.isomorphic(g2$tree, graph(c(1,2, 1,3, 2,8, 2,5, 3,6,
                                                 3,9, 2,7, 1,4))), is_true())
   expect_that(g2$vertex_index, equals(c(1,2,3,4,5,6,7,4,7)))
diff --git a/inst/tests/test_walktrap.community.R b/inst/tests/test_walktrap.community.R
index cb5d681..b8bfdc4 100644
--- a/inst/tests/test_walktrap.community.R
+++ b/inst/tests/test_walktrap.community.R
@@ -1,19 +1,20 @@
 
-context("walktrap.community")
+context("cluster_walktrap")
 
-test_that("walktrap.community works", {
+test_that("cluster_walktrap works", {
 
   library(igraph)
 
-  g <- graph.famous("Zachary")
+  g <- make_graph("Zachary")
   set.seed(42)
-  wc <- walktrap.community(g)
+  wc <- cluster_walktrap(g)
 
   expect_that(modularity(g, membership(wc)), equals(modularity(wc)))
-  expect_that(membership(wc), equals(c(1, 1, 2, 1, 5, 5, 5, 1, 2, 2,
-                                       5, 1, 1, 2, 3, 3, 5, 1, 3, 1,
-                                       3, 1, 3, 4, 4, 4, 3, 4, 2, 3,
-                                       2, 2, 3, 3)))
+  expect_that(as.vector(membership(wc)),
+              equals(c(1, 1, 2, 1, 5, 5, 5, 1, 2, 2,
+                       5, 1, 1, 2, 3, 3, 5, 1, 3, 1,
+                       3, 1, 3, 4, 4, 4, 3, 4, 2, 3,
+                       2, 2, 3, 3)))
   expect_that(length(wc), equals(5))
   expect_that(sizes(wc), equals(structure(c(9L, 7L, 9L, 4L, 5L), .Dim=5L,
     .Dimnames = structure(list(`Community sizes` = c("1", "2", "3", "4",
@@ -25,7 +26,7 @@ test_that("walktrap.community works", {
               prints_text("2 branches.*20 members.*height 31"))
   expect_that(print(d[[2]]),
               prints_text("2 branches.*14 members.*height 32"))
-  m2 <- cutat(wc, no=3)
+  m2 <- cut_at(wc, no=3)
   expect_that(modularity(g, m2),
               equals(wc$modularity[length(wc$modularity)-2],
                      tolerance=1e-7))
diff --git a/inst/tests/test_watts.strogatz.game.R b/inst/tests/test_watts.strogatz.game.R
index d352687..6907667 100644
--- a/inst/tests/test_watts.strogatz.game.R
+++ b/inst/tests/test_watts.strogatz.game.R
@@ -1,7 +1,7 @@
 
-context("watts.strogatz.game")
+context("sample_smallworld")
 
-test_that("watts.strogatz.game works", {
+test_that("sample_smallworld works", {
 
   library(igraph)
 
@@ -9,8 +9,8 @@ test_that("watts.strogatz.game works", {
     p <- runif(1)
     d <- sample(1:3, 1)
     nei <- sample(2:5, 1)
-    g <- watts.strogatz.game(d, 10, nei, p, loops=FALSE)
-    expect_that(any(is.loop(g)), is_false())
+    g <- sample_smallworld(d, 10, nei, p, loops=FALSE)
+    expect_that(any(which_loop(g)), is_false())
   }
 
 })
diff --git a/man/E.Rd b/man/E.Rd
new file mode 100644
index 0000000..f2763a8
--- /dev/null
+++ b/man/E.Rd
@@ -0,0 +1,100 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{E}
+\alias{E}
+\title{Edges of a graph}
+\usage{
+E(graph, P = NULL, path = NULL, directed = TRUE)
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{P}{A list of vertices to select edges via pairs of vertices.
+The first and second vertices select the first edge, the third
+and fourth the second, etc.}
+
+\item{path}{A list of vertices, to select edges along a path.
+Note that this only works reliable for simple graphs. If the graph
+has multiple edges, one of them will be chosen arbitrarily to
+be included in the edge sequence.}
+
+\item{directed}{Whether to consider edge directions in the \code{P}
+argument, for directed graphs.}
+}
+\value{
+An edge sequence of the graph.
+}
+\description{
+An edge sequence is a vector containing numeric edge ids, with a special
+class attribute that allows custom operations: selecting subsets of
+edges based on attributes, or graph structure, creating the
+intersection, union of edges, etc.
+}
+\details{
+Edge sequences are usually used as igraph function arguments that
+refer to edges of a graph.
+
+An edge sequence is tied to the graph it refers to: it really denoted
+the specific edges of that graph, and cannot be used together with
+another graph.
+
+An edge sequence is most often created by the \code{E()} function. The
+result includes edges in increasing edge id order by default (if. none
+of the \code{P} and \code{path} arguments are used). An edge
+sequence can be indexed by a numeric vector, just like a regular R
+vector. See links to other edge sequence operations below.
+}
+\section{Indexing edge sequences}{
+
+Edge sequences mostly behave like regular vectors, but there are some
+additional indexing operations that are specific for them;
+e.g. selecting edges based on graph structure, or based on edge
+attributes. See \code{\link{[.igraph.es}} for details.
+}
+
+\section{Querying or setting attributes}{
+
+Edge sequences can be used to query or set attributes for the
+edges in the sequence. See \code{\link{$.igraph.es}} for details.
+}
+\examples{
+# Edges of an unnamed graph
+g <- make_ring(10)
+E(g)
+
+# Edges of a named graph
+g2 <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = letters[1:10])
+E(g2)
+}
+\seealso{
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{V}};
+  \code{\link{[.igraph.es}}, \code{\link{\%--\%}},
+  \code{\link{\%->\%}}, \code{\link{\%<-\%}},
+  \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/SCGintro.Rd b/man/SCGintro.Rd
deleted file mode 100644
index d5ddca6..0000000
--- a/man/SCGintro.Rd
+++ /dev/null
@@ -1,156 +0,0 @@
-\name{Spectral coarse graining}
-\alias{SCG}
-\concept{Spectral coarse graining}
-\title{Spectral Coarse Graining}
-\description{
-  Functions to perform the Spectral Coarse Graining (SCG) of matrices
-  and graphs.
-}
-\section{Introduction}{
-  The SCG functions provide a framework, called Spectral Coarse Graining
-  (SCG), for reducing large graphs while preserving their
-  \emph{spectral-related features}, that is features closely related
-  with the eigenvalues and eigenvectors of a graph matrix (which for now
-  can be the adjacency, the stochastic, or the Laplacian matrix).
-
-  Common examples of such features comprise the first-passage-time of
-  random walkers on Markovian graphs, thermodynamic properties of
-  lattice models in statistical physics (e.g. Ising model), and the
-  epidemic threshold of epidemic network models (SIR and SIS models).
-
-  SCG differs from traditional clustering schemes by producing a
-  \emph{coarse-grained graph} (not just a partition of the vertices),
-  representative of the original one. As shown in [1], Principal
-  Component Analysis can be viewed as a particular SCG, called
-  \emph{exact SCG}, where the matrix to be coarse-grained is the
-  covariance matrix of some data set. 
-
-  SCG should be of interest to practitioners of various
-  fields dealing with problems where matrix eigenpairs play an important
-  role, as for instance is the case of dynamical processes on networks.
-}
-\section{SCG in brief}{
-  The main idea of SCG is to operate on a matrix a shrinkage operation
-  specifically designed to preserve some of the matrix eigenpairs while
-  not altering other important matrix features (such as its structure). 
-  Mathematically, this idea was expressed as follows. Consider a
-  (complex) \eqn{n \times n}{n x n} matrix \eqn{M} and form the product
-  \deqn{\widetilde{M} = LMR^*,}{M'=LMR*,}
-  where \eqn{\tilde n < n}{n' < n} and
-  \eqn{L,R \in \mathbf{C}^{\tilde n \times n}}{L,R in C[n'xn]} are such
-  that \eqn{LR^*=I_{\tilde n}}{LR*=I[n']} (\eqn{R^*}{R*} denotes the
-  conjugate transpose of \eqn{R}). Under these assumptions, it can be
-  shown that \eqn{P=R^*L}{P=R*L} is an \eqn{\tilde n}{n'}-rank projector
-  and that, if \eqn{(\lambda, v)}{(lambda, v)} is a (right) 
-  eigenpair of \eqn{M} (i.e. \eqn{Mv=\lambda v}{Mv=lambda v}) and
-  \eqn{P} is orthogonal, there exists an eigenvalue \eqn{\tilde
-    \lambda}{lambda'} of \eqn{\widetilde M}{M'} such that
-  \deqn{|\lambda-\tilde{\lambda}| \le \textrm{const} \Vert e_P(v)\Vert
-    [1 + O(\Vert e_P(v)\Vert^2)],}{%
-  |lambda-lambda'| <= const ||e[P](v)|| [1+O(||e[P](v)||^2)],}
-  where \eqn{\Vert e_P(v)\Vert = \Vert
-    v-Pv\Vert}{||e[P](v)||=||v-Pv||}. 
-  Hence, if \eqn{P} (or equivalently \eqn{L}, \eqn{R}) is chosen so as
-  to make \eqn{\Vert e_P(v)\Vert}{||e[P](v)||} as small as possible, one
-  can preserve to any desired level the original eigenvalue
-  \eqn{\lambda}{lambda} in the coarse-grained matrix \eqn{\widetilde M}{M'};
-  under extra assumptions on \eqn{M}, this result can be generalized to
-  eigenvectors [1]. This leads to the following generic definition of a
-  SCG problem.
-
-  Given \eqn{M\in\mathbf{C}^{n\times n}}{M in C[nxn]} and
-  \eqn{(\lambda,v)}{(lambda,v)} a (right) eigenpair of \eqn{M} to be
-  preserved by the coarse graining, the problem is to find a projector
-  \eqn{\widehat{P}}{P'} solving
-  \deqn{\min_{P\in \Omega} \Vert e_{P}(v)\Vert,}{%
-  min(||e[P](v)||, p in Omega),}
-  where \eqn{\Omega}{Omega} is a set of projectors in
-  \eqn{\mathbf{C}^{n\times n}}{C[nxn]} described by some 
-  ad hoc constraints \eqn{c_{1},\dots c_{r}}{c[1], ..., c[r]}
-  (e.g. \eqn{c_{1}:P\in\mathbf{R}^{n\times n}, c_{2}:P=P^{t},
-    c_{3}:P_{ij}\ge 0}{c[1]: P in R[nxn], c[2]: P=t(P), c[3]: P[i,j] >=
-    0}, etc).
-
-  Choosing pertinent constraints to solve the SCG problem is of great
-  importance in applications. For instance, in the absence of
-  constraints the SCG problem is solved trivially by
-  \eqn{\widehat{P}=vv^*}{P'=vv*} (\eqn{v} is assumed normalized). We have
-  designed a particular constraint, called \emph{homogeneous mixing},
-  which ensures that vertices belonging to the same group are merged
-  consistently from a physical point of view (see [1] for
-  details). Under this constraint the SCG problem reduces to finding the
-  partition of \eqn{\{1,\dots,n\}}{1, ..., n} (labeling the original
-  vertices) minimizing
-  \deqn{\Vert e_P(v)\Vert^{2} =
-    \sum_{\alpha=1}^{\tilde{n}}\sum_{i\in\alpha}[v(i)-(Pv)(i)]^{2},}{%
-    ||e[P](v)||^2 = sum([v(i)-(Pv)(i)]^2; alpha=1,...,n', i in alpha),} 
-  where \eqn{\alpha}{alpha} denotes a group (i.e. a block) in a partition of
-  \eqn{ \{1,\dots,n\} }{{1, ..., n}}, and \eqn{|\alpha|}{|alpha|} is the
-  number of elements in \eqn{\alpha}{alpha}. 
-
-  If \eqn{M} is symmetric or stochastic, for instance, then it may be
-  desirable (or mandatory) to choose \eqn{L}, \eqn{R} so that
-  \eqn{\widetilde M}{M'} is symmetric or stochastic as well. This
-  \emph{structural constraint} has led to the construction of particular
-  semi-projectors for symmetric [1], stochastic [3] and Laplacian [2]
-  matrices, that are made available.
-
-  In short, the coarse graining of matrices and graphs involves: 
-  \enumerate{
-    \item Retrieving a matrix or a graph matrix \eqn{M} from the
-    problem. 
-    \item Computing the eigenpairs of \eqn{M} to be preserved in the
-    coarse-grained graph or matrix. 
-    \item Setting some problem-specific constraints (e.g. dimension of
-    the coarse-grained object). 
-    \item Solving the constrained SCG problem, that is finding
-    \eqn{\widehat{P}}{P'}. 
-    \item Computing from \eqn{\widehat{P}}{P'} two semi-projectors
-    \eqn{\widehat{L}}{L'} and \eqn{\widehat{R}}{R'} (e.g. following the method
-    proposed in [1]). 
-    \item Working out the product \eqn{\widetilde{M}=\widehat{L} M
-      \widehat{R}^*}{M'=L'MR'*} and, if needed, defining from
-    \eqn{\widetilde{M}}{M'} a coarse-grained graph. 
-  }
-}
-\section{Functions for performing SCG}{
-  The main function is the \dQuote{all-in-one}
-  \code{\link{scg}}. This function handles all the steps involved in the
-  Spectral Coarse Graining (SCG) of some particular matrices and graphs
-  as described above and in reference [1]. In more details,
-  \code{\link{scg}} computes some prescribed eigenpairs of a matrix or a
-  graph matrix (for now adjacency, Laplacian and stochastic matrices are
-  available), works out an optimal partition to preserve the eigenpairs,
-  and finally outputs a coarse-grained matrix or graph along with other
-  useful information. 
- 
-  These steps can also be carried out independently: (1) Use
-  \code{\link{get.adjacency}}, \code{\link{graph.laplacian}} or
-  \code{\link{get.stochastic}} to compute a matrix \eqn{M}. (2) Work
-  out some prescribed eigenpairs of \eqn{M} e.g. by 
-  means of \code{eigen} or \code{arpack}. (3) Invoke one the four
-  algorithms of the function \code{\link{scgGrouping}} to get a
-  partition that will preserve the eigenpairs in the coarse-grained
-  matrix. (4) Compute the semi-projectors \eqn{L} and \eqn{R} using
-  \code{\link{scgSemiProjectors}} and from there the coarse-grained
-  matrix \eqn{\widetilde{M}=LMR^*}{M'=LMR*}. If necessary, construct a
-  coarse-grained graph from \eqn{\widetilde{M}}{M'} (e.g. as in [1]). 
-}
-\references{
-  D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
-  Shrinking Matrices while Preserving their Eigenpairs with Application
-  to the Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM
-    Journal on Matrix Analysis and Applications}, 2008. 
-  \url{http://people.epfl.ch/david.morton}
-  
-  D. Gfeller, and P. De Los Rios, Spectral Coarse Graining and
-  Synchronization in Oscillator Networks. \emph{Physical Review
-    Letters}, \bold{100}(17), 2008. 
-  \url{http://arxiv.org/abs/0708.2055}
-
-  D. Gfeller, and P. De Los Rios, Spectral Coarse Graining of Complex
-  Networks, \emph{Physical Review Letters}, \bold{99}(3), 2007. 
-  \url{http://arxiv.org/abs/0706.0812}
-}
-\author{David Morton de Lachapelle, \url{http://people.epfl.ch/david.morton}.}
-\keyword{graphs}
diff --git a/man/V.Rd b/man/V.Rd
new file mode 100644
index 0000000..91b52e7
--- /dev/null
+++ b/man/V.Rd
@@ -0,0 +1,93 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{V}
+\alias{V}
+\title{Vertices of a graph}
+\usage{
+V(graph)
+}
+\arguments{
+\item{graph}{The graph}
+}
+\value{
+A vertex sequence containing all vertices, in the order
+  of their numeric vertex ids.
+}
+\description{
+Create a vertex sequence (vs) containing all vertices of a graph.
+}
+\details{
+A vertex sequence is just what the name says it is: a sequence of
+vertices. Vertex sequences are usually used as igraph function arguments
+that refer to vertices of a graph.
+
+A vertex sequence is tied to the graph it refers to: it really denoted
+the specific vertices of that graph, and cannot be used together with
+another graph.
+
+At the implementation level, a vertex sequence is simply a vector
+containing numeric vertex ids, but it has a special class attribute
+which makes it possible to perform graph specific operations on it, like
+selecting a subset of the vertices based on graph structure, or vertex
+attributes.
+
+A vertex sequence is most often created by the \code{V()} function. The
+result of this includes all vertices in increasing vertex id order. A
+vertex sequence can be indexed by a numeric vector, just like a regular
+R vector. See \code{\link{[.igraph.vs}} and additional links to other
+vertex sequence operations below.
+}
+\section{Indexing vertex sequences}{
+
+Vertex sequences mostly behave like regular vectors, but there are some
+additional indexing operations that are specific for them;
+e.g. selecting vertices based on graph structure, or based on vertex
+attributes. See \code{\link{[.igraph.vs}} for details.
+}
+
+\section{Querying or setting attributes}{
+
+Vertex sequences can be used to query or set attributes for the
+vertices in the sequence. See \code{\link{$.igraph.vs}} for details.
+}
+\examples{
+# Vertex ids of an unnamed graph
+g <- make_ring(10)
+V(g)
+
+# Vertex ids of a named graph
+g2 <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = letters[1:10])
+V(g2)
+}
+\seealso{
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{[.igraph.es}}, \code{\link{\%--\%}},
+  \code{\link{\%->\%}}, \code{\link{\%<-\%}},
+  \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/aaa-igraph-package.Rd b/man/aaa-igraph-package.Rd
index 7bcc0b9..1abf6ec 100644
--- a/man/aaa-igraph-package.Rd
+++ b/man/aaa-igraph-package.Rd
@@ -1,22 +1,29 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/igraph-package.R
 \docType{package}
 \name{igraph-package}
-\alias{igraph-package}
 \alias{igraph}
+\alias{igraph-package}
 \title{The igraph package}
-\description{igraph is a library and R package for network analysis.}
+\description{
+igraph is a library and R package for network analysis.
+}
 \section{Introduction}{
-  The main goals of the igraph library is 
-  to provide a set of data types and functions for 1) pain-free
-  implementation of graph algorithms, 2) fast handling of large graphs,
-  with millions of vertices and edges, 3) allowing rapid prototyping via
-  high level languages like R.
+
+The main goals of the igraph library is to provide a set of data types
+and functions for 1) pain-free implementation of graph algorithms, 2)
+fast handling of large graphs, with millions of vertices and edges, 3)
+allowing rapid prototyping via high level languages like R.
 }
+
 \section{Igraph graphs}{
+
   Igraph graphs have a class \sQuote{\code{igraph}}. They are printed to
   the screen in a special format, here is an example, a ring graph
-  created using \code{\link{graph.ring}}: \preformatted{    IGRAPH U--- 10 10 -- Ring graph
+  created using \code{\link{make_ring}}: \preformatted{
+    IGRAPH U--- 10 10 -- Ring graph
     + attr: name (g/c), mutual (g/x), circular (g/x)  }
-  The \sQuote{\code{IGRAPH}} denotes that this is an igraph graph. Then
+  \sQuote{\code{IGRAPH}} denotes that this is an igraph graph. Then
   come four bits that denote the kind of the graph: the first is
   \sQuote{\code{U}} for undirected and \sQuote{\code{D}} for directed
   graphs. The second is \sQuote{\code{N}} for named graph (i.e. if the
@@ -26,7 +33,7 @@
   \sQuote{\code{B}} for bipartite graphs (i.e. if the
   \sQuote{\code{type}} vertex attribute is set).
 
-  Then comes two numbers, the number of vertices and the number of edges
+  Then come two numbers, the number of vertices and the number of edges
   in the graph, and after a double dash, the name of the graph (the
   \sQuote{\code{name}} graph attribute) is printed if present. The
   second line is optional and it contains all the attributes of the
@@ -45,34 +52,38 @@
     + edges:
      [1] 1-- 2 2-- 3 3-- 4 4-- 5 5-- 6 6-- 7 7-- 8 8-- 9 9--10 1--10 }
 }
+
 \section{Creating graphs}{
+
   There are many functions in igraph for creating graphs, both
   deterministic and stochastic; stochastic graph constructors are called
   \sQuote{games}.
 
   To create small graphs with a given structure probably the
-  \code{\link{graph.formula}} function is easiest. It uses R's formula
+  \code{\link{graph_from_literal}} function is easiest. It uses R's formula
   interface, its manual page contains many examples. Another option is
   \code{\link{graph}}, which takes numeric vertex ids directly.
   \code{\link{graph.atlas}} creates graph from the Graph Atlas,
-  \code{\link{graph.famous}} can create some special graphs.
+  \code{\link{make_graph}} can create some special graphs.
 
-  To create graphs from field data, \code{\link{graph.edgelist}},
-  \code{\link{graph.data.frame}} and \code{\link{graph.adjacency}} are
+  To create graphs from field data, \code{\link{graph_from_edgelist}},
+  \code{\link{graph_from_data_frame}} and \code{\link{graph_from_adjacency_matrix}} are
   probably the best choices.
 
   The igraph package includes some classic random graphs like the
-  Erdos-Renyi GNP and GNM graphs (\code{\link{erdos.renyi.game}}) and
+  Erdos-Renyi GNP and GNM graphs (\code{\link{sample_gnp}}, \code{\link{sample_gnm}}) and
   some recent  popular models, like preferential attachment
-  (\code{\link{barabasi.game}}) and the small-world model
-  (\code{\link{watts.strogatz.game}}). 
+  (\code{\link{sample_pa}}) and the small-world model
+  (\code{\link{sample_smallworld}}).
 }
+
 \section{Vertex and edge IDs}{
+
   Vertices and edges have numerical vertex ids in igraph. Vertex ids are
   always consecutive and they start with one. I.e. for a graph with
   \eqn{n} vertices the vertex ids are between \eqn{1} and
   \eqn{n}. If some operation changes the number of vertices in the
-  graphs, e.g. a subgraph is created via \code{\link{induced.subgraph}}, then
+  graphs, e.g. a subgraph is created via \code{\link{induced_subgraph}}, then
   the vertices are renumbered to satisfty this criteria.
 
   The same is true for the edges as well, edge ids are always between
@@ -84,12 +95,14 @@
   vertices. These are kept by all operations, if possible. See more
   about attributes in the next section.
 }
+
 \section{Attributes}{
+
   In igraph it is possible to assign attributes to the vertices or edges
   of a graph, or to the graph itself. igraph provides flexible
   constructs for selecting a set of vertices or edges based on their
-  attribute values, see \code{\link{get.vertex.attribute}} and
-  \code{\link{iterators}} for details.
+  attribute values, see \code{\link{vertex_attr}},
+  \code{\link{V}} and \code{\link{E}} for details.
 
   Some vertex/edge/graph attributes are treated specially. One of them
   is the \sQuote{name} attribute. This is used for printing the graph
@@ -101,7 +114,7 @@
 
   Edges can also have a \sQuote{name} attribute, and this is treated
   specially as well. Just like for vertices, edges can also be selected
-  based on their names, e.g. in the \code{\link{delete.edges}} and
+  based on their names, e.g. in the \code{\link{delete_edges}} and
   other functions.
 
   We note here, that vertex names can also be used to select edges.
@@ -110,7 +123,7 @@
   directed, edge going from \sQuote{\code{from}} to
   \sQuote{\code{to}}. The two forms can also be mixed in the same edge
   selector.
-  
+
   Other attributes define visualization parameters, see
   \code{\link{igraph.plotting}} for details.
 
@@ -120,7 +133,9 @@
   \code{\link[base]{save}} and \code{\link[base]{load}} to store/retrieve your
   graphs.
 }
+
 \section{Visualization}{
+
   igraph provides three different ways for visualization. The first is
   the \code{\link{plot.igraph}} function. (Actually you don't need to
   write \code{plot.igraph}, \code{plot} is enough. This function uses
@@ -136,16 +151,20 @@
   Make sure you read \code{\link{igraph.plotting}} before you start
   plotting your graphs.
 }
+
 \section{File formats}{
+
   igraph can handle various graph file formats, usually both for reading
   and writing. We suggest that you use the GraphML file format for your
   graphs, except if the graphs are too big. For big graphs a simpler
-  format is recommended. See \code{\link{read.graph}} and
-  \code{\link{write.graph}} for details.
+  format is recommended. See \code{\link{read_graph}} and
+  \code{\link{write_graph}} for details.
 }
+
 \section{Further information}{
+
   The igraph homepage is at \url{http://igraph.org}.
   See especially the documentation section. Join the igraph-help mailing
   list if you have questions or comments.
 }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
+
diff --git a/man/add_edges.Rd b/man/add_edges.Rd
new file mode 100644
index 0000000..684d407
--- /dev/null
+++ b/man/add_edges.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{add_edges}
+\alias{add.edges}
+\alias{add_edges}
+\title{Add edges to a graph}
+\usage{
+add_edges(graph, edges, ..., attr = list())
+}
+\arguments{
+\item{graph}{The input graph}
+
+\item{edges}{The edges to add, a vertex sequence with even number
+of vertices.}
+
+\item{...}{Additional arguments, they must be named,
+and they will be added as edge attributes, for the newly added
+edges. See also details below.}
+
+\item{attr}{A named list, its elements will be added
+as edge attributes, for the newly added edges. See also details
+below.}
+}
+\value{
+The graph, with the edges (and attributes) added.
+}
+\description{
+The new edges are given as a vertex sequence, e.g. internal
+numeric vertex ids, or vertex names. The first edge points from
+\code{edges[1]} to \code{edges[2]}, the second from \code{edges[3]}
+to \code{edges[4]}, etc.
+}
+\details{
+If attributes are supplied, and they are not present in the graph,
+their values for the original edges of the graph are set to \code{NA}.
+}
+\examples{
+g <- make_empty_graph(n = 5) \%>\%
+  add_edges(c(1,2, 2,3, 3,4, 4,5)) \%>\%
+  set_edge_attr("color", value = "red") \%>\%
+  add_edges(c(5,1), color = "green")
+E(g)[[]]
+plot(g)
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{path}};
+  \code{\link{vertex}}, \code{\link{vertices}}
+}
+
diff --git a/man/add_layout_.Rd b/man/add_layout_.Rd
new file mode 100644
index 0000000..21f8ff5
--- /dev/null
+++ b/man/add_layout_.Rd
@@ -0,0 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{add_layout_}
+\alias{add_layout_}
+\title{Add layout to graph}
+\usage{
+add_layout_(graph, ..., overwrite = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{...}{Additional arguments are passed to \code{\link{layout_}}.}
+
+\item{overwrite}{Whether to overwrite the layout of the graph,
+if it already has one.}
+}
+\value{
+The input graph, with the layout added.
+}
+\description{
+Add layout to graph
+}
+\examples{
+(make_star(11) + make_star(11)) \%>\%
+  add_layout_(as_star(), component_wise()) \%>\%
+  plot()
+}
+\seealso{
+\code{\link{layout_}} for a description of the layout API.
+
+Other graph layouts: \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+
diff --git a/man/add_vertices.Rd b/man/add_vertices.Rd
new file mode 100644
index 0000000..cca6f44
--- /dev/null
+++ b/man/add_vertices.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{add_vertices}
+\alias{add.vertices}
+\alias{add_vertices}
+\title{Add vertices to a graph}
+\usage{
+add_vertices(graph, nv, ..., attr = list())
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{nv}{The number of vertices to add.}
+
+\item{...}{Additional arguments, they must be named,
+and they will be added as vertex attributes, for the newly added
+vertices. See also details below.}
+
+\item{attr}{A named list, its elements will be added
+as vertex attributes, for the newly added vertices. See also details
+below.}
+}
+\value{
+The graph, with the vertices (and attributes) added.
+}
+\description{
+If attributes are supplied, and they are not present in the graph,
+their values for the original vertices of the graph are set to
+\code{NA}.
+}
+\examples{
+g <- make_empty_graph() \%>\%
+  add_vertices(3, color = "red") \%>\%
+  add_vertices(2, color = "green") \%>\%
+  add_edges(c(1,2, 2,3, 3,4, 4,5))
+g
+V(g)[[]]
+plot(g)
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{path}};
+  \code{\link{vertex}}, \code{\link{vertices}}
+}
+
diff --git a/man/adjacent.triangles.Rd b/man/adjacent.triangles.Rd
deleted file mode 100644
index 87d4461..0000000
--- a/man/adjacent.triangles.Rd
+++ /dev/null
@@ -1,36 +0,0 @@
-\name{adjacent.triangles}
-\alias{adjacent.triangles}
-\title{Count adjacenct triangles}
-\description{Count how many triangles a vertex is part of, in a graph.}
-\usage{
-adjacent.triangles (graph, vids = V(graph))
-}
-\arguments{
-  \item{graph}{The input graph. It might be directed, but edge
-    directions are ignored.}
-  \item{vids}{The vertices to query, all of them by default. This might
-    be a vector of numeric ids, or a character vector of symbolic vertex
-    names for named graphs.}
-}
-\details{
-  Count how many triangles a vertex is part of.
-}
-\value{
-  A numeric vector, the number of triangles for all vertices queried.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{\code{\link{transitivity}}}
-\examples{
-## A small graph
-kite <- graph.famous("Krackhardt_Kite")
-atri <- adjacent.triangles(kite)
-plot(kite, vertex.label=atri)
-
-## Should match, local transitivity is the
-## number of adjacent triangles divided by the number
-## of adjacency triples
-transitivity(kite, type="local")
-adjacent.triangles(kite) / (degree(kite) * (degree(kite)-1)/2)
-}
-\keyword{graphs}
diff --git a/man/adjacent_vertices.Rd b/man/adjacent_vertices.Rd
new file mode 100644
index 0000000..4c0aeb1
--- /dev/null
+++ b/man/adjacent_vertices.Rd
@@ -0,0 +1,41 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{adjacent_vertices}
+\alias{adjacent_vertices}
+\title{Adjacent vertices of multiple vertices in a graph}
+\usage{
+adjacent_vertices(graph, v, mode = c("out", "in", "all", "total"))
+}
+\arguments{
+\item{graph}{Input graph.}
+
+\item{v}{The vertices to query.}
+
+\item{mode}{Whether to query outgoing (\sQuote{out}), incoming
+(\sQuote{in}) edges, or both types (\sQuote{all}). This is
+ignored for undirected graphs.}
+}
+\value{
+A list of vertex sequences.
+}
+\description{
+This function is similar to \code{\link{neighbors}}, but it queries
+the adjacent vertices for multiple vertices at once.
+}
+\examples{
+g <- make_graph("Zachary")
+adjacent_vertices(g, c(1, 34))
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{are.connected}},
+  \code{\link{are_adjacent}}; \code{\link{ecount}},
+  \code{\link{gsize}}; \code{\link{ends}},
+  \code{\link{get.edge}}, \code{\link{get.edges}};
+  \code{\link{get.edge.ids}}; \code{\link{gorder}},
+  \code{\link{vcount}}; \code{\link{head_of}};
+  \code{\link{incident_edges}}; \code{\link{incident}};
+  \code{\link{is.directed}}, \code{\link{is_directed}};
+  \code{\link{neighbors}}; \code{\link{tail_of}}
+}
+
diff --git a/man/aging.prefatt.game.Rd b/man/aging.prefatt.game.Rd
deleted file mode 100644
index 1cf81d2..0000000
--- a/man/aging.prefatt.game.Rd
+++ /dev/null
@@ -1,120 +0,0 @@
-\name{aging.prefatt.game}
-\alias{aging.prefatt.game}
-\alias{aging.barabasi.game}
-\alias{aging.ba.game}
-\concept{Preferential attachment}
-\concept{Aging of vertices}
-\concept{Random graph model}
-\title{Generate an evolving random graph with preferential attachment
-  and aging}
-\description{This function creates a random graph by simulating its
-  evolution. Each time a new vertex is added it creates a number of links
-  to old vertices and the probability that an old vertex is cited depends on
-  its in-degree (preferential attachment) and age.}
-\usage{
-aging.prefatt.game (n, pa.exp, aging.exp, m = NULL, aging.bin = 300,
-     out.dist = NULL, out.seq = NULL, out.pref = FALSE,
-     directed = TRUE, zero.deg.appeal = 1, zero.age.appeal = 0,
-     deg.coef = 1, age.coef = 1, time.window = NULL)
-}
-\arguments{
-  \item{n}{The number of vertices in the graph.}
-  \item{pa.exp}{The preferantial attachment exponent, see the details
-    below.}
-  \item{aging.exp}{The exponent of the aging, usually a non-positive
-    number, see details below.}
-  \item{m}{The number of edges each new vertex creates (except the very
-    first vertex). This argument is used only if both the
-    \code{out.dist} and \code{out.seq} arguments are NULL.}
-  \item{aging.bin}{The number of bins to use for measuring the age of
-    vertices, see details below.}
-  \item{out.dist}{The discrete distribution to generate the number of
-    edges to add in each time step if \code{out.seq} is NULL. See
-    details below.}
-  \item{out.seq}{The number of edges to add in each time step, a vector
-    containing as many elements as the number of vertices. See details
-    below.}
-  \item{out.pref}{Logical constant, whether to include edges not
-    initiated by the vertex as a basis of preferential attachment. See
-    details below.}
-  \item{directed}{Logical constant, whether to generate a directed
-    graph. See details below.}
-  \item{zero.deg.appeal}{The degree-dependent part of the
-    \sQuote{attractiveness} of the vertices with no adjacent edges. See
-    also details below.} 
-  \item{zero.age.appeal}{The age-dependent part of the
-    \sQuote{attrativeness} of the vertices with age zero. It is usually
-    zero, see details below.} 
-  \item{deg.coef}{The coefficient of the degree-dependent
-    \sQuote{attractiveness}. See details below.}
-  \item{age.coef}{The coefficient of the age-dependent part of the
-    \sQuote{attractiveness}. See details below.}
-  \item{time.window}{Integer constant, if NULL only adjacent added in
-    the last \code{time.windows} time steps are counted as a basis of
-    the preferential attachment. See also details below.}
-}
-\details{
-  This is a discrete time step model of a growing graph. We start with a
-  network containing a single vertex (and no edges) in the first time
-  step. Then in each time step (starting with the second) a new vertex
-  is added and it initiates a number of edges to the old vertices in the
-  network. The probability that an old vertex is connected to is
-  proportional to 
-  \deqn{P[i] \sim (c\cdot k_i^\alpha+a)(d\cdot l_i^\beta+b)\cdot }{%
-        P[i] ~ (c k[i]^alpha + a) (d l[i]^beta + a)}
-
-  Here \eqn{k_i}{k[i]} is the in-degree of vertex \eqn{i} in the current
-  time step and \eqn{l_i}{l[i]} is the age of vertex \eqn{i}. The age is
-  simply defined as the number of time steps passed since the vertex is
-  added, with the extension that vertex age is divided to be in
-  \code{aging.bin} bins.
-
- \eqn{c}, \eqn{\alpha}{alpha}, \eqn{a}, \eqn{d}, \eqn{\beta}{beta} and
- \eqn{b} are parameters and they can be set via the following
- arguments: \code{pa.exp} (\eqn{\alpha}{alpha}, mandatory argument),
- \code{aging.exp} (\eqn{\beta}{beta}, mandatory argument),
- \code{zero.deg.appeal} (\eqn{a}, optional, the default value is 1),
- \code{zero.age.appeal} (\eqn{b}, optional, the default is 0),
- \code{deg.coef} (\eqn{c}, optional, the default is 1),
- and \code{age.coef} (\eqn{d}, optional, the default is 1).
-
- The number of edges initiated in each time step is governed by the
- \code{m}, \code{out.seq} and \code{out.pref} parameters. If
- \code{out.seq} is given then it is interpreted as a vector giving the
- number of edges to be added in each time step. It should be of length
- \code{n} (the number of vertices), and its first element will be
- ignored. If \code{out.seq} is not given (or NULL) and \code{out.dist}
- is given then it will be used as a discrete probability distribution to
- generate the number of edges. Its first element gives the probability
- that zero edges are added at a time step, the second element is the
- probability that one edge is added, etc. (\code{out.seq} should contain
- non-negative numbers, but if they don't sum up to 1, they will be
- normalized to sum up to 1. This behavior is similar to the \code{prob}
- argument of the \code{sample} command.)
-
- By default a directed graph is generated, but it \code{directed} is set
- to \code{FALSE} then an undirected is created. Even if an undirected
- graph is generaed \eqn{k_i}{k[i]} denotes only the adjacent edges not
- initiated by the vertex itself except if \code{out.pref} is set to
- \code{TRUE}.
-
- If the \code{time.window} argument is given (and not NULL) then
- \eqn{k_i}{k[i]} means only the adjacent edges added in the previous
- \code{time.window} time steps.
-
- This function might generate graphs with multiple edges.
-}
-\value{A new graph.}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{barabasi.game}}, \code{\link{erdos.renyi.game}}}
-\examples{
-# The maximum degree for graph with different aging exponents
-g1 <- aging.prefatt.game(10000, pa.exp=1, aging.exp=0, aging.bin=1000)
-g2 <- aging.prefatt.game(10000, pa.exp=1, aging.exp=-1,   aging.bin=1000)
-g3 <- aging.prefatt.game(10000, pa.exp=1, aging.exp=-3,   aging.bin=1000)
-max(degree(g1))
-max(degree(g2))
-max(degree(g3))
-}
-\keyword{graphs}
diff --git a/man/all.st.cuts.Rd b/man/all.st.cuts.Rd
deleted file mode 100644
index 0870b5b..0000000
--- a/man/all.st.cuts.Rd
+++ /dev/null
@@ -1,51 +0,0 @@
-\name{stCuts}
-\alias{stCuts}
-\concept{Edge cuts}
-\concept{(s,t)-cuts}
-\title{List all (s,t)-cuts of a graph}
-\description{
-  List all (s,t)-cuts in a directed graph.
-}
-\usage{
-stCuts(graph, source, target)
-}
-\arguments{
-  \item{graph}{The input graph. It must be directed.}
-  \item{source}{The source vertex.}
-  \item{target}{The target vertex.}
-}
-\details{
-  Given a \eqn{G} directed graph and two, different and non-ajacent
-  vertices, \eqn{s} and \eqn{t}, an \eqn{(s,t)}-cut is a set of edges,
-  such that after removing these edges from \eqn{G} there is no directed
-  path from \eqn{s} to \eqn{t}.
-}
-\value{
-  A list with entries:
-  \item{cuts}{A list of numeric vectors containing edge ids. Each vector
-    is an \eqn{(s,t)}-cut.}
-  \item{partition1s}{A list of numeric vectors containing vertex
-    ids, they correspond to the edge cuts. Each vertex set is a 
-    generator of the corresponding cut, i.e. in the graph \eqn{G=(V,E)}, the
-    vertex set \eqn{X} and its complementer \eqn{V-X}, generates the cut
-    that contains exactly the edges that go from \eqn{X} to \eqn{V-X}.}
-}
-\references{
-  JS Provan and DR Shier: A Paradigm for listing
-  (s,t)-cuts in graphs, \emph{Algorithmica} 15, 351--372, 1996.    
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  \code{\link{stMincuts}} to list all minimum cuts.
-}
-\examples{
-# A very simple graph
-g <- graph.formula(a -+ b -+ c -+ d -+ e)
-stCuts(g, source="a", target="e")
-
-# A somewhat more difficult graph
-g2 <- graph.formula(s --+ a:b, a:b --+ t,
-                   a --+ 1:2:3, 1:2:3 --+ b)
-stCuts(g2, source="s", target="t")
-}
-\keyword{graphs}
diff --git a/man/all.st.mincuts.Rd b/man/all.st.mincuts.Rd
deleted file mode 100644
index 4bc2110..0000000
--- a/man/all.st.mincuts.Rd
+++ /dev/null
@@ -1,63 +0,0 @@
-\name{stMincuts}
-\alias{stMincuts}
-\concept{Edge cuts}
-\concept{(s,t)-cuts}
-\concept{Minimum cuts}
-\concept{Minimum (s,t)-cuts}
-\title{List all minimum \eqn{(s,t)}-cuts of a graph}
-\description{
-  Listing all minimum \eqn{(s,t)}-cuts of a directed graph, for given
-  \eqn{s} and \eqn{t}.
-}
-\usage{
-stMincuts(graph, source, target, capacity = NULL)
-}
-\arguments{
-  \item{graph}{The input graph. It must be directed.}
-  \item{source}{The id of the source vertex.}
-  \item{target}{The id of the target vertex.}
-  \item{capacity}{Numeric vector giving the edge capacities. If this is
-    \code{NULL} and the graph has a \code{weight} edge
-    attribute, then this attribute defines the edge capacities. For
-    forcing unit edge capacities, even for graphs that have a
-    \code{weight} edge attribute, supply \code{NA} here.}
-}
-\details{
-  Given a \eqn{G} directed graph and two, different and non-ajacent
-  vertices, \eqn{s} and \eqn{t}, an \eqn{(s,t)}-cut is a set of edges,
-  such that after removing these edges from \eqn{G} there is no directed
-  path from \eqn{s} to \eqn{t}.
-
-  The size of an \eqn{(s,t)}-cut is defined as the sum of the
-  capacities (or weights) in the cut. For unweighed (=equally weighted)
-  graphs, this is simply the number of edges.
-  
-  An \eqn{(s,t)}-cut is minimum if it is of the smallest possible
-  size.
-}
-\value{
-  A list with entries:
-  \item{value}{Numeric scalar, the size of the minimum cut(s).}
-  \item{cuts}{A list of numeric vectors containing edge ids. Each vector
-    is a minimum \eqn{(s,t)}-cut.}
-  \item{partition1s}{A list of numeric vectors containing vertex
-    ids, they correspond to the edge cuts. Each vertex set is a 
-    generator of the corresponding cut, i.e. in the graph \eqn{G=(V,E)}, the
-    vertex set \eqn{X} and its complementer \eqn{V-X}, generates the cut
-    that contains exactly the edges that go from \eqn{X} to \eqn{V-X}.}
-}
-\references{
-  JS Provan and DR Shier: A Paradigm for listing
-  (s,t)-cuts in graphs, \emph{Algorithmica} 15, 351--372, 1996.  
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  \code{\link{stCuts}}, \code{\link{minimum.size.separators}}
-}
-\examples{
-# A difficult graph, from the Provan-Shier paper
-g <- graph.formula(s --+ a:b, a:b --+ t,
-                   a --+ 1:2:3:4:5, 1:2:3:4:5 --+ b)
-stMincuts(g, source="s", target="t")
-}
-\keyword{graphs}
diff --git a/man/all_simple_paths.Rd b/man/all_simple_paths.Rd
new file mode 100644
index 0000000..e1c308d
--- /dev/null
+++ b/man/all_simple_paths.Rd
@@ -0,0 +1,47 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/paths.R
+\name{all_simple_paths}
+\alias{all_simple_paths}
+\title{List all simple paths from one source}
+\usage{
+all_simple_paths(graph, from, to = V(graph), mode = c("out", "in", "all",
+  "total"))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{from}{The source vertex.}
+
+\item{to}{The target vertex of vertices. Defaults to all vertices.}
+
+\item{mode}{Character constant, gives whether the shortest paths to or
+from the given vertices should be calculated for directed graphs. If
+\code{out} then the shortest paths \emph{from} the vertex, if \code{in}
+then \emph{to} it will be considered. If \code{all}, the default, then
+the corresponding undirected graph will be used, ie. not directed paths
+are searched. This argument is ignored for undirected graphs.}
+}
+\value{
+A list of integer vectors, each integer vector is a path from
+  the source vertex to one of the target vertices. A path is given by its
+  vertex ids.
+}
+\description{
+This function lists are simple paths from one source vertex to another
+vertex or vertices. A path is simple if the vertices it visits are not
+visited more than once.
+}
+\details{
+Note that potentially there are exponentially many paths between two
+vertices of a graph, and you may run out of memory when using this
+function, if your graph is lattice-like.
+
+This function currently ignored multiple and loop edges.
+}
+\examples{
+g <- make_ring(10)
+all_simple_paths(g, 1, 5)
+all_simple_paths(g, 1, c(3,5))
+}
+\keyword{graphs}
+
diff --git a/man/alpha.centrality.Rd b/man/alpha.centrality.Rd
deleted file mode 100644
index fea01e1..0000000
--- a/man/alpha.centrality.Rd
+++ /dev/null
@@ -1,73 +0,0 @@
-\name{alpha.centrality}
-\alias{alpha.centrality}
-\concept{Alpha centrality}
-\title{Find Bonacich alpha centrality scores of network positions}
-\description{\code{alpha.centrality} calculates the alpha centrality of
-  some (or all) vertices in a graph.
-}
-\usage{
-alpha.centrality(graph, nodes=V(graph), alpha=1, loops=FALSE,
-                 exo=1, weights=NULL, tol=1e-7, sparse=TRUE)
-}
-\arguments{
-  \item{graph}{The input graph, can be directed or undirected}
-  \item{nodes}{Vertex sequence, the vertices for which the alpha
-    centrality values are returned. (For technical reasons they
-    will be calculated for all vertices, anyway.)}
-  \item{alpha}{Parameter specifying the relative importance of
-    endogenous versus exogenous factors in the determination of
-    centrality. See details below.}
-  \item{loops}{Whether to eliminate loop edges from the graph before the
-    calculation.}
-  \item{exo}{The exogenous factors, in most cases this is either a
-    constant -- the same factor for every node, or a vector giving the
-    factor for every vertex. Note that too long vectors will be
-    truncated and too short vectors will be replicated to match the
-    number of vertices.}
-  \item{weights}{A character scalar that gives the name of the edge
-    attribute to use in the adjacency matrix. If it is \code{NULL}, then
-    the \sQuote{weight} edge attribute of the graph is used, if there is
-    one. Otherwise, or if it is \code{NA}, then the calculation uses the
-    standard adjacency matrix.}
-  \item{tol}{Tolerance for near-singularities during matrix inversion,
-    see \code{\link{solve}}.}
-  \item{sparse}{Logical scalar, whether to use sparse matrices for the
-    calculation. The \sQuote{Matrix} package is required for sparse
-    matrix support}
-}
-\details{
-  The alpha centrality measure can be considered as a generalization of
-  eigenvector centerality to directed graphs. It was proposed by
-  Bonacich in 2001 (see reference below).
-
-  The alpha centrality of the vertices in a graph is defined as the
-  solution of the following matrix equation:
-  \deqn{x=\alpha A^T x+e,}{x=alpha t(A)x+e,}
-  where \eqn{A}{A} is the (not neccessarily symmetric) adjacency matrix of
-  the graph, \eqn{e}{e} is the vector of exogenous sources of status of the
-  vertices and \eqn{\alpha}{alpha} is the relative importance of the endogenous
-  versus exogenous factors.
-}
-\value{
-  A numeric vector contaning the centrality scores for the selected
-  vertices.
-}
-\references{
-  Bonacich, P. and Paulette, L. (2001). ``Eigenvector-like measures of
-  centrality for asymmetric relations'' \emph{Social Networks}, 23,
-  191-201.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\section{Warning}{Singular adjacency matrices cause problems for this
-  algorithm, the routine may fail is certain cases.}
-\seealso{\code{\link{evcent}} and \code{\link{bonpow}}}
-\examples{
-# The examples from Bonacich's paper
-g.1 <- graph( c(1,3,2,3,3,4,4,5) )
-g.2 <- graph( c(2,1,3,1,4,1,5,1) )
-g.3 <- graph( c(1,2,2,3,3,4,4,1,5,1) )
-alpha.centrality(g.1)
-alpha.centrality(g.2)
-alpha.centrality(g.3,alpha=0.5)
-}
-\keyword{graphs}
diff --git a/man/alpha_centrality.Rd b/man/alpha_centrality.Rd
new file mode 100644
index 0000000..d93c866
--- /dev/null
+++ b/man/alpha_centrality.Rd
@@ -0,0 +1,88 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{alpha_centrality}
+\alias{alpha.centrality}
+\alias{alpha_centrality}
+\title{Find Bonacich alpha centrality scores of network positions}
+\usage{
+alpha_centrality(graph, nodes = V(graph), alpha = 1, loops = FALSE,
+  exo = 1, weights = NULL, tol = 1e-07, sparse = TRUE)
+}
+\arguments{
+\item{graph}{The input graph, can be directed or undirected}
+
+\item{nodes}{Vertex sequence, the vertices for which the alpha centrality
+values are returned. (For technical reasons they will be calculated for all
+vertices, anyway.)}
+
+\item{alpha}{Parameter specifying the relative importance of endogenous
+versus exogenous factors in the determination of centrality. See details
+below.}
+
+\item{loops}{Whether to eliminate loop edges from the graph before the
+calculation.}
+
+\item{exo}{The exogenous factors, in most cases this is either a constant --
+the same factor for every node, or a vector giving the factor for every
+vertex. Note that too long vectors will be truncated and too short vectors
+will be replicated to match the number of vertices.}
+
+\item{weights}{A character scalar that gives the name of the edge attribute
+to use in the adjacency matrix. If it is \code{NULL}, then the
+\sQuote{weight} edge attribute of the graph is used, if there is one.
+Otherwise, or if it is \code{NA}, then the calculation uses the standard
+adjacency matrix.}
+
+\item{tol}{Tolerance for near-singularities during matrix inversion, see
+\code{\link{solve}}.}
+
+\item{sparse}{Logical scalar, whether to use sparse matrices for the
+calculation. The \sQuote{Matrix} package is required for sparse matrix
+support}
+}
+\value{
+A numeric vector contaning the centrality scores for the selected
+vertices.
+}
+\description{
+\code{alpha_centrality} calculates the alpha centrality of some (or all)
+vertices in a graph.
+}
+\details{
+The alpha centrality measure can be considered as a generalization of
+eigenvector centerality to directed graphs. It was proposed by Bonacich in
+2001 (see reference below).
+
+The alpha centrality of the vertices in a graph is defined as the solution
+of the following matrix equation: \deqn{x=\alpha A^T x+e,}{x=alpha t(A)x+e,}
+where \eqn{A}{A} is the (not neccessarily symmetric) adjacency matrix of the
+graph, \eqn{e}{e} is the vector of exogenous sources of status of the
+vertices and \eqn{\alpha}{alpha} is the relative importance of the
+endogenous versus exogenous factors.
+}
+\section{Warning}{
+ Singular adjacency matrices cause problems for this
+algorithm, the routine may fail is certain cases.
+}
+\examples{
+# The examples from Bonacich's paper
+g.1 <- graph( c(1,3,2,3,3,4,4,5) )
+g.2 <- graph( c(2,1,3,1,4,1,5,1) )
+g.3 <- graph( c(1,2,2,3,3,4,4,1,5,1) )
+alpha_centrality(g.1)
+alpha_centrality(g.2)
+alpha_centrality(g.3,alpha=0.5)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Bonacich, P. and Paulette, L. (2001). ``Eigenvector-like
+measures of centrality for asymmetric relations'' \emph{Social Networks},
+23, 191-201.
+}
+\seealso{
+\code{\link{eigen_centrality}} and \code{\link{power_centrality}}
+}
+\keyword{graphs}
+
diff --git a/man/are_adjacent.Rd b/man/are_adjacent.Rd
new file mode 100644
index 0000000..aa46102
--- /dev/null
+++ b/man/are_adjacent.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structure.info.R
+\name{are_adjacent}
+\alias{are.connected}
+\alias{are_adjacent}
+\title{Are two vertices adjacent?}
+\usage{
+are_adjacent(graph, v1, v2)
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{v1}{The first vertex, tail in directed graphs.}
+
+\item{v2}{The second vertex, head in directed graphs.}
+}
+\value{
+A logical scalar, \code{TRUE} is a \code{(v1, v2)} exists in the
+  graph.
+}
+\description{
+The order of the vertices only matters in directed graphs,
+where the existence of a directed \code{(v1, v2)} edge is queried.
+}
+\examples{
+ug <- make_ring(10)
+ug
+are_adjacent(ug, 1, 2)
+are_adjacent(ug, 2, 1)
+
+dg <- make_ring(10, directed = TRUE)
+dg
+are_adjacent(ug, 1, 2)
+are_adjacent(ug, 2, 1)
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{neighbors}};
+  \code{\link{tail_of}}
+}
+
diff --git a/man/arpack.Rd b/man/arpack.Rd
index 852282f..97ff0ce 100644
--- a/man/arpack.Rd
+++ b/man/arpack.Rd
@@ -1,230 +1,174 @@
-\name{arpack}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\docType{data}
+\name{arpack_defaults}
 \alias{arpack}
 \alias{arpack-options}
-\alias{igraph.arpack.default}
 \alias{arpack.unpack.complex}
-\concept{Eigenvalues}
-\concept{Eigenvectors}
-\concept{ARPACK}
+\alias{arpack_defaults}
+\alias{igraph.arpack.default}
 \title{ARPACK eigenvector calculation}
-\description{Interface to the ARPACK library for calculating
-  eigenvectors of sparse matrices}
+\format{\preformatted{List of 14
+ $ bmat   : chr "I"
+ $ n      : num 0
+ $ which  : chr "XX"
+ $ nev    : num 1
+ $ tol    : num 0
+ $ ncv    : num 3
+ $ ldv    : num 0
+ $ ishift : num 1
+ $ maxiter: num 1000
+ $ nb     : num 1
+ $ mode   : num 1
+ $ start  : num 0
+ $ sigma  : num 0
+ $ sigmai : num 0
+}}
 \usage{
-arpack(func, extra = NULL, sym = FALSE, options = igraph.arpack.default, 
-    env = parent.frame(), complex=!sym)
-arpack.unpack.complex(vectors, values, nev)
+arpack_defaults
+
+arpack(func, extra = NULL, sym = FALSE, options = arpack_defaults,
+  env = parent.frame(), complex = !sym)
 }
 \arguments{
-  \item{func}{The function to perform the matrix-vector
-    multiplication. ARPACK requires to perform these by the user. The
-    function gets the vector \eqn{x} as the first argument, and it should
-    return \eqn{Ax}, where \eqn{A} is the \dQuote{input matrix}. (The
-    input matrix is never given explicitly.) The second argument is
-    \code{extra}.}
-  \item{extra}{Extra argument to supply to \code{func}.}
-  \item{sym}{Logical scalar, whether the input matrix is
-    symmetric. Always supply \code{TRUE} here if it is, since it can
-    speed up the computation. }
-  \item{options}{Options to ARPACK, a named list to overwrite some of
-    the default option values. See details below.}
-  \item{env}{The environment in which \code{func} will be evaluated.}
-  \item{complex}{Whether to convert the eigenvectors returned by ARPACK
-    into R complex vectors. By default this is not done for symmetric
-    problems (these only have real eigenvectors/values), but only
-    non-symmetric ones. If you have a non-symmetric problem, but you're
-    sure that the results will be real, then supply \code{FALSE} here.
-    The conversion is done by calling \code{arpack.unpack.complex}.
-  }
-  \item{vectors}{Eigenvectors, as returned by ARPACK.}
-  \item{values}{Eigenvalues, as returned by ARPACK}
-  \item{nev}{The number of eigenvectors/values to extract. This can be
-    less than or equal to the number of eigenvalues requested in the
-    original ARPACK call.}
+\item{func}{The function to perform the matrix-vector multiplication. ARPACK
+requires to perform these by the user. The function gets the vector \eqn{x}
+as the first argument, and it should return \eqn{Ax}, where \eqn{A} is the
+\dQuote{input matrix}. (The input matrix is never given explicitly.) The
+second argument is \code{extra}.}
+
+\item{extra}{Extra argument to supply to \code{func}.}
+
+\item{sym}{Logical scalar, whether the input matrix is symmetric. Always
+supply \code{TRUE} here if it is, since it can speed up the computation.}
+
+\item{options}{Options to ARPACK, a named list to overwrite some of the
+default option values. See details below.}
+
+\item{env}{The environment in which \code{func} will be evaluated.}
+
+\item{complex}{Whether to convert the eigenvectors returned by ARPACK into R
+complex vectors. By default this is not done for symmetric problems (these
+only have real eigenvectors/values), but only non-symmetric ones. If you
+have a non-symmetric problem, but you're sure that the results will be real,
+then supply \code{FALSE} here.}
+}
+\value{
+A named list with the following members: \item{values}{Numeric
+vector, the desired eigenvalues.} \item{vectors}{Numeric matrix, the desired
+eigenvectors as columns. If \code{complex=TRUE} (the default for
+non-symmetric problems), then the matrix is complex.} \item{options}{A named
+list with the supplied \code{options} and some information about the
+performed calculation, including an ARPACK exit code. See the details above.
+}
+}
+\description{
+Interface to the ARPACK library for calculating eigenvectors of sparse
+matrices
 }
 \details{
-  ARPACK is a library for solving large scale eigenvalue problems.
-  The package is designed to compute a few eigenvalues and corresponding
-  eigenvectors of a general \eqn{n} by \eqn{n} matrix \eqn{A}. It is
-  most appropriate for large sparse or structured matrices \eqn{A} where
-  structured means that a matrix-vector product \code{w <- Av} requires
-  order \eqn{n} rather than the usual order \eqn{n^2} floating point
-  operations. Please see 
-  \url{http://www.caam.rice.edu/software/ARPACK/} for details.
-
-  This function is an interface to ARPACK. igraph does not contain all
-  ARPACK routines, only the ones dealing with symmetric and
-  non-symmetric eigenvalue problems using double precision real
-  numbers.
+ARPACK is a library for solving large scale eigenvalue problems.  The
+package is designed to compute a few eigenvalues and corresponding
+eigenvectors of a general \eqn{n} by \eqn{n} matrix \eqn{A}. It is most
+appropriate for large sparse or structured matrices \eqn{A} where structured
+means that a matrix-vector product \code{w <- Av} requires order \eqn{n}
+rather than the usual order \eqn{n^2} floating point operations. Please see
+\url{http://www.caam.rice.edu/software/ARPACK/} for details.
 
-  The eigenvalue calculation in ARPACK (in the simplest
-  case) involves the calculation of the \eqn{Av} product where \eqn{A}
-  is the matrix we work with and \eqn{v} is an arbitrary vector. The
-  function supplied in the \code{fun} argument is expected to perform
-  this product. If the product can be done efficiently, e.g. if the
-  matrix is sparse, then \code{arpack} is usually able to calculate the
-  eigenvalues very quickly.
+This function is an interface to ARPACK. igraph does not contain all ARPACK
+routines, only the ones dealing with symmetric and non-symmetric eigenvalue
+problems using double precision real numbers.
 
-  The \code{options} argument specifies what kind of calculation to
-  perform. It is a list with the following members, they correspond
-  directly to ARPACK parameters. On input it has the following fields:
-  \describe{
-    \item{bmat}{Character constant, possible values: \sQuote{\code{I}},
-      stadard eigenvalue problem, \eqn{Ax=\lambda x}{A*x=lambda*x}; and
-      \sQuote{\code{G}}, generalized eigenvalue problem,
-      \eqn{Ax=\lambda B x}{A*x=lambda B*x}. Currently only
-      \sQuote{\code{I}} is supported.}
-    \item{n}{Numeric scalar. The dimension of the eigenproblem. You only
-      need to set this if you call \code{\link{arpack}}
-      directly. (I.e. not needed for \code{\link{evcent}},
-      \code{\link{page.rank}}, etc.)}
-    \item{which}{Specify which eigenvalues/vectors to compute, character
-      constant with exactly two characters.
+The eigenvalue calculation in ARPACK (in the simplest case) involves the
+calculation of the \eqn{Av} product where \eqn{A} is the matrix we work with
+and \eqn{v} is an arbitrary vector. The function supplied in the \code{fun}
+argument is expected to perform this product. If the product can be done
+efficiently, e.g. if the matrix is sparse, then \code{arpack} is usually
+able to calculate the eigenvalues very quickly.
 
-      Possible values for symmetric input matrices:
-      \describe{
-	\item{\sQuote{\code{LA}}}{Compute \code{nev} largest (algebraic)
-	  eigenvalues.}
-	\item{\sQuote{\code{SA}}}{Compute \code{nev} smallest (algebraic)
-	  eigenvalues.}
-	\item{\sQuote{\code{LM}}}{Compute \code{nev} largest (in magnitude)
-	  eigenvalues.}
-	\item{\sQuote{\code{SM}}}{Compute \code{nev} smallest (in magnitude)
-	  eigenvalues.}
-	\item{\sQuote{\code{BE}}}{Compute \code{nev} eigenvalues, half
-	  from each end of the spectrum. When \code{nev} is odd, compute
-	  one more from the high end than from the low end.}
-      }
+The \code{options} argument specifies what kind of calculation to perform.
+It is a list with the following members, they correspond directly to ARPACK
+parameters. On input it has the following fields: \describe{
+\item{bmat}{Character constant, possible values: \sQuote{\code{I}}, stadard
+eigenvalue problem, \eqn{Ax=\lambda x}{A*x=lambda*x}; and \sQuote{\code{G}},
+generalized eigenvalue problem, \eqn{Ax=\lambda B x}{A*x=lambda B*x}.
+Currently only \sQuote{\code{I}} is supported.} \item{n}{Numeric scalar. The
+dimension of the eigenproblem. You only need to set this if you call
+\code{\link{arpack}} directly. (I.e. not needed for
+\code{\link{eigen_centrality}}, \code{\link{page_rank}}, etc.)}
+\item{which}{Specify which eigenvalues/vectors to compute, character
+constant with exactly two characters.
 
-      Possible values for non-symmetric input matrices:
-      \describe{
-	\item{\sQuote{\code{LM}}}{Compute \code{nev} eigenvalues of
-	  largest magnitude.}
-	\item{\sQuote{\code{SM}}}{Compute \code{nev} eigenvalues of
-	  smallest magnitude.}
-	\item{\sQuote{\code{LR}}}{Compute \code{nev} eigenvalues of
-	  largest real part.}
-	\item{\sQuote{\code{SR}}}{Compute \code{nev} eigenvalues of
-	  smallest real part.}
-	\item{\sQuote{\code{LI}}}{Compute \code{nev} eigenvalues of
-	  largest imaginary part.}
-	\item{\sQuote{\code{SI}}}{Compute \code{nev} eigenvalues of
-	  smallest imaginary part.}
-      }	
+Possible values for symmetric input matrices: \describe{
+\item{"LA"}{Compute \code{nev} largest (algebraic) eigenvalues.}
+\item{"SA"}{Compute \code{nev} smallest (algebraic)
+eigenvalues.} \item{"LM"}{Compute \code{nev} largest (in
+magnitude) eigenvalues.} \item{"SM"}{Compute \code{nev} smallest
+(in magnitude) eigenvalues.} \item{"BE"}{Compute \code{nev}
+eigenvalues, half from each end of the spectrum. When \code{nev} is odd,
+compute one more from the high end than from the low end.} }
 
-      This parameter is sometimes overwritten by the various functions,
-      e.g. \code{\link{page.rank}} always sets \sQuote{\code{LM}}.
-    }
-    \item{nev}{Numeric scalar. The number of eigenvalues to be computed.}
-    \item{tol}{Numeric scalar. Stopping criterion: the relative accuracy
-      of the Ritz value is considered acceptable if its error is less
-      than \code{tol} times its estimated value. If this is set to zero
-      then machine precision is used.}
-    \item{ncv}{Number of Lanczos vectors to be generated.}
-    \item{ldv}{Numberic scalar. It should be set to
-      zero in the current implementation.}
-    \item{ishift}{Either zero or one. If zero then the shifts are
-      provided by the user via reverse communication. If one then exact
-      shifts with respect to the reduced tridiagonal matrix \eqn{T}.
-      Please always set this to one.}
-    \item{maxiter}{Maximum number of Arnoldi update iterations allowed. }
-    \item{nb}{Blocksize to be used in the recurrence. Please always
-      leave this on the default value, one.}
-    \item{mode}{The type of the eigenproblem to be solved.
-      Possible values if the input matrix is symmetric:
-      \describe{
-	\item{1}{\eqn{Ax=\lambda x}{A*x=lambda*x}, \eqn{A} is symmetric.}
-	\item{2}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{A} is
-	  symmetric, \eqn{M} is symmetric positive definite.}
-	\item{3}{\eqn{Kx=\lambda Mx}{K*x=lambda*M*x}, \eqn{K} is
-	  symmetric, \eqn{M} is symmetric positive semi-definite.}
-	\item{4}{\eqn{Kx=\lambda KGx}{K*x=lambda*KG*x}, \eqn{K} is
-	  symmetric positive semi-definite, \eqn{KG} is symmetric
-	  indefinite.}
-	\item{5}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{A} is
-	  symmetric, \eqn{M} is symmetric positive
-	  semi-definite. (Cayley transformed mode.)}
-      }
-      Please note that only \code{mode==1} was tested and other values
-      might not work properly.
+Possible values for non-symmetric input matrices: \describe{
+\item{"LM"}{Compute \code{nev} eigenvalues of largest
+magnitude.} \item{"SM"}{Compute \code{nev} eigenvalues of
+smallest magnitude.} \item{"LR"}{Compute \code{nev} eigenvalues
+of largest real part.} \item{"SR"}{Compute \code{nev}
+eigenvalues of smallest real part.} \item{"LI"}{Compute
+\code{nev} eigenvalues of largest imaginary part.}
+\item{"SI"}{Compute \code{nev} eigenvalues of smallest imaginary
+part.} }
 
-      Possible values if the input matrix is not symmetric:
-      \describe{
-	\item{1}{\eqn{Ax=\lambda x}{A*x=lambda*x}.}
-	\item{2}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is
-	  symmetric positive definite.}
-	\item{3}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is
-	  symmetric semi-definite.}
-	\item{4}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is
-	      symmetric semi-definite.}
-      }
-      Please note that only \code{mode==1} was tested and other values
-      might not work properly.
-    }
-    \item{start}{Not used currently. Later it be used to set a starting
-      vector.}
-    \item{sigma}{Not used currently.}
-    \item{sigmai}{Not use currently.}
+This parameter is sometimes overwritten by the various functions, e.g.
+\code{\link{page_rank}} always sets \sQuote{\code{LM}}.  }
+\item{nev}{Numeric scalar. The number of eigenvalues to be computed.}
+\item{tol}{Numeric scalar. Stopping criterion: the relative accuracy of the
+Ritz value is considered acceptable if its error is less than \code{tol}
+times its estimated value. If this is set to zero then machine precision is
+used.} \item{ncv}{Number of Lanczos vectors to be generated.}
+\item{ldv}{Numberic scalar. It should be set to zero in the current
+implementation.} \item{ishift}{Either zero or one. If zero then the shifts
+are provided by the user via reverse communication. If one then exact shifts
+with respect to the reduced tridiagonal matrix \eqn{T}.  Please always set
+this to one.} \item{maxiter}{Maximum number of Arnoldi update iterations
+allowed. } \item{nb}{Blocksize to be used in the recurrence. Please always
+leave this on the default value, one.} \item{mode}{The type of the
+eigenproblem to be solved.  Possible values if the input matrix is
+symmetric: \describe{ \item{1}{\eqn{Ax=\lambda x}{A*x=lambda*x}, \eqn{A} is
+symmetric.} \item{2}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{A} is
+symmetric, \eqn{M} is symmetric positive definite.} \item{3}{\eqn{Kx=\lambda
+Mx}{K*x=lambda*M*x}, \eqn{K} is symmetric, \eqn{M} is symmetric positive
+semi-definite.} \item{4}{\eqn{Kx=\lambda KGx}{K*x=lambda*KG*x}, \eqn{K} is
+symmetric positive semi-definite, \eqn{KG} is symmetric indefinite.}
+\item{5}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{A} is symmetric, \eqn{M}
+is symmetric positive semi-definite. (Cayley transformed mode.)} } Please
+note that only \code{mode==1} was tested and other values might not work
+properly.
 
-    On output the following additional fields are added:
-    \describe{
-      \item{info}{Error flag of ARPACK. Possible values:
-	\describe{
-	  \item{0}{Normal exit.}
-	  \item{1}{Maximum number of iterations taken.}
-	  \item{3}{No shifts could be applied during a cycle of the
-	    Implicitly restarted Arnoldi iteration. One possibility
-	    is to increase the size of \code{ncv} relative to \code{nev}.}
-	}
+Possible values if the input matrix is not symmetric: \describe{
+\item{1}{\eqn{Ax=\lambda x}{A*x=lambda*x}.} \item{2}{\eqn{Ax=\lambda
+Mx}{A*x=lambda*M*x}, \eqn{M} is symmetric positive definite.}
+\item{3}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is symmetric
+semi-definite.} \item{4}{\eqn{Ax=\lambda Mx}{A*x=lambda*M*x}, \eqn{M} is
+symmetric semi-definite.} } Please note that only \code{mode==1} was tested
+and other values might not work properly.  } \item{start}{Not used
+currently. Later it be used to set a starting vector.} \item{sigma}{Not used
+currently.} \item{sigmai}{Not use currently.}
 
-	ARPACK can return more error conditions than these, but they are
-	converted to regular igraph errors.
-      }
-      \item{iter}{Number of Arnoldi iterations taken.}
-      \item{nconv}{Number of \dQuote{converged} Ritz values. This
-	represents the number of Ritz values that satisfy the
-	convergence critetion. }
-      \item{numop}{Total number of matrix-vector multiplications.}
-      \item{numopb}{Not used currently.}
-      \item{numreo}{Total number of steps of re-orthogonalization.}
-    }
-  }
-  Please see the ARPACK documentation for additional details.
+On output the following additional fields are added: \describe{
+\item{info}{Error flag of ARPACK. Possible values: \describe{
+\item{0}{Normal exit.} \item{1}{Maximum number of iterations taken.}
+\item{3}{No shifts could be applied during a cycle of the Implicitly
+restarted Arnoldi iteration. One possibility is to increase the size of
+\code{ncv} relative to \code{nev}.} }
 
-  \code{arpack.unpack.complex} is a (semi-)internal function that
-  converts the output of the non-symmetric ARPACK solver to a more
-  readable format. It is called internally by \code{arpack}.
-  
-}
-\value{
-  A named list with the following members:
-  \item{values}{Numeric vector, the desired eigenvalues.}
-  \item{vectors}{Numeric matrix, the desired eigenvectors as
-    columns. If \code{complex=TRUE} (the default for non-symmetric
-    problems), then the matrix is complex.}
-  \item{options}{A named list with the supplied \code{options} and
-    some information about the performed calculation, including an
-    ARPACK exit code. See the details above.
-  }
-}
-\references{
-  D.C. Sorensen, Implicit Application of Polynomial Filters in
-  a k-Step Arnoldi Method. \emph{SIAM J. Matr. Anal. Apps.}, 13 (1992),
-  pp 357-385.
-  
-  R.B. Lehoucq, Analysis and Implementation of an Implicitly
-  Restarted Arnoldi Iteration. \emph{Rice University Technical Report}
-  TR95-13, Department of Computational and Applied Mathematics.
-  
-  B.N. Parlett & Y. Saad, Complex Shift and Invert Strategies for
-  Real Matrices. \emph{Linear Algebra and its Applications}, vol 88/89,
-  pp 575-595, (1987).
-}
-\author{Rich Lehoucq, Kristi Maschhoff, Danny Sorensen, Chao Yang for
-  ARPACK, Gabor Csardi \email{csardi.gabor at gmail.com} for the R interface.}
-\seealso{\code{\link{evcent}}, \code{\link{page.rank}},
-  \code{\link{hub.score}}, \code{\link{leading.eigenvector.community}}
-  are some of the functions in igraph which use ARPACK. The ARPACK
-  homepage is at \url{http://www.caam.rice.edu/software/ARPACK/}.
+ARPACK can return more error conditions than these, but they are converted
+to regular igraph errors.  } \item{iter}{Number of Arnoldi iterations
+taken.} \item{nconv}{Number of \dQuote{converged} Ritz values. This
+represents the number of Ritz values that satisfy the convergence critetion.
+} \item{numop}{Total number of matrix-vector multiplications.}
+\item{numopb}{Not used currently.} \item{numreo}{Total number of steps of
+re-orthogonalization.} } } Please see the ARPACK documentation for
+additional details.
 }
 \examples{
 # Identity matrix
@@ -245,16 +189,41 @@ f <- function(x, extra=NULL) {
 arpack(f, options=list(n=10, nev=1, ncv=3), sym=TRUE)
 
 # double check
-eigen(graph.laplacian(graph.star(10, mode="undirected")))
+eigen(laplacian_matrix(make_star(10, mode="undirected")))
 
 ## First three eigenvalues of the adjacency matrix of a graph
 ## We need the 'Matrix' package for this
 if (require(Matrix)) {
-  g <- erdos.renyi.game(1000, 5/1000)
-  M <- get.adjacency(g, sparse=TRUE)
+  g <- sample_gnp(1000, 5/1000)
+  M <- as_adj(g, sparse=TRUE)
   f2 <- function(x, extra=NULL) { cat("."); as.vector(M \%*\% x) }
   baev <- arpack(f2, sym=TRUE, options=list(n=vcount(g), nev=3, ncv=8,
                                   which="LM", maxiter=200))
 }
 }
+\author{
+Rich Lehoucq, Kristi Maschhoff, Danny Sorensen, Chao Yang for
+ARPACK, Gabor Csardi \email{csardi.gabor at gmail.com} for the R interface.
+}
+\references{
+D.C. Sorensen, Implicit Application of Polynomial Filters in a
+k-Step Arnoldi Method. \emph{SIAM J. Matr. Anal. Apps.}, 13 (1992), pp
+357-385.
+
+R.B. Lehoucq, Analysis and Implementation of an Implicitly Restarted Arnoldi
+Iteration. \emph{Rice University Technical Report} TR95-13, Department of
+Computational and Applied Mathematics.
+
+B.N. Parlett & Y. Saad, Complex Shift and Invert Strategies for Real
+Matrices. \emph{Linear Algebra and its Applications}, vol 88/89, pp 575-595,
+(1987).
+}
+\seealso{
+\code{\link{eigen_centrality}}, \code{\link{page_rank}},
+\code{\link{hub_score}}, \code{\link{cluster_leading_eigen}} are some of the
+functions in igraph which use ARPACK. The ARPACK homepage is at
+\url{http://www.caam.rice.edu/software/ARPACK/}.
+}
+\keyword{datasets}
 \keyword{graphs}
+
diff --git a/man/articulation.points.Rd b/man/articulation.points.Rd
deleted file mode 100644
index b55ee25..0000000
--- a/man/articulation.points.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-\name{articulation.points}
-\alias{articulation.points}
-\concept{Articulation point}
-\title{Articulation points of a graph}
-\description{Articuation points or cut vertices are vertices whose
-  removal increases the number of connected components in a graph.}
-\usage{
-articulation.points(graph)
-}
-\arguments{
-  \item{graph}{The input graph. It is treated as an undirected graph,
-    even if it is directed.}
-}
-\details{
-  Articuation points or cut vertices are vertices whose
-  removal increases the number of connected components in a graph. If
-  the original graph was connected, then the removal of a single
-  articulation point makes it undirected. If a graph contains no
-  articulation points, then its vertex connectivity is at least two.  
-}
-\value{A numeric vector giving the vertex ids of the articulation points
-  of the input graph.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{biconnected.components}}, \code{\link{clusters}},
-  \code{\link{is.connected}}, \code{\link{vertex.connectivity}}}
-\examples{
-g <- graph.disjoint.union( graph.full(5), graph.full(5) )
-clu <- clusters(g)$membership
-g <- add.edges(g, c(match(1, clu), match(2, clu)) )
-articulation.points(g)
-}
-\keyword{graphs}
diff --git a/man/articulation_points.Rd b/man/articulation_points.Rd
new file mode 100644
index 0000000..f7995a4
--- /dev/null
+++ b/man/articulation_points.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/components.R
+\name{articulation_points}
+\alias{articulation.points}
+\alias{articulation_points}
+\title{Articulation points of a graph}
+\usage{
+articulation_points(graph)
+}
+\arguments{
+\item{graph}{The input graph. It is treated as an undirected graph, even if
+it is directed.}
+}
+\value{
+A numeric vector giving the vertex ids of the articulation points of
+the input graph.
+}
+\description{
+Articuation points or cut vertices are vertices whose removal increases the
+number of connected components in a graph.
+}
+\details{
+Articuation points or cut vertices are vertices whose removal increases the
+number of connected components in a graph. If the original graph was
+connected, then the removal of a single articulation point makes it
+undirected. If a graph contains no articulation points, then its vertex
+connectivity is at least two.
+}
+\examples{
+g <- disjoint_union( make_full_graph(5), make_full_graph(5) )
+clu <- components(g)$membership
+g <- add_edges(g, c(match(1, clu), match(2, clu)) )
+articulation_points(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{biconnected_components}}, \code{\link{components}},
+\code{\link{is_connected}}, \code{\link{vertex_connectivity}}
+}
+\keyword{graphs}
+
diff --git a/man/as.directed.Rd b/man/as.directed.Rd
index 4e278f4..cdf4e7d 100644
--- a/man/as.directed.Rd
+++ b/man/as.directed.Rd
@@ -1,78 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
 \name{as.directed}
 \alias{as.directed}
 \alias{as.undirected}
-\concept{Directed graph}
-\concept{Undirected graph}
 \title{Convert between directed and undirected graphs}
-\description{\code{as.directed} converts an undirected graph to
-  directed, \code{as.undirected} does the opposite, it converts a directed
-  graph to undirected.}
 \usage{
-as.directed(graph, mode = c("mutual", "arbitrary")) 
+as.directed(graph, mode = c("mutual", "arbitrary"))
+
 as.undirected(graph, mode = c("collapse", "each", "mutual"),
-       edge.attr.comb = getIgraphOpt("edge.attr.comb"))
+  edge.attr.comb = igraph_opt("edge.attr.comb"))
 }
 \arguments{
-  \item{graph}{The graph to convert.}
-  \item{mode}{Character constant, defines the conversion algorithm. For
-    \code{as.directed} it can be \code{mutual} or \code{arbitrary}. For
-    \code{as.undirected} it can be \code{each}, \code{collapse} or
-    \code{mutual}. See details below.}
-  \item{edge.attr.comb}{Specifies what to do with edge attributes, if
-    \code{mode="collapse"} or \code{mode="mutual"}.
-    In these cases many edges might be mapped to a
-    single one in the new graph, and their attributes are
-    combined. Please see \code{\link{attribute.combination}} for details
-    on this.}
-}
-\details{
-  Conversion algorithms for \code{as.directed}:
-  \describe{
-    \item{\code{arbitrary}}{The number of
-      edges in the graph stays the same, an arbitrarily directed edge is
-      created for each undirected edge.}
-    \item{\code{mutual}}{Two directed edges are created for each undirected
-      edge, one in each direction.}
-  }
+\item{graph}{The graph to convert.}
 
-  Conversion algorithms for \code{as.undirected}:
-  \describe{
-    \item{\code{each}}{The number of edges remains constant, an
-      undirected edge is created for each directed one, this version
-      might create graphs with multiple edges.}
-    \item{\code{collapse}}{One undirected edge will be created for each
-      pair of vertices which are connected with at least one directed
-      edge, no multiple edges will be created.}
-    \item{\code{mutual}}{One undirected edge will be created for each
-      pair of mutual edges. Non-mutual edges are ignored. This mode
-      might create multiple edges if there are more than one mutual edge
-      pairs between the same pair of vertices.
-    }
-  }
+\item{mode}{Character constant, defines the conversion algorithm. For
+\code{as.directed} it can be \code{mutual} or \code{arbitrary}. For
+\code{as.undirected} it can be \code{each}, \code{collapse} or
+\code{mutual}. See details below.}
+
+\item{edge.attr.comb}{Specifies what to do with edge attributes, if
+\code{mode="collapse"} or \code{mode="mutual"}.  In these cases many edges
+might be mapped to a single one in the new graph, and their attributes are
+combined. Please see \code{\link{attribute.combination}} for details on
+this.}
 }
 \value{
-  A new graph object.
+A new graph object.
+}
+\description{
+\code{as.directed} converts an undirected graph to directed,
+\code{as.undirected} does the opposite, it converts a directed graph to
+undirected.
+}
+\details{
+Conversion algorithms for \code{as.directed}: \describe{
+\item{"arbitrary"}{The number of edges in the graph stays the same, an
+arbitrarily directed edge is created for each undirected edge.}
+\item{"mutual"}{Two directed edges are created for each undirected
+edge, one in each direction.} }
+
+Conversion algorithms for \code{as.undirected}: \describe{
+\item{"each"}{The number of edges remains constant, an undirected edge
+is created for each directed one, this version might create graphs with
+multiple edges.} \item{"collapse"}{One undirected edge will be created
+for each pair of vertices which are connected with at least one directed
+edge, no multiple edges will be created.} \item{"mutual"}{One
+undirected edge will be created for each pair of mutual edges. Non-mutual
+edges are ignored. This mode might create multiple edges if there are more
+than one mutual edge pairs between the same pair of vertices.  } }
 }
-%\references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{simplify}} for removing multiple and/or loop edges
-  from a graph.}
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 as.directed(g, "mutual")
-g2 <- graph.star(10)
+g2 <- make_star(10)
 as.undirected(g)
 
 # Combining edge attributes
-g3 <- graph.ring(10, directed=TRUE, mutual=TRUE)
+g3 <- make_ring(10, directed=TRUE, mutual=TRUE)
 E(g3)$weight <- seq_len(ecount(g3))
 ug3 <- as.undirected(g3)
 print(ug3, e=TRUE)
 \dontrun{
   x11(width=10, height=5)
   layout(rbind(1:2))
-  plot( g3, layout=layout.circle, edge.label=E(g3)$weight)
-  plot(ug3, layout=layout.circle, edge.label=E(ug3)$weight)
+  plot( g3, layout=layout_in_circle, edge.label=E(g3)$weight)
+  plot(ug3, layout=layout_in_circle, edge.label=E(ug3)$weight)
 }
 
 g4 <- graph(c(1,2, 3,2,3,4,3,4, 5,4,5,4,
@@ -83,4 +75,12 @@ ug4 <- as.undirected(g4, mode="mutual",
               edge.attr.comb=list(weight=length))
 print(ug4, e=TRUE)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{simplify}} for removing multiple and/or loop edges from
+a graph.
+}
 \keyword{graphs}
+
diff --git a/man/as.igraph.Rd b/man/as.igraph.Rd
index 0707087..8ed3976 100644
--- a/man/as.igraph.Rd
+++ b/man/as.igraph.Rd
@@ -1,33 +1,36 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
 \name{as.igraph}
 \alias{as.igraph}
 \alias{as.igraph.igraphHRG}
-\concept{Hierarchical random graphs}
 \title{Conversion to igraph}
-\description{These fucntions convert various objects to igraph graphs.}
 \usage{
-\method{as.igraph}{igraphHRG}(x, \dots)
+as.igraph(x, ...)
 }
 \arguments{
-  \item{x}{The object to convert.}
-  \item{\dots}{Additional arguments. None currently.}
-}
-\details{
-  You can use \code{as.igraph} to convert various objects to igraph
-  graphs. Right now the following objects are supported:
-  \itemize{
-    \item code{igraphHRG} These objects are created by the
-    \code{\link{hrg.fit}} and \code{\link{hrg.consensus}} functions.
-  }
+\item{x}{The object to convert.}
+
+\item{\dots}{Additional arguments. None currently.}
 }
 \value{
-  All these functions return an igraph graph.
+All these functions return an igraph graph.
+}
+\description{
+These fucntions convert various objects to igraph graphs.
+}
+\details{
+You can use \code{as.igraph} to convert various objects to igraph graphs.
+Right now the following objects are supported: \itemize{ \item codeigraphHRG
+These objects are created by the \code{\link{fit_hrg}} and
+\code{\link{consensus_tree}} functions.  }
 }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}.}
-% \seealso{}
 \examples{
-g <- graph.full(5) + graph.full(5)
-hrg <- hrg.fit(g)
+g <- make_full_graph(5) + make_full_graph(5)
+hrg <- fit_hrg(g)
 as.igraph(hrg)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}.
+}
 \keyword{graphs}
+
diff --git a/man/as_adj_list.Rd b/man/as_adj_list.Rd
new file mode 100644
index 0000000..9bbf8b3
--- /dev/null
+++ b/man/as_adj_list.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{as_adj_list}
+\alias{as_adj_edge_list}
+\alias{as_adj_list}
+\alias{get.adjedgelist}
+\alias{get.adjlist}
+\title{Adjacency lists}
+\usage{
+as_adj_list(graph, mode = c("all", "out", "in", "total"))
+
+as_adj_edge_list(graph, mode = c("all", "out", "in", "total"))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{mode}{Character scalar, it gives what kind of adjacent edges/vertices
+to include in the lists. \sQuote{\code{out}} is for outgoing edges/vertices,
+\sQuote{\code{in}} is for incoming edges/vertices, \sQuote{\code{all}} is
+for both. This argument is ignored for undirected graphs.}
+}
+\value{
+A list of numeric vectors.
+}
+\description{
+Create adjacency lists from a graph, either for adjacent edges or for
+neighboring vertices
+}
+\details{
+\code{as_adj_list} returns a list of numeric vectors, which include the ids
+of neighbor vertices (according to the \code{mode} argument) of all
+vertices.
+
+\code{as_adj_edge_list} returns a list of numeric vectors, which include the
+ids of adjacent edgs (according to the \code{mode} argument) of all
+vertices.
+}
+\examples{
+g <- make_ring(10)
+as_adj_list(g)
+as_adj_edge_list(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{as_edgelist}}, \code{\link{as_adj}}
+}
+\keyword{graphs}
+
diff --git a/man/as_adjacency_matrix.Rd b/man/as_adjacency_matrix.Rd
new file mode 100644
index 0000000..7f42c7c
--- /dev/null
+++ b/man/as_adjacency_matrix.Rd
@@ -0,0 +1,73 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{as_adjacency_matrix}
+\alias{as_adj}
+\alias{as_adjacency_matrix}
+\alias{get.adjacency}
+\title{Convert a graph to an adjacency matrix}
+\usage{
+as_adjacency_matrix(graph, type = c("both", "upper", "lower"), attr = NULL,
+  edges = FALSE, names = TRUE, sparse = igraph_opt("sparsematrices"))
+
+as_adj(graph, type = c("both", "upper", "lower"), attr = NULL,
+  edges = FALSE, names = TRUE, sparse = igraph_opt("sparsematrices"))
+}
+\arguments{
+\item{graph}{The graph to convert.}
+
+\item{type}{Gives how to create the adjacency matrix for undirected graphs.
+It is ignored for directed graphs. Possible values: \code{upper}: the upper
+right triangle of the matrix is used, \code{lower}: the lower left triangle
+of the matrix is used. \code{both}: the whole matrix is used, a symmetric
+matrix is returned.}
+
+\item{attr}{Either \code{NULL} or a character string giving an edge
+attribute name. If \code{NULL} a traditional adjacency matrix is returned.
+If not \code{NULL} then the values of the given edge attribute are included
+in the adjacency matrix. If the graph has multiple edges, the edge attribute
+of an arbitrarily chosen edge (for the multiple edges) is included. This
+argument is ignored if \code{edges} is \code{TRUE}.
+
+Note that this works only for certain attribute types. If the \code{sparse}
+argumen is \code{TRUE}, then the attribute must be either logical or
+numeric. If the \code{sparse} argument is \code{FALSE}, then character is
+also allowed. The reason for the difference is that the \code{Matrix}
+package does not support character sparse matrices yet.}
+
+\item{edges}{Logical scalar, whether to return the edge ids in the matrix.
+For non-existant edges zero is returned.}
+
+\item{names}{Logical constant, whether to assign row and column names
+to the matrix. These are only assigned if the \code{name} vertex attribute
+is present in the graph.}
+
+\item{sparse}{Logical scalar, whether to create a sparse matrix. The
+\sQuote{\code{Matrix}} package must be installed for creating sparse
+matrices.}
+}
+\value{
+A \code{vcount(graph)} by \code{vcount(graph)} (usually) numeric
+matrix.
+}
+\description{
+Sometimes it is useful to work with a standard representation of a
+graph, like an adjacency matrix.
+}
+\details{
+\code{as_adjacency_matrix} returns the adjacency matrix of a graph, a
+regular matrix if \code{sparse} is \code{FALSE}, or a sparse matrix, as
+defined in the \sQuote{\code{Matrix}} package, if \code{sparse} if
+\code{TRUE}.
+}
+\examples{
+g <- sample_gnp(10, 2/10)
+as_adjacency_matrix(g)
+V(g)$name <- letters[1:vcount(g)]
+as_adjacency_matrix(g)
+E(g)$weight <- runif(ecount(g))
+as_adjacency_matrix(g, attr="weight")
+}
+\seealso{
+\code{\link{graph_from_adjacency_matrix}}, \code{\link{read_graph}}
+}
+
diff --git a/man/as_edgelist.Rd b/man/as_edgelist.Rd
new file mode 100644
index 0000000..61d340d
--- /dev/null
+++ b/man/as_edgelist.Rd
@@ -0,0 +1,38 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{as_edgelist}
+\alias{as_edgelist}
+\alias{get.edgelist}
+\title{Convert a graph to an edge list}
+\usage{
+as_edgelist(graph, names = TRUE)
+}
+\arguments{
+\item{graph}{The graph to convert.}
+
+\item{names}{Whether to return a character matrix containing vertex
+names (ie. the \code{name} vertex attribute) if they exist or numeric
+vertex ids.}
+}
+\value{
+A \code{gsize(graph)} by 2 numeric matrix.
+}
+\description{
+Sometimes it is useful to work with a standard representation of a
+graph, like an edge list.
+}
+\details{
+\code{as_edgelist} returns the list of edges in a graph.
+}
+\examples{
+g <- sample_gnp(10, 2/10)
+as_edgelist(g)
+
+V(g)$name <- LETTERS[seq_len(gorder(g))]
+as_edgelist(g)
+}
+\seealso{
+\code{\link{graph_from_adjacency_matrix}}, \code{\link{read_graph}}
+}
+\keyword{graphs}
+
diff --git a/man/as_graphnel.Rd b/man/as_graphnel.Rd
new file mode 100644
index 0000000..3d4a3f7
--- /dev/null
+++ b/man/as_graphnel.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{as_graphnel}
+\alias{as_graphnel}
+\alias{igraph.to.graphNEL}
+\title{Convert igraph graphs to graphNEL objects from the graph package}
+\usage{
+as_graphnel(graph)
+}
+\arguments{
+\item{graph}{An igraph graph object.}
+}
+\value{
+\code{as_graphnel} returns a graphNEL graph object.
+}
+\description{
+The graphNEL class is defined in the \code{graph} package, it is another
+way to represent graphs. These functions are provided to convert between
+the igraph and the graphNEL objects.
+}
+\details{
+\code{as_graphnel} converts and igraph graph to a graphNEL graph. It
+converts all graph/vertex/edge attributes. If the igraph graph has a
+vertex attribute \sQuote{\code{name}}, then it will be used to assign
+vertex names in the graphNEL graph. Otherwise numeric igraph vertex ids
+will be used for this purpose.
+}
+\examples{
+## Undirected
+\dontrun{
+g <- make_ring(10)
+V(g)$name <- letters[1:10]
+GNEL <- as_graphnel(g)
+g2 <- graph_from_graphnel(GNEL)
+g2
+
+## Directed
+g3 <- make_star(10, mode="in")
+V(g3)$name <- letters[1:10]
+GNEL2 <- as_graphnel(g3)
+g4 <- graph_from_graphnel(GNEL2)
+g4
+}
+#'
+}
+\seealso{
+\code{\link{graph_from_graphnel}} for the other direction,
+\code{\link{as_adj}}, \code{\link{graph_from_adjacency_matrix}},
+\code{\link{as_adj_list}} and \code{\link{graph.adjlist}} for
+other graph representations.
+}
+
diff --git a/man/as_ids.Rd b/man/as_ids.Rd
new file mode 100644
index 0000000..e8638ff
--- /dev/null
+++ b/man/as_ids.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{as_ids}
+\alias{as_ids}
+\alias{as_ids.igraph.es}
+\alias{as_ids.igraph.vs}
+\title{Convert a vertex or edge sequence to an ordinary vector}
+\usage{
+as_ids(seq)
+
+\method{as_ids}{igraph.vs}(seq)
+
+\method{as_ids}{igraph.es}(seq)
+}
+\arguments{
+\item{seq}{The vertex or edge sequence.}
+}
+\value{
+A character or numeric vector, see details below.
+}
+\description{
+Convert a vertex or edge sequence to an ordinary vector
+}
+\details{
+For graphs without names, a numeric vector is returned, containing the
+internal numeric vertex or edge ids.
+
+For graphs with names, and vertex sequences, the vertex names are
+returned in a character vector.
+
+For graphs with names and edge sequences, a character vector is
+returned, with the \sQuote{bar} notation: \code{a|b} means an edge from
+vertex \code{a} to vertex \code{b}.
+}
+\examples{
+g <- make_ring(10)
+as_ids(V(g))
+as_ids(E(g))
+
+V(g)$name <- letters[1:10]
+as_ids(V(g))
+as_ids(E(g))
+}
+
diff --git a/man/as_incidence_matrix.Rd b/man/as_incidence_matrix.Rd
new file mode 100644
index 0000000..945a58f
--- /dev/null
+++ b/man/as_incidence_matrix.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{as_incidence_matrix}
+\alias{as_incidence_matrix}
+\alias{get.incidence}
+\title{Incidence matrix of a bipartite graph}
+\usage{
+as_incidence_matrix(graph, types = NULL, attr = NULL, names = TRUE,
+  sparse = FALSE)
+}
+\arguments{
+\item{graph}{The input graph. The direction of the edges is ignored in
+directed graphs.}
+
+\item{types}{An optional vertex type vector to use instead of the
+\code{type} vertex attribute. You must supply this argument if the graph has
+no \code{type} vertex attribute.}
+
+\item{attr}{Either \code{NULL} or a character string giving an edge
+attribute name. If \code{NULL}, then a traditional incidence matrix is
+returned. If not \code{NULL} then the values of the given edge attribute are
+included in the incidence matrix. If the graph has multiple edges, the edge
+attribute of an arbitrarily chosen edge (for the multiple edges) is
+included.}
+
+\item{names}{Logical scalar, if \code{TRUE} and the vertices in the graph
+are named (i.e. the graph has a vertex attribute called \code{name}), then
+vertex names will be added to the result as row and column names. Otherwise
+the ids of the vertices are used as row and column names.}
+
+\item{sparse}{Logical scalar, if it is \code{TRUE} then a sparse matrix is
+created, you will need the \code{Matrix} package for this.}
+}
+\value{
+A sparse or dense matrix.
+}
+\description{
+This function can return a sparse or dense incidence matrix of a bipartite
+network. The incidence matrix is an \eqn{n} times \eqn{m} matrix, \eqn{n}
+and \eqn{m} are the number of vertices of the two kinds.
+}
+\details{
+Bipartite graphs have a \code{type} vertex attribute in igraph, this is
+boolean and \code{FALSE} for the vertices of the first kind and \code{TRUE}
+for vertices of the second kind.
+}
+\examples{
+g <- make_bipartite_graph( c(0,1,0,1,0,0), c(1,2,2,3,3,4) )
+as_incidence_matrix(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{graph_from_incidence_matrix}} for the opposite operation.
+}
+\keyword{graphs}
+
diff --git a/man/as_long_data_frame.Rd b/man/as_long_data_frame.Rd
new file mode 100644
index 0000000..0dd40ed
--- /dev/null
+++ b/man/as_long_data_frame.Rd
@@ -0,0 +1,32 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{as_long_data_frame}
+\alias{as_long_data_frame}
+\title{Convert a graph to a long data frame}
+\usage{
+as_long_data_frame(graph)
+}
+\arguments{
+\item{graph}{Input graph}
+}
+\value{
+A long data frame.
+}
+\description{
+A long data frame contains all metadata about both the vertices
+and edges of the graph. It contains one row for each edge, and
+all metadata about that edge and its incident vertices are included
+in that row. The names of the columns that contain the metadata
+of the incident vertices are prefixed with \code{from_} and \code{to_}.
+The first two columns are always named \code{from} and \code{to} and
+they contain the numeric ids of the incident vertices. The rows are
+listed in the order of numeric vertex ids.
+}
+\examples{
+g <- make_(ring(10),
+        with_vertex_(name = letters[1:10], color = "red"),
+        with_edge_(weight = 1:10, color = "green")
+      )
+as_long_data_frame(g)
+}
+
diff --git a/man/as_membership.Rd b/man/as_membership.Rd
new file mode 100644
index 0000000..b8a8f9a
--- /dev/null
+++ b/man/as_membership.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{as_membership}
+\alias{as_membership}
+\title{Declare a numeric vector as a membership vector}
+\usage{
+as_membership(x)
+}
+\arguments{
+\item{x}{The input vector.}
+}
+\value{
+The input vector, with the \code{membership} class added.
+}
+\description{
+This is useful if you want to use functions defined on
+membership vectors, but your membership vector does not
+come from an igraph clustering method.
+}
+\examples{
+## Compare to the correct clustering
+g <- (make_full_graph(10) + make_full_graph(10)) \%>\%
+  rewire(each_edge(p = 0.2))
+correct <- rep(1:2, each = 10) \%>\% as_membership
+fc <- cluster_fast_greedy(g)
+compare(correct, fc)
+compare(correct, membership(fc))
+}
+
diff --git a/man/assortativity.Rd b/man/assortativity.Rd
index 6701c94..d46d68c 100644
--- a/man/assortativity.Rd
+++ b/man/assortativity.Rd
@@ -1,107 +1,104 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/assortativity.R
 \name{assortativity}
 \alias{assortativity}
 \alias{assortativity.degree}
 \alias{assortativity.nominal}
-\concept{Assortativity coefficient}
+\alias{assortativity_degree}
+\alias{assortativity_nominal}
 \title{Assortativity coefficient}
-\description{
-  The assortativity coefficient is positive is similar vertices (based
-  on some external property) tend to connect to each, and negative
-  otherwise.
-}
 \usage{
-assortativity (graph, types1, types2 = NULL, directed = TRUE) 
-assortativity.nominal (graph, types, directed = TRUE) 
-assortativity.degree (graph, directed = TRUE) 
+assortativity(graph, types1, types2 = NULL, directed = TRUE)
+
+assortativity_nominal(graph, types, directed = TRUE)
+
+assortativity_degree(graph, directed = TRUE)
 }
 \arguments{
-  \item{graph}{The input graph, it can be directed or undirected.}
-  \item{types}{Vector giving the vertex types. They as assumed to be
-    integer numbers, starting with one. Non-integer values are
-    converted to integers with \code{\link{as.integer}}.}
-  \item{types1}{The vertex values, these can be arbitrary numeric
-    values.}
-  \item{types2}{A second value vector to be using for the incoming
-    edges when calculating assortativity for a directed graph. 
-    Supply \code{NULL} here if you want to use the same values
-    for outgoing and incoming edges. This argument is ignored
-    (with a warning) if it is not \code{NULL} and undirected
-    assortativity coefficient is being calculated.}
-  \item{directed}{Logical scalar, whether to consider edge directions
-    for directed graphs. This argument is ignored for undirected
-    graphs. Supply \code{TRUE} here to do the natural thing, i.e. use
-    directed version of the measure for directed graphs and the
-    undirected version for undirected graphs.}
-}
-\details{
-  The assortativity coefficient measures the level of homophyly of the
-  graph, based on some vertex labeling or values assigned to
-  vertices. If the coefficient is high, that means that connected
-  vertices tend to have the same labels or similar assigned values.
-  
-  M.E.J. Newman defined two kinds of assortativity coefficients, the
-  first one is for categorical labels of
-  vertices. \code{assortativity.nominal} calculates this measure. It is
-  defines as
-
-  \deqn{r=\frac{\sum_i e_{ii}-\sum_i a_i b_i}{1-\sum_i a_i b_i}}{
-    r=(sum(e(i,i), i) - sum(a(i)b(i), i)) / (1 - sum(a(i)b(i), i))}
-
-  where \eqn{e_{ij}}{e(i,j)} is the fraction of edges connecting vertices
-  of type \eqn{i} and \eqn{j},
-  \eqn{a_i=\sum_j e_{ij}}{a(i)=sum(e(i,j), j)} and
-  \eqn{b_j=\sum_i e_{ij}}{b(j)=sum(e(i,j), i)}.
-  
-  The second assortativity variant is based on values assigned to the
-  vertices. \code{assortativity} calculates this measure. It is defined
-  as
-
-  \deqn{r=\frac1{\sigma_q^2}\sum_{jk} jk(e_{jk}-q_j q_k)}{
-    sum(jk(e(j,k)-q(j)q(k)), j, k) / sigma(q)^2}
-
-  for undirected graphs (\eqn{q_i=\sum_j e_{ij}}{q(i)=sum(e(i,j), j)})
-  and as 
-
-  \deqn{r=\frac1{\sigma_o\sigma_i}\sum_{jk}jk(e_{jk}-q_j^o q_k^i)}{
-    sum(jk(e(j,k)-qout(j)qin(k)), j, k) / sigma(qin) / sigma(qout)
-  }
-
-  for directed ones. Here
-  \eqn{q_i^o=\sum_j e_{ij}}{qout(i)=sum(e(i,j), j)},
-  \eqn{q_i^i=\sum_j e_{ji}}{qin(i)=sum(e(j,i), j)},
-  moreover, \eqn{\sigma_q}{sigma(q)},
-  \eqn{sigma_o}{sigma(qout)} and
-  \eqn{sigma_i}{sigma(qin)} are the standard deviations of \eqn{q},
-  \eqn{q^o}{qout} and \eqn{q^i}{qin}, respectively.
-
-  The reason of the difference is that in directed
-  networks the relationship is not symmetric, so it is possible to
-  assign different values to the outgoing and the incoming end of the
-  edges.
-
-  \code{assortativity.degree} uses vertex degree (minus one) as vertex
-  values and calls \code{assortativity}.
+\item{graph}{The input graph, it can be directed or undirected.}
+
+\item{types1}{The vertex values, these can be arbitrary numeric values.}
+
+\item{types2}{A second value vector to be using for the incoming edges when
+calculating assortativity for a directed graph.  Supply \code{NULL} here if
+you want to use the same values for outgoing and incoming edges. This
+argument is ignored (with a warning) if it is not \code{NULL} and undirected
+assortativity coefficient is being calculated.}
+
+\item{directed}{Logical scalar, whether to consider edge directions for
+directed graphs. This argument is ignored for undirected graphs. Supply
+\code{TRUE} here to do the natural thing, i.e. use directed version of the
+measure for directed graphs and the undirected version for undirected
+graphs.}
+
+\item{types}{Vector giving the vertex types. They as assumed to be integer
+numbers, starting with one. Non-integer values are converted to integers
+with \code{\link{as.integer}}.}
 }
 \value{
-  A single real number.
+A single real number.
 }
-\references{
- M. E. J. Newman: Mixing patterns in networks, \emph{Phys. Rev. E} 67,
- 026126 (2003) \url{http://arxiv.org/abs/cond-mat/0209450}
-
- M. E. J. Newman: Assortative mixing in networks,
- \emph{Phys. Rev. Lett.} 89, 208701 (2002)
- \url{http://arxiv.org/abs/cond-mat/0205405/}
+\description{
+The assortativity coefficient is positive is similar vertices (based on some
+external property) tend to connect to each, and negative otherwise.
 }
-\author{
-  Gabor Csardi \email{csardi.gabor at gmail.com}
+\details{
+The assortativity coefficient measures the level of homophyly of the graph,
+based on some vertex labeling or values assigned to vertices. If the
+coefficient is high, that means that connected vertices tend to have the
+same labels or similar assigned values.
+
+M.E.J. Newman defined two kinds of assortativity coefficients, the first one
+is for categorical labels of vertices. \code{assortativity_nominal}
+calculates this measure. It is defines as
+
+\deqn{r=\frac{\sum_i e_{ii}-\sum_i a_i b_i}{1-\sum_i a_i b_i}}{
+r=(sum(e(i,i), i) - sum(a(i)b(i), i)) / (1 - sum(a(i)b(i), i))}
+
+where \eqn{e_{ij}}{e(i,j)} is the fraction of edges connecting vertices of
+type \eqn{i} and \eqn{j}, \eqn{a_i=\sum_j e_{ij}}{a(i)=sum(e(i,j), j)} and
+\eqn{b_j=\sum_i e_{ij}}{b(j)=sum(e(i,j), i)}.
+
+The second assortativity variant is based on values assigned to the
+vertices. \code{assortativity} calculates this measure. It is defined as
+
+\deqn{r=\frac1{\sigma_q^2}\sum_{jk} jk(e_{jk}-q_j q_k)}{
+sum(jk(e(j,k)-q(j)q(k)), j, k) / sigma(q)^2}
+
+for undirected graphs (\eqn{q_i=\sum_j e_{ij}}{q(i)=sum(e(i,j), j)}) and as
+
+\deqn{r=\frac1{\sigma_o\sigma_i}\sum_{jk}jk(e_{jk}-q_j^o q_k^i)}{
+sum(jk(e(j,k)-qout(j)qin(k)), j, k) / sigma(qin) / sigma(qout) }
+
+for directed ones. Here \eqn{q_i^o=\sum_j e_{ij}}{qout(i)=sum(e(i,j), j)},
+\eqn{q_i^i=\sum_j e_{ji}}{qin(i)=sum(e(j,i), j)}, moreover,
+\eqn{\sigma_q}{sigma(q)}, \eqn{sigma_o}{sigma(qout)} and
+\eqn{sigma_i}{sigma(qin)} are the standard deviations of \eqn{q},
+\eqn{q^o}{qout} and \eqn{q^i}{qin}, respectively.
+
+The reason of the difference is that in directed networks the relationship
+is not symmetric, so it is possible to assign different values to the
+outgoing and the incoming end of the edges.
+
+\code{assortativity_degree} uses vertex degree (minus one) as vertex values
+and calls \code{assortativity}.
 }
-% \seealso{}
 \examples{
 # random network, close to zero
-assortativity.degree(erdos.renyi.game(10000,3/10000))
+assortativity_degree(sample_gnp(10000, 3/10000))
 
 # BA model, tends to be dissortative
-assortativity.degree(ba.game(10000, m=4))
+assortativity_degree(sample_pa(10000, m=4))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+M. E. J. Newman: Mixing patterns in networks, \emph{Phys. Rev.
+E} 67, 026126 (2003) \url{http://arxiv.org/abs/cond-mat/0209450}
+
+M. E. J. Newman: Assortative mixing in networks, \emph{Phys. Rev. Lett.} 89,
+208701 (2002) \url{http://arxiv.org/abs/cond-mat/0205405/}
 }
 \keyword{graphs}
+
diff --git a/man/attribute.combination.Rd b/man/attribute.combination.Rd
deleted file mode 100644
index c4bc39f..0000000
--- a/man/attribute.combination.Rd
+++ /dev/null
@@ -1,144 +0,0 @@
-\name{Combining attributes}
-\alias{attribute.combination}
-\concept{Vertex/edge/graph attributes}
-\title{How igraph functions handle attributes when the graph changes}
-\description{Many times, when the structure of a graph is modified,
-  vertices/edges map of the original graph map to vertices/edges in the
-  newly created (modified) graph. For example \code{\link{simplify}}
-  maps multiple edges to single edges. igraph provides a flexible
-  mechanism to specify what to do with the vertex/edge attributes in
-  these cases.}
-\details{
-  The functions that support the combination of attributes have one or
-  two extra arguments called \code{vertex.attr.comb} and/or
-  \code{edge.attr.comb} that specify how to perform the mapping of the
-  attributes. E.g. \code{\link{contract.vertices}} contracts many
-  vertices into a single one, the attributes of the vertices can be
-  combined and stores as the vertex attributes of the new graph.
-
-  The specification of the combination of (vertex or edge) attributes
-  can be given as
-  \enumerate{
-    \item{a character scalar,}
-    \item{a function object or}
-    \item{a list of character scalars and/or function objects.}
-  }
-
-  If it is a character scalar, then it refers to one of the predefined
-  combinations, see their list below.
-
-  If it is a function, then the given function is expected to perform
-  the combination. It will be called once for each new vertex/edge in
-  the graph, with a single argument: the attribute values of the
-  vertices that map to that single vertex.
-
-  The third option, a list can be used to specify different combination
-  methods for different attributes. A named entry of the list
-  corresponds to the attribute with the same name. An unnamed entry
-  (i.e. if the name is the empty string) of the list specifies the
-  default combination method. I.e.
-  \preformatted{list(weight="sum", "ignore")}
-  specifies that the weight of the new edge should be sum of the weights
-  of the corresponding edges in the old graph; and that the rest of the
-  attributes should be ignored (=dropped).
-}
-\section{Predefined combination functions}{
-  The following combination behaviors are predefined:
-  \describe{
-    \item{\sQuote{ignore}}{The attribute is ignored and dropped.}
-    \item{\sQuote{sum}}{The sum of the attributes is calculated. This
-      does not work for character attributes and works for complex
-      attributes only if they have a \code{sum} generic
-      defined. (E.g. it works for sparse matrices from the \code{Matrix}
-      package, because they have a \code{sum} method.)}
-    \item{\sQuote{prod}}{The product of the attributes is
-      calculated. This does not work for character attributes and 
-      works for complex attributes only if they have a \code{prod}
-      function defined.}
-    \item{\sQuote{min}}{The minimum of the attributes is calculated and
-      returned. For character and complex attributes the standard R
-      \code{min} function is used.}
-    \item{\sQuote{max}}{The maximum of the attributes is calculated and
-      returned. For character and complex attributes the standard R
-      \code{max} function is used.}
-    \item{\sQuote{random}}{Chooses one of the supplied attribute
-      values, uniformly randomly. For character and complex attributes
-      this is implemented by calling \code{sample}.}
-    \item{\sQuote{first}}{Always chooses the first attribute value. It
-      is implemented by calling the \code{head} function.}
-    \item{\sQuote{last}}{Always chooses the last attribute value. It is
-      implemented by calling the \code{tail} function.}
-    \item{\sQuote{mean}}{The mean of the attributes is calculated and
-      returned. For character and complex attributes this simply calls
-      the \code{mean} function.}
-    \item{\sQuote{median}}{The median of the attributes is
-      selected. Calls the R \code{median} function for all attribute
-      types.}
-    \item{\sQuote{concat}}{Concatenate the attributes, using the
-      \code{c} function. This results almost always a complex
-      attribute.}
-  }
-}
-\section{Specifying combination methods for all graphs}{
-  The are two standard igraph parameters that define the default
-  behavior when combining vertices and edges: \code{vertex.attr.comb}
-  specifies how to combine vertices by default, \code{edge.attr.comb}
-  does the same for edges.
-
-  E.g. if you want to drop all vertex attributes when combining
-  vertices, you can specify
-  \preformatted{igraph.options(vertex.attr.comb="ignore")}
-
-  As another example, if -- when combining edges -- you want to keep the
-  mean weight of the edges, concatenate their names into a single
-  character scalar, and drop everything else, then use
-  \preformatted{igraph.options(edge.attr.comb=list(weight="mean",
-    name=toString, "ignore")}
-}
-\section{Simple and complex attributes}{
-  An attribute is simple if (for all vertices/edges) it can be specified
-  as an atomic vector. Character and numeric attributes are always
-  simple. E.g. a vertex attribute that is a numeric vector of arbitrary
-  length for each vertex, is a complex attribute.
-
-  Combination of attributes might turn a complex attribute into
-  a single one, and the opposite is possible, too. E.g. when
-  contatenating attribute values to form the new attribute value, the
-  result will be typically a complex attribute.
-
-  See also examples below.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link[igraph]{attributes}} on how to use
-  graph/vertex/edges attributes in general. \code{\link{igraph.options}} on
-  igraph parameters.}
-\examples{
-g <- graph( c(1,2, 1,2, 1,2, 2,3, 3,4) )
-E(g)$weight <- 1:5
-
-## print attribute values with the graph
-igraph.options(print.graph.attributes=TRUE)
-igraph.options(print.vertex.attributes=TRUE)
-igraph.options(print.edge.attributes=TRUE)
-
-## new attribute is the sum of the old ones
-simplify(g, edge.attr.comb="sum")
-
-## collect attributes into a string
-simplify(g, edge.attr.comb=toString)
-
-## concatenate them into a vector, this creates a complex
-## attribute
-simplify(g, edge.attr.comb="concat")
-
-E(g)$name <- letters[seq_len(ecount(g))]
-
-## both attributes are collected into strings
-simplify(g, edge.attr.comb=toString)
-
-## harmonic average of weights, names are dropped
-simplify(g, edge.attr.comb=list(weight=function(x) length(x)/sum(1/x),
-                                name="ignore"))
-
-}
-\keyword{graphs}
diff --git a/man/attributes.Rd b/man/attributes.Rd
deleted file mode 100644
index b448ed6..0000000
--- a/man/attributes.Rd
+++ /dev/null
@@ -1,183 +0,0 @@
-\name{attributes}
-\alias{attributes}
-\alias{set.graph.attribute}
-\alias{get.graph.attribute}
-\alias{remove.graph.attribute}
-\alias{list.graph.attributes}
-\alias{graph.attributes}
-\alias{graph.attributes<-}
-\alias{set.vertex.attribute}
-\alias{get.vertex.attribute}
-\alias{remove.vertex.attribute}
-\alias{list.vertex.attributes}
-\alias{vertex.attributes}
-\alias{vertex.attributes<-}
-\alias{set.edge.attribute}
-\alias{get.edge.attribute}
-\alias{remove.edge.attribute}
-\alias{list.edge.attributes}
-\alias{edge.attributes}
-\alias{edge.attributes<-}
-\concept{Vertex/edge/graph attributes}
-\title{Graph, vertex and edge attributes}
-\description{Attributes are associated values belonging to a graph,
-  vertices or edges. These can represent some property, like data
-  about how the graph was constructed, the color of the vertices when
-  the graph is plotted, or simply the weights of the edges in a weighted
-  graph.}
-\usage{
-get.graph.attribute(graph, name)
-set.graph.attribute(graph, name, value)
-list.graph.attributes(graph)
-graph.attributes(graph)
-remove.graph.attribute(graph, name)
-get.vertex.attribute(graph, name, index=V(graph))
-set.vertex.attribute(graph, name, index=V(graph), value)
-remove.vertex.attribute(graph, name)
-list.vertex.attributes(graph)
-vertex.attributes(graph)
-get.edge.attribute(graph, name, index=E(graph))
-set.edge.attribute(graph, name, index=E(graph), value)
-remove.edge.attribute(graph, name)
-list.edge.attributes(graph)
-edge.attributes(graph)
-}
-\arguments{
-  \item{graph}{The graph object to work on. Note that the original graph
-  is never modified, a new graph object is returned instead; if you don't
-  assign it to a variable your modifications will be lost! See examples
-  below.}
-  \item{name}{Character constant, the name of the attribute.}
-  \item{index}{Numeric vector, the ids of the vertices or edges.
-    It is not recycled, even if \code{value} is longer.}
-  \item{value}{Numeric vector, the new value(s) of the attributes, it
-    will be recycled if needed.}
-}
-\details{
-  There are three types of attributes in igraph: graph, vertex and edge
-  attributes. Graph attributes are associated with graph, vertex
-  attributes with vertices and edge attributes with edges.
-
-  Examples for graph attributes are the date when the graph data was
-  collected or other types of memos like the type of the data, or
-  whether the graph is a simple graph, ie. one without loops and
-  multiple edges.
-
-  Examples of vertex attributes are vertex properties, like the
-  vertex coordinates for the visualization of the graph, or other
-  visualization parameters, or meta-data associated with the vertices,
-  like the gender and the age of the individuals in a friendship
-  network, the type of the neurons in a graph representing neural
-  circuitry or even some pre-computed structual properties, like the
-  betweenness centrality of the vertices.
-
-  Examples of edge attributes are data associated with edges: most
-  commonly edge weights, or visualization parameters.
-
-  In recent igraph versions, arbitrary R objects can be assigned as
-  graph, vertex or edge attributes.
-  
-  Some igraph functions use the values or graph, vertex and edge
-  attributes if they are present but this is not done in the current
-  version very extensively. Expect more in the (near) future.
-
-  Graph attributes can be created with the \code{set.graph.attribute}
-  function, and removed with \code{remove.graph.attribute}. Graph
-  attributes are queried with \code{get.graph.attribute} and the
-  assigned graph attributes are listed with
-  \code{list.graph.attributes}.
-
-  The function \code{graph.attributes} returns all graph attributes in a
-  named list. This function has a counterpart that sets all graph
-  attributes at once, see an example below.
-
-  There is a simpler notation for using graph attributes: the
-  \sQuote{\code{$}} operator. It can be used both to query and set graph
-  attributes, see an example below.
-  
-  The functions for vertex attributes are
-  \code{set.vertex.attribute}, \code{get.vertex.attribute},
-  \code{remove.vertex.attribute} and \code{list.vertex.attributes} and
-  for edge attributes they are \code{set.edge.attribute},
-  \code{get.edge.attribute}, \code{remove.edge.attribute} and
-  \code{list.edge.attributes}.
-
-  Similarly to graph attributes, \code{vertex.attributes} returns all
-  vertex attributes, in a named list, and \code{edge.attributes} returns
-  all edge attributes, in a named list.
-  
-  There is however a (syntactically) much simpler way to handle vertex
-  and edge attribute by using vertex and edge selectors, it works like this:
-  \code{V(g)} selects all vertices in a graph, and \code{V(g)$name}
-  queries the \code{name} attribute for all vertices. Similarly is
-  \code{vs} is a vertex set \code{vs$name} gives the values of the
-  \code{name} attribute for the vertices in the vertex set.
-
-  This form can also be used to set the values of the attributes, like
-  the regular R convention:
-  \preformatted{V(g)$color <- "red"}
-  It works for vertex subsets as well:
-  \preformatted{V(g)[1:5]$color <- "green"}
-
-  The notation for edges is similar: \code{E(g)} means all edges
-  \code{E(g)$weight} is the \code{weight} attribute for all edges, etc.
-
-  See also the manual page for \code{iterators} about how to create
-  various vertex and edge sets.
-}
-\value{
-  \code{get.graph.attribute}, \code{get.vertex.attribute} and
-  \code{get.edge.attribute} return an R object, or a list of R objects
-  if attributes of more vertices/edges are requested.
-
-  \code{set.graph.attribute}, \code{set.vertex.attribute},
-  \code{set.edge.attribute}, and also \code{remove.graph.attribute},
-  \code{remove.vertex.attribute} and \code{remove.edge.attribute} return
-  a new graph object with the updates/removes performed.
-
-  \code{list.graph.attributes}, \code{list.vertex.attributes} and
-  \code{list.edge.attributes} return a character vector, the names of
-  the attributes present.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{print.igraph}} can print attributes. See
-  \code{\link{attribute.combination}} for details on how igraph combines
-  attributes if several vertices or edges are mapped into one.}
-\examples{
-g <- graph.ring(10)
-g <- set.graph.attribute(g, "name", "RING")
-# It is the same as
-g$name <- "RING"
-g$name
-
-g <- set.vertex.attribute(g, "color", value=c("red", "green"))
-get.vertex.attribute(g, "color")
-
-g <- set.edge.attribute(g, "weight", value=runif(ecount(g)))
-get.edge.attribute(g, "weight")
-
-# The following notation is more convenient
-g <- graph.star(10)
-
-V(g)$color <- c("red", "green")
-V(g)$color
-
-E(g)$weight <- runif(ecount(g))
-E(g)$weight
-
-str(g, g=TRUE, v=TRUE, e=TRUE)
-
-# Setting all attributes at once
-g2 <- graph.empty(10)
-g2
-
-graph.attributes(g2) <- graph.attributes(g)
-vertex.attributes(g2) <- vertex.attributes(g)
-edge.attributes(g2) <- list()
-g2
-
-edge.attributes(g2) <- list(weight=numeric())
-g2
-}
-\keyword{graphs}
diff --git a/man/authority_score.Rd b/man/authority_score.Rd
new file mode 100644
index 0000000..459436f
--- /dev/null
+++ b/man/authority_score.Rd
@@ -0,0 +1,67 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{authority_score}
+\alias{authority.score}
+\alias{authority_score}
+\title{Kleinberg's authority centrality scores.}
+\usage{
+authority_score(graph, scale = TRUE, weights = NULL,
+  options = arpack_defaults)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{scale}{Logical scalar, whether to scale the result to have a maximum
+score of one. If no scaling is used then the result vector has unit length
+in the Euclidean norm.}
+
+\item{weights}{Optional positive weight vector for calculating weighted
+scores. If the graph has a \code{weight} edge attribute, then this is used
+by default.}
+
+\item{options}{A named list, to override some ARPACK options. See
+\code{\link{arpack}} for details.}
+}
+\value{
+A named list with members:
+  \item{vector}{The authority/hub scores of the vertices.}
+  \item{value}{The corresponding eigenvalue of the calculated
+    principal eigenvector.}
+  \item{options}{Some information about the ARPACK computation, it has
+    the same members as the \code{options} member returned
+    by \code{\link{arpack}}, see that for documentation.}
+}
+\description{
+The authority scores of the vertices are defined as the principal
+eigenvector of \eqn{A^T A}{t(A)*A}, where \eqn{A} is the adjacency
+matrix of the graph.
+}
+\details{
+For undirected matrices the adjacency matrix is symmetric and the
+authority scores are the same as hub scores, see
+\code{\link{hub_score}}.
+}
+\examples{
+## An in-star
+g <- make_star(10)
+hub_score(g)$vector
+authority_score(g)$vector
+
+## A ring
+g2 <- make_ring(10)
+hub_score(g2)$vector
+authority_score(g2)$vector
+}
+\references{
+J. Kleinberg. Authoritative sources in a hyperlinked
+environment. \emph{Proc. 9th ACM-SIAM Symposium on Discrete Algorithms},
+1998. Extended version in \emph{Journal of the ACM} 46(1999). Also appears
+as IBM Research Report RJ 10076, May 1997.
+}
+\seealso{
+\code{\link{hub_score}}, \code{\link{eigen_centrality}} for
+eigenvector centrality, \code{\link{page_rank}} for the Page Rank
+scores. \code{\link{arpack}} for the underlining machinery of the
+computation.
+}
+
diff --git a/man/autocurve.edges.Rd b/man/autocurve.edges.Rd
deleted file mode 100644
index f6cdd20..0000000
--- a/man/autocurve.edges.Rd
+++ /dev/null
@@ -1,43 +0,0 @@
-\name{autocurve.edges}
-\alias{autocurve.edges}
-\title{Optimal edge curvature when plotting graphs}
-\description{
-  If graphs have multiple edges, then drawing them as straight lines
-  does not show them when plotting the graphs; they will be on top
-  of each other. One solution is to bend the edges, with diffenent
-  curvature, so that all of them are visible.}
-\usage{
-autocurve.edges (graph, start = 0.5)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{start}{The curvature at the two extreme edges. All edges will
-    have a curvature between \code{-start} and \code{start}, spaced
-    equally.}
-}
-\details{
-  \code{autocurve.edges} calculates the optimal \code{edge.curved}
-  vector for plotting a graph with multiple edges, so that all edges
-  are visible.
-}
-\value{
-  A numeric vector, its length is the number of edges in the graph.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{igraph.plotting}} for all plotting parameters,
-  \code{\link{plot.igraph}}, \code{\link{tkplot}} and
-  \code{\link{rglplot}} for plotting functions.
-}
-\examples{
-g <- graph( c(0,1,1,0,1,2,1,3,1,3,1,3,
-              2,3,2,3,2,3,2,3,0,1)+1 )
-
-autocurve.edges(g)
-
-\dontrun{
-set.seed(42)
-plot(g)
-}
-}
-\keyword{graphs}
diff --git a/man/automorphisms.Rd b/man/automorphisms.Rd
new file mode 100644
index 0000000..fd56b70
--- /dev/null
+++ b/man/automorphisms.Rd
@@ -0,0 +1,63 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{automorphisms}
+\alias{automorphisms}
+\alias{graph.automorphisms}
+\title{Number of automorphisms}
+\usage{
+automorphisms(graph, sh = "fm")
+}
+\arguments{
+\item{graph}{The input graph, it is treated as undirected.}
+
+\item{sh}{The splitting heuristics for the BLISS algorithm. Possible values
+are: \sQuote{\code{f}}: first non-singleton cell, \sQuote{\code{fl}}: first
+largest non-singleton cell, \sQuote{\code{fs}}: first smallest non-singleton
+cell, \sQuote{\code{fm}}: first maximally non-trivially connected
+non-singleton cell, \sQuote{\code{flm}}: first largest maximally
+non-trivially connected non-singleton cell, \sQuote{\code{fsm}}: first
+smallest maximally non-trivially connected non-singleton cell.}
+}
+\value{
+A named list with the following members: \item{group_size}{The size
+of the automorphism group of the input graph, as a string. This number is
+exact if igraph was compiled with the GMP library, and approximate
+otherwise.} \item{nof_nodes}{The number of nodes in the search tree.}
+\item{nof_leaf_nodes}{The number of leaf nodes in the search tree.}
+\item{nof_bad_nodes}{Number of bad nodes.} \item{nof_canupdates}{Number of
+canrep updates.} \item{max_level}{Maximum level.}
+}
+\description{
+Calculate the number of automorphisms of a graph, i.e. the number of
+isomorphisms to itself.
+}
+\details{
+An automorphism of a graph is a permutation of its vertices which brings the
+graph into itself.
+
+This function calculates the number of automorphism of a graph using the
+BLISS algorithm. See also the BLISS homepage at
+\url{http://www.tcs.hut.fi/Software/bliss/index.html}.
+}
+\examples{
+## A ring has n*2 automorphisms, you can "turn" it by 0-9 vertices
+## and each of these graphs can be "flipped"
+g <- make_ring(10)
+automorphisms(g)
+}
+\author{
+Tommi Junttila (\url{http://users.ics.aalto.fi/tjunttil/}) for BLISS
+and Gabor Csardi \email{csardi.gabor at gmail.com} for the igraph glue code
+and this manual page.
+}
+\references{
+Tommi Junttila and Petteri Kaski: Engineering an Efficient
+Canonical Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of
+the Ninth Workshop on Algorithm Engineering and Experiments and the Fourth
+Workshop on Analytic Algorithms and Combinatorics.} 2007.
+}
+\seealso{
+\code{\link{canonical_permutation}}, \code{\link{permute}}
+}
+\keyword{graphs}
+
diff --git a/man/ba.game.Rd b/man/ba.game.Rd
deleted file mode 100644
index c34536c..0000000
--- a/man/ba.game.Rd
+++ /dev/null
@@ -1,108 +0,0 @@
-\name{barabasi.game}
-\alias{barabasi.game}
-\alias{ba.game}
-\concept{Preferential attachment model}
-\concept{Random graph model}
-\title{Generate scale-free graphs according to the Barabasi-Albert
-  model}
-\description{The BA-model is a very simple stochastic algorithm for
-  building a graph.}
-\usage{
-barabasi.game(n, power = 1, m = NULL, out.dist = NULL, out.seq = NULL, 
-    out.pref = FALSE, zero.appeal = 1, directed = TRUE,
-    algorithm = c("psumtree", "psumtree-multiple", "bag"),
-    start.graph = NULL)
-}
-\arguments{
-  \item{n}{Number of vertices.}
-  \item{power}{The power of the preferential attachment, the default is
-    one, ie. linear preferential attachment.}
-  \item{m}{Numeric constant, the number of edges to add in each time
-    step This argument is only used if both \code{out.dist} and
-    \code{out.seq} are omitted or NULL.}
-  \item{out.dist}{Numeric vector, the distribution of the number of
-    edges to add in each time step. This argument is only used if the
-    \code{out.seq} argument is omitted or NULL.}
-  \item{out.seq}{Numeric vector giving the number of edges to add in
-    each time step. Its first element is ignored as no edges are added
-    in the first time step.}
-  \item{out.pref}{Logical, if true the total degree is used for
-    calculating the citation probability, otherwise the in-degree is
-    used. }
-  \item{zero.appeal}{The \sQuote{attractiveness} of the vertices with no
-    adjacent edges. See details below.}
-  \item{directed}{Whether to create a directed graph.}
-  \item{algorithm}{The algorithm to use for the graph generation.
-    \code{psumtree} uses a partial prefix-sum tree to generate
-    the graph, this algorithm can handle any \code{power} and
-    \code{zero.appeal} values and never generates multiple edges.
-    \code{psumtree-multiple} also uses a partial prefix-sum
-    tree, but the generation of multiple edges is allowed. Before the
-    0.6 version igraph used this algorithm if \code{power} was not one,
-    or \code{zero.appeal} was not one.
-    \code{bag} is the algorithm that was previously (before
-    version 0.6) used if \code{power} was one and \code{zero.appeal} was
-    one as well. It works by putting the ids of the vertices into a bag
-    (mutliset, really), exactly as many times as their (in-)degree, plus
-    once more. Then the required number of cited vertices are drawn from
-    the bag, with replacement. This method might generate multiple
-    edges. It only works if \code{power} and \code{zero.appeal} are
-    equal one.
-  }
-  \item{start.graph}{\code{NULL} or an igraph graph. If a graph, then
-    the supplied graph is used as a starting graph for the preferential
-    attachment algorithm. The graph should have at least one vertex. If
-    a graph is supplied here and the \code{out.seq} argument is not
-    \code{NULL}, then it should contain the out degrees of the new
-    vertices only, not the ones in the \code{start.graph}.}
-}
-\details{
-  This is a simple stochastic algorithm to generate a graph. It is a
-  discrete time step model and in each time step a single vertex is
-  added.
-
-  We start with a single vertex and no edges in the first time
-  step. Then we add one vertex in each time step and the new vertex
-  initiates some edges to old vertices. The probability that an old vertex
-  is chosen is given by
-  \deqn{P[i] \sim k_i^\alpha+a}{P[i] ~ k[i]^alpha + a}
-  where \eqn{k_i}{k[i]} is the in-degree of vertex \eqn{i} in the
-  current time step (more precisely the number of adjacent edges of
-  \eqn{i} which were not initiated by \eqn{i} itself) and
-  \eqn{\alpha}{alpha} and \eqn{a} are parameters given by the
-  \code{power} and \code{zero.appeal} arguments.
-
-  The number of edges initiated in a time step is given by the \code{m},
-  \code{out.dist} and \code{out.seq} arguments. If \code{out.seq} is
-  given and not NULL then it gives the number of edges to add in a
-  vector, the first element is ignored, the second is the number of
-  edges to add in the second time step and so on. If \code{out.seq} is
-  not given or null and \code{out.dist} is given and not NULL then it is
-  used as a discrete distribution to generate the number of edges in
-  each time step. Its first element is the probability that no edges
-  will be added, the second is the probability that one edge is added,
-  etc. (\code{out.dist} does not need to sum up to one, it normalized
-  automatically.) \code{out.dist} should contain non-negative numbers
-  and at east one element should be positive.
-
-  If both \code{out.seq} and \code{out.dist} are omitted or NULL then
-  \code{m} will be used, it should be a positive integer constant and
-  \code{m} edges will be added in each time step.
-
-  \code{barabasi.game} generates a directed graph by default, set
-  \code{directed} to \code{FALSE} to generate an undirected graph. Note
-  that even if an undirected graph is generated \eqn{k_i}{k[i]} denotes
-  the number of adjacent edges not initiated by the vertex itself and
-  not the total (in- + out-) degree of the vertex, unless the
-  \code{out.pref} argument is set to \code{TRUE}.
-}
-\value{A graph object.}
-\references{  Barabasi, A.-L. and Albert R. 1999. Emergence of scaling
-  in random networks \emph{Science}, 286 509--512.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{random.graph.game}}}
-\examples{
-g <- barabasi.game(10000)
-degree.distribution(g)
-}
-\keyword{graphs}
diff --git a/man/betweenness.Rd b/man/betweenness.Rd
index 2bf8102..31d15b5 100644
--- a/man/betweenness.Rd
+++ b/man/betweenness.Rd
@@ -1,96 +1,113 @@
-\name{betweenness}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{estimate_betweenness}
 \alias{betweenness}
-\alias{edge.betweenness}
 \alias{betweenness.estimate}
+\alias{edge.betweenness}
 \alias{edge.betweenness.estimate}
-\concept{Betweenness centrality}
-\concept{Edge betweenness}
+\alias{edge_betweenness}
+\alias{estimate_betweenness}
+\alias{estimate_edge_betweenness}
 \title{Vertex and edge betweenness centrality}
-\description{The vertex and edge betweenness are (roughly) defined by
-  the number of geodesics (shortest paths) going through a vertex or an
-  edge. 
-}
 \usage{
-betweenness(graph, v=V(graph), directed = TRUE, weights = NULL,
-     nobigint = TRUE, normalized = FALSE)
-edge.betweenness(graph, e=E(graph), directed = TRUE, weights = NULL)
-betweenness.estimate(graph, vids = V(graph), directed = TRUE, cutoff,
-     weights = NULL, nobigint = TRUE)
-edge.betweenness.estimate(graph, e=E(graph),
-     directed = TRUE, cutoff, weights = NULL)
+estimate_betweenness(graph, vids = V(graph), directed = TRUE, cutoff,
+  weights = NULL, nobigint = TRUE)
+
+betweenness(graph, v = V(graph), directed = TRUE, weights = NULL,
+  nobigint = TRUE, normalized = FALSE)
+
+edge_betweenness(graph, e = E(graph), directed = TRUE, weights = NULL)
 }
 \arguments{
-  \item{graph}{The graph to analyze.}
-  \item{v}{The vertices for which the vertex betweenness will be
-    calculated.}
-  \item{e}{The edges for which the edge betweenness will be
-    calculated.}
-  \item{directed}{Logical, whether directed paths should be considered
-    while determining the shortest paths.}
-  \item{weights}{Optional positive weight vector for calculating
-    weighted betweenness. If the graph has a \code{weight} edge
-    attribute, then this is used by default.}
-  \item{nobigint}{Logical scalar, whether to use big integers during the
-    calculation. This is only required for lattice-like graphs that have
-    very many shortest paths between a pair of vertices. If \code{TRUE}
-    (the default), then big integers are not used.}
-  \item{normalized}{Logical scalar, whether to normalize the betweenness
-    scores. If \code{TRUE}, then the results are normalized according to
-    \deqn{B^n=\frac{2B}{n^2-3n+2}}{Bnorm=2*B/(n*n-3*n+2)}, where
-    \eqn{B^n}{Bnorm} is the normalized, \eqn{B} the raw betweenness, and
-    \eqn{n} is the number of vertices in the graph.}
-  \item{vids}{The vertices for which the vertex betweenness estimation
-    will be calculated.}
-  \item{cutoff}{The maximum path length to consider when calculating the
-    betweenness. If zero or negative then there is no such limit.}
-}
-\details{The vertex betweenness of vertex \eqn{v}{\code{v}} is defined
-  by
+\item{graph}{The graph to analyze.}
 
-  \deqn{\sum_{i\ne j, i\ne v, j\ne v} g_{ivj}/g_{ij}}{sum( g_ivj / g_ij, i!=j,i!=v,j!=v)}
-  
-  The edge betweenness of edge \eqn{e}{\code{e}} is defined by
+\item{vids}{The vertices for which the vertex betweenness estimation will be
+calculated.}
 
-  \deqn{\sum_{i\ne j} g{iej}/g_{ij}.}{sum( g_iej / g_ij, i!=j).}
+\item{directed}{Logical, whether directed paths should be considered while
+determining the shortest paths.}
 
-  \code{betweenness} calculates vertex betweenness,
-  \code{edge.betweenness} calculates edge.betweenness.
+\item{cutoff}{The maximum path length to consider when calculating the
+betweenness. If zero or negative then there is no such limit.}
 
-  \code{betweenness.estimate} only considers paths of length
-  \code{cutoff} or smaller, this can be run for larger graphs, as the
-  running time is not quadratic (if \code{cutoff} is small). If
-  \code{cutoff} is zero or negative then the function calculates the
-  exact betweenness scores.
+\item{weights}{Optional positive weight vector for calculating weighted
+betweenness. If the graph has a \code{weight} edge attribute, then this is
+used by default.}
 
-  \code{edge.betweenness.estimate} is similar, but for edges.
+\item{nobigint}{Logical scalar, whether to use big integers during the
+calculation. This is only required for lattice-like graphs that have very
+many shortest paths between a pair of vertices. If \code{TRUE} (the
+default), then big integers are not used.}
 
-  For calculating the betweenness a similar algorithm to the one
-  proposed by Brandes (see References) is used.
+\item{v}{The vertices for which the vertex betweenness will be calculated.}
+
+\item{normalized}{Logical scalar, whether to normalize the betweenness
+scores. If \code{TRUE}, then the results are normalized according to
+\deqn{B^n=\frac{2B}{n^2-3n+2}}{Bnorm=2*B/(n*n-3*n+2)}, where
+\eqn{B^n}{Bnorm} is the normalized, \eqn{B} the raw betweenness, and \eqn{n}
+is the number of vertices in the graph.}
+
+\item{e}{The edges for which the edge betweenness will be calculated.}
 }
-\value{A numeric vector with the betweenness score for each vertex in
-  \code{v} for \code{betweenness}.
+\value{
+A numeric vector with the betweenness score for each vertex in
+\code{v} for \code{betweenness}.
 
-  A numeric vector with the edge betweenness score for each edge in
-  \code{e} for \code{edge.betweenness}.
+A numeric vector with the edge betweenness score for each edge in \code{e}
+for \code{edge_betweenness}.
 
-  \code{betweenness.estimate} returns the estimated betweenness scores
-  for vertices in \code{vids}, \code{edge.betweenness.estimate}
-  the estimated edge betweenness score for \emph{all} edges; both in
-  a numeric vector.
+\code{estimate_betweenness} returns the estimated betweenness scores for
+vertices in \code{vids}, \code{estimate_edge_betweenness} the estimated edge
+betweenness score for \emph{all} edges; both in a numeric vector.
+}
+\description{
+The vertex and edge betweenness are (roughly) defined by the number of
+geodesics (shortest paths) going through a vertex or an edge.
 }
-\note{\code{edge.betweenness} might give false values for graphs with
-  multiple edges.}
-\references{Freeman, L.C. (1979). Centrality in Social Networks I:
-  Conceptual Clarification. \emph{Social Networks}, 1, 215-239.
+\details{
+The vertex betweenness of vertex \eqn{v}{\code{v}} is defined by
+
+\deqn{\sum_{i\ne j, i\ne v, j\ne v} g_{ivj}/g_{ij}}{sum( g_ivj / g_ij,
+i!=j,i!=v,j!=v)}
+
+The edge betweenness of edge \eqn{e}{\code{e}} is defined by
 
-  Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. \emph{Journal
-  of Mathematical Sociology} 25(2):163-177, 2001. 
+\deqn{\sum_{i\ne j} g{iej}/g_{ij}.}{sum( g_iej / g_ij, i!=j).}
+
+\code{betweenness} calculates vertex betweenness, \code{edge_betweenness}
+calculates edge betweenness.
+
+\code{estimate_betweenness} only considers paths of length \code{cutoff} or
+smaller, this can be run for larger graphs, as the running time is not
+quadratic (if \code{cutoff} is small). If \code{cutoff} is zero or negative
+then the function calculates the exact betweenness scores.
+
+\code{estimate_edge_betweenness} is similar, but for edges.
+
+For calculating the betweenness a similar algorithm to the one proposed by
+Brandes (see References) is used.
+}
+\note{
+\code{edge_betweenness} might give false values for graphs with
+multiple edges.
 }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{closeness}}, \code{\link{degree}}}
 \examples{
-g <- random.graph.game(10, 3/10)
+g <- sample_gnp(10, 3/10)
 betweenness(g)
-edge.betweenness(g)
+edge_betweenness(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Freeman, L.C. (1979). Centrality in Social Networks I:
+Conceptual Clarification. \emph{Social Networks}, 1, 215-239.
+
+Ulrik Brandes, A Faster Algorithm for Betweenness Centrality. \emph{Journal
+of Mathematical Sociology} 25(2):163-177, 2001.
+}
+\seealso{
+\code{\link{closeness}}, \code{\link{degree}}
 }
 \keyword{graphs}
+
diff --git a/man/bfs.Rd b/man/bfs.Rd
new file mode 100644
index 0000000..4527f5d
--- /dev/null
+++ b/man/bfs.Rd
@@ -0,0 +1,116 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{bfs}
+\alias{bfs}
+\alias{graph.bfs}
+\title{Breadth-first search}
+\usage{
+bfs(graph, root, neimode = c("out", "in", "all", "total"),
+  unreachable = TRUE, restricted = NULL, order = TRUE, rank = FALSE,
+  father = FALSE, pred = FALSE, succ = FALSE, dist = FALSE,
+  callback = NULL, extra = NULL, rho = parent.frame())
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{root}{Numeric vector, usually of length one. The root vertex, or root
+vertices to start the search from.}
+
+\item{neimode}{For directed graphs specifies the type of edges to follow.
+\sQuote{out} follows outgoing, \sQuote{in} incoming edges. \sQuote{all}
+ignores edge directions completely. \sQuote{total} is a synonym for
+\sQuote{all}. This argument is ignored for undirected graphs.}
+
+\item{unreachable}{Logical scalar, whether the search should visit the
+vertices that are unreachable from the given root vertex (or vertices). If
+\code{TRUE}, then additional searches are performed until all vertices are
+visited.}
+
+\item{restricted}{\code{NULL} (=no restriction), or a vector of vertices
+(ids or symbolic names). In the latter case, the search is restricted to the
+given vertices.}
+
+\item{order}{Logical scalar, whether to return the ordering of the vertices.}
+
+\item{rank}{Logical scalar, whether to return the rank of the vertices.}
+
+\item{father}{Logical scalar, whether to return the father of the vertices.}
+
+\item{pred}{Logical scalar, whether to return the predecessors of the
+vertices.}
+
+\item{succ}{Logical scalar, whether to return the successors of the
+vertices.}
+
+\item{dist}{Logical scalar, whether to return the distance from the root of
+the search tree.}
+
+\item{callback}{If not \code{NULL}, then it must be callback function. This
+is called whenever a vertex is visited. See details below.}
+
+\item{extra}{Additional argument to supply to the callback function.}
+
+\item{rho}{The environment in which the callback function is evaluated.}
+}
+\value{
+A named list with the following entries: \item{root}{Numeric scalar.
+The root vertex that was used as the starting point of the search.}
+\item{neimode}{Character scalar. The \code{neimode} argument of the function
+call. Note that for undirected graphs this is always \sQuote{all},
+irrespectively of the supplied value.} \item{order}{Numeric vector. The
+vertex ids, in the order in which they were visited by the search.}
+\item{rank}{Numeric vector. The rank for each vertex.} \item{father}{Numeric
+vector. The father of each vertex, i.e. the vertex it was discovered from.}
+\item{pred}{Numeric vector. The previously visited vertex for each vertex,
+or 0 if there was no such vertex.} \item{succ}{Numeric vector. The next
+vertex that was visited after the current one, or 0 if there was no such
+vertex.} \item{dist}{Numeric vector, for each vertex its distance from the
+root of the search tree.}
+
+Note that \code{order}, \code{rank}, \code{father}, \code{pred}, \code{succ}
+and \code{dist} might be \code{NULL} if their corresponding argument is
+\code{FALSE}, i.e. if their calculation is not requested.
+}
+\description{
+Breadth-first search is an algorithm to traverse a graph. We start from a
+root vertex and spread along every edge \dQuote{simultaneously}.
+}
+\details{
+The callback function must have the following arguments: \describe{
+\item{graph}{The input graph is passed to the callback function here.}
+\item{data}{A named numeric vector, with the following entries:
+\sQuote{vid}, the vertex that was just visited, \sQuote{pred}, its
+predecessor, \sQuote{succ}, its successor, \sQuote{rank}, the rank of the
+current vertex, \sQuote{dist}, its distance from the root of the search
+tree.} \item{extra}{The extra argument.} } See examples below on how to use
+the callback function.
+}
+\examples{
+## Two rings
+bfs(make_ring(10) \%du\% make_ring(10), root=1, "out",
+          order=TRUE, rank=TRUE, father=TRUE, pred=TRUE,
+          succ=TRUE, dist=TRUE)
+
+## How to use a callback
+f <- function(graph, data, extra) {
+  print(data)
+  FALSE
+}
+tmp <- bfs(make_ring(10) \%du\% make_ring(10), root=1, "out",
+                 callback=f)
+
+## How to use a callback to stop the search
+## We stop after visiting all vertices in the initial component
+f <- function(graph, data, extra) {
+ data['succ'] == -1
+}
+bfs(make_ring(10) \%du\% make_ring(10), root=1, callback=f)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{dfs}} for depth-first search.
+}
+\keyword{graphs}
+
diff --git a/man/biconnected.components.Rd b/man/biconnected.components.Rd
deleted file mode 100644
index 8ce5470..0000000
--- a/man/biconnected.components.Rd
+++ /dev/null
@@ -1,48 +0,0 @@
-\name{biconnected.components}
-\alias{biconnected.components}
-\concept{Biconnected component}
-\title{Biconnected components}
-\description{Finding the biconnected components of a graph}
-\usage{
-biconnected.components(graph)
-}
-\arguments{
-  \item{graph}{The input graph. It is treated as an undirected graph,
-    even if it is directed.}
-}
-\details{
-  A graph is biconnected if the removal of any single vertex (and its
-  adjacent edges) does not disconnect it.
-
-  A biconnected component of a graph is a maximal biconnected subgraph
-  of it. The biconnected components of a graph can be given by the
-  partition of its edges: every edge is a member of exactly one
-  biconnected component. Note that this is not true for vertices: the same
-  vertex can be part of many biconnected components.  
-}
-\value{
-  A named list with three components:
-  \item{no}{Numeric scalar, an integer giving the number of
-    biconnected components in the graph.}
-  \item{tree_edges}{The components themselves, a list of numeric
-    vectors. Each vector is a set of edge ids giving the edges in a
-    biconnected component. These edges define a spanning tree of the
-    component.}
-  \item{component_edges}{A list of numeric vectors. It gives all edges
-  in the components.}
-  \item{components}{A list of numeric vectors, the vertices of the
-    components.}
-  \item{articulation_points}{The articulation points of the graph. See
-    \code{\link{articulation.points}}.}
-}
-%\references
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{articulation.points}}, \code{\link{clusters}},
-  \code{\link{is.connected}}, \code{\link{vertex.connectivity}}}
-\examples{
-g <- graph.disjoint.union( graph.full(5), graph.full(5) )
-clu <- clusters(g)$membership
-g <- add.edges(g, c(which(clu==1), which(clu==2)))
-bc <- biconnected.components(g)
-}
-\keyword{graphs}
diff --git a/man/biconnected_components.Rd b/man/biconnected_components.Rd
new file mode 100644
index 0000000..f42d289
--- /dev/null
+++ b/man/biconnected_components.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/components.R
+\name{biconnected_components}
+\alias{biconnected.components}
+\alias{biconnected_components}
+\title{Biconnected components}
+\usage{
+biconnected_components(graph)
+}
+\arguments{
+\item{graph}{The input graph. It is treated as an undirected graph, even if
+it is directed.}
+}
+\value{
+A named list with three components: \item{no}{Numeric scalar, an
+integer giving the number of biconnected components in the graph.}
+\item{tree_edges}{The components themselves, a list of numeric vectors. Each
+vector is a set of edge ids giving the edges in a biconnected component.
+These edges define a spanning tree of the component.}
+\item{component_edges}{A list of numeric vectors. It gives all edges in the
+components.} \item{components}{A list of numeric vectors, the vertices of
+the components.} \item{articulation_points}{The articulation points of the
+graph. See \code{\link{articulation_points}}.}
+}
+\description{
+Finding the biconnected components of a graph
+}
+\details{
+A graph is biconnected if the removal of any single vertex (and its adjacent
+edges) does not disconnect it.
+
+A biconnected component of a graph is a maximal biconnected subgraph of it.
+The biconnected components of a graph can be given by the partition of its
+edges: every edge is a member of exactly one biconnected component. Note
+that this is not true for vertices: the same vertex can be part of many
+biconnected components.
+}
+\examples{
+g <- disjoint_union( make_full_graph(5), make_full_graph(5) )
+clu <- components(g)$membership
+g <- add_edges(g, c(which(clu==1), which(clu==2)))
+bc <- biconnected_components(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{articulation_points}}, \code{\link{components}},
+\code{\link{is_connected}}, \code{\link{vertex_connectivity}}
+}
+\keyword{graphs}
+
diff --git a/man/bipartite.projection.Rd b/man/bipartite.projection.Rd
deleted file mode 100644
index 627fd8c..0000000
--- a/man/bipartite.projection.Rd
+++ /dev/null
@@ -1,83 +0,0 @@
-\name{bipartite.projection}
-\alias{bipartite.projection}
-\alias{bipartite.projection.size}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\title{Project a bipartite graph}
-\description{A bipartite graph is projected into two one-mode networks}
-\usage{
-bipartite.projection.size(graph, types = NULL)
-bipartite.projection (graph, types = NULL, multiplicity = TRUE,
-       probe1 = NULL, which=c("both", "true", "false"),
-       remove.type = TRUE)
-}
-\arguments{
-  \item{graph}{The input graph. It can be directed, but edge directions
-    are ignored during the computation.}
-  \item{types}{An optional vertex type vector to use instead of the
-    \sQuote{\code{type}} vertex attribute. You must supply this argument
-    if the graph has no \sQuote{\code{type}} vertex attribute.}
-  \item{multiplicity}{If \code{TRUE}, then igraph keeps the multiplicity
-    of the edges as an edge attribute. E.g. if there is an A-C-B and
-    also an A-D-B triple in the bipartite graph (but no more X, such
-    that A-X-B is also in the graph), then the multiplicity of the A-B
-    edge in the projection will be 2.}
-  \item{probe1}{This argument can be used to specify the order of the
-    projections in the resulting list. If given, then it is considered
-    as a vertex id (or a symbolic vertex name); the projection
-    containing this vertex will be the first one in the result list.
-    This argument is ignored if only one projection is requested in
-    argument \code{which}.}
-  \item{which}{A character scalar to specify which projection(s) to
-    calculate. The default is to calculate both.}
-  \item{remove.type}{Logical scalar, whether to remove the
-    \code{type} vertex attribute from the projections. This makes
-    sense because these graphs are not bipartite any more. However if
-    you want to combine them with each other (or other bipartite
-    graphs), then it is worth keeping this attribute. By default it
-    will be removed.}
-}
-\details{
-  Bipartite graphs have a \code{type} vertex attribute in
-  igraph, this is boolean and \code{FALSE} for the vertices of the first
-  kind and \code{TRUE} for vertices of the second kind.
-
-  \code{bipartite.projection.size} calculates the number of vertices and
-  edges in the two projections of the bipartite graphs, without
-  calculating the projections themselves. This is useful to check how
-  much memory the projections would need if you have a large bipartite
-  graph.
-
-  \code{bipartite.projections} calculates the actual projections.
-  You can use the \code{probe1} argument to specify the order of the
-  projections in the result. By default vertex type \code{FALSE} is the
-  first and \code{TRUE} is the second.
-
-  \code{bipartite.projections} keeps vertex attributes.
-}
-\value{
-  A list of two undirected graphs. See details above.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## Projection of a full bipartite graph is a full graph
-g <- graph.full.bipartite(10,5)
-proj <- bipartite.projection(g)
-graph.isomorphic(proj[[1]], graph.full(10))
-graph.isomorphic(proj[[2]], graph.full(5))
-
-## The projection keeps the vertex attributes
-M <- matrix(0, nr=5, nc=3)
-rownames(M) <- c("Alice", "Bob", "Cecil", "Dan", "Ethel")
-colnames(M) <- c("Party", "Skiing", "Badminton")
-M[] <- sample(0:1, length(M), replace=TRUE)
-M
-g2 <- graph.incidence(M)
-g2$name <- "Event network"
-proj2 <- bipartite.projection(g2)
-print(proj2[[1]], g=TRUE, e=TRUE)
-print(proj2[[2]], g=TRUE, e=TRUE)
-}
-\keyword{graphs}
diff --git a/man/bipartite.random.game.Rd b/man/bipartite.random.game.Rd
deleted file mode 100644
index 28ab6d0..0000000
--- a/man/bipartite.random.game.Rd
+++ /dev/null
@@ -1,58 +0,0 @@
-\name{bipartite.random.game}
-\alias{bipartite.random.game}
-\concept{Random graph model}
-\concept{Bipartite graph}
-\title{Bipartite random graphs}
-\description{Generate bipartite graphs using the Erdos-Renyi model}
-\usage{
-bipartite.random.game(n1, n2, type = c("gnp", "gnm"), p, m,
-    directed = FALSE, mode = c("out", "in", "all")) 
-}
-\arguments{
-  \item{n1}{Integer scalar, the number of bottom vertices.}
-  \item{n2}{Integer scalar, the number of top vertices.}
-  \item{type}{Character scalar, the type of the graph, \sQuote{gnp}
-    creates a $G(n,p)$ graph, \sQuote{gnm} creates a $G(n,m)$ graph. See
-    details below.} 
-  \item{p}{Real scalar, connection probability for $G(n,p)$
-    graphs. Should not be given for $G(n,m)$ graphs.}
-  \item{m}{Integer scalar, the number of edges for $G(n,p)$
-    graphs. Should not be given for $G(n,p)$ graphs.}
-  \item{directed}{Logical scalar, whether to create a directed
-    graph. See also the \code{mode} argument.}
-  \item{mode}{Character scalar, specifies how to direct the edges in
-    directed graphs. If it is \sQuote{out}, then directed edges point
-    from bottom vertices to top vertices. If it is \sQuote{in}, edges
-    point from top vertices to bottom vertices. \sQuote{out} and
-    \sQuote{in} do not generate mutual edges. If this argument is 
-    \sQuote{all}, then each edge direction is considered
-    independently and mutual edges might be generated. This
-    argument is ignored for undirected graphs.
-  }
-}
-\details{
-  Similarly to unipartite (one-mode) networks, we can define the 
-  $G(n,p)$, and $G(n,m)$ graph classes for bipartite graphs, via their 
-  generating process. In $G(n,p)$ every possible edge between top and
-  bottom vertices is realized with probablity $p$, independently of the 
-  rest of the edges. In $G(n,m)$, we uniformly choose $m$ edges to
-  realize.
-}
-\value{A bipartite igraph graph.}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{erdos.renyi.game}} for the unipartite version.}
-\examples{
-## empty graph
-bipartite.random.game(10, 5, p=0)
-
-## full graph
-bipartite.random.game(10, 5, p=1)
-
-## random bipartite graph
-bipartite.random.game(10, 5, p=.1)
-
-## directed bipartite graph, G(n,m)
-bipartite.random.game(10, 5, type="Gnm", m=20, directed=TRUE, mode="all")
-}
-\keyword{graphs}
\ No newline at end of file
diff --git a/man/bipartite_mapping.Rd b/man/bipartite_mapping.Rd
new file mode 100644
index 0000000..a8b4aac
--- /dev/null
+++ b/man/bipartite_mapping.Rd
@@ -0,0 +1,57 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/bipartite.R
+\name{bipartite_mapping}
+\alias{bipartite.mapping}
+\alias{bipartite_mapping}
+\title{Decide whether a graph is bipartite}
+\usage{
+bipartite_mapping(graph)
+}
+\arguments{
+\item{graph}{The input graph.}
+}
+\value{
+A named list with two elements: \item{res}{A logical scalar,
+\code{TRUE} if the can be bipartite, \code{FALSE} otherwise.} \item{type}{A
+possibly vertex type mapping, a logical vector. If no such mapping exists,
+then an empty vector.}
+}
+\description{
+This function decides whether the vertices of a network can be mapped to two
+vertex types in a way that no vertices of the same type are connected.
+}
+\details{
+A bipartite graph in igraph has a \sQuote{\code{type}} vertex attribute
+giving the two vertex types.
+
+This function simply checks whether a graph \emph{could} be bipartite. It
+tries to find a mapping that gives a possible division of the vertices into
+two classes, such that no two vertices of the same class are connected by an
+edge.
+
+The existence of such a mapping is equivalent of having no circuits of odd
+length in the graph. A graph with loop edges cannot bipartite.
+
+Note that the mapping is not necessarily unique, e.g. if the graph has at
+least two components, then the vertices in the separate components can be
+mapped independently.
+}
+\examples{
+## A ring has just one loop, so it is fine
+g <- make_ring(10)
+bipartite_mapping(g)
+
+## A star is fine, too
+g2 <- make_star(10)
+bipartite_mapping(g2)
+
+## A graph containing a triangle is not fine
+g3 <- make_ring(10)
+g3 <- add_edges(g3, c(1,3))
+bipartite_mapping(g3)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/bipartite_projection.Rd b/man/bipartite_projection.Rd
new file mode 100644
index 0000000..dae7daf
--- /dev/null
+++ b/man/bipartite_projection.Rd
@@ -0,0 +1,87 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/bipartite.R
+\name{bipartite_projection}
+\alias{bipartite.projection}
+\alias{bipartite.projection.size}
+\alias{bipartite_projection}
+\alias{bipartite_projection_size}
+\title{Project a bipartite graph}
+\usage{
+bipartite_projection(graph, types = NULL, multiplicity = TRUE,
+  probe1 = NULL, which = c("both", "true", "false"), remove.type = TRUE)
+}
+\arguments{
+\item{graph}{The input graph. It can be directed, but edge directions are
+ignored during the computation.}
+
+\item{types}{An optional vertex type vector to use instead of the
+\sQuote{\code{type}} vertex attribute. You must supply this argument if the
+graph has no \sQuote{\code{type}} vertex attribute.}
+
+\item{multiplicity}{If \code{TRUE}, then igraph keeps the multiplicity of
+the edges as an edge attribute. E.g. if there is an A-C-B and also an A-D-B
+triple in the bipartite graph (but no more X, such that A-X-B is also in the
+graph), then the multiplicity of the A-B edge in the projection will be 2.}
+
+\item{probe1}{This argument can be used to specify the order of the
+projections in the resulting list. If given, then it is considered as a
+vertex id (or a symbolic vertex name); the projection containing this vertex
+will be the first one in the result list.  This argument is ignored if only
+one projection is requested in argument \code{which}.}
+
+\item{which}{A character scalar to specify which projection(s) to calculate.
+The default is to calculate both.}
+
+\item{remove.type}{Logical scalar, whether to remove the \code{type} vertex
+attribute from the projections. This makes sense because these graphs are
+not bipartite any more. However if you want to combine them with each other
+(or other bipartite graphs), then it is worth keeping this attribute. By
+default it will be removed.}
+}
+\value{
+A list of two undirected graphs. See details above.
+}
+\description{
+A bipartite graph is projected into two one-mode networks
+}
+\details{
+Bipartite graphs have a \code{type} vertex attribute in igraph, this is
+boolean and \code{FALSE} for the vertices of the first kind and \code{TRUE}
+for vertices of the second kind.
+
+\code{bipartite_projection_size} calculates the number of vertices and edges
+in the two projections of the bipartite graphs, without calculating the
+projections themselves. This is useful to check how much memory the
+projections would need if you have a large bipartite graph.
+
+\code{bipartite_projection} calculates the actual projections.  You can use
+the \code{probe1} argument to specify the order of the projections in the
+result. By default vertex type \code{FALSE} is the first and \code{TRUE} is
+the second.
+
+\code{bipartite_projection} keeps vertex attributes.
+}
+\examples{
+## Projection of a full bipartite graph is a full graph
+g <- make_full_bipartite_graph(10,5)
+proj <- bipartite_projection(g)
+graph.isomorphic(proj[[1]], make_full_graph(10))
+graph.isomorphic(proj[[2]], make_full_graph(5))
+
+## The projection keeps the vertex attributes
+M <- matrix(0, nr=5, nc=3)
+rownames(M) <- c("Alice", "Bob", "Cecil", "Dan", "Ethel")
+colnames(M) <- c("Party", "Skiing", "Badminton")
+M[] <- sample(0:1, length(M), replace=TRUE)
+M
+g2 <- graph_from_incidence_matrix(M)
+g2$name <- "Event network"
+proj2 <- bipartite_projection(g2)
+print(proj2[[1]], g=TRUE, e=TRUE)
+print(proj2[[2]], g=TRUE, e=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/bonpow.Rd b/man/bonpow.Rd
deleted file mode 100644
index d26e980..0000000
--- a/man/bonpow.Rd
+++ /dev/null
@@ -1,117 +0,0 @@
-\name{bonpow}
-\alias{bonpow}
-\concept{Bonacich Power centrality}
-%- Also NEED an `\alias' for EACH other topic documented here.
-\title{ Find Bonacich Power Centrality Scores of Network Positions }
-\description{
-  \code{bonpow} takes a graph (\code{dat}) and returns the
-  Boncich power centralities of positions (selected by \code{nodes}).
-  The decay rate for power contributions is specified by \code{exponent}
-  (1 by default).
-}
-\usage{
-bonpow(graph, nodes=V(graph), loops=FALSE, exponent=1,
-    rescale=FALSE, tol=1e-7, sparse=TRUE)
-}
-%- maybe also `usage' for other objects documented here.
-\arguments{
-  \item{graph}{ the input graph. }
-  \item{nodes}{ vertex sequence indicating which vertices are to be
-    included in the calculation.  By default, all vertices are included. } 
-  \item{loops}{ boolean indicating whether or not the diagonal should be
-    treated as valid data.  Set this true if and only if the data can
-    contain loops.  \code{loops} is \code{FALSE} by default. } 
-  \item{exponent}{ exponent (decay rate) for the Bonacich power
-    centrality score; can be negative } 
-  \item{rescale}{ if true, centrality scores are rescaled such that they
-    sum to 1. } 
-  \item{tol}{ tolerance for near-singularities during matrix inversion
-    (see \code{\link{solve}}) }
-  \item{sparse}{Logical scalar, whether to use sparse matrices for the
-    calculation. The \sQuote{Matrix} package is required for sparse
-    matrix support}
-}
-\details{
-Bonacich's power centrality measure is defined by
-\eqn{C_{BP}\left(\alpha,\beta\right)=\alpha\left(\mathbf{I}-\beta\mathbf{A}\right)^{-1}\mathbf{A}\mathbf{1}}{C_BP(alpha,beta)=alpha
-  (I-beta A)^-1 A 1}, where \eqn{\beta}{beta} is an attenuation parameter
-(set here by \code{exponent}) and \eqn{\mathbf{A}}{A} is the graph
-adjacency matrix.  (The coefficient \eqn{\alpha}{alpha} acts as a
-scaling parameter, and is set here (following Bonacich (1987)) such that
-the sum of squared scores is equal to the number of vertices.  This
-allows 1 to be used as a reference value for the ``middle'' of the
-centrality range.)  When \eqn{\beta \rightarrow
-  1/\lambda_{\mathbf{A}1}}{beta->1/lambda_A1} (the reciprocal of the
-largest eigenvalue of \eqn{\mathbf{A}}{A}), this is to within a constant
-multiple of the familiar eigenvector centrality score; for other values
-of \eqn{\beta}, the behavior of the measure is quite different.  In
-particular, \eqn{\beta} gives positive and negative weight to even and
-odd walks, respectively, as can be seen from the series expansion
-\eqn{C_{BP}\left(\alpha,\beta\right)=\alpha \sum_{k=0}^\infty \beta^k
-  \mathbf{A}^{k+1} \mathbf{1}}{C_BP(alpha,beta) = alpha sum( beta^k
-  A^(k+1) 1, k in 0..infinity )} which converges so long as \eqn{|\beta|
-  < 1/\lambda_{\mathbf{A}1}}{|beta|<1/lambda_A1}.  The magnitude of
-\eqn{\beta}{beta} controls the influence of distant actors on ego's
-centrality score, with larger magnitudes indicating slower rates of
-decay.  (High rates, hence, imply a greater sensitivity to edge
-effects.) 
-
-Interpretively, the Bonacich power measure corresponds to the notion
-that the power of a vertex is recursively defined by the sum of the
-power of its alters.  The nature of the recursion involved is then
-controlled by the power exponent: positive values imply that vertices
-become more powerful as their alters become more powerful (as occurs in
-cooperative relations), while negative values imply that vertices become
-more powerful only as their alters become \emph{weaker} (as occurs in
-competitive or antagonistic relations).  The magnitude of the exponent
-indicates the tendency of the effect to decay across long walks; higher
-magnitudes imply slower decay.  One interesting feature of this measure
-is its relative instability to changes in exponent magnitude
-(particularly in the negative case).  If your theory motivates use of
-this measure, you should be very careful to choose a decay parameter on
-a non-ad hoc basis.
-}
-\value{
-  A vector, containing the centrality scores.
-}
-\references{ Bonacich, P.  (1972).  ``Factoring and Weighting Approaches
-  to Status Scores and Clique Identification.''  \emph{Journal of
-    Mathematical Sociology}, 2, 113-120. 
-
-  Bonacich, P.  (1987).  ``Power and Centrality: A Family of Measures.''
-  \emph{American Journal of Sociology}, 92, 1170-1182. 
- }
- \author{ Carter T. Butts
-  (\url{http://www.faculty.uci.edu/profile.cfm?faculty_id=5057}), 
-   ported to igraph by Gabor Csardi \email{csardi.gabor at gmail.com}}
-\section{Warning }{Singular adjacency matrices cause no end of headaches
-  for this algorithm; thus, the routine may fail in certain cases.  This
-  will be fixed when I get a better algorithm.  \code{bonpow} will not
-  symmetrize your data before extracting eigenvectors; don't send this
-  routine asymmetric matrices unless you really mean to do so.} 
-\seealso{ \code{\link{evcent}} and \code{\link{alpha.centrality}} }
-\note{ This function was ported (ie. copied) from the SNA package. }
-\examples{
-# Generate some test data from Bonacich, 1987:
-g.c <- graph( c(1,2,1,3,2,4,3,5), dir=FALSE)
-g.d <- graph( c(1,2,1,3,1,4,2,5,3,6,4,7), dir=FALSE)
-g.e <- graph( c(1,2,1,3,1,4,2,5,2,6,3,7,3,8,4,9,4,10), dir=FALSE)
-g.f <- graph( c(1,2,1,3,1,4,2,5,2,6,2,7,3,8,3,9,3,10,4,11,4,12,4,13), dir=FALSE)
-# Compute Bonpow scores
-for (e in seq(-0.5,.5, by=0.1)) {
-  print(round(bonpow(g.c, exp=e)[c(1,2,4)], 2))
-}
-
-for (e in seq(-0.4,.4, by=0.1)) {
-  print(round(bonpow(g.d, exp=e)[c(1,2,5)], 2))
-}
-
-for (e in seq(-0.4,.4, by=0.1)) {
-  print(round(bonpow(g.e, exp=e)[c(1,2,5)], 2))
-}
-
-for (e in seq(-0.4,.4, by=0.1)) {
-  print(round(bonpow(g.f, exp=e)[c(1,2,5)], 2))
-}
-}
-\keyword{graphs}
diff --git a/man/c.igraph.es.Rd b/man/c.igraph.es.Rd
new file mode 100644
index 0000000..80501af
--- /dev/null
+++ b/man/c.igraph.es.Rd
@@ -0,0 +1,47 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{c.igraph.es}
+\alias{c.igraph.es}
+\title{Concatenate edge sequences}
+\usage{
+\method{c}{igraph.es}(..., recursive = FALSE)
+}
+\arguments{
+\item{...}{The edge sequences to concatenate. They must
+all refer to the same graph.}
+
+\item{recursive}{Ignored, included for S3 compatibility with the
+base \code{c} function.}
+}
+\value{
+An edge sequence, the input sequences concatenated.
+}
+\description{
+Concatenate edge sequences
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+c(E(g)[1], E(g)['A|B'], E(g)[1:4])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/c.igraph.vs.Rd b/man/c.igraph.vs.Rd
new file mode 100644
index 0000000..a51647b
--- /dev/null
+++ b/man/c.igraph.vs.Rd
@@ -0,0 +1,47 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{c.igraph.vs}
+\alias{c.igraph.vs}
+\title{Concatenate vertex sequences}
+\usage{
+\method{c}{igraph.vs}(..., recursive = FALSE)
+}
+\arguments{
+\item{...}{The vertex sequences to concatenate. They must
+refer to the same graph.}
+
+\item{recursive}{Ignored, included for S3 compatibility with
+the base \code{c} function.}
+}
+\value{
+A vertex sequence, the input sequences concatenated.
+}
+\description{
+Concatenate vertex sequences
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+c(V(g)[1], V(g)['A'], V(g)[1:4])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/canonical.permutation.Rd b/man/canonical.permutation.Rd
deleted file mode 100644
index 54ab82c..0000000
--- a/man/canonical.permutation.Rd
+++ /dev/null
@@ -1,88 +0,0 @@
-\name{canonical.permutation}
-\alias{canonical.permutation}
-\concept{Canonical permutation}
-\concept{BLISS}
-\title{Canonical permutation of a graph}
-\description{The canonical permutation brings every isomorphic graphs
-  into the same (labeled) graph.}
-\usage{
-canonical.permutation(graph, sh="fm")
-}
-\arguments{
-  \item{graph}{The input graph, treated as undirected.}
-  \item{sh}{Type of the heuristics to use for the BLISS
-    algorithm. See details for possible values.}
-}
-\details{
-  \code{canonical.permutation} computes a permutation which brings the
-  graph into canonical form, as defined by the BLISS algorithm.
-  All isomorphic graphs have the same canonical form.
-
-  See the paper below for the details about BLISS. This and more
-  information is available at
-  \url{http://www.tcs.hut.fi/Software/bliss/index.html}.
-
-  The possible values for the \code{sh} argument are:
-  \describe{
-    \item{\code{f}}{First non-singleton cell.}
-    \item{\code{fl}}{First largest non-singleton cell.}
-    \item{\code{fs}}{First smallest non-singleton cell.}
-    \item{\code{fm}}{First maximally non-trivially connectec
-      non-singleton cell.}
-    \item{\code{flm}}{Largest maximally non-trivially connected
-      non-singleton cell.}
-    \item{\code{fsm}}{Smallest maximally non-trivially connected
-      non-singleton cell.}
-  }
-  See the paper in references for details about these.
-}
-\value{
-  A list with the following members:
-  \item{labeling}{The canonical parmutation which takes the input
-    graph into canonical form. A numeric vector, the first element is
-    the new label of vertex 0, the second element for vertex 1, etc. }
-  \item{info}{Some information about the BLISS computation. A named
-    list with the following members:
-    \describe{
-      \item{\code{nof_nodes}}{The number of nodes in the search tree.}
-      \item{\code{nof_leaf_nodes}}{The number of leaf nodes in the search
-	tree.}
-      \item{\code{nof_bad_nodes}}{Number of bad nodes.}
-      \item{\code{nof_canupdates}}{Number of canrep updates.}
-      \item{\code{max_level}}{Maximum level.}
-      \item{\code{group_size}}{The size of the automorphism group of the
-	input graph, as a string. This number is exact if igraph was
-	compiled with the GMP library, and approximate otherwise.}
-    }
-  }
-}
-\references{
-  Tommi Junttila and Petteri Kaski: Engineering an Efficient Canonical
-  Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of the
-    Ninth Workshop on Algorithm Engineering and Experiments and the
-    Fourth Workshop on Analytic Algorithms and Combinatorics.} 2007.
-}
-\author{Tommi Junttila for BLISS, Gabor Csardi
-  \email{csardi.gabor at gmail.com} for the igraph and R interfaces.}
-\seealso{\code{\link{permute.vertices}} to apply a permutation to a
-  graph, \code{\link{graph.isomorphic}} for deciding graph isomorphism,
-  possibly based on canonical labels.}
-\examples{
-## Calculate the canonical form of a random graph
-g1 <- erdos.renyi.game(10, 20, type="gnm")
-cp1 <- canonical.permutation(g1)
-cf1 <- permute.vertices(g1, cp1$labeling)
-
-## Do the same with a random permutation of it
-g2 <- permute.vertices(g1, sample(vcount(g1)))
-cp2 <- canonical.permutation(g2)
-cf2 <- permute.vertices(g2, cp2$labeling)
-
-## Check that they are the same
-el1 <- get.edgelist(cf1)
-el2 <- get.edgelist(cf2)
-el1 <- el1[ order(el1[,1], el1[,2]), ]
-el2 <- el2[ order(el2[,1], el2[,2]), ]
-all(el1 == el2)
-}
-\keyword{graphs}
diff --git a/man/canonical_permutation.Rd b/man/canonical_permutation.Rd
new file mode 100644
index 0000000..78d8e0f
--- /dev/null
+++ b/man/canonical_permutation.Rd
@@ -0,0 +1,86 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{canonical_permutation}
+\alias{canonical.permutation}
+\alias{canonical_permutation}
+\title{Canonical permutation of a graph}
+\usage{
+canonical_permutation(graph, sh = "fm")
+}
+\arguments{
+\item{graph}{The input graph, treated as undirected.}
+
+\item{sh}{Type of the heuristics to use for the BLISS algorithm. See details
+for possible values.}
+}
+\value{
+A list with the following members: \item{labeling}{The canonical
+parmutation which takes the input graph into canonical form. A numeric
+vector, the first element is the new label of vertex 0, the second element
+for vertex 1, etc. } \item{info}{Some information about the BLISS
+computation. A named list with the following members: \describe{
+\item{"nof_nodes"}{The number of nodes in the search tree.}
+\item{"nof_leaf_nodes"}{The number of leaf nodes in the search tree.}
+\item{"nof_bad_nodes"}{Number of bad nodes.}
+\item{"nof_canupdates"}{Number of canrep updates.}
+\item{"max_level"}{Maximum level.} \item{"group_size"}{The size
+of the automorphism group of the input graph, as a string. This number is
+exact if igraph was compiled with the GMP library, and approximate
+otherwise.} } }
+}
+\description{
+The canonical permutation brings every isomorphic graphs into the same
+(labeled) graph.
+}
+\details{
+\code{canonical_permutation} computes a permutation which brings the graph
+into canonical form, as defined by the BLISS algorithm.  All isomorphic
+graphs have the same canonical form.
+
+See the paper below for the details about BLISS. This and more information
+is available at \url{http://www.tcs.hut.fi/Software/bliss/index.html}.
+
+The possible values for the \code{sh} argument are: \describe{
+\item{"f"}{First non-singleton cell.} \item{"fl"}{First largest
+non-singleton cell.} \item{"fs"}{First smallest non-singleton cell.}
+\item{"fm"}{First maximally non-trivially connectec non-singleton
+cell.} \item{"flm"}{Largest maximally non-trivially connected
+non-singleton cell.} \item{"fsm"}{Smallest maximally non-trivially
+connected non-singleton cell.} } See the paper in references for details
+about these.
+}
+\examples{
+## Calculate the canonical form of a random graph
+g1 <- sample_gnm(10, 20)
+cp1 <- canonical_permutation(g1)
+cf1 <- permute(g1, cp1$labeling)
+
+## Do the same with a random permutation of it
+g2 <- permute(g1, sample(vcount(g1)))
+cp2 <- canonical_permutation(g2)
+cf2 <- permute(g2, cp2$labeling)
+
+## Check that they are the same
+el1 <- as_edgelist(cf1)
+el2 <- as_edgelist(cf2)
+el1 <- el1[ order(el1[,1], el1[,2]), ]
+el2 <- el2[ order(el2[,1], el2[,2]), ]
+all(el1 == el2)
+}
+\author{
+Tommi Junttila for BLISS, Gabor Csardi
+\email{csardi.gabor at gmail.com} for the igraph and R interfaces.
+}
+\references{
+Tommi Junttila and Petteri Kaski: Engineering an Efficient
+Canonical Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of
+the Ninth Workshop on Algorithm Engineering and Experiments and the Fourth
+Workshop on Analytic Algorithms and Combinatorics.} 2007.
+}
+\seealso{
+\code{\link{permute}} to apply a permutation to a graph,
+\code{\link{graph.isomorphic}} for deciding graph isomorphism, possibly
+based on canonical labels.
+}
+\keyword{graphs}
+
diff --git a/man/categorical_pal.Rd b/man/categorical_pal.Rd
new file mode 100644
index 0000000..1803d49
--- /dev/null
+++ b/man/categorical_pal.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/palette.R
+\name{categorical_pal}
+\alias{categorical_pal}
+\title{Palette for categories}
+\usage{
+categorical_pal(n)
+}
+\arguments{
+\item{n}{The number of colors in the palette. We simply take the first
+\code{n} colors from the total 8.}
+}
+\value{
+A character vector of RGB color codes.
+}
+\description{
+This is a color blind friendly palette from
+\url{http://jfly.iam.u-tokyo.ac.jp/color}. It has 8 colors.
+}
+\details{
+This is the suggested palette for visualizations where vertex colors
+mark categories, e.g. community membership.
+}
+\examples{
+\dontrun{
+library(igraphdata)
+data(karate)
+karate <- karate \%>\%
+  add_layout_(with_fr()) \%>\%
+  set_vertex_attr("size", value = 10)
+
+cl_k <- cluster_optimal(karate)
+
+V(karate)$color <- membership(cl_k)
+karate$palette <- categorical_pal(length(cl_k))
+plot(karate)
+}
+}
+\seealso{
+Other palettes: \code{\link{diverging_pal}};
+  \code{\link{r_pal}}; \code{\link{sequential_pal}}
+}
+
diff --git a/man/centr_betw.Rd b/man/centr_betw.Rd
new file mode 100644
index 0000000..324f467
--- /dev/null
+++ b/man/centr_betw.Rd
@@ -0,0 +1,61 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_betw}
+\alias{centr_betw}
+\alias{centralization.betweenness}
+\title{Centralize a graph according to the betweenness of vertices}
+\usage{
+centr_betw(graph, directed = TRUE, nobigint = TRUE, normalized = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{directed}{logical scalar, whether to use directed shortest paths for
+calculating betweenness.}
+
+\item{nobigint}{Logical scalar, whether to use big integers for the
+betweenness calculation. This argument is passed to the
+\code{\link{betweenness}} function.}
+
+\item{normalized}{Logical scalar. Whether to normalize the graph level
+centrality score by dividing by the theoretical maximum.}
+}
+\value{
+A named list with the following components:
+  \item{res}{The node-level centrality scores.}
+  \item{centralization}{The graph level centrality index.}
+  \item{theoretical_max}{The maximum theoretical graph level
+    centralization score for a graph with the given number of vertices,
+    using the same parameters. If the \code{normalized} argument was
+    \code{TRUE}, then the result was divided by this number.}
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_degree(g)$centralization
+centr_clo(g, mode = "all")$centralization
+centr_betw(g, directed = FALSE)$centralization
+centr_eigen(g, directed = FALSE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_betw_tmax.Rd b/man/centr_betw_tmax.Rd
new file mode 100644
index 0000000..dd1f044
--- /dev/null
+++ b/man/centr_betw_tmax.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_betw_tmax}
+\alias{centr_betw_tmax}
+\alias{centralization.betweenness.tmax}
+\title{Theoretical maximum for betweenness centralization}
+\usage{
+centr_betw_tmax(graph = NULL, nodes = 0, directed = TRUE)
+}
+\arguments{
+\item{graph}{The input graph. It can also be \code{NULL}, if
+\code{nodes} is given.}
+
+\item{nodes}{The number of vertices. This is ignored if the graph is
+given.}
+
+\item{directed}{logical scalar, whether to use directed shortest paths
+for calculating betweenness.}
+}
+\value{
+Real scalar, the theoratical maximum (unnormalized) graph
+  betweenness centrality score for graphs with given order and other
+  parameters.
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_betw(g, normalized = FALSE)$centralization \%>\%
+ `/`(centr_betw_tmax(g))
+centr_betw(g, normalized = TRUE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_clo.Rd b/man/centr_clo.Rd
new file mode 100644
index 0000000..d526cc3
--- /dev/null
+++ b/man/centr_clo.Rd
@@ -0,0 +1,57 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_clo}
+\alias{centr_clo}
+\alias{centralization.closeness}
+\title{Centralize a graph according to the closeness of vertices}
+\usage{
+centr_clo(graph, mode = c("out", "in", "all", "total"), normalized = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{mode}{This is the same as the \code{mode} argument of
+\code{closeness}.}
+
+\item{normalized}{Logical scalar. Whether to normalize the graph level
+centrality score by dividing by the theoretical maximum.}
+}
+\value{
+A named list with the following components:
+  \item{res}{The node-level centrality scores.}
+  \item{centralization}{The graph level centrality index.}
+  \item{theoretical_max}{The maximum theoretical graph level
+    centralization score for a graph with the given number of vertices,
+    using the same parameters. If the \code{normalized} argument was
+    \code{TRUE}, then the result was divided by this number.}
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_degree(g)$centralization
+centr_clo(g, mode = "all")$centralization
+centr_betw(g, directed = FALSE)$centralization
+centr_eigen(g, directed = FALSE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_clo_tmax.Rd b/man/centr_clo_tmax.Rd
new file mode 100644
index 0000000..eec1a53
--- /dev/null
+++ b/man/centr_clo_tmax.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_clo_tmax}
+\alias{centr_clo_tmax}
+\alias{centralization.closeness.tmax}
+\title{Theoretical maximum for closeness centralization}
+\usage{
+centr_clo_tmax(graph = NULL, nodes = 0, mode = c("out", "in", "all",
+  "total"))
+}
+\arguments{
+\item{graph}{The input graph. It can also be \code{NULL}, if
+\code{nodes} is given.}
+
+\item{nodes}{The number of vertices. This is ignored if the graph is
+given.}
+
+\item{mode}{This is the same as the \code{mode} argument of
+\code{closeness}.}
+}
+\value{
+Real scalar, the theoratical maximum (unnormalized) graph
+  closeness centrality score for graphs with given order and other
+  parameters.
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_clo(g, normalized = FALSE)$centralization \%>\%
+ `/`(centr_clo_tmax(g))
+centr_clo(g, normalized = TRUE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_degree.Rd b/man/centr_degree.Rd
new file mode 100644
index 0000000..1b59b18
--- /dev/null
+++ b/man/centr_degree.Rd
@@ -0,0 +1,61 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_degree}
+\alias{centr_degree}
+\alias{centralization.degree}
+\title{Centralize a graph according to the degrees of vertices}
+\usage{
+centr_degree(graph, mode = c("all", "out", "in", "total"), loops = TRUE,
+  normalized = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{mode}{This is the same as the \code{mode} argument of
+\code{degree}.}
+
+\item{loops}{Logical scalar, whether to consider loops edges when
+calculating the degree.}
+
+\item{normalized}{Logical scalar. Whether to normalize the graph level
+centrality score by dividing by the theoretical maximum.}
+}
+\value{
+A named list with the following components:
+  \item{res}{The node-level centrality scores.}
+  \item{centralization}{The graph level centrality index.}
+  \item{theoretical_max}{The maximum theoretical graph level
+    centralization score for a graph with the given number of vertices,
+    using the same parameters. If the \code{normalized} argument was
+    \code{TRUE}, then the result was divided by this number.}
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_degree(g)$centralization
+centr_clo(g, mode = "all")$centralization
+centr_betw(g, directed = FALSE)$centralization
+centr_eigen(g, directed = FALSE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_degree_tmax.Rd b/man/centr_degree_tmax.Rd
new file mode 100644
index 0000000..6cefd05
--- /dev/null
+++ b/man/centr_degree_tmax.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_degree_tmax}
+\alias{centr_degree_tmax}
+\alias{centralization.degree.tmax}
+\title{Theoretical maximum for degree centralization}
+\usage{
+centr_degree_tmax(graph = NULL, nodes = 0, mode = c("all", "out", "in",
+  "total"), loops = FALSE)
+}
+\arguments{
+\item{graph}{The input graph. It can also be \code{NULL}, if
+\code{nodes}, \code{mode} and \code{loops} are all given.}
+
+\item{nodes}{The number of vertices. This is ignored if the graph is given.}
+
+\item{mode}{This is the same as the \code{mode} argument of
+\code{degree}.}
+
+\item{loops}{Logical scalar, whether to consider loops edges when
+calculating the degree.}
+}
+\value{
+Real scalar, the theoratical maximum (unnormalized) graph degree
+  centrality score for graphs with given order and other parameters.
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_degree(g, normalized = FALSE)$centralization \%>\%
+ `/`(centr_degree_tmax(g))
+centr_degree(g, normalized = TRUE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_eigen.Rd b/man/centr_eigen.Rd
new file mode 100644
index 0000000..af47de4
--- /dev/null
+++ b/man/centr_eigen.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_eigen}
+\alias{centr_eigen}
+\alias{centralization.evcent}
+\title{Centralize a graph according to the eigenvector centrality of vertices}
+\usage{
+centr_eigen(graph, directed = FALSE, scale = TRUE,
+  options = arpack_defaults, normalized = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{directed}{logical scalar, whether to use directed shortest paths for
+calculating eigenvector centrality.}
+
+\item{scale}{Whether to rescale the eigenvector centrality scores, such that
+the maximum score is one.}
+
+\item{options}{This is passed to \code{\link{eigen_centrality}}, the options
+for the ARPACK eigensolver.}
+
+\item{normalized}{Logical scalar. Whether to normalize the graph level
+centrality score by dividing by the theoretical maximum.}
+}
+\value{
+A named list with the following components:
+  \item{vector}{The node-level centrality scores.}
+  \item{value}{The corresponding eigenvalue.}
+  \item{options}{ARPACK options, see the return value of
+    \code{\link{eigen_centrality}} for details.}
+  \item{centralization}{The graph level centrality index.}
+  \item{theoretical_max}{The same as above, the theoretical maximum
+    centralization score for a graph with the same number of vertices.}
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_degree(g)$centralization
+centr_clo(g, mode = "all")$centralization
+centr_betw(g, directed = FALSE)$centralization
+centr_eigen(g, directed = FALSE)$centralization
+
+# The most centralized graph according to eigenvector centrality
+g0 <- make_graph(c(2,1), n = 10, dir = FALSE)
+g1 <- make_star(10, mode = "undirected")
+centr_eigen(g0)$centralization
+centr_eigen(g1)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centr_eigen_tmax.Rd b/man/centr_eigen_tmax.Rd
new file mode 100644
index 0000000..e654c7c
--- /dev/null
+++ b/man/centr_eigen_tmax.Rd
@@ -0,0 +1,57 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centr_eigen_tmax}
+\alias{centr_eigen_tmax}
+\alias{centralization.evcent.tmax}
+\title{Theoretical maximum for betweenness centralization}
+\usage{
+centr_eigen_tmax(graph = NULL, nodes = 0, directed = FALSE,
+  scale = TRUE)
+}
+\arguments{
+\item{graph}{The input graph. It can also be \code{NULL}, if
+\code{nodes} is given.}
+
+\item{nodes}{The number of vertices. This is ignored if the graph is
+given.}
+
+\item{directed}{logical scalar, whether to use directed shortest paths
+for calculating betweenness.}
+
+\item{scale}{Whether to rescale the eigenvector centrality scores,
+such that the maximum score is one.}
+}
+\value{
+Real scalar, the theoratical maximum (unnormalized) graph
+  betweenness centrality score for graphs with given order and other
+  parameters.
+}
+\description{
+See \code{\link{centralize}} for a summary of graph centralization.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m = 4)
+centr_eigen(g, normalized = FALSE)$centralization \%>\%
+ `/`(centr_eigen_tmax(g))
+centr_eigen(g, normalized = TRUE)$centralization
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}};
+  \code{\link{centralization}}, \code{\link{centralize}},
+  \code{\link{centralize.scores}}
+}
+
diff --git a/man/centralization.Rd b/man/centralization.Rd
deleted file mode 100644
index 44439f8..0000000
--- a/man/centralization.Rd
+++ /dev/null
@@ -1,156 +0,0 @@
-\name{centralization}
-\alias{centralization}
-\alias{centralize.scores}
-\alias{centralization.degree}
-\alias{centralization.closeness}
-\alias{centralization.betweenness}
-\alias{centralization.evcent}
-\alias{centralization.degree.tmax}
-\alias{centralization.closeness.tmax}
-\alias{centralization.betweenness.tmax}
-\alias{centralization.evcent.tmax}
-\title{Centralization of a graph.tmax}
-\description{
-  Centralization is a method for creating a graph level centralization
-  measure from the centrality scores of the vertices.
-}
-\usage{
-centralize.scores (scores, theoretical.max, normalized = TRUE)
-
-centralization.degree (graph, mode = c("all", "out", "in", "total"),
-    loops = TRUE, normalized = TRUE) 
-centralization.closeness (graph, mode = c("out", "in", "all", "total"),
-    normalized = TRUE)
-centralization.betweenness (graph, directed = TRUE, nobigint = TRUE,
-    normalized = TRUE)
-centralization.evcent (graph, directed = FALSE, scale = TRUE,
-    options = igraph.arpack.default, normalized = TRUE)
-
-centralization.degree.tmax (graph = NULL, nodes = 0,
-    mode = c("all", "out", "in", "total"), loops = FALSE)
-centralization.closeness.tmax (graph = NULL, nodes = 0,
-    mode = c("out", "in", "all", "total"))
-centralization.betweenness.tmax (graph = NULL, nodes = 0,
-    directed = TRUE)
-centralization.evcent.tmax (graph = NULL, nodes = 0,
-    directed = FALSE, scale = TRUE)
-}
-\arguments{
-  \item{scores}{The vertex level centrality scores.}
-  \item{theoretical.max}{Real scalar. The graph level centrality score
-    of the most centralized graph with the same number of vertices as
-    the graph under study. This is only used if the \code{normalized}
-    argument is set to \code{TRUE}.}
-  \item{normalized}{Logical scalar. Whether to normalize the graph level
-    centrality score by dividing the supplied theoretical maximum.}
-  \item{graph}{The input graph. For the \dQuote{tmax} functions it can
-    be \code{NULL}, see the details below.}
-  \item{mode}{This is the same as the \code{mode} argument of
-    \code{degree} and \code{closeness}.}
-  \item{loops}{Logical scalar, whether to consider loops edges when
-    calculating the degree.}
-  \item{directed}{logical scalar, whether to use directed shortest paths
-    for calculating betweenness.}
-  \item{nobigint}{Logical scalar, whether to use big integers for the
-    betweenness calculation. This argument is passed to the
-    \code{\link{betweenness}} function.}
-  \item{scale}{Whether to rescale the eigenvector centrality scores,
-    such that the maximum score is one.}
-  \item{nodes}{The number of vertices. This is ignored if the graph is
-    given.}
-  \item{options}{This is passed to \code{\link{evcent}}, the options for
-    the ARPACK eigensolver.}
-}
-\details{
-  Centralization is a general method for calculating a graph-level
-  centrality score based on node-level centrality measure. The
-  formula for this is
-
-  \deqn{C(G)=\sum_v (\max_w c_w - c_v),}{
-    C(G)=sum( max(c(w), w) - c(v),v),}
-  
-  where \eqn{c_v}{c(v)} is the centrality of vertex \eqn{v}.
-
-  The graph-level centrality score can be normalized by dividing by the
-  maximum theoretical score for a graph with the same number of
-  vertices, using the same parameters, e.g. directedness, whether we
-  consider loop edges, etc.
-
-  For degree, closeness and betweenness the most centralized structure
-  is some version of the star graph, in-star, out-star or undirected
-  star.
-
-  For eigenvector centrality the most centralized structure is the graph
-  with a single edge (and potentially many isolates).
-
-  \code{centralize.scores} using the general centralization formula to
-  calculate a graph-level score from vertex-level scores.
-
-  \code{centralization.degree}, \code{centralization.closeness},
-  \code{centralization.betweenness} calculate both the vertex-level and
-  the graph-level indices.
-
-  \code{centralization.degree.tmax},
-  \code{centralization.closeness.tmax},
-  \code{centralization.betweenness.tmax} and
-  \code{centralization.evcent.tmax} return the theoretical maximum
-  scores. They operate in two modes. In the first mode, a graph is given
-  and the maximum score is calculated based on that. E.g. the number of
-  vertices and directedness is taken from this graph.
-
-  The other way to call these functions is to omit the
-  \code{graph} argument, but explicitly specify the rest of the
-  arguments.
-}
-\value{
-  For \code{centralize.scores} a real scalar.
-
-  For \code{centralization.degree}, \code{centralization.closeness} and
-  \code{centralization.betweenness} a named list with the following
-  components:
-  \item{res}{The node-level centrality scores.}
-  \item{centralization}{The graph level centrality index.}
-  \item{theoretical_max}{The maximum theoretical graph level
-    centralization score for a graph with the given number of vertices,
-    using the same parameters. If the \code{normalized} argument was
-    \code{TRUE}, then the result was divided by this number.}
-
-  For \code{centralization.evcent} a named list with the following
-  components:
-  \item{vector}{The node-level centrality scores.}
-  \item{value}{The corresponding eigenvalue.}
-  \item{options}{ARPACK options, see the return value of
-  \code{\link{evcent}} for details.} 
-  \item{centralization}{The graph level centrality index.}
-  \item{theoretical_max}{The same as above, the theoretical maximum
-    centralization score for a graph with the same number of vertices.}
-
-  For \code{centralization.degree.tmax},
-  \code{centralization.closeness.tmax},
-  \code{centralization.betweenness.tmax} and
-  \code{centralization.evcent.tmax} a real scalar.
-}
-\references{
-  Freeman, L.C.  (1979).  Centrality in Social Networks I:
-  Conceptual Clarification. \emph{Social Networks} 1, 215--239.
-
-  Wasserman, S., and Faust, K.  (1994).  \emph{Social Network Analysis:
-  Methods and Applications.}  Cambridge University Press.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-%\seealso{}
-\examples{
-# A BA graph is quite centralized
-g <- ba.game(1000, m=4)
-centralization.degree(g)$centralization
-centralization.closeness(g, mode="all")$centralization
-centralization.evcent(g, directed=FALSE)$centralization
-
-# The most centralized graph according to eigenvector centrality
-g0 <- graph( c(2,1), n=10, dir=FALSE )
-g1 <- graph.star(10, mode="undirected")
-centralization.evcent(g0)$centralization
-centralization.evcent(g1)$centralization
-}
-\keyword{graphs}
-
diff --git a/man/centralize.Rd b/man/centralize.Rd
new file mode 100644
index 0000000..6cb6138
--- /dev/null
+++ b/man/centralize.Rd
@@ -0,0 +1,89 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centralization.R
+\name{centralize}
+\alias{centralization}
+\alias{centralize}
+\alias{centralize.scores}
+\title{Centralization of a graph}
+\usage{
+centralize(scores, theoretical.max = 0, normalized = TRUE)
+}
+\arguments{
+\item{scores}{The vertex level centrality scores.}
+
+\item{theoretical.max}{Real scalar. The graph level centrality score of
+the most centralized graph with the same number of vertices as the graph
+under study. This is only used if the \code{normalized} argument is set
+to \code{TRUE}.}
+
+\item{normalized}{Logical scalar. Whether to normalize the graph level
+centrality score by dividing by the supplied theoretical maximum.}
+}
+\value{
+A real scalar, the centralization of the graph from which
+  \code{scores} were derived.
+}
+\description{
+Centralization is a method for creating a graph level centralization
+measure from the centrality scores of the vertices.
+}
+\details{
+Centralization is a general method for calculating a graph-level
+centrality score based on node-level centrality measure. The formula for
+this is
+\deqn{C(G)=\sum_v (\max_w c_w - c_v),}{ C(G)=sum( max(c(w), w) - c(v),v),}
+where \eqn{c_v}{c(v)} is the centrality of vertex \eqn{v}.
+
+The graph-level centrality score can be normalized by dividing by the
+maximum theoretical score for a graph with the same number of vertices,
+using the same parameters, e.g. directedness, whether we consider loop
+edges, etc.
+
+For degree, closeness and betweenness the most centralized structure is
+some version of the star graph, in-star, out-star or undirected star.
+
+For eigenvector centrality the most centralized structure is the graph
+with a single edge (and potentially many isolates).
+
+\code{centralize} implements general centralization formula to calculate
+a graph-level score from vertex-level scores.
+}
+\examples{
+# A BA graph is quite centralized
+g <- sample_pa(1000, m=4)
+centr_degree(g)$centralization
+centr_clo(g, mode="all")$centralization
+centr_eigen(g, directed=FALSE)$centralization
+
+# The most centralized graph according to eigenvector centrality
+g0 <- graph( c(2,1), n=10, dir=FALSE )
+g1 <- make_star(10, mode="undirected")
+centr_eigen(g0)$centralization
+centr_eigen(g1)$centralization
+}
+\references{
+Freeman, L.C.  (1979).  Centrality in Social Networks I:
+Conceptual Clarification. \emph{Social Networks} 1, 215--239.
+
+Wasserman, S., and Faust, K.  (1994).  \emph{Social Network Analysis:
+Methods and Applications.} Cambridge University Press.
+}
+\seealso{
+Other centralization related: \code{\link{centr_betw_tmax}},
+  \code{\link{centralization.betweenness.tmax}};
+  \code{\link{centr_betw}},
+  \code{\link{centralization.betweenness}};
+  \code{\link{centr_clo_tmax}},
+  \code{\link{centralization.closeness.tmax}};
+  \code{\link{centr_clo}},
+  \code{\link{centralization.closeness}};
+  \code{\link{centr_degree_tmax}},
+  \code{\link{centralization.degree.tmax}};
+  \code{\link{centr_degree}},
+  \code{\link{centralization.degree}};
+  \code{\link{centr_eigen_tmax}},
+  \code{\link{centralization.evcent.tmax}};
+  \code{\link{centr_eigen}},
+  \code{\link{centralization.evcent}}
+}
+
diff --git a/man/cliques.Rd b/man/cliques.Rd
index 2dfae06..3025a17 100644
--- a/man/cliques.Rd
+++ b/man/cliques.Rd
@@ -1,92 +1,101 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/cliques.R
 \name{cliques}
+\alias{clique.number}
+\alias{clique_num}
 \alias{cliques}
+\alias{count_max_cliques}
 \alias{largest.cliques}
+\alias{largest_cliques}
+\alias{max_cliques}
 \alias{maximal.cliques}
 \alias{maximal.cliques.count}
-\alias{clique.number}
-\concept{Clique}
-\concept{Maximal clique}
-\concept{Largest clique}
 \title{The functions find cliques, ie. complete subgraphs in a graph}
-\description{These functions find all, the largest or all the maximal
-  cliques in an undirected graph. The size of the largest clique can
-  also be calculated.}
 \usage{
-cliques(graph, min=NULL, max=NULL)
-largest.cliques(graph)
-maximal.cliques(graph, min=NULL, max=NULL, subset=NULL, file=NULL)
-maximal.cliques.count(graph, min=NULL, max=NULL, subset=NULL)
-clique.number(graph)
+cliques(graph, min = NULL, max = NULL)
+
+max_cliques(graph, min = NULL, max = NULL, subset = NULL, file = NULL)
 }
 \arguments{
-  \item{graph}{The input graph, directed graphs will be considered as
-    undirected ones, multiple edges and loops are ignored.}
-  \item{min}{Numeric constant, lower limit on the size of the cliques to
-    find. \code{NULL} means no limit, ie. it is the same as 0.}
-  \item{max}{Numeric constant, upper limit on the size of the cliques to
-    find. \code{NULL} means no limit.}
-  \item{subset}{If not \code{NULL}, then it must be a vector of vertex
-    ids, numeric or symbolic if the graph is named. The algorithm is run
-    from these vertices only, so only a subset of all maximal cliques is
-    returned. See the Eppstein paper for details. This argument makes it
-    possible to easily parallelize the finding of maximal cliques.}
-  \item{file}{If not \code{NULL}, then it must be a file name, i.e. a
-    character scalar. The output of the algorithm is written to this
-    file. (If it exists, then it will be overwritten.) Each clique will
-    be a separate line in the file, given with the numeric ids of its
-    vertices, separated by whitespace.}
-}
-\details{
-  \code{cliques} find all complete subgraphs in the input graph, obeying
-  the size limitations given in the \code{min} and \code{max} arguments.
-
-  \code{largest.cliques} finds all largest cliques in the input graph. A
-  clique is largest if there is no other clique including more vertices.
+\item{graph}{The input graph, directed graphs will be considered as
+undirected ones, multiple edges and loops are ignored.}
 
-  \code{maximal.cliques} finds all maximal cliques in the input graph.
-  A clique in maximal if it cannot be extended to a larger clique. The
-  largest cliques are always maximal, but a maximal clique is not
-  neccessarily the largest.
+\item{min}{Numeric constant, lower limit on the size of the cliques to find.
+\code{NULL} means no limit, ie. it is the same as 0.}
 
-  \code{maximal.cliques.count} counts the maximal cliques.
+\item{max}{Numeric constant, upper limit on the size of the cliques to find.
+\code{NULL} means no limit.}
 
-  \code{clique.number} calculates the size of the largest clique(s).
+\item{subset}{If not \code{NULL}, then it must be a vector of vertex ids,
+numeric or symbolic if the graph is named. The algorithm is run from these
+vertices only, so only a subset of all maximal cliques is returned. See the
+Eppstein paper for details. This argument makes it possible to easily
+parallelize the finding of maximal cliques.}
 
-  The current implementation of these functions searches
-  for maximal independent vertex sets (see
-  \code{\link{independent.vertex.sets}}) in the complementer graph.
+\item{file}{If not \code{NULL}, then it must be a file name, i.e. a
+character scalar. The output of the algorithm is written to this file. (If
+it exists, then it will be overwritten.) Each clique will be a separate line
+in the file, given with the numeric ids of its vertices, separated by
+whitespace.}
 }
 \value{
-  \code{cliques}, \code{largest.cliques} and \code{clique.number} return
-  a list containing numeric vectors of vertex ids. Each list element is
-  a clique.
+\code{cliques}, \code{largest_cliques} and \code{clique_num}
+return a list containing numeric vectors of vertex ids. Each list element is
+a clique.
 
-  \code{maximal.cliques} returns \code{NULL}, invisibly, if its
-  \code{file} argument is not \code{NULL}. The output is written to the
-  specified file in this case.
-  
-  \code{clique.number} and \code{maximal.cliques.count} return an
-  integer scalar.
+\code{max_cliques} returns \code{NULL}, invisibly, if its \code{file}
+argument is not \code{NULL}. The output is written to the specified file in
+this case.
+
+\code{clique_num} and \code{count_max_cliques} return an integer
+scalar.
 }
-\references{
-  For maximal cliques the following algorithm is implemented:
-  David Eppstein, Maarten Loffler, Darren Strash:
-  Listing All Maximal Cliques in Sparse Graphs in Near-optimal Time.
-  \url{http://arxiv.org/abs/1006.5440}
+\description{
+These functions find all, the largest or all the maximal cliques in an
+undirected graph. The size of the largest clique can also be calculated.
+}
+\details{
+\code{cliques} find all complete subgraphs in the input graph, obeying the
+size limitations given in the \code{min} and \code{max} arguments.
+
+\code{largest_cliques} finds all largest cliques in the input graph. A
+clique is largest if there is no other clique including more vertices.
+
+\code{max_cliques} finds all maximal cliques in the input graph.  A
+clique in maximal if it cannot be extended to a larger clique. The largest
+cliques are always maximal, but a maximal clique is not neccessarily the
+largest.
+
+\code{count_max_cliques} counts the maximal cliques.
+
+\code{clique_num} calculates the size of the largest clique(s).
+
+The current implementation of these functions searches for maximal
+independent vertex sets (see \code{\link{ivs}}) in the
+complementer graph.
 }
-\author{Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
-  \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{independent.vertex.sets}}}
 \examples{
 # this usually contains cliques of size six
-g <- erdos.renyi.game(100, 0.3)
-clique.number(g)
+g <- sample_gnp(100, 0.3)
+clique_num(g)
 cliques(g, min=6)
-largest.cliques(g)
+largest_cliques(g)
 
 # To have a bit less maximal cliques, about 100-200 usually
-g <- erdos.renyi.game(100, 0.03)
-maximal.cliques(g)
-
+g <- sample_gnp(100, 0.03)
+max_cliques(g)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
+\references{
+For maximal cliques the following algorithm is implemented:
+David Eppstein, Maarten Loffler, Darren Strash: Listing All Maximal Cliques
+in Sparse Graphs in Near-optimal Time.  \url{http://arxiv.org/abs/1006.5440}
+}
+\seealso{
+\code{\link{ivs}}
 }
 \keyword{graphs}
+
diff --git a/man/closeness.Rd b/man/closeness.Rd
index b1ac763..88847da 100644
--- a/man/closeness.Rd
+++ b/man/closeness.Rd
@@ -1,62 +1,80 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{closeness}
 \alias{closeness}
 \alias{closeness.estimate}
-\concept{Closeness centrality}
+\alias{estimate_closeness}
 \title{Closeness centrality of vertices}
-\description{Cloness centrality measures how many steps is required
-  to access every other vertex from a given vertex.}
 \usage{
-closeness(graph, vids=V(graph), mode = c("out", "in", "all", "total"),
-        weights = NULL, normalized = FALSE)
-closeness.estimate(graph, vids=V(graph), mode = c("out", "in", "all",
-       "total"), cutoff, weights = NULL, normalized = FALSE) 
+closeness(graph, vids = V(graph), mode = c("out", "in", "all", "total"),
+  weights = NULL, normalized = FALSE)
+
+estimate_closeness(graph, vids = V(graph), mode = c("out", "in", "all",
+  "total"), cutoff, weights = NULL, normalized = FALSE)
 }
 \arguments{
-  \item{graph}{The graph to analyze.}
-  \item{vids}{The vertices for which closeness will be calculated.}
-  \item{mode}{Character string, defined the types of the paths used for
-    measuring the distance in directed graphs. \dQuote{in} measures the
-    paths \emph{to} a vertex, \dQuote{out} measures paths \emph{from} a
-    vertex, \emph{all} uses undirected paths. This argument is ignored
-    for undirected graphs.}
-  \item{normalized}{Logical scalar, whether to calculate the normalized
-    closeness. Normalization is performed by multiplying the raw
-    closeness by \eqn{n-1}, where \eqn{n} is the number of vertices in
-    the graph.}
-  \item{cutoff}{The maximum path length to consider when calculating the
-    betweenness. If zero or negative then there is no such limit.}
-  \item{weights}{Optional positive weight vector for calculating
-    weighted closeness. If the graph has a \code{weight} edge
-    attribute, then this is used by default.}
-}
-\details{The closeness centrality of a vertex is defined by the inverse
-  of the average length of the shortest paths to/from all the other
-  vertices in the graph:
-
-  \deqn{\frac{1}{\sum_{i\ne v} d_vi}}{1/sum( d(v,i), i != v)}
-
-  If there is no (directed) path between vertex \eqn{v}{\code{v}} and
-  \eqn{i}{\code{i}} then the total number of vertices is used in the
-  formula instead of the path length.
-
-  \code{closeness.estimate} only considers paths of length
-  \code{cutoff} or smaller, this can be run for larger graphs, as the
-  running time is not quadratic (if \code{cutoff} is small). If
-  \code{cutoff} is zero or negative then the function calculates the
-  exact closeness scores.  
-}
-\value{Numeric vector with the closeness values of all the vertices in
-  \code{v}.} 
-\references{ Freeman, L.C. (1979). Centrality in Social Networks I:
-  Conceptual Clarification. \emph{Social Networks}, 1, 215-239. }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{betweenness}}, \code{\link{degree}}}
+\item{graph}{The graph to analyze.}
+
+\item{vids}{The vertices for which closeness will be calculated.}
+
+\item{mode}{Character string, defined the types of the paths used for
+measuring the distance in directed graphs. \dQuote{in} measures the paths
+\emph{to} a vertex, \dQuote{out} measures paths \emph{from} a vertex,
+\emph{all} uses undirected paths. This argument is ignored for undirected
+graphs.}
+
+\item{weights}{Optional positive weight vector for calculating weighted
+closeness. If the graph has a \code{weight} edge attribute, then this is
+used by default.}
+
+\item{normalized}{Logical scalar, whether to calculate the normalized
+closeness. Normalization is performed by multiplying the raw closeness by
+\eqn{n-1}, where \eqn{n} is the number of vertices in the graph.}
+
+\item{cutoff}{The maximum path length to consider when calculating the
+betweenness. If zero or negative then there is no such limit.}
+}
+\value{
+Numeric vector with the closeness values of all the vertices in
+\code{v}.
+}
+\description{
+Cloness centrality measures how many steps is required to access every other
+vertex from a given vertex.
+}
+\details{
+The closeness centrality of a vertex is defined by the inverse of the
+average length of the shortest paths to/from all the other vertices in the
+graph:
+
+\deqn{\frac{1}{\sum_{i\ne v} d_vi}}{1/sum( d(v,i), i != v)}
+
+If there is no (directed) path between vertex \eqn{v}{\code{v}} and
+\eqn{i}{\code{i}} then the total number of vertices is used in the formula
+instead of the path length.
+
+\code{estimate_closeness} only considers paths of length \code{cutoff} or
+smaller, this can be run for larger graphs, as the running time is not
+quadratic (if \code{cutoff} is small). If \code{cutoff} is zero or negative
+then the function calculates the exact closeness scores.
+}
 \examples{
-g <- graph.ring(10)
-g2 <- graph.star(10)
+g <- make_ring(10)
+g2 <- make_star(10)
 closeness(g)
 closeness(g2, mode="in")
 closeness(g2, mode="out")
 closeness(g2, mode="all")
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Freeman, L.C. (1979). Centrality in Social Networks I:
+Conceptual Clarification. \emph{Social Networks}, 1, 215-239.
+}
+\seealso{
+\code{\link{betweenness}}, \code{\link{degree}}
+}
 \keyword{graphs}
+
diff --git a/man/cluster_edge_betweenness.Rd b/man/cluster_edge_betweenness.Rd
new file mode 100644
index 0000000..a5b99ef
--- /dev/null
+++ b/man/cluster_edge_betweenness.Rd
@@ -0,0 +1,102 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_edge_betweenness}
+\alias{cluster_edge_betweenness}
+\alias{edge.betweenness.community}
+\title{Community structure detection based on edge betweenness}
+\usage{
+cluster_edge_betweenness(graph, weights = E(graph)$weight, directed = TRUE,
+  edge.betweenness = TRUE, merges = TRUE, bridges = TRUE,
+  modularity = TRUE, membership = TRUE)
+}
+\arguments{
+\item{graph}{The graph to analyze.}
+
+\item{weights}{The edge weights. Supply \code{NULL} to omit edge weights. By
+default the \sQuote{\code{weight}} edge attribute is used, if it is present.}
+
+\item{directed}{Logical constant, whether to calculate directed edge
+betweenness for directed graphs. It is ignored for undirected graphs.}
+
+\item{edge.betweenness}{Logical constant, whether to return the edge
+betweenness of the edges at the time of their removal.}
+
+\item{merges}{Logical constant, whether to return the merge matrix
+representing the hierarchical community structure of the network.  This
+argument is called \code{merges}, even if the community structure algorithm
+itself is divisive and not agglomerative: it builds the tree from top to
+bottom. There is one line for each merge (i.e. split) in matrix, the first
+line is the first merge (last split). The communities are identified by
+integer number starting from one. Community ids smaller than or equal to
+\eqn{N}, the number of vertices in the graph, belong to singleton
+communities, ie. individual vertices. Before the first merge we have \eqn{N}
+communities numbered from one to \eqn{N}. The first merge, the first line of
+the matrix creates community \eqn{N+1}, the second merge creates community
+\eqn{N+2}, etc.}
+
+\item{bridges}{Logical constant, whether to return a list the edge removals
+which actually splitted a component of the graph.}
+
+\item{modularity}{Logical constant, whether to calculate the maximum
+modularity score, considering all possibly community structures along the
+edge-betweenness based edge removals.}
+
+\item{membership}{Logical constant, whether to calculate the membership
+vector corresponding to the highest possible modularity score.}
+}
+\value{
+\code{cluster_edge_betweenness} returns a
+\code{\link{communities}} object, please see the \code{\link{communities}}
+manual page for details.
+}
+\description{
+Many networks consist of modules which are densely connected themselves but
+sparsely connected to other modules.
+}
+\details{
+The edge betweenness score of an edge measures the number of shortest paths
+through it, see \code{\link{edge_betweenness}} for details. The idea of the
+edge betweenness based community structure detection is that it is likely
+that edges connecting separate modules have high edge betweenness as all the
+shortest paths from one module to another must traverse through them. So if
+we gradually remove the edge with the highest edge betweenness score we will
+get a hierarchical map, a rooted tree, called a dendrogram of the graph. The
+leafs of the tree are the individual vertices and the root of the tree
+represents the whole graph.
+
+\code{cluster_edge_betweenness} performs this algorithm by calculating the
+edge betweenness of the graph, removing the edge with the highest edge
+betweenness score, then recalculating edge betweenness of the edges and
+again removing the one with the highest score, etc.
+
+\code{edge.betweeness.community} returns various information collected
+throught the run of the algorithm. See the return value down here.
+}
+\examples{
+g <- barabasi.game(100,m=2)
+eb <- cluster_edge_betweenness(g)
+
+g <- make_full_graph(10) \%du\% make_full_graph(10)
+g <- add_edges(g, c(1,11))
+eb <- cluster_edge_betweenness(g)
+eb
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+M Newman and M Girvan: Finding and evaluating community
+structure in networks, \emph{Physical Review E} 69, 026113 (2004)
+}
+\seealso{
+\code{\link{edge_betweenness}} for the definition and calculation
+of the edge betweenness, \code{\link{cluster_walktrap}},
+\code{\link{cluster_fast_greedy}},
+\code{\link{cluster_leading_eigen}} for other community detection
+methods.
+
+See \code{\link{communities}} for extracting the results of the community
+detection.
+}
+\keyword{graphs}
+
diff --git a/man/cluster_fast_greedy.Rd b/man/cluster_fast_greedy.Rd
new file mode 100644
index 0000000..ab9d220
--- /dev/null
+++ b/man/cluster_fast_greedy.Rd
@@ -0,0 +1,66 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_fast_greedy}
+\alias{cluster_fast_greedy}
+\alias{fastgreedy.community}
+\title{Community structure via greedy optimization of modularity}
+\usage{
+cluster_fast_greedy(graph, merges = TRUE, modularity = TRUE,
+  membership = TRUE, weights = E(graph)$weight)
+}
+\arguments{
+\item{graph}{The input graph}
+
+\item{merges}{Logical scalar, whether to return the merge matrix.}
+
+\item{modularity}{Logical scalar, whether to return a vector containing the
+modularity after each merge.}
+
+\item{membership}{Logical scalar, whether to calculate the membership vector
+corresponding to the maximum modularity score, considering all possible
+community structures along the merges.}
+
+\item{weights}{If not \code{NULL}, then a numeric vector of edge weights.
+The length must match the number of edges in the graph.  By default the
+\sQuote{\code{weight}} edge attribute is used as weights. If it is not
+present, then all edges are considered to have the same weight.}
+}
+\value{
+\code{cluster_fast_greedy} returns a \code{\link{communities}}
+object, please see the \code{\link{communities}} manual page for details.
+}
+\description{
+This function tries to find dense subgraph, also called communities in
+graphs via directly optimizing a modularity score.
+}
+\details{
+This function implements the fast greedy modularity optimization algorithm
+for finding community structure, see A Clauset, MEJ Newman, C Moore: Finding
+community structure in very large networks,
+http://www.arxiv.org/abs/cond-mat/0408187 for the details.
+}
+\examples{
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6, 11))
+fc <- cluster_fast_greedy(g)
+membership(fc)
+sizes(fc)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com} for the R interface.
+}
+\references{
+A Clauset, MEJ Newman, C Moore: Finding community structure in
+very large networks, http://www.arxiv.org/abs/cond-mat/0408187
+}
+\seealso{
+\code{\link{communities}} for extracting the results.
+
+See also \code{\link{cluster_walktrap}},
+\code{\link{cluster_spinglass}},
+\code{\link{cluster_leading_eigen}} and
+\code{\link{cluster_edge_betweenness}} for other methods.
+}
+\keyword{graphs}
+
diff --git a/man/cluster_infomap.Rd b/man/cluster_infomap.Rd
new file mode 100644
index 0000000..7af70d3
--- /dev/null
+++ b/man/cluster_infomap.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_infomap}
+\alias{cluster_infomap}
+\alias{infomap.community}
+\title{Infomap community finding}
+\usage{
+cluster_infomap(graph, e.weights = NULL, v.weights = NULL, nb.trials = 10,
+  modularity = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{e.weights}{If not \code{NULL}, then a numeric vector of edge weights.
+The length must match the number of edges in the graph.  By default the
+\sQuote{\code{weight}} edge attribute is used as weights. If it is not
+present, then all edges are considered to have the same weight.}
+
+\item{v.weights}{If not \code{NULL}, then a numeric vector of vertex
+weights. The length must match the number of vertices in the graph.  By
+default the \sQuote{\code{weight}} vertex attribute is used as weights. If
+it is not present, then all vertices are considered to have the same weight.}
+
+\item{nb.trials}{The number of attempts to partition the network (can be any
+integer value equal or larger than 1).}
+
+\item{modularity}{Logical scalar, whether to calculate the modularity score
+of the detected community structure.}
+}
+\value{
+\code{cluster_infomap} returns a \code{\link{communities}} object,
+please see the \code{\link{communities}} manual page for details.
+}
+\description{
+Find community structure that minimizes the expected description length of a
+random walker trajectory
+}
+\details{
+Please see the details of this method in the references given below.
+}
+\examples{
+## Zachary's karate club
+g <- make_graph("Zachary")
+
+imc <- cluster_infomap(g)
+membership(imc)
+communities(imc)
+}
+\author{
+Martin Rosvall (\url{http://www.tp.umu.se/~rosvall/}) wrote the
+original C++ code. This was ported to be more igraph-like by Emmanuel
+Navarro (\url{http://enavarro.me/}).  The R interface and
+some cosmetics was done by Gabor Csardi \email{csardi.gabor at gmail.com}.
+}
+\references{
+The original paper: M. Rosvall and C. T. Bergstrom, Maps of
+information flow reveal community structure in complex networks, \emph{PNAS}
+105, 1118 (2008) \url{http://dx.doi.org/10.1073/pnas.0706851105},
+\url{http://arxiv.org/abs/0707.0609}
+
+A more detailed paper: M. Rosvall, D. Axelsson, and C. T. Bergstrom, The map
+equation, \emph{Eur. Phys. J. Special Topics} 178, 13 (2009).
+\url{http://dx.doi.org/10.1140/epjst/e2010-01179-1},
+\url{http://arxiv.org/abs/0906.1405}.
+}
+\seealso{
+Other community finding methods and \code{\link{communities}}.
+}
+\keyword{graphs}
+
diff --git a/man/cluster_label_prop.Rd b/man/cluster_label_prop.Rd
new file mode 100644
index 0000000..4f3b113
--- /dev/null
+++ b/man/cluster_label_prop.Rd
@@ -0,0 +1,72 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_label_prop}
+\alias{cluster_label_prop}
+\alias{label.propagation.community}
+\title{Finding communities based on propagating labels}
+\usage{
+cluster_label_prop(graph, weights = NULL, initial = NULL, fixed = NULL)
+}
+\arguments{
+\item{graph}{The input graph, should be undirected to make sense.}
+
+\item{weights}{An optional weight vector. It should contain a positive
+weight for all the edges. The \sQuote{weight} edge attribute is used if
+present. Supply \sQuote{\code{NA}} here if you want to ignore the
+\sQuote{weight} edge attribute.}
+
+\item{initial}{The initial state. If \code{NULL}, every vertex will have a
+different label at the beginning. Otherwise it must be a vector with an
+entry for each vertex. Non-negative values denote different labels, negative
+entries denote vertices without labels.}
+
+\item{fixed}{Logical vector denoting which labels are fixed. Of course this
+makes sense only if you provided an initial state, otherwise this element
+will be ignored. Also note that vertices without labels cannot be fixed.}
+}
+\value{
+\code{cluster_label_prop} returns a
+\code{\link{communities}} object, please see the \code{\link{communities}}
+manual page for details.
+}
+\description{
+This is a fast, nearly linear time algorithm for detecting community
+structure in networks. In works by labeling the vertices with unique labels
+and then updating the labels by majority voting in the neighborhood of the
+vertex.
+}
+\details{
+This function implements the community detection method described in:
+Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time algorithm to
+detect community structures in large-scale networks. Phys Rev E 76, 036106.
+(2007). This version extends the original method by the ability to take edge
+weights into consideration and also by allowing some labels to be fixed.
+
+From the abstract of the paper: \dQuote{In our algorithm every node is
+initialized with a unique label and at every step each node adopts the label
+that most of its neighbors currently have. In this iterative process densely
+connected groups of nodes form a consensus on a unique label to form
+communities.}
+}
+\examples{
+g <- sample_gnp(10, 5/10) \%du\% sample_gnp(9, 5/9)
+  g <- add_edges(g, c(1, 12))
+  cluster_label_prop(g)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} for the C implementation,
+Gabor Csardi \email{csardi.gabor at gmail.com} for this manual page.
+}
+\references{
+Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time
+algorithm to detect community structures in large-scale networks. \emph{Phys
+Rev E} 76, 036106. (2007)
+}
+\seealso{
+\code{\link{communities}} for extracting the actual results.
+
+\code{\link{cluster_fast_greedy}}, \code{\link{cluster_walktrap}} and
+\code{\link{cluster_spinglass}} for other community detection methods.
+}
+\keyword{graphs}
+
diff --git a/man/cluster_leading_eigen.Rd b/man/cluster_leading_eigen.Rd
new file mode 100644
index 0000000..de33e47
--- /dev/null
+++ b/man/cluster_leading_eigen.Rd
@@ -0,0 +1,116 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_leading_eigen}
+\alias{cluster_leading_eigen}
+\alias{leading.eigenvector.community}
+\title{Community structure detecting based on the leading eigenvector of the
+community matrix}
+\usage{
+cluster_leading_eigen(graph, steps = -1, weights = NULL, start = NULL,
+  options = arpack_defaults, callback = NULL, extra = NULL,
+  env = parent.frame())
+}
+\arguments{
+\item{graph}{The input graph. Should be undirected as the method needs a
+symmetric matrix.}
+
+\item{steps}{The number of steps to take, this is actually the number of
+tries to make a step. It is not a particularly useful parameter.
+#'}
+
+\item{weights}{An optional weight vector. The \sQuote{weight} edge attribute
+is used if present. Supply \sQuote{\code{NA}} here if you want to ignore the
+\sQuote{weight} edge attribute.}
+
+\item{start}{\code{NULL}, or a numeric membership vector, giving the start
+configuration of the algorithm.}
+
+\item{options}{A named list to override some ARPACK options.}
+
+\item{callback}{If not \code{NULL}, then it must be callback function. This
+is called after each iteration, after calculating the leading eigenvector of
+the modularity matrix. See details below.}
+
+\item{extra}{Additional argument to supply to the callback function.}
+
+\item{env}{The environment in which the callback function is evaluated.}
+}
+\value{
+\code{cluster_leading_eigen} returns a named list with the
+following members: \item{membership}{The membership vector at the end of the
+algorithm, when no more splits are possible.} \item{merges}{The merges
+matrix starting from the state described by the \code{membership} member.
+This is a two-column matrix and each line describes a merge of two
+communities, the first line is the first merge and it creates community
+\sQuote{\code{N}}, \code{N} is the number of initial communities in the
+graph, the second line creates community \code{N+1}, etc.  }
+\item{options}{Information about the underlying ARPACK computation, see
+\code{\link{arpack}} for details.  }
+}
+\description{
+This function tries to find densely connected subgraphs in a graph by
+calculating the leading non-negative eigenvector of the modularity matrix of
+the graph.
+}
+\details{
+The function documented in these section implements the \sQuote{leading
+eigenvector} method developed by Mark Newman, see the reference below.
+
+The heart of the method is the definition of the modularity matrix,
+\code{B}, which is \code{B=A-P}, \code{A} being the adjacency matrix of the
+(undirected) network, and \code{P} contains the probability that certain
+edges are present according to the \sQuote{configuration model}. In other
+words, a \code{P[i,j]} element of \code{P} is the probability that there is
+an edge between vertices \code{i} and \code{j} in a random network in which
+the degrees of all vertices are the same as in the input graph.
+
+The leading eigenvector method works by calculating the eigenvector of the
+modularity matrix for the largest positive eigenvalue and then separating
+vertices into two community based on the sign of the corresponding element
+in the eigenvector. If all elements in the eigenvector are of the same sign
+that means that the network has no underlying comuunity structure.  Check
+Newman's paper to understand why this is a good method for detecting
+community structure.
+}
+\section{Callback functions}{
+ The \code{callback} argument can be used to
+supply a function that is called after each eigenvector calculation. The
+following arguments are supplied to this function: \describe{
+  \item{membership}{The actual membership vector, with zero-based indexing.}
+  \item{community}{The community that the algorithm just tried to split,
+    community numbering starts with zero here.}
+  \item{value}{The eigenvalue belonging to the leading eigenvector the
+    algorithm just found.}
+  \item{vector}{The leading eigenvector the algorithm just found.}
+  \item{multiplier}{An R function that can be used to multiple the actual
+    modularity matrix with an arbitrary vector. Supply the vector as an
+    argument to perform this multiplication. This function can be used
+    with ARPACK.}
+  \item{extra}{The \code{extra} argument that was passed to
+    \code{cluster_leading_eigen}. }
+  The callback function should return a scalar number. If this number
+  is non-zero, then the clustering is terminated.
+}
+}
+\examples{
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6, 11))
+lec <- cluster_leading_eigen(g)
+lec
+
+cluster_leading_eigen(g, start=membership(lec))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+MEJ Newman: Finding community structure using the eigenvectors
+of matrices, Physical Review E 74 036104, 2006.
+}
+\seealso{
+\code{\link{modularity}}, \code{\link{cluster_walktrap}},
+\code{\link{cluster_edge_betweenness}},
+\code{\link{cluster_fast_greedy}}, \code{\link[stats]{as.dendrogram}}
+}
+\keyword{graphs}
+
diff --git a/man/cluster_louvain.Rd b/man/cluster_louvain.Rd
new file mode 100644
index 0000000..86f2acf
--- /dev/null
+++ b/man/cluster_louvain.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_louvain}
+\alias{cluster_louvain}
+\alias{multilevel.community}
+\title{Finding community structure by multi-level optimization of modularity}
+\usage{
+cluster_louvain(graph, weights = NULL)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{weights}{Optional positive weight vector.  If the graph has a
+\code{weight} edge attribute, then this is used by default. Supply \code{NA}
+here if the graph has a \code{weight} edge attribute, but you want to ignore
+it.}
+}
+\value{
+\code{cluster_louvain} returns a \code{\link{communities}}
+object, please see the \code{\link{communities}} manual page for details.
+}
+\description{
+This function implements the multi-level modularity optimization algorithm
+for finding community structure, see references below. It is based on the
+modularity measure and a hierarchial approach.
+}
+\details{
+This function implements the multi-level modularity optimization algorithm
+for finding community structure, see VD Blondel, J-L Guillaume, R Lambiotte
+and E Lefebvre: Fast unfolding of community hierarchies in large networks,
+\url{http://arxiv.org/abs/arXiv:0803.0476} for the details.
+
+It is based on the modularity measure and a hierarchial approach.
+Initially, each vertex is assigned to a community on its own. In every step,
+vertices are re-assigned to communities in a local, greedy way: each vertex
+is moved to the community with which it achieves the highest contribution to
+modularity. When no vertices can be reassigned, each community is considered
+a vertex on its own, and the process starts again with the merged
+communities. The process stops when there is only a single vertex left or
+when the modularity cannot be increased any more in a step.
+
+This function was contributed by Tom Gregorovic.
+}
+\examples{
+# This is so simple that we will have only one level
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6, 11))
+cluster_louvain(g)
+}
+\author{
+Tom Gregorovic, Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Vincent D. Blondel, Jean-Loup Guillaume, Renaud Lambiotte,
+Etienne Lefebvre: Fast unfolding of communities in large networks. J. Stat.
+Mech. (2008) P10008
+}
+\seealso{
+See \code{\link{communities}} for extracting the membership,
+modularity scores, etc. from the results.
+
+Other community detection algorithms: \code{\link{cluster_walktrap}},
+\code{\link{cluster_spinglass}},
+\code{\link{cluster_leading_eigen}},
+\code{\link{cluster_edge_betweenness}},
+\code{\link{cluster_fast_greedy}},
+\code{\link{cluster_label_prop}}
+}
+\keyword{graphs}
+
diff --git a/man/cluster_optimal.Rd b/man/cluster_optimal.Rd
new file mode 100644
index 0000000..5620ebd
--- /dev/null
+++ b/man/cluster_optimal.Rd
@@ -0,0 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_optimal}
+\alias{cluster_optimal}
+\alias{optimal.community}
+\title{Optimal community structure}
+\usage{
+cluster_optimal(graph, weights = NULL)
+}
+\arguments{
+\item{graph}{The input graph. Edge directions are ignored for directed
+graphs.}
+
+\item{weights}{Optional positive weight vector for optimizing weighted
+modularity. If the graph has a \code{weight} edge attribute, then this is
+used by default. Supply \code{NA} to ignore the weights of a weighted graph.}
+}
+\value{
+\code{cluster_optimal} returns a \code{\link{communities}} object,
+please see the \code{\link{communities}} manual page for details.
+}
+\description{
+This function calculates the optimal community structure of a graph, by
+maximizing the modularity measure over all possible partitions.
+}
+\details{
+This function calculates the optimal community structure for a graph, in
+terms of maximal modularity score.
+
+The calculation is done by transforming the modularity maximization into an
+integer programming problem, and then calling the GLPK library to solve
+that. Please the reference below for details.
+
+Note that modularity optimization is an NP-complete problem, and all known
+algorithms for it have exponential time complexity. This means that you
+probably don't want to run this function on larger graphs. Graphs with up to
+fifty vertices should be fine, graphs with a couple of hundred vertices
+might be possible.
+}
+\examples{
+## Zachary's karate club
+g <- make_graph("Zachary")
+
+## We put everything into a big 'try' block, in case
+## igraph was compiled without GLPK support
+
+try({
+  ## The calculation only takes a couple of seconds
+  oc <- cluster_optimal(g)
+
+  ## Double check the result
+  print(modularity(oc))
+  print(modularity(g, membership(oc)))
+
+  ## Compare to the greedy optimizer
+  fc <- cluster_fast_greedy(g)
+  print(modularity(fc))
+}, silent=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Ulrik Brandes, Daniel Delling, Marco Gaertler, Robert Gorke,
+Martin Hoefer, Zoran Nikoloski, Dorothea Wagner: On Modularity Clustering,
+\emph{IEEE Transactions on Knowledge and Data Engineering} 20(2):172-188,
+2008.
+}
+\seealso{
+\code{\link{communities}} for the documentation of the result,
+\code{\link{modularity}}. See also \code{\link{cluster_fast_greedy}} for a
+fast greedy optimizer.
+}
+\keyword{graphs}
+
diff --git a/man/cluster_spinglass.Rd b/man/cluster_spinglass.Rd
new file mode 100644
index 0000000..f7a2065
--- /dev/null
+++ b/man/cluster_spinglass.Rd
@@ -0,0 +1,146 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_spinglass}
+\alias{cluster_spinglass}
+\alias{spinglass.community}
+\title{Finding communities in graphs based on statistical meachanics}
+\usage{
+cluster_spinglass(graph, weights = NULL, vertex = NULL, spins = 25,
+  parupdate = FALSE, start.temp = 1, stop.temp = 0.01, cool.fact = 0.99,
+  update.rule = c("config", "random", "simple"), gamma = 1,
+  implementation = c("orig", "neg"), gamma.minus = 1)
+}
+\arguments{
+\item{graph}{The input graph, can be directed but the direction of the edges
+is neglected.}
+
+\item{weights}{The weights of the edges. Either a numeric vector or
+\code{NULL}. If it is null and the input graph has a \sQuote{weight} edge
+attribute then that will be used. If \code{NULL} and no such attribute is
+present then the edges will have equal weights. Set this to \code{NA} if the
+graph was a \sQuote{weight} edge attribute, but you don't want to use it for
+community detection.}
+
+\item{vertex}{This parameter can be used to calculate the community of a
+given vertex without calculating all communities. Note that if this argument
+is present then some other arguments are ignored.}
+
+\item{spins}{Integer constant, the number of spins to use. This is the upper
+limit for the number of communities. It is not a problem to supply a
+(reasonably) big number here, in which case some spin states will be
+unpopulated.}
+
+\item{parupdate}{Logical constant, whether to update the spins of the
+vertices in parallel (synchronously) or not. This argument is ignored if the
+second form of the function is used (ie. the \sQuote{\code{vertex}} argument
+is present). It is also not implemented in the \dQuote{neg} implementation.}
+
+\item{start.temp}{Real constant, the start temperature.  This argument is
+ignored if the second form of the function is used (ie. the
+\sQuote{\code{vertex}} argument is present).}
+
+\item{stop.temp}{Real constant, the stop temperature. The simulation
+terminates if the temperature lowers below this level.  This argument is
+ignored if the second form of the function is used (ie. the
+\sQuote{\code{vertex}} argument is present).}
+
+\item{cool.fact}{Cooling factor for the simulated annealing.  This argument
+is ignored if the second form of the function is used (ie. the
+\sQuote{\code{vertex}} argument is present).}
+
+\item{update.rule}{Character constant giving the \sQuote{null-model} of the
+simulation. Possible values: \dQuote{simple} and \dQuote{config}.
+\dQuote{simple} uses a random graph with the same number of edges as the
+baseline probability and \dQuote{config} uses a random graph with the same
+vertex degrees as the input graph.}
+
+\item{gamma}{Real constant, the gamma argument of the algorithm. This
+specifies the balance between the importance of present and non-present
+edges in a community. Roughly, a comunity is a set of vertices having many
+edges inside the community and few edges outside the community. The default
+1.0 value makes existing and non-existing links equally important. Smaller
+values make the existing links, greater values the missing links more
+important.}
+
+\item{implementation}{Character scalar. Currently igraph contains two
+implementations for the Spin-glass community finding algorithm. The faster
+original implementation is the default. The other implementation, that takes
+into account negative weights, can be chosen by supplying \sQuote{neg} here.}
+
+\item{gamma.minus}{Real constant, the gamma.minus parameter of the
+algorithm. This specifies the balance between the importance of present and
+non-present negative weighted edges in a community. Smaller values of
+gamma.minus, leads to communities with lesser negative intra-connectivity.
+If this argument is set to zero, the algorithm reduces to a graph coloring
+algorithm, using the number of spins as the number of colors. This argument
+is ignored if the \sQuote{orig} implementation is chosen.}
+}
+\value{
+If the \code{vertex} argument is not given, ie. the first form is
+used then a \code{\link{cluster_spinglass}} returns a
+\code{\link{communities}} object.
+
+If the \code{vertex} argument is present, ie. the second form is used then a
+named list is returned with the following components:
+\item{community}{Numeric vector giving the ids of the vertices in the same
+community as \code{vertex}.} \item{cohesion}{The cohesion score of the
+result, see references.} \item{adhesion}{The adhesion score of the result,
+see references.} \item{inner.links}{The number of edges within the community
+of \code{vertex}.} \item{outer.links}{The number of edges between the
+community of \code{vertex} and the rest of the graph. }
+}
+\description{
+This function tries to find communities in graphs via a spin-glass model and
+simulated annealing.
+}
+\details{
+This function tries to find communities in a graph. A community is a set of
+nodes with many edges inside the community and few edges between outside it
+(i.e. between the community itself and the rest of the graph.)
+
+This idea is reversed for edges having a negative weight, ie. few negative
+edges inside a community and many negative edges between communities. Note
+that only the \sQuote{neg} implementation supports negative edge weights.
+
+The \code{spinglass.cummunity} function can solve two problems related to
+community detection. If the \code{vertex} argument is not given (or it is
+\code{NULL}), then the regular community detection problem is solved
+(approximately), i.e. partitioning the vertices into communities, by
+optimizing the an energy function.
+
+If the \code{vertex} argument is given and it is not \code{NULL}, then it
+must be a vertex id, and the same energy function is used to find the
+community of the the given vertex. See also the examples below.
+}
+\examples{
+g <- sample_gnp(10, 5/10) \%du\% sample_gnp(9, 5/9)
+  g <- add_edges(g, c(1, 12))
+  g <- induced_subgraph(g, subcomponent(g, 1))
+  cluster_spinglass(g, spins=2)
+  cluster_spinglass(g, vertex=1)
+}
+\author{
+Jorg Reichardt
+(\url{http://theorie.physik.uni-wuerzburg.de/~reichardt/}) for the original
+code and Gabor Csardi \email{csardi.gabor at gmail.com} for the igraph glue
+code.
+
+Changes to the original function for including the possibility of negative
+ties were implemented by Vincent Traag (\url{http://www.traag.net/}).
+}
+\references{
+J. Reichardt and S. Bornholdt: Statistical Mechanics of
+Community Detection, \emph{Phys. Rev. E}, 74, 016110 (2006),
+\url{http://arxiv.org/abs/cond-mat/0603718}
+
+M. E. J. Newman and M. Girvan: Finding and evaluating community structure in
+networks, \emph{Phys. Rev. E} 69, 026113 (2004)
+
+V.A. Traag and Jeroen Bruggeman: Community detection in networks with
+positive and negative links, \url{http://arxiv.org/abs/0811.2329} (2008).
+}
+\seealso{
+\code{\link{communities}}, \code{\link{components}}
+}
+\keyword{graphs}
+
diff --git a/man/cluster_walktrap.Rd b/man/cluster_walktrap.Rd
new file mode 100644
index 0000000..c4baea8
--- /dev/null
+++ b/man/cluster_walktrap.Rd
@@ -0,0 +1,67 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{cluster_walktrap}
+\alias{cluster_walktrap}
+\alias{walktrap.community}
+\title{Community strucure via short random walks}
+\usage{
+cluster_walktrap(graph, weights = E(graph)$weight, steps = 4,
+  merges = TRUE, modularity = TRUE, membership = TRUE)
+}
+\arguments{
+\item{graph}{The input graph, edge directions are ignored in directed
+graphs.}
+
+\item{weights}{The edge weights.}
+
+\item{steps}{The length of the random walks to perform.}
+
+\item{merges}{Logical scalar, whether to include the merge matrix in the
+result.}
+
+\item{modularity}{Logical scalar, whether to include the vector of the
+modularity scores in the result. If the \code{membership} argument is true,
+then it will be always calculated.}
+
+\item{membership}{Logical scalar, whether to calculate the membership vector
+for the split corresponding to the highest modularity value.}
+}
+\value{
+\code{cluster_walktrap} returns a \code{\link{communities}}
+object, please see the \code{\link{communities}} manual page for details.
+}
+\description{
+This function tries to find densely connected subgraphs, also called
+communities in a graph via random walks. The idea is that short random walks
+tend to stay in the same community.
+}
+\details{
+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
+}
+\examples{
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6, 11))
+cluster_walktrap(g)
+}
+\author{
+Pascal Pons (\url{http://psl.pons.free.fr/}) and Gabor Csardi
+\email{csardi.gabor at gmail.com} for the R and igraph interface
+}
+\references{
+Pascal Pons, Matthieu Latapy: Computing communities in large
+networks using random walks, http://arxiv.org/abs/physics/0512106
+}
+\seealso{
+See \code{\link{communities}} on getting the actual membership
+vector, merge matrix, modularity score, etc.
+
+\code{\link{modularity}} and \code{\link{cluster_fast_greedy}},
+\code{\link{cluster_spinglass}},
+\code{\link{cluster_leading_eigen}},
+\code{\link{cluster_edge_betweenness}} for other community detection
+methods.
+}
+\keyword{graphs}
+
diff --git a/man/clusters.Rd b/man/clusters.Rd
deleted file mode 100644
index 582e9a6..0000000
--- a/man/clusters.Rd
+++ /dev/null
@@ -1,73 +0,0 @@
-\name{clusters}
-\alias{no.clusters}
-\alias{clusters}
-\alias{is.connected}
-\alias{cluster.distribution}
-\concept{Connectedness}
-\concept{Graph component}
-\title{Connected components of a graph}
-\description{Calculate the maximal (weakly or strongly) 
-  connected components of a graph
-}
-\usage{
-is.connected(graph, mode=c("weak", "strong"))
-clusters(graph, mode=c("weak", "strong"))
-no.clusters(graph, mode=c("weak", "strong"))
-cluster.distribution(graph, cumulative = FALSE, mul.size = FALSE, \dots)
-}
-\arguments{
-  \item{graph}{The graph to analyze.}
-  \item{mode}{Character string, either \dQuote{weak} or \dQuote{strong}.
-    For directed graphs \dQuote{weak} implies weakly, \dQuote{strong}
-    strongly connected components to search. It is ignored for
-    undirected graphs.}
-  \item{cumulative}{Logical, if TRUE the cumulative distirubution
-    (relative frequency) is calculated.}
-  \item{mul.size}{Logical. If TRUE the relative frequencies will be
-    multiplied by the cluster sizes.}
-  \item{\dots}{Additional attributes to pass to \code{cluster}, right
-    now only \code{mode} makes sense.}
-}
-\details{
-  \code{is.connected} decides whether the graph is weakly or strongly
-  connected.
-
-  \code{clusters} finds the maximal (weakly or strongly) connected
-  components of a graph.
-
-  \code{no.clusters} does almost the same as \code{clusters} but returns
-  only the number of clusters found instead of returning the actual
-  clusters.
-
-  \code{cluster.distribution} creates a histogram for the maximal
-  connected component sizes.
-
-  The weakly connected components are found by a simple breadth-first
-  search. The strongly connected components are implemented by two
-  consecutive depth-first searches.
-}
-\value{
-  For \code{is.connected} a logical constant.
-
-  For \code{clusters} a named list with three components:
-  \item{membership}{numeric vector giving the cluster id to which each
-    vertex belongs.}
-  \item{csize}{numeric vector giving the sizes of the clusters.}
-  \item{no}{numeric constant, the number of clusters.}
-
-  For \code{no.clusters} an integer constant is returned.
-  
-  For \code{cluster.distribution} a numeric vector with the relative
-  frequencies. The length of the vector is the size of the largest
-  component plus one. Note that (for currently unknown reasons) the
-  first element of the vector is the number of clusters of size zero, so
-  this is always zero.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{subcomponent}}}
-\examples{
-g <- erdos.renyi.game(20, 1/20)
-clusters(g)
-}
-\keyword{graphs}
diff --git a/man/cocitation.Rd b/man/cocitation.Rd
index bbcf62a..2e5cddc 100644
--- a/man/cocitation.Rd
+++ b/man/cocitation.Rd
@@ -1,47 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/cocitation.R
 \name{cocitation}
-\alias{cocitation}
 \alias{bibcoupling}
-\concept{Cocication}
-\concept{Bibliographic coupling}
+\alias{cocitation}
 \title{Cocitation coupling}
-\description{Two vertices are cocited if there is another vertex citing
-  both of them. \code{cocitation} siply counts how many types two vertices
-  are cocited. The bibliographic coupling of two vertices is the number
-  of other vertices they both cite, \code{bibcoupling} calculates this.
-}
 \usage{
-cocitation(graph, v=V(graph))
-bibcoupling(graph, v=V(graph))
+cocitation(graph, v = V(graph))
 }
 \arguments{
-  \item{graph}{The graph object to analyze}
-  \item{v}{Vertex sequence or numeric vector, the vertex ids for which
-    the cocitation or bibliographic coupling values we want to
-    calculate. The default is all vertices.} 
+\item{graph}{The graph object to analyze}
+
+\item{v}{Vertex sequence or numeric vector, the vertex ids for which the
+cocitation or bibliographic coupling values we want to calculate. The
+default is all vertices.}
+}
+\value{
+A numeric matrix with \code{length(v)} lines and
+\code{vcount(graph)} columns. Element \code{(i,j)} contains the cocitation
+or bibliographic coupling for vertices \code{v[i]} and \code{j}.
+}
+\description{
+Two vertices are cocited if there is another vertex citing both of them.
+\code{cocitation} siply counts how many types two vertices are cocited. The
+bibliographic coupling of two vertices is the number of other vertices they
+both cite, \code{bibcoupling} calculates this.
 }
 \details{
-  \code{cocitation} calculates the cocitation counts for the vertices in the
-  \code{v} argument and all vertices in the graph.
+\code{cocitation} calculates the cocitation counts for the vertices in the
+\code{v} argument and all vertices in the graph.
 
-  \code{bibcoupling} calculates the bibliographic coupling for vertices
-  in \code{v} and all vertices in the graph.
+\code{bibcoupling} calculates the bibliographic coupling for vertices in
+\code{v} and all vertices in the graph.
 
-  Calculating the cocitation or bibliographic coupling for only one
-  vertex costs the same amount of computation as for all vertices. This
-  might change in the future. 
+Calculating the cocitation or bibliographic coupling for only one vertex
+costs the same amount of computation as for all vertices. This might change
+in the future.
 }
-\value{
-  A numeric matrix with \code{length(v)} lines and \code{vcount(graph)}
-  columns. Element \code{(i,j)} contains the cocitation or bibliographic
-  coupling for vertices \code{v[i]} and \code{j}.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 cocitation(g)
 bibcoupling(g)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
 \keyword{graphs}
 
diff --git a/man/cohesive.blocks.Rd b/man/cohesive.blocks.Rd
deleted file mode 100644
index aabf92e..0000000
--- a/man/cohesive.blocks.Rd
+++ /dev/null
@@ -1,269 +0,0 @@
-\name{cohesive.blocks}
-\alias{cohesive.blocks}
-\alias{cohesiveBlocks}
-\alias{blocks}
-\alias{blockGraphs}
-\alias{cohesion}
-\alias{hierarchy}
-\alias{parent}
-\alias{plotHierarchy}
-\alias{exportPajek}
-\alias{maxcohesion}
-\alias{plot.cohesiveBlocks}
-\alias{summary.cohesiveBlocks}
-\alias{length.cohesiveBlocks}
-\alias{print.cohesiveBlocks}
-\concept{Structurally cohesive blocks}
-\title{Calculate Cohesive Blocks}
-\description{Calculates cohesive blocks for objects of class \code{igraph}.}
-\usage{
-cohesive.blocks(graph, labels = TRUE)
-
-blocks(blocks)
-blockGraphs(blocks, graph)
-cohesion(blocks)
-hierarchy(blocks)
-parent(blocks)
-plotHierarchy(blocks,
-   layout=layout.reingold.tilford(hierarchy(blocks), root=1), \dots)
-exportPajek(blocks, graph, file, project.file = TRUE)
-maxcohesion(blocks)
-
-\method{print}{cohesiveBlocks}(x, \dots)
-\method{summary}{cohesiveBlocks}(object, \dots)
-\method{length}{cohesiveBlocks}(x)
-\method{plot}{cohesiveBlocks}(x, y, colbar = rainbow(max(cohesion(x))+1),
-     col = colbar[maxcohesion(x)+1], mark.groups = blocks(x)[-1], \dots)
-}
-\arguments{
-    \item{graph}{For \code{cohesive.blocks} a graph object of class
-      \code{igraph}. It must be undirected and simple. (See
-      \code{\link{is.simple}}.)
-
-      For \code{blockGraphs} and \code{exportPajek} the same graph must
-      be supplied whose cohesive block structure is given in the
-      \code{blocks} argument.
-    }
-    \item{labels}{Logical scalar, whether to add the vertex labels to
-      the result object. These labels can be then used when reporting 
-      and plotting the cohesive blocks.}
-    \item{blocks,x,object}{A \code{cohesiveBlocks} object, created with
-      the \code{cohesive.blocks} function.}
-    \item{file}{Defines the file (or connection) the Pajek file is
-      written to.
-
-      If the \code{project.file} argument is \code{TRUE},
-      then it can be a filename (with extension), a file object, or in
-      general any king of connection object. The file/connection will be
-      opened if it wasn't already.
-
-      If the \code{project.file} argument is \code{FALSE}, then several
-      files are created and \code{file} must be a character scalar
-      containing the base name of the files, without extension. (But it
-      can contain the path to the files.)
-
-      See also details below.
-    }
-    \item{project.file}{Logical scalar, whether to create a single Pajek
-      project file containing all the data, or to create separated files
-      for each item. See details below.}
-    \item{y}{The graph whose cohesive blocks are supplied in the
-      \code{x} argument.}
-    \item{colbar}{Color bar for the vertex colors. Its length should be
-      at least \eqn{m+1}, where \eqn{m} is the maximum cohesion in the
-      graph. Alternatively, the vertex colors can also be directly
-    specified via the \code{col} argument.}
-    \item{col}{A vector of vertex colors, in any of the usual
-      formats. (Symbolic color names (e.g. \sQuote{red}, \sQuote{blue},
-      etc.) , RGB colors (e.g. \sQuote{#FF9900FF}), integer numbers
-      referring to the current palette. By default the given
-      \code{colbar} is used and vertices with the same maximal cohesion
-      will have the same color.}
-    \item{mark.groups}{A list of vertex sets to mark on the plot by
-      circling them. By default all cohesive blocks are marked, except
-      the one corresponding to the all vertices.}
-    \item{layout}{The layout of a plot, it is simply passed on to
-      \code{plot.igraph}, see the possible formats there. By default the
-      Reingold-Tilford layout generator is used.}
-    \item{\dots}{Additional arguments. \code{plotHierarchy} and
-      \code{plot} pass them to \code{plot.igraph}.
-      \code{print} and \code{summary} ignore them.
-    }
-}
-\details{
-  Cohesive blocking is a method of determining hierarchical subsets of
-  graph vertices based on their structural cohesion (or vertex
-  connectivity). For a given graph \eqn{G}, a subset of its vertices
-  \eqn{S\subset V(G)}{S} is said to be maximally \eqn{k}-cohesive if there is
-  no superset of \eqn{S} with vertex connectivity greater than or equal to
-  \eqn{k}. Cohesive blocking is a process through which, given a
-  \eqn{k}-cohesive set of vertices, maximally \eqn{l}-cohesive subsets are
-  recursively identified with \eqn{l>k}. Thus a hiearchy of vertex subsets
-  is found, whith the entire graph \eqn{G} at its root. 
-  
-  The function \code{cohesive.blocks} implements cohesive blocking.
-  It returns a \code{cohesiveBlocks} object. \code{cohesiveBlocks}
-  should be handled as an opaque class, i.e. its internal structure
-  should not be accessed directly, but through the functions listed
-  here.
-
-  The function \code{length} can be used on \code{cohesiveBlocks}
-  objects and it gives the number of blocks.
-  
-  The function \code{blocks} returns the actual blocks stored in the
-  \code{cohesiveBlocks} object. They are returned in a list of numeric
-  vectors, each containing vertex ids.
-
-  The function \code{blockGraphs} is similar, but returns the blocks as
-  (induced) subgraphs of the input graph. The various (graph, vertex and
-  edge) attributes are kept in the subgraph.
-
-  The function \code{cohesion} returns a numeric vector, the cohesion of
-  the different blocks. The order of the blocks is the same as for
-  the \code{blocks} and \code{blockGraphs} functions.
-
-  The block hierarchy can be queried using the \code{hierarchy}
-  function. It returns an igraph graph, its vertex ids are ordered
-  according the order of the blocks in the \code{blocks} and
-  \code{blockGraphs}, \code{cohesion}, etc. functions.
-
-  \code{parent} gives the parent vertex of each block, in the block
-  hierarchy, for the root vertex it gives 0.
-
-  \code{plotHierarchy} plots the hierarchy tree of the cohesive blocks
-  on the active graphics device, by calling \code{igraph.plot}.
-
-  The \code{exportPajek} function can be used to export the graph and
-  its cohesive blocks in Pajek format. It can either export a single
-  Pajek project file with all the information, or a set of files,
-  depending on its \code{project.file} argument. If \code{project.file}
-  is \code{TRUE}, then the following information is written to the file
-  (or connection) given in the \code{file} argument: (1) the input
-  graph, together with its attributes, see \code{\link{write.graph}} for
-  details; (2) the hierarchy graph; and (3) one binary partition for
-  each cohesive block. If \code{project.file} is \code{FALSE}, then the
-  \code{file} argument must be a character scalar and it is used as the
-  base name for the generated files. If \code{file} is
-  \sQuote{basename}, then the following files are created: (1)
-  \sQuote{basename.net} for the original graph; (2)
-  \sQuote{basename_hierarchy.net} for the hierarchy graph; (3)
-  \sQuote{basename_block_x.net} for each cohesive block, where
-  \sQuote{x} is the number of the block, starting with one.
-
-  \code{maxcohesion} returns the maximal cohesion of each vertex,
-  i.e. the cohesion of the most cohesive block of the vertex.
-
-  The generic function \code{summary} works on \code{cohesiveBlocks}
-  objects and it prints a one line summary to the terminal.
-
-  The generic function \code{print} is also defined on
-  \code{cohesiveBlocks} objects and it is invoked automatically if the
-  name of the \code{cohesiveBlocks} object is typed in. It produces
-  an output like this: \preformatted{
-    Cohesive block structure:
-    B-1         c 1, n 23
-    '- B-2      c 2, n 14   oooooooo.. .o......oo ooo 
-       '- B-4   c 5, n  7   ooooooo... .......... ... 
-    '- B-3      c 2, n 10   ......o.oo o.oooooo.. ... 
-       '- B-5   c 3, n  4   ......o.oo o......... ...     
-  }
-  The left part shows the block structure, in this case for five
-  blocks. The first block always corresponds to the whole graph, even if
-  its cohesion is zero. Then cohesion of the block and the number of
-  vertices in the block are shown. The last part is only printed if the
-  display is wide enough and shows the vertices in the blocks,
-  ordered by vertex ids. \sQuote{o} means that the vertex is included,
-  a dot means that it is not, and the vertices are shown in groups of
-  ten.
-  
-  The generic function \code{plot} plots the graph, showing one or more
-  cohesive blocks in it.  
-}
-\value{
-  \code{cohesive.blocks} returns a \code{cohesiveBlocks}
-  object.
-
-  \code{blocks} returns a list of numeric vectors, containing vertex
-  ids.
-
-  \code{blockGraphs} returns a list of igraph graphs, corresponding to
-  the cohesive blocks.
-
-  \code{cohesion} returns a numeric vector, the cohesion of each block.
-
-  \code{hierarchy} returns an igraph graph, the representation of the
-  cohesive block hierarchy.
-
-  \code{parent} returns a numeric vector giving the parent block of each
-  cohesive block, in the block hierarchy. The block at the root of the
-  hierarchy has no parent and \code{0} is returned for it.
-
-  \code{plotHierarchy}, \code{plot} and \code{exportPajek} return
-  \code{NULL}, invisibly.
-
-  \code{maxcohesion} returns a numeric vector with one entry for each
-  vertex, giving the cohesion of its most cohesive block.
-
-  \code{print} and \code{summary} return the \code{cohesiveBlocks}
-  object itself, invisibly.
-
-  \code{length} returns a numeric scalar, the number of blocks.  
-}
-\references{
-  J. Moody and D. R. White. Structural cohesion and embeddedness: A
-  hierarchical concept of social groups. \emph{American Sociological
-    Review}, 68(1):103--127, Feb 2003. 
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com} for the current
-  implementation, Peter McMahan
-  (\url{http://home.uchicago.edu/~mcmahan/})
-  wrote the first version in R.}
-\seealso{\code{\link{graph.cohesion}}}
-\examples{
-## The graph from the Moody-White paper
-mw <- graph.formula(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
-                    5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
-                    10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
-                    17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
-                    21-22:23, 22-23)
-
-mwBlocks <- cohesive.blocks(mw)
-
-# Inspect block membership and cohesion
-mwBlocks
-blocks(mwBlocks)
-cohesion(mwBlocks)
-
-# Save results in a Pajek file
-\dontrun{
-exportPajek(mwBlocks, mw, file="/tmp/mwBlocks.paj")
-}
-
-# Plot the results
-if (interactive()) {
-  plot(mwBlocks, mw)
-}
-
-## The science camp network
-camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
-                      Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
-                      Holly   - Carol:Pat:Pam:Jennie:Bill,
-                      Bill    - Pauline:Michael:Lee:Holly,
-                      Pauline - Bill:Jennie:Ann,
-                      Jennie  - Holly:Michael:Lee:Ann:Pauline,
-                      Michael - Bill:Jennie:Ann:Lee:John,
-                      Ann     - Michael:Jennie:Pauline,
-                      Lee     - Michael:Bill:Jennie,
-                      Gery    - Pat:Steve:Russ:John,
-                      Russ    - Steve:Bert:Gery:John,
-                      John    - Gery:Russ:Michael)
-campBlocks <- cohesive.blocks(camp)
-campBlocks
-
-if (interactive()) {
-  plot(campBlocks, camp, vertex.label=V(camp)$name, margin=-0.2,
-       vertex.shape="rectangle", vertex.size=24, vertex.size2=8,
-       mark.border=1, colbar=c(NA, NA,"cyan","orange") )
-}
-}
-\keyword{graphs}
diff --git a/man/cohesive_blocks.Rd b/man/cohesive_blocks.Rd
new file mode 100644
index 0000000..1145388
--- /dev/null
+++ b/man/cohesive_blocks.Rd
@@ -0,0 +1,282 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/cohesive.blocks.R
+\name{cohesive_blocks}
+\alias{blockGraphs}
+\alias{blocks}
+\alias{cohesion.cohesiveBlocks}
+\alias{cohesive.blocks}
+\alias{cohesiveBlocks}
+\alias{cohesive_blocks}
+\alias{exportPajek}
+\alias{export_pajek}
+\alias{graphs_from_cohesive_blocks}
+\alias{hierarchy}
+\alias{length.cohesiveBlocks}
+\alias{max_cohesion}
+\alias{maxcohesion}
+\alias{parent}
+\alias{plot.cohesiveBlocks}
+\alias{plotHierarchy}
+\alias{plot_hierarchy}
+\alias{print.cohesiveBlocks}
+\alias{summary.cohesiveBlocks}
+\title{Calculate Cohesive Blocks}
+\usage{
+cohesive_blocks(graph, labels = TRUE)
+
+\method{length}{cohesiveBlocks}(x)
+
+blocks(blocks)
+
+graphs_from_cohesive_blocks(blocks, graph)
+
+\method{cohesion}{cohesiveBlocks}(x, ...)
+
+hierarchy(blocks)
+
+parent(blocks)
+
+\method{print}{cohesiveBlocks}(x, ...)
+
+\method{summary}{cohesiveBlocks}(object, ...)
+
+\method{plot}{cohesiveBlocks}(x, y, colbar = rainbow(max(cohesion(x)) + 1),
+  col = colbar[max_cohesion(x) + 1], mark.groups = blocks(x)[-1], ...)
+
+plot_hierarchy(blocks, layout = layout_as_tree(hierarchy(blocks), root = 1),
+  ...)
+
+export_pajek(blocks, graph, file, project.file = TRUE)
+
+max_cohesion(blocks)
+}
+\arguments{
+\item{graph}{For \code{cohesive_blocks} a graph object of class
+\code{igraph}. It must be undirected and simple. (See
+\code{\link{is_simple}}.)
+
+For \code{graphs_from_cohesive_blocks} and \code{export_pajek} the same graph must be
+supplied whose cohesive block structure is given in the \code{blocks}
+argument.}
+
+\item{labels}{Logical scalar, whether to add the vertex labels to the result
+object. These labels can be then used when reporting and plotting the
+cohesive blocks.}
+
+\item{blocks,x,object}{A \code{cohesiveBlocks} object, created with the
+\code{cohesive_blocks} function.}
+
+\item{y}{The graph whose cohesive blocks are supplied in the \code{x}
+argument.}
+
+\item{colbar}{Color bar for the vertex colors. Its length should be at least
+\eqn{m+1}, where \eqn{m} is the maximum cohesion in the graph.
+Alternatively, the vertex colors can also be directly specified via the
+\code{col} argument.}
+
+\item{col}{A vector of vertex colors, in any of the usual formats. (Symbolic
+color names (e.g. \sQuote{red}, \sQuote{blue}, etc.) , RGB colors (e.g.
+\sQuote{#FF9900FF}), integer numbers referring to the current palette. By
+default the given \code{colbar} is used and vertices with the same maximal
+cohesion will have the same color.}
+
+\item{mark.groups}{A list of vertex sets to mark on the plot by circling
+them. By default all cohesive blocks are marked, except the one
+corresponding to the all vertices.}
+
+\item{layout}{The layout of a plot, it is simply passed on to
+\code{plot.igraph}, see the possible formats there. By default the
+Reingold-Tilford layout generator is used.}
+
+\item{file}{Defines the file (or connection) the Pajek file is written to.
+
+If the \code{project.file} argument is \code{TRUE}, then it can be a
+filename (with extension), a file object, or in general any king of
+connection object. The file/connection will be opened if it wasn't already.
+
+If the \code{project.file} argument is \code{FALSE}, then several files are
+created and \code{file} must be a character scalar containing the base name
+of the files, without extension. (But it can contain the path to the files.)
+
+See also details below.}
+
+\item{project.file}{Logical scalar, whether to create a single Pajek project
+file containing all the data, or to create separated files for each item.
+See details below.}
+
+\item{\dots}{Additional arguments. \code{plot_hierarchy} and \code{plot} pass
+them to \code{plot.igraph}.  \code{print} and \code{summary} ignore them.}
+}
+\value{
+\code{cohesive_blocks} returns a \code{cohesiveBlocks} object.
+
+\code{blocks} returns a list of numeric vectors, containing vertex ids.
+
+\code{graphs_from_cohesive_blocks} returns a list of igraph graphs, corresponding to the
+cohesive blocks.
+
+\code{cohesion} returns a numeric vector, the cohesion of each block.
+
+\code{hierarchy} returns an igraph graph, the representation of the cohesive
+block hierarchy.
+
+\code{parent} returns a numeric vector giving the parent block of each
+cohesive block, in the block hierarchy. The block at the root of the
+hierarchy has no parent and \code{0} is returned for it.
+
+\code{plot_hierarchy}, \code{plot} and \code{export_pajek} return \code{NULL},
+invisibly.
+
+\code{max_cohesion} returns a numeric vector with one entry for each vertex,
+giving the cohesion of its most cohesive block.
+
+\code{print} and \code{summary} return the \code{cohesiveBlocks} object
+itself, invisibly.
+
+\code{length} returns a numeric scalar, the number of blocks.
+}
+\description{
+Calculates cohesive blocks for objects of class \code{igraph}.
+}
+\details{
+Cohesive blocking is a method of determining hierarchical subsets of graph
+vertices based on their structural cohesion (or vertex connectivity). For a
+given graph \eqn{G}, a subset of its vertices \eqn{S\subset V(G)}{S} is said
+to be maximally \eqn{k}-cohesive if there is no superset of \eqn{S} with
+vertex connectivity greater than or equal to \eqn{k}. Cohesive blocking is a
+process through which, given a \eqn{k}-cohesive set of vertices, maximally
+\eqn{l}-cohesive subsets are recursively identified with \eqn{l>k}. Thus a
+hiearchy of vertex subsets is found, whith the entire graph \eqn{G} at its
+root.
+
+The function \code{cohesive_blocks} implements cohesive blocking.  It
+returns a \code{cohesiveBlocks} object. \code{cohesiveBlocks} should be
+handled as an opaque class, i.e. its internal structure should not be
+accessed directly, but through the functions listed here.
+
+The function \code{length} can be used on \code{cohesiveBlocks} objects and
+it gives the number of blocks.
+
+The function \code{blocks} returns the actual blocks stored in the
+\code{cohesiveBlocks} object. They are returned in a list of numeric
+vectors, each containing vertex ids.
+
+The function \code{graphs_from_cohesive_blocks} is similar, but returns the blocks as
+(induced) subgraphs of the input graph. The various (graph, vertex and edge)
+attributes are kept in the subgraph.
+
+The function \code{cohesion} returns a numeric vector, the cohesion of the
+different blocks. The order of the blocks is the same as for the
+\code{blocks} and \code{graphs_from_cohesive_blocks} functions.
+
+The block hierarchy can be queried using the \code{hierarchy} function. It
+returns an igraph graph, its vertex ids are ordered according the order of
+the blocks in the \code{blocks} and \code{graphs_from_cohesive_blocks}, \code{cohesion},
+etc. functions.
+
+\code{parent} gives the parent vertex of each block, in the block hierarchy,
+for the root vertex it gives 0.
+
+\code{plot_hierarchy} plots the hierarchy tree of the cohesive blocks on the
+active graphics device, by calling \code{igraph.plot}.
+
+The \code{export_pajek} function can be used to export the graph and its
+cohesive blocks in Pajek format. It can either export a single Pajek project
+file with all the information, or a set of files, depending on its
+\code{project.file} argument. If \code{project.file} is \code{TRUE}, then
+the following information is written to the file (or connection) given in
+the \code{file} argument: (1) the input graph, together with its attributes,
+see \code{\link{write_graph}} for details; (2) the hierarchy graph; and (3)
+one binary partition for each cohesive block. If \code{project.file} is
+\code{FALSE}, then the \code{file} argument must be a character scalar and
+it is used as the base name for the generated files. If \code{file} is
+\sQuote{basename}, then the following files are created: (1)
+\sQuote{basename.net} for the original graph; (2)
+\sQuote{basename_hierarchy.net} for the hierarchy graph; (3)
+\sQuote{basename_block_x.net} for each cohesive block, where \sQuote{x} is
+the number of the block, starting with one.
+
+\code{max_cohesion} returns the maximal cohesion of each vertex, i.e. the
+cohesion of the most cohesive block of the vertex.
+
+The generic function \code{summary} works on \code{cohesiveBlocks} objects
+and it prints a one line summary to the terminal.
+
+The generic function \code{print} is also defined on \code{cohesiveBlocks}
+objects and it is invoked automatically if the name of the
+\code{cohesiveBlocks} object is typed in. It produces an output like this:
+\preformatted{ Cohesive block structure:
+B-1 c 1, n 23
+'- B-2 c 2, n 14 oooooooo.. .o......oo ooo
+'- B-4 c 5, n  7 ooooooo... .......... ...
+'- B-3 c 2, n 10 ......o.oo o.oooooo.. ...
+'- B-5 c 3, n  4 ......o.oo o......... ...  }
+The left part shows the block structure, in this case for five
+blocks. The first block always corresponds to the whole graph, even if its
+cohesion is zero. Then cohesion of the block and the number of vertices in
+the block are shown. The last part is only printed if the display is wide
+enough and shows the vertices in the blocks, ordered by vertex ids.
+\sQuote{o} means that the vertex is included, a dot means that it is not,
+and the vertices are shown in groups of ten.
+
+The generic function \code{plot} plots the graph, showing one or more
+cohesive blocks in it.
+}
+\examples{
+## The graph from the Moody-White paper
+mw <- graph_from_literal(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
+                5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
+                10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
+                17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
+                21-22:23, 22-23)
+
+mwBlocks <- cohesive_blocks(mw)
+
+# Inspect block membership and cohesion
+mwBlocks
+blocks(mwBlocks)
+cohesion(mwBlocks)
+
+# Save results in a Pajek file
+\dontrun{
+export_pajek(mwBlocks, mw, file="/tmp/mwBlocks.paj")
+}
+
+# Plot the results
+plot(mwBlocks, mw)
+
+## The science camp network
+camp <- graph_from_literal(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
+                  Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
+                  Holly   - Carol:Pat:Pam:Jennie:Bill,
+                  Bill    - Pauline:Michael:Lee:Holly,
+                  Pauline - Bill:Jennie:Ann,
+                  Jennie  - Holly:Michael:Lee:Ann:Pauline,
+                  Michael - Bill:Jennie:Ann:Lee:John,
+                  Ann     - Michael:Jennie:Pauline,
+                  Lee     - Michael:Bill:Jennie,
+                  Gery    - Pat:Steve:Russ:John,
+                  Russ    - Steve:Bert:Gery:John,
+                  John    - Gery:Russ:Michael)
+campBlocks <- cohesive_blocks(camp)
+campBlocks
+
+plot(campBlocks, camp, vertex.label=V(camp)$name, margin=-0.2,
+     vertex.shape="rectangle", vertex.size=24, vertex.size2=8,
+     mark.border=1, colbar=c(NA, NA,"cyan","orange") )
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com} for the current
+implementation, Peter McMahan (\url{http://home.uchicago.edu/~mcmahan/})
+wrote the first version in R.
+}
+\references{
+J. Moody and D. R. White. Structural cohesion and embeddedness:
+A hierarchical concept of social groups. \emph{American Sociological
+Review}, 68(1):103--127, Feb 2003.
+}
+\seealso{
+\code{\link{cohesion}}
+}
+\keyword{graphs}
+
diff --git a/man/communities.Rd b/man/communities.Rd
index a70f368..7d865d5 100644
--- a/man/communities.Rd
+++ b/man/communities.Rd
@@ -1,268 +1,275 @@
-\name{communities}
-\alias{communities}
-\alias{membership}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{membership}
 \alias{algorithm}
+\alias{as.dendrogram.communities}
+\alias{as.hclust.communities}
+\alias{asPhylo}
+\alias{asPhylo.communities}
+\alias{as_phylo}
+\alias{as_phylo.communities}
+\alias{code.length}
+\alias{code_len}
+\alias{communities}
 \alias{crossing}
+\alias{cut_at}
 \alias{cutat}
-\alias{merges}
-\alias{sizes}
 \alias{is.hierarchical}
-\alias{print.communities}
-\alias{plot.communities}
+\alias{is_hierarchical}
 \alias{length.communities}
+\alias{membership}
+\alias{merges}
 \alias{modularity.communities}
-\alias{as.dendrogram.communities}
-\alias{as.hclust.communities}
-\alias{asPhylo}
-\alias{asPhylo.communities}
+\alias{plot.communities}
+\alias{print.communities}
+\alias{show_trace}
 \alias{showtrace}
-\alias{code.length}
-\alias{create.communities}
-\concept{Community structure}
+\alias{sizes}
 \title{Functions to deal with the result of network community detection}
-\description{igraph community detection functions return their results
-  as an object from the \code{communities} class. This manual page
-  describes the operations of this class.}
 \usage{
-\method{print}{communities}(x, \dots)
+membership(communities)
+
+\method{print}{communities}(x, ...)
+
+\method{modularity}{communities}(x, ...)
 
 \method{length}{communities}(x)
+
 sizes(communities)
-membership(communities)
-\method{modularity}{communities}(x, \dots)
+
 algorithm(communities)
-crossing(communities, graph)
 
-is.hierarchical(communities, full = FALSE)
 merges(communities)
-cutat(communities, no, steps)
-\method{as.dendrogram}{communities}(object, hang=-1,
-   use.modularity=FALSE, \dots)
-\method{as.hclust}{communities}(x, hang = -1,
-   use.modularity = FALSE, \dots)
-\method{asPhylo}{communities}(x, use.modularity=FALSE, \dots)
-showtrace(communities)
-
-code.length(communities)
-
-\method{plot}{communities}(x, y,
-   colbar=rainbow(length(x)),
-   col=colbar[membership(x)],
-   mark.groups=communities(x),
-   edge.color=c("black", "red")[crossing(x,y)+1],
-   \dots)
-
-create.communities(membership, algorithm = NULL, merges = NULL,
-                   modularity = NULL, \dots)
+
+crossing(communities, graph)
+
+code_len(communities)
+
+is_hierarchical(communities)
+
+\method{as.dendrogram}{communities}(object, hang = -1,
+  use.modularity = FALSE, ...)
+
+\method{as.hclust}{communities}(x, hang = -1, use.modularity = FALSE, ...)
+
+as_phylo(x, ...)
+
+\method{as_phylo}{communities}(x, use.modularity = FALSE, ...)
+
+cut_at(communities, no, steps)
+
+show_trace(communities)
+
+\method{plot}{communities}(x, y, col = membership(x),
+  mark.groups = communities(x), edge.color = c("black", "red")[crossing(x,
+  y) + 1], ...)
 }
 \arguments{
-  \item{communities,x,object}{A \code{communities} object, the result of
-    an igraph community detection function.}
-  \item{graph}{An igraph graph object, corresponding to
-    \code{communities}.}
-  \item{full}{Logical scalar, if \code{TRUE}, then
-    \code{is.hierarchical} only returns \code{TRUE} for fully
-   hierarchical algorithms. The \sQuote{leading eigenvector} algorithm
-   is hierarchical, it gives a hierarchy of groups, but not a full
-   dendrogram with all vertices, so it is not fully hierarchical.}
-  \item{y}{An igraph graph object, corresponding to the communities in
-    \code{x}.}
-  \item{no}{Integer scalar, the desired number of communities. If too
-    low or two high, then an error message is given. Exactly one of
-    \code{no} and \code{steps} must be supplied.}
-  \item{steps}{The number of merge operations to perform to produce the
-    communities. Exactly one of \code{no} and \code{steps} must be
-    supplied.}
-  \item{colbar}{A vector of colors, in any format that is accepted by
-    the regular R plotting methods. E.g. it may be an integer vector, a
-    character vector of color names, a character vector of RGB
-    colors. This vector gives the color bar for the vertices. The length
-    of the vector should be the same as the number of communities.}
-  \item{col}{A vector of colors, in any format that is accepted by the
-    regular R plotting methods. This vector gives the colors of the
-    vertices explicitly.}
-  \item{mark.groups}{A list of numeric vectors. The communities can be
-    highlighted using colored polygons. The groups for which the
-    polygons are drawn are given here. The default is to use the groups
-    given by the communities. Supply \code{NULL} here if you do not want
-    to highlight any groups.}
-  \item{edge.color}{The colors of the edges. By default the edges within
-    communities are colored green and other edges are red.}
-  \item{hang}{Numeric scalar indicating how the height of leaves should
-    be computed from the heights of their parents; see
-   \code{\link{plot.hclust}}.}
- \item{use.modularity}{Logical scalar, whether to use the modularity
-   values to define the height of the branches.}
- \item{\dots}{Additional arguments. \code{plot.communities} passes
-   these to \code{\link{plot.igraph}}. \code{create.communities} adds
-   them to the \code{communtiies} object it creates. The other functions
-   silently ignore them.}
- \item{membership}{Numeric vector, one value for each vertex, the
-   membership vector of the community structure.}
- \item{algorithm}{If not \code{NULL} (meaning an unknown algorithm), then
-   a character scalar, the name of the algorithm that produced the
-   community structure.}
- \item{merges}{If not \code{NULL}, then the merge matrix of the
-   hierarchical community structure. See \code{merges} below for more
-   information on its format.}
- \item{modularity}{Numeric scalar or vector, the modularity value of the
-   community structure. It can also be \code{NULL}, if the modularity of
-   the (best) split is not available.}
-}
-\details{
-  Community structure detection algorithms try to find dense subgraphs
-  in directed or undirected graphs, by optimizing some criteria, and
-  usually using heuristics.
-
-  igraph implements a number of commmunity detection methods (see them
-  below), all of which return an object of the class
-  \code{communities}. Because the community structure detection
-  algorithms are different, \code{communities} objects do not always
-  have the same structure. Nevertheless, they have some common
-  operations, these are documented here.
-
-  The \code{print} generic function is defined for \code{communities},
-  it prints a short summary.
-
-  The \code{length} generic function call be called on
-  \code{communities} and returns the number of communities.
-
-  The \code{sizes} function returns the community sizes, in the order of
-  their ids.
-  
-  \code{membership} gives the division of the vertices, into
-  communities. It returns a numeric vector, one value for each vertex,
-  the id of its community. Community ids start from one. Note that some
-  algorithms calculate the complete (or incomplete) hierarchical
-  structure of the communities, and not just a single
-  partitioning. For these algorithms typically the membership for the
-  highest modularity value is returned, but see also the manual pages of
-  the individual algorithms.
-  
-  \code{modularity} gives the modularity score of the partitioning. (See
-  \code{\link{modularity.igraph}} for details. For algorithms that do
-  not result a single partitioning, the highest modularity value is
-  returned.
-
-  \code{algorithm} gives the name of the algorithm that was used to
-  calculate the community structure.
-
-  \code{crossing} returns a logical vector, with one value for each
-  edge, ordered according to the edge ids. The value is \code{TRUE} iff
-  the edge connects two different communities, according to the (best)
-  membership vector, as returned by \code{membership()}.
-
-  \code{is.hierarchical} checks whether a hierarchical algorithm was
-  used to find the community structure. Some functions only make sense
-  for hierarchical methods (e.g. \code{merges}, \code{cutat} and
-  \code{as.dendrogram}).
-  
-  \code{merges} returns the merge matrix for hierarchical methods. An
-  error message is given, if a non-hierarchical method was used to find
-  the community structure. You can check this by calling
-  \code{is.hierarchical} on the \code{communities} object.
-
-  \code{cutat} cuts the merge tree of a hierarchical community finding
-  method, at the desired place and returns a membership vector. The
-  desired place can be expressed as the desired number of communities or
-  as the number of merge steps to make. The function gives an error
-  message, if called with a non-hierarchical method.
-
-  \code{as.dendrogram} converts a hierarchical community structure to a
-  \code{dendrogram} object. It only works for hierarchical methods, and
-  gives an error message to others. See \code{\link[stats]{dendrogram}}
-  for details.
-
-  \code{as.hclust} is similar to \code{as.dendrogram}, but converts a
-  hierarchical community structure to a \code{hclust} object.
-
-  \code{asPhylo} converts a hierarchical community structure to
-  a \code{phylo} object, you will need the \code{ape} package for this.
-  
-  \code{showtrace} works (currently) only for communities found by the
-  leading eigenvector method
-  (\code{\link{leading.eigenvector.community}}), and returns a character
-  vector that gives the steps performed by the algorithm while finding
-  the communities.
-
-  \code{code.length} is defined for the InfoMAP method
-  (\code{\link{infomap.community}} and returns the code length of the
-  partition.
-  
-  It is possibly to call the \code{plot} function on \code{communities}
-  objects. This will plot the graph (and uses \code{\link{plot.igraph}}
-  internally), with the communities shown. By default it colores the
-  vertices according to their communities, and also marks the vertex
-  groups corresponding to the communities. It passes additional
-  arguments to \code{\link{plot.igraph}}, please see that and also
-  \code{\link{igraph.plotting}} on how to change the plot.
-
-  \code{create.communities} creates a \code{communities} object. This is
-  useful to integrate the results of community finding algorithms (that
-  are not included in igraph).
+\item{communities,x,object}{A \code{communities} object, the result of an
+igraph community detection function.}
+
+\item{graph}{An igraph graph object, corresponding to \code{communities}.}
+
+\item{hang}{Numeric scalar indicating how the height of leaves should be
+computed from the heights of their parents; see \code{\link{plot.hclust}}.}
+
+\item{use.modularity}{Logical scalar, whether to use the modularity values
+to define the height of the branches.}
+
+\item{no}{Integer scalar, the desired number of communities. If too low or
+two high, then an error message is given. Exactly one of \code{no} and
+\code{steps} must be supplied.}
+
+\item{steps}{The number of merge operations to perform to produce the
+communities. Exactly one of \code{no} and \code{steps} must be supplied.}
+
+\item{y}{An igraph graph object, corresponding to the communities in
+\code{x}.}
+
+\item{col}{A vector of colors, in any format that is accepted by the regular
+R plotting methods. This vector gives the colors of the vertices explicitly.}
+
+\item{mark.groups}{A list of numeric vectors. The communities can be
+highlighted using colored polygons. The groups for which the polygons are
+drawn are given here. The default is to use the groups given by the
+communities. Supply \code{NULL} here if you do not want to highlight any
+groups.}
+
+\item{edge.color}{The colors of the edges. By default the edges within
+communities are colored green and other edges are red.}
+
+\item{\dots}{Additional arguments. \code{plot.communities} passes these to
+\code{\link{plot.igraph}}. The other functions silently ignore
+them.}
+
+\item{membership}{Numeric vector, one value for each vertex, the membership
+vector of the community structure. Might also be \code{NULL} if the
+community structure is given in another way, e.g. by a merge matrix.}
+
+\item{algorithm}{If not \code{NULL} (meaning an unknown algorithm), then a
+character scalar, the name of the algorithm that produced the community
+structure.}
+
+\item{merges}{If not \code{NULL}, then the merge matrix of the hierarchical
+community structure. See \code{merges} below for more information on its
+format.}
+
+\item{modularity}{Numeric scalar or vector, the modularity value of the
+community structure. It can also be \code{NULL}, if the modularity of the
+(best) split is not available.}
 }
 \value{
-  \code{print} returns the \code{communities} object itself, invisibly.
+\code{print} returns the \code{communities} object itself,
+invisibly.
+
+\code{length} returns an integer scalar.
+
+\code{sizes} returns a numeric vector.
+
+\code{membership} returns a numeric vector, one number for each vertex in
+the graph that was the input of the community detection.
 
-  \code{length} returns an integer scalar.
+\code{modularity} returns a numeric scalar.
 
-  \code{sizes} returns a numeric vector.
-  
-  \code{membership} returns a numeric vector, one number for each vertex
-  in the graph that was the input of the community detection.
-  
-  \code{modularity} returns a numeric scalar.
+\code{algorithm} returns a character scalar.
 
-  \code{algorithm} returns a character scalar.
+\code{crossing} returns a logical vector.
 
-  \code{crossing} returns a logical vector.
+\code{is_hierarchical} returns a logical scalar.
 
-  \code{is.hierarchical} returns a logical scalar.
+\code{merges} returns a two-column numeric matrix.
 
-  \code{merges} returns a two-column numeric matrix.
+\code{cut_at} returns a numeric vector, the membership vector of the
+vertices.
 
-  \code{cutat} returns a numeric vector, the membership vector of the
-  vertices.
+\code{as.dendrogram} returns a \code{\link[stats]{dendrogram}} object.
 
-  \code{as.dendrogram} returns a \code{\link[stats]{dendrogram}}
-  object.
+\code{show_trace} returns a character vector.
 
-  \code{showtrace} returns a character vector.
+\code{code_len} returns a numeric scalar for communities found with the
+InfoMAP method and \code{NULL} for other methods.
 
-  \code{code.length} returns a numeric scalar for communities found with
-  the InfoMAP method and \code{NULL} for other methods.
-  
-  \code{plot} for \code{communities} objects returns \code{NULL},
-  invisibly.
+\code{plot} for \code{communities} objects returns \code{NULL}, invisibly.
 
-  \code{create.communities} returns a \code{communities} object.
+#'
 }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  See \code{\link{dendPlot}} for plotting community structure
-  dendrograms.
-  
-  See \code{\link{compare.communities}} for comparing two community
-  structures on the same graph.
-  
-  The different methods for finding communities, they all return a
-  \code{communities} object:
-  \code{\link{edge.betweenness.community}},
-  \code{\link{fastgreedy.community}},
-  \code{\link{label.propagation.community}},
-  \code{\link{leading.eigenvector.community}},
-  \code{\link{multilevel.community}},
-  \code{\link{optimal.community}},
-  \code{\link{spinglass.community}},
-  \code{\link{walktrap.community}}.
+\description{
+igraph community detection functions return their results as an object from
+the \code{communities} class. This manual page describes the operations of
+this class.
+}
+\details{
+Community structure detection algorithms try to find dense subgraphs in
+directed or undirected graphs, by optimizing some criteria, and usually
+using heuristics.
+
+igraph implements a number of community detection methods (see them below),
+all of which return an object of the class \code{communities}. Because the
+community structure detection algorithms are different, \code{communities}
+objects do not always have the same structure. Nevertheless, they have some
+common operations, these are documented here.
+
+The \code{print} generic function is defined for \code{communities}, it
+prints a short summary.
+
+The \code{length} generic function call be called on \code{communities} and
+returns the number of communities.
+
+The \code{sizes} function returns the community sizes, in the order of their
+ids.
+
+\code{membership} gives the division of the vertices, into communities. It
+returns a numeric vector, one value for each vertex, the id of its
+community. Community ids start from one. Note that some algorithms calculate
+the complete (or incomplete) hierarchical structure of the communities, and
+not just a single partitioning. For these algorithms typically the
+membership for the highest modularity value is returned, but see also the
+manual pages of the individual algorithms.
+
+\code{communities} is also the name of a function, that returns a list of
+communities, each identified by their vertices. The vertices will have
+symbolic names if the \code{add.vertex.names} igraph option is set, and the
+graph itself was named. Otherwise numeric vertex ids are used.
+
+\code{modularity} gives the modularity score of the partitioning. (See
+\code{\link{modularity.igraph}} for details. For algorithms that do not
+result a single partitioning, the highest modularity value is returned.
+
+\code{algorithm} gives the name of the algorithm that was used to calculate
+the community structure.
+
+\code{crossing} returns a logical vector, with one value for each edge,
+ordered according to the edge ids. The value is \code{TRUE} iff the edge
+connects two different communities, according to the (best) membership
+vector, as returned by \code{membership()}.
+
+\code{is_hierarchical} checks whether a hierarchical algorithm was used to
+find the community structure. Some functions only make sense for
+hierarchical methods (e.g. \code{merges}, \code{cut_at} and
+\code{as.dendrogram}).
+
+\code{merges} returns the merge matrix for hierarchical methods. An error
+message is given, if a non-hierarchical method was used to find the
+community structure. You can check this by calling \code{is_hierarchical} on
+the \code{communities} object.
+
+\code{cut_at} cuts the merge tree of a hierarchical community finding method,
+at the desired place and returns a membership vector. The desired place can
+be expressed as the desired number of communities or as the number of merge
+steps to make. The function gives an error message, if called with a
+non-hierarchical method.
+
+\code{as.dendrogram} converts a hierarchical community structure to a
+\code{dendrogram} object. It only works for hierarchical methods, and gives
+an error message to others. See \code{\link[stats]{dendrogram}} for details.
+
+\code{as.hclust} is similar to \code{as.dendrogram}, but converts a
+hierarchical community structure to a \code{hclust} object.
+
+\code{as_phylo} converts a hierarchical community structure to a \code{phylo}
+object, you will need the \code{ape} package for this.
+
+\code{show_trace} works (currently) only for communities found by the leading
+eigenvector method (\code{\link{cluster_leading_eigen}}), and
+returns a character vector that gives the steps performed by the algorithm
+while finding the communities.
+
+\code{code_len} is defined for the InfoMAP method
+(\code{\link{cluster_infomap}} and returns the code length of the
+partition.
+
+It is possibly to call the \code{plot} function on \code{communities}
+objects. This will plot the graph (and uses \code{\link{plot.igraph}}
+internally), with the communities shown. By default it colores the vertices
+according to their communities, and also marks the vertex groups
+corresponding to the communities. It passes additional arguments to
+\code{\link{plot.igraph}}, please see that and also
+\code{\link{igraph.plotting}} on how to change the plot.
 }
 \examples{
-karate <- graph.famous("Zachary")
-wc <- walktrap.community(karate)
+karate <- make_graph("Zachary")
+wc <- cluster_walktrap(karate)
 modularity(wc)
 membership(wc)
 plot(wc, karate)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+See \code{\link{plot_dendrogram}} for plotting community structure
+dendrograms.
+
+See \code{\link{compare}} for comparing two community structures
+on the same graph.
+
+The different methods for finding communities, they all return a
+\code{communities} object: \code{\link{cluster_edge_betweenness}},
+\code{\link{cluster_fast_greedy}},
+\code{\link{cluster_label_prop}},
+\code{\link{cluster_leading_eigen}},
+\code{\link{cluster_louvain}}, \code{\link{cluster_optimal}},
+\code{\link{cluster_spinglass}}, \code{\link{cluster_walktrap}}.
+}
 \keyword{graphs}
 
diff --git a/man/community.edge.betweenness.Rd b/man/community.edge.betweenness.Rd
deleted file mode 100644
index 49570ae..0000000
--- a/man/community.edge.betweenness.Rd
+++ /dev/null
@@ -1,96 +0,0 @@
-\name{edge.betweenness.community}
-\alias{edge.betweenness.community}
-\alias{edge.betweenness.community.merges}
-\concept{Edge betweenness}
-\concept{Community structure}
-\title{Community structure detection based on edge betweenness}
-\description{Many networks consist of modules which are densely
-  connected themselves but sparsely connected to other modules.}
-\usage{
-edge.betweenness.community (graph, weights = E(graph)$weight,
-    directed = TRUE, edge.betweenness = TRUE, merges = TRUE,
-    bridges = TRUE, modularity = TRUE, membership = TRUE)
-}
-\arguments{
-  \item{graph}{The graph to analyze.}
-  \item{weights}{The edge weights. Supply \code{NULL} to omit edge
-    weights. By default the \sQuote{\code{weight}} edge attribute is
-    used, if it is present.}
-  \item{directed}{Logical constant, whether to calculate directed edge
-    betweenness for directed graphs. It is ignored for undirected
-    graphs.}
-  \item{edge.betweenness}{Logical constant, whether to return the edge
-    betweenness of the edges at the time of their removal.}
-  \item{merges}{Logical constant, whether to return the merge matrix
-    representing the hierarchical community structure of the network.
-    This argument is called \code{merges}, even if the community
-    structure algorithm itself is divisive and not agglomerative: it
-    builds the tree from top to bottom. There is one line for each merge
-    (i.e. split) in matrix, the first line is the first merge (last
-    split). The communities are identified by integer number starting from
-    one. Community ids smaller than or equal to \eqn{N}, the
-    number of vertices in the graph, belong to singleton communities,
-    ie. individual vertices. Before the first merge we have
-    \eqn{N} communities numbered from one to \eqn{N}. The
-    first merge, the first line of the matrix creates community
-    \eqn{N+1}, the second merge creates community \eqn{N+2},
-    etc.
-  }
-  \item{bridges}{Logical constant, whether to return a list the edge
-    removals which actually splitted a component of the graph.}
-  \item{modularity}{Logical constant, whether to calculate the
-    maximum modularity score, considering all possibly community
-    structures along the edge-betweenness based edge removals.}
-  \item{membership}{Logical constant, whether to calculate the
-    membership vector corresponding to the highest possible modularity
-    score.}
-}
-\details{
-  The edge betweenness score of an edge measures the number of shortest
-  paths through it, see \code{\link{edge.betweenness}} for details. The
-  idea of the edge betweenness based community structure detection is
-  that it is likely that edges connecting separate modules have high
-  edge betweenness as all the shortest paths from one module to another
-  must traverse through them. So if we gradually remove the edge with
-  the highest edge betweenness score we will get a hierarchical map, a
-  rooted tree, called a dendrogram of the graph. The leafs of the tree
-  are the individual vertices and the root of the tree represents the
-  whole graph. 
-
-  \code{edge.betweenness.community} performs this algorithm by
-  calculating the edge betweenness of the graph, removing the edge with
-  the highest edge betweenness score, then recalculating edge
-  betweenness of the edges and again removing the one with the highest
-  score, etc.
-
-  \code{edge.betweeness.community} returns various information collected
-  throught the run of the algorithm. See the return value down here.
-}
-\value{
-  \code{edge.betweenness.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{edge.betweenness}} for the definition and
-  calculation of the edge betweenness,
-  \code{\link{walktrap.community}}, \code{\link{fastgreedy.community}},
-  \code{\link{leading.eigenvector.community}} for other community
-  detection methods.
-
-  See \code{\link{communities}} for extracting the results of the
-  community detection.
-}
-\references{M Newman and M Girvan: Finding and evaluating community
-  structure in networks, \emph{Physical Review E} 69, 026113 (2004)
-}
-\examples{
-g <- barabasi.game(100,m=2)
-eb <- edge.betweenness.community(g)
-
-g <- graph.full(10) \%du\% graph.full(10)
-g <- add.edges(g, c(1,11))
-eb <- edge.betweenness.community(g)
-eb
-}
-\keyword{graphs}
diff --git a/man/community.structure.Rd b/man/community.structure.Rd
deleted file mode 100644
index aa66bba..0000000
--- a/man/community.structure.Rd
+++ /dev/null
@@ -1,44 +0,0 @@
-\name{community.to.membership}
-\alias{community.to.membership}
-\concept{Community structure}
-\title{Common functions supporting community detection algorithms}
-\description{
-  \code{community.to.membership} takes a merge matrix, a typical result
-  of community structure detection algorithms and creates a membership
-  vector by performing a given number of merges in the merge matrix.
-}
-\usage{
-community.to.membership(graph, merges, steps, membership=TRUE, csize=TRUE)
-}
-\arguments{
-  \item{graph}{The graph to which the merge matrix belongs.}
-  \item{merges}{The merge matrix, see
-    e.g. \code{\link{walktrap.community}} for the exact format.}
-  \item{steps}{The number of steps, ie. merges to be performed.}
-  \item{membership}{Logical scalar, whether to include the membership
-    vector in the result.}
-  \item{csize}{Logical scalar, whether to include the sizes of the
-    communities in the result.}
-}
-%\details{}
-\value{
-  A named list with two members:
-  \item{membership}{The membership vector.}
-  \item{csize}{A numeric vector giving the sizes of the communities.}
-}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  \code{\link{walktrap.community}},
-  \code{\link{edge.betweenness.community}},
-  \code{\link{fastgreedy.community}},
-  \code{\link{spinglass.community}} for various community detection
-  methods.
-}
-\examples{
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
-wtc <- walktrap.community(g)
-community.to.membership(g, wtc$merges, steps=12)
-}
-\keyword{graphs}
diff --git a/man/compare.Rd b/man/compare.Rd
new file mode 100644
index 0000000..ebd2b34
--- /dev/null
+++ b/man/compare.Rd
@@ -0,0 +1,73 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{compare}
+\alias{compare}
+\alias{compare.communities}
+\alias{compare.membership}
+\title{Compares community structures using various metrics}
+\usage{
+compare(comm1, comm2, method = c("vi", "nmi", "split.join", "rand",
+  "adjusted.rand"))
+}
+\arguments{
+\item{comm1}{A \code{\link{communities}} object containing a community
+structure; or a numeric vector, the membership vector of the first community
+structure. The membership vector should contain the community id of each
+vertex, the numbering of the communities starts with one.}
+
+\item{comm2}{A \code{\link{communities}} object containing a community
+structure; or a numeric vector, the membership vector of the second
+community structure, in the same format as for the previous argument.}
+
+\item{method}{Character scalar, the comparison method to use. Possible
+values: \sQuote{vi} is the variation of information (VI) metric of Meila
+(2003), \sQuote{nmi} is the normalized mutual information measure proposed
+by Danon et al. (2005), \sQuote{split.join} is the split-join distance of
+can Dongen (2000), \sQuote{rand} is the Rand index of Rand (1971),
+\sQuote{adjusted.rand} is the adjusted Rand index by Hubert and Arabie
+(1985).}
+}
+\value{
+A real number.
+}
+\description{
+This function assesses the distance between two community structures.
+}
+\examples{
+g <- make_graph("Zachary")
+sg <- cluster_spinglass(g)
+le <- cluster_leading_eigen(g)
+compare(sg, le, method="rand")
+compare(membership(sg), membership(le))
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Meila M: Comparing clusterings by the variation of information.
+In: Scholkopf B, Warmuth MK (eds.). \emph{Learning Theory and Kernel
+Machines: 16th Annual Conference on Computational Learning Theory and 7th
+Kernel Workshop}, COLT/Kernel 2003, Washington, DC, USA. Lecture Notes in
+Computer Science, vol. 2777, Springer, 2003. ISBN: 978-3-540-40720-1.
+
+Danon L, Diaz-Guilera A, Duch J, Arenas A: Comparing community structure
+identification. \emph{J Stat Mech} P09008, 2005.
+
+van Dongen S: Performance criteria for graph clustering and Markov cluster
+experiments. Technical Report INS-R0012, National Research Institute for
+Mathematics and Computer Science in the Netherlands, Amsterdam, May 2000.
+
+Rand WM: Objective criteria for the evaluation of clustering methods.
+\emph{J Am Stat Assoc} 66(336):846-850, 1971.
+
+Hubert L and Arabie P: Comparing partitions. \emph{Journal of
+Classification} 2:193-218, 1985.
+}
+\seealso{
+\code{\link{cluster_walktrap}},
+\code{\link{cluster_edge_betweenness}},
+\code{\link{cluster_fast_greedy}}, \code{\link{cluster_spinglass}} for
+various community detection methods.
+}
+\keyword{graphs}
+
diff --git a/man/compare.communities.Rd b/man/compare.communities.Rd
deleted file mode 100644
index ab6d6fc..0000000
--- a/man/compare.communities.Rd
+++ /dev/null
@@ -1,75 +0,0 @@
-\name{compare.communities}
-\alias{compare.communities}
-\alias{compare.numeric}
-\alias{compare}
-\concept{Community structure}
-\title{Compares community structures using various metrics}
-\description{
-  This function assesses the distance between two community structures.
-}
-\usage{
-\method{compare}{communities}(comm1, comm2, method = c("vi", "nmi",
-                                      "split.join", "rand",
-                                      "adjusted.rand"))
-\method{compare}{numeric}(comm1, comm2, method = c("vi", "nmi",
-                                      "split.join", "rand",
-                                      "adjusted.rand"))
-}
-\arguments{
-  \item{comm1}{A \code{\link{communities}} object containing a community
-    structure; or a numeric vector, the membership vector of the first
-    community structure. The membership vector should contain the
-    community id of each vertex, the numbering of the communities starts
-    with one.}
-  \item{comm2}{A \code{\link{communities}} object containing a community
-    structure; or a numeric vector, the membership vector of the second
-    community structure, in the same format as for the previous
-    argument.} 
-  \item{method}{Character scalar, the comparison method to use. Possible
-    values: \sQuote{vi} is the variation of information (VI) metric of
-    Meila (2003), \sQuote{nmi} is the normalized mutual information
-    measure proposed by Danon et al. (2005), \sQuote{split.join} is the
-    split-join distance of can Dongen (2000), \sQuote{rand} is the Rand
-    index of Rand (1971), \sQuote{adjusted.rand} is the adjusted Rand
-    index by Hubert and Arabie (1985).}
-}
-% \details{}
-\value{A real number.}
-\references{
-  Meila M: Comparing clusterings by the variation of information.
-  In: Scholkopf B, Warmuth MK (eds.). \emph{Learning Theory and Kernel
-    Machines: 16th Annual Conference on Computational Learning Theory
-    and 7th Kernel Workshop}, COLT/Kernel 2003, Washington, DC,
-  USA. Lecture Notes in Computer Science, vol. 2777, Springer,
-  2003. ISBN: 978-3-540-40720-1.
-
-  Danon L, Diaz-Guilera A, Duch J, Arenas A: Comparing community structure
-  identification. \emph{J Stat Mech} P09008, 2005.
-
-  van Dongen S: Performance criteria for graph clustering and Markov cluster
-  experiments. Technical Report INS-R0012, National Research Institute for
-  Mathematics and Computer Science in the Netherlands, Amsterdam, May 2000.
- 
-  Rand WM: Objective criteria for the evaluation of clustering methods.
-  \emph{J Am Stat Assoc} 66(336):846-850, 1971.
-
-  Hubert L and Arabie P: Comparing partitions. \emph{Journal of
-    Classification} 2:193-218, 1985.
-  
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com}}
-\seealso{
-  \code{\link{walktrap.community}},
-  \code{\link{edge.betweenness.community}},
-  \code{\link{fastgreedy.community}},
-  \code{\link{spinglass.community}} for various community detection
-  methods.
-}
-\examples{
-g <- graph.famous("Zachary")
-sg <- spinglass.community(g)
-le <- leading.eigenvector.community(g)
-compare(sg, le, method="rand")
-compare(membership(sg), membership(le))
-}
-\keyword{graphs}
diff --git a/man/complementer.Rd b/man/complementer.Rd
new file mode 100644
index 0000000..9b26bcd
--- /dev/null
+++ b/man/complementer.Rd
@@ -0,0 +1,46 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{complementer}
+\alias{complementer}
+\alias{graph.complementer}
+\title{Complementer of a graph}
+\usage{
+complementer(graph, loops = FALSE)
+}
+\arguments{
+\item{graph}{The input graph, can be directed or undirected.}
+
+\item{loops}{Logical constant, whether to generate loop edges.}
+}
+\value{
+A new graph object.
+}
+\description{
+A complementer graph contains all edges that were not present in the input
+graph.
+}
+\details{
+\code{complementer} creates the complementer of a graph. Only edges
+which are \emph{not} present in the original graph will be included in the
+new graph.
+
+\code{complementer} keeps graph and vertex attriubutes, edge
+attributes are lost.
+}
+\examples{
+## Complementer of a ring
+g <- make_ring(10)
+complementer(g)
+
+## A graph and its complementer give together the full graph
+g <- make_ring(10)
+gc <- complementer(g)
+gu <- union(g, gc)
+gu
+graph.isomorphic(gu, make_full_graph(vcount(g)))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/component_wise.Rd b/man/component_wise.Rd
new file mode 100644
index 0000000..0e3ea70
--- /dev/null
+++ b/man/component_wise.Rd
@@ -0,0 +1,67 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{component_wise}
+\alias{component_wise}
+\title{Component-wise layout}
+\usage{
+component_wise(merge_method = "dla")
+}
+\arguments{
+\item{merge_method}{Merging algorithm, the \code{method}
+  argument of \code{\link{merge_coords}}.}
+}
+\description{
+This is a layout modifier function, and it can be used
+to calculate the layout separately for each component
+of the graph.
+}
+\examples{
+g <- make_ring(10) + make_ring(10)
+g \%>\%
+  add_layout_(in_circle(), component_wise()) \%>\%
+  plot()
+}
+\seealso{
+\code{\link{merge_coords}}, \code{\link{layout_}}.
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{in_circle}}, \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+
+Other layout modifiers: \code{\link{normalize}}
+}
+
diff --git a/man/components.Rd b/man/components.Rd
index e0dd703..6e45e5e 100644
--- a/man/components.Rd
+++ b/man/components.Rd
@@ -1,33 +1,81 @@
-\name{components}
-\alias{subcomponent}
-\concept{Subcomponent}
-\title{In- or out- component of a vertex}
-\description{Finds all vertices reachable from a given vertex, or the
-  opposite: all vertices from which a given vertex is reachable via a
-  directed path.}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/components.R, R/structural.properties.R
+\name{component_distribution}
+\alias{cluster.distribution}
+\alias{clusters}
+\alias{component_distribution}
+\alias{components}
+\alias{count_components}
+\alias{is.connected}
+\alias{is_connected}
+\alias{no.clusters}
+\title{Connected components of a graph}
 \usage{
-subcomponent(graph, v, mode = c("all", "out", "in"))
+component_distribution(graph, cumulative = FALSE, mul.size = FALSE, ...)
+
+components(graph, mode = c("weak", "strong"))
 }
 \arguments{
-  \item{graph}{The graph to analyze.}
-  \item{v}{The vertex to start the search from.}
-  \item{mode}{Character string, either \dQuote{in}, \dQuote{out} or
-    \dQuote{all}. If \dQuote{in} all vertices from which \code{v} is
-    reachable are listed. If \dQuote{out} all vertices reachable from
-    \code{v} are returned. If \dQuote{all} returns the union of
-    these. It is ignored for undirected graphs.} 
-}
-\details{A breadh-first search is conducted starting from vertex
-  \code{v}.}
-\value{Numeric vector, the ids of the vertices in the same component as
-  \code{v}.} 
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{clusters}}}
+\item{graph}{The graph to analyze.}
+
+\item{cumulative}{Logical, if TRUE the cumulative distirubution (relative
+frequency) is calculated.}
+
+\item{mul.size}{Logical. If TRUE the relative frequencies will be multiplied
+by the cluster sizes.}
+
+\item{mode}{Character string, either \dQuote{weak} or \dQuote{strong}.  For
+directed graphs \dQuote{weak} implies weakly, \dQuote{strong} strongly
+connected components to search. It is ignored for undirected graphs.}
+
+\item{\dots}{Additional attributes to pass to \code{cluster}, right now only
+\code{mode} makes sense.}
+}
+\value{
+For \code{is_connected} a logical constant.
+
+For \code{components} a named list with three components:
+\item{membership}{numeric vector giving the cluster id to which each vertex
+belongs.} \item{csize}{numeric vector giving the sizes of the clusters.}
+\item{no}{numeric constant, the number of clusters.}
+
+For \code{count_components} an integer constant is returned.
+
+For \code{component_distribution} a numeric vector with the relative
+frequencies. The length of the vector is the size of the largest component
+plus one. Note that (for currently unknown reasons) the first element of the
+vector is the number of clusters of size zero, so this is always zero.
+}
+\description{
+Calculate the maximal (weakly or strongly) connected components of a graph
+}
+\details{
+\code{is_connected} decides whether the graph is weakly or strongly
+connected.
+
+\code{components} finds the maximal (weakly or strongly) connected components
+of a graph.
+
+\code{count_components} does almost the same as \code{components} but returns only
+the number of clusters found instead of returning the actual clusters.
+
+\code{component_distribution} creates a histogram for the maximal connected
+component sizes.
+
+The weakly connected components are found by a simple breadth-first search.
+The strongly connected components are implemented by two consecutive
+depth-first searches.
+}
 \examples{
-g <- erdos.renyi.game(100, 1/200)
-subcomponent(g, 1, "in")
-subcomponent(g, 1, "out")
-subcomponent(g, 1, "all")
+g <- sample_gnp(20, 1/20)
+clu <- components(g)
+groups(clu)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{subcomponent}}, \code{\link{groups}}
 }
 \keyword{graphs}
+
diff --git a/man/compose.Rd b/man/compose.Rd
new file mode 100644
index 0000000..8e1863e
--- /dev/null
+++ b/man/compose.Rd
@@ -0,0 +1,76 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{compose}
+\alias{\%c\%}
+\alias{compose}
+\alias{graph.compose}
+\title{Compose two graphs as binary relations}
+\usage{
+compose(g1, g2, byname = "auto")
+}
+\arguments{
+\item{g1}{The first input graph.}
+
+\item{g2}{The second input graph.}
+
+\item{byname}{A logical scalar, or the character scalar \code{auto}. Whether
+to perform the operation based on symbolic vertex names. If it is
+\code{auto}, that means \code{TRUE} if both graphs are named and
+\code{FALSE} otherwise. A warning is generated if \code{auto} and one graph,
+but not both graphs are named.}
+}
+\value{
+A new graph object.
+}
+\description{
+Relational composition of two graph.
+}
+\details{
+\code{compose} creates the relational composition of two graphs. The
+new graph will contain an (a,b) edge only if there is a vertex c, such that
+edge (a,c) is included in the first graph and (c,b) is included in the
+second graph. The corresponding operator is \%c\%.
+
+The function gives an error if one of the input graphs is directed and the
+other is undirected.
+
+If the \code{byname} argument is \code{TRUE} (or \code{auto} and the graphs
+are all named), then the operation is performed based on symbolic vertex
+names. Otherwise numeric vertex ids are used.
+
+\code{compose} keeps the attributes of both graphs. All graph, vertex
+and edge attributes are copied to the result. If an attribute is present in
+multiple graphs and would result a name clash, then this attribute is
+renamed by adding suffixes: _1, _2, etc.
+
+The \code{name} vertex attribute is treated specially if the operation is
+performed based on symbolic vertex names. In this case \code{name} must be
+present in both graphs, and it is not renamed in the result graph.
+
+Note that an edge in the result graph corresponds to two edges in the input,
+one in the first graph, one in the second. This mapping is not injective and
+several edges in the result might correspond to the same edge in the first
+(and/or the second) graph. The edge attributes in the result graph are
+updated accordingly.
+
+Also note that the function may generate multigraphs, if there are more than
+one way to find edges (a,b) in g1 and (b,c) in g2 for an edge (a,c) in the
+result. See \code{\link{simplify}} if you want to get rid of the multiple
+edges.
+
+The function may create loop edges, if edges (a,b) and (b,a) are present in
+g1 and g2, respectively, then (a,a) is included in the result. See
+\code{\link{simplify}} if you want to get rid of the self-loops.
+}
+\examples{
+g1 <- make_ring(10)
+g2 <- make_star(10, mode="undirected")
+gc <- compose(g1, g2)
+str(gc)
+str(simplify(gc))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/consensus_tree.Rd b/man/consensus_tree.Rd
new file mode 100644
index 0000000..18fd2b6
--- /dev/null
+++ b/man/consensus_tree.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{consensus_tree}
+\alias{consensus_tree}
+\alias{hrg.consensus}
+\title{Create a consensus tree from several hierarchical random graph models}
+\usage{
+consensus_tree(graph, hrg = NULL, start = FALSE, num.samples = 10000)
+}
+\arguments{
+\item{graph}{The graph the models were fitted to.}
+
+\item{hrg}{A hierarchical random graph model, in the form of an
+\code{igraphHRG} object. \code{consensus_tree} allows this to be
+\code{NULL} as well, then a HRG is fitted to the graph first, from a
+random starting point.}
+
+\item{start}{Logical, whether to start the fitting/sampling from the
+supplied \code{igraphHRG} object, or from a random starting point.}
+
+\item{num.samples}{Number of samples to use for consensus generation or
+missing edge prediction.}
+}
+\value{
+\code{consensus_tree} returns a list of two objects. The first
+is an \code{igraphHRGConsensus} object, the second is an
+\code{igraphHRG} object.  The \code{igraphHRGConsensus} object has the
+following members:
+  \item{parents}{For each vertex, the id of its parent vertex is stored,
+    or zero, if the vertex is the root vertex in the tree. The first n
+    vertex ids (from 0) refer to the original vertices of the graph, the
+    other ids refer to vertex groups.}
+  \item{weights}{Numeric vector, counts the number of times a given tree
+    split occured in the generated network samples, for each internal
+    vertices. The order is the same as in the \code{parents} vector.}
+}
+\description{
+\code{consensus_tree} creates a consensus tree from several fitted
+hierarchical random graph models, using phylogeny methods. If the \code{hrg}
+argument is given and \code{start} is set to \code{TRUE}, then it starts
+sampling from the given HRG. Otherwise it optimizes the HRG log-likelihood
+first, and then samples starting from the optimum.
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg_tree}}; \code{\link{hrg}},
+  \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/console.Rd b/man/console.Rd
new file mode 100644
index 0000000..60e788c
--- /dev/null
+++ b/man/console.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/console.R
+\name{console}
+\alias{console}
+\alias{igraph.console}
+\title{The igraph console}
+\usage{
+console()
+}
+\value{
+\code{NULL}, invisibly.
+}
+\description{
+The igraph console is a GUI windows that shows what the currently running
+igraph function is doing.
+}
+\details{
+The console can be started by calling the \code{console} function.
+Then it stays open, until the user closes it.
+
+Another way to start it to set the \code{verbose} igraph option to
+\dQuote{tkconsole} via \code{igraph_options}. Then the console (re)opens
+each time an igraph function supporting it starts; to close it, set the
+\code{verbose} option to another value.
+
+The console is written in Tcl/Tk and required the \code{tcltk} package.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{igraph_options}} and the \code{verbose} option.
+}
+\keyword{graphs}
+
diff --git a/man/constraint.Rd b/man/constraint.Rd
index 602b67f..b125612 100644
--- a/man/constraint.Rd
+++ b/man/constraint.Rd
@@ -1,49 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{constraint}
 \alias{constraint}
-\concept{Burt's constraint}
 \title{Burt's constraint}
-\description{Given a graph, \code{constraint} calculates Burt's constraint for
-  each vertex.
-}
 \usage{
-constraint(graph, nodes=V(graph), weights=NULL)
+constraint(graph, nodes = V(graph), weights = NULL)
 }
 \arguments{
-  \item{graph}{A graph object, the input graph.}
-  \item{nodes}{The vertices for which the constraint will be
-    calculated. Defaults to all vertices.}
-  \item{weights}{The weights of the edges. If this is \code{NULL} and
-    there is a \code{weight} edge attribute this is used. If there is no
-    such edge attribute all edges will have the same weight.}
-}
-\details{Burt's constraint is higher if ego has less, or mutually
-  stronger related (i.e. more redundant) contacts. Burt's measure of
-  constraint, \eqn{C_i}{C[i]}, of vertex \eqn{i}'s ego network
-  \eqn{V_i}{V[i]}, is defined for directed and valued graphs,
-  \deqn{C_i=\sum_{j \in V_i \setminus \{i\}} (p_{ij}+\sum_{q \in V_i
-      \setminus \{i,j\}} p_{iq} p_{qj})^2}{%
-    C[i] = sum( [sum( p[i,j] + p[i,q] p[q,j], q in V[i], q != i,j )]^2, j in
-    V[i], j != i).
-  }
-  for a graph of order (ie. number of vertices) \eqn{N}, where
-  proportional tie strengths are defined as 
-  \deqn{p_{ij} = \frac{a_{ij}+a_{ji}}{\sum_{k \in V_i \setminus \{i\}}(a_{ik}+a_{ki})},}{%
-    p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),
-  }
-  \eqn{a_{ij}}{a[i,j]} are elements of \eqn{A} and the latter being the
-  graph adjacency matrix. For isolated vertices, constraint is undefined.
-}
-\value{A numeric vector of constraint scores}
-\author{Jeroen Bruggeman
-  (\url{https://sites.google.com/site/jebrug/jeroen-bruggeman-social-science})
-  and Gabor Csardi \email{csardi.gabor at gmail.com}
-}
-\references{Burt, R.S. (2004). Structural holes and good ideas. \emph{American
-    Journal of Sociology} 110, 349-399.
+\item{graph}{A graph object, the input graph.}
+
+\item{nodes}{The vertices for which the constraint will be calculated.
+Defaults to all vertices.}
+
+\item{weights}{The weights of the edges. If this is \code{NULL} and there is
+a \code{weight} edge attribute this is used. If there is no such edge
+attribute all edges will have the same weight.}
+}
+\value{
+A numeric vector of constraint scores
+}
+\description{
+Given a graph, \code{constraint} calculates Burt's constraint for each
+vertex.
+}
+\details{
+Burt's constraint is higher if ego has less, or mutually
+stronger related (i.e. more redundant) contacts. Burt's measure of
+constraint, \eqn{C_i}{C[i]}, of vertex \eqn{i}'s ego network
+\eqn{V_i}{V[i]}, is defined for directed and valued graphs,
+\deqn{C_i=\sum_{j \in V_i \setminus \{i\}} (p_{ij}+\sum_{q \in V_i
+    \setminus \{i,j\}} p_{iq} p_{qj})^2}{
+  C[i] = sum( [sum( p[i,j] + p[i,q] p[q,j], q in V[i], q != i,j )]^2, j in
+  V[i], j != i).
+}
+for a graph of order (ie. number of vertices) \eqn{N}, where
+proportional tie strengths are defined as
+\deqn{p_{ij} = \frac{a_{ij}+a_{ji}}{\sum_{k \in V_i \setminus \{i\}}(a_{ik}+a_{ki})},}{
+  p[i,j]=(a[i,j]+a[j,i]) / sum(a[i,k]+a[k,i], k in V[i], k != i),
+}
+\eqn{a_{ij}}{a[i,j]} are elements of \eqn{A} and the latter being the
+graph adjacency matrix. For isolated vertices, constraint is undefined.
 }
 \examples{
-g <- erdos.renyi.game(20, 5/20)
+g <- sample_gnp(20, 5/20)
 constraint(g)
 }
+\author{
+Jeroen Bruggeman
+(\url{https://sites.google.com/site/jebrug/jeroen-bruggeman-social-science})
+and Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Burt, R.S. (2004). Structural holes and good ideas.
+\emph{American Journal of Sociology} 110, 349-399.
+}
 \keyword{graphs}
 
diff --git a/man/contract.Rd b/man/contract.Rd
new file mode 100644
index 0000000..f3f44e4
--- /dev/null
+++ b/man/contract.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{contract}
+\alias{contract}
+\alias{contract.vertices}
+\title{Contract several vertices into a single one}
+\usage{
+contract(graph, mapping, vertex.attr.comb = igraph_opt("vertex.attr.comb"))
+}
+\arguments{
+\item{graph}{The input graph, it can be directed or undirected.}
+
+\item{mapping}{A numeric vector that specifies the mapping. Its elements
+correspond to the vertices, and for each element the id in the new graph is
+given.}
+
+\item{vertex.attr.comb}{Specifies how to combine the vertex attributes in
+the new graph. Please see \code{\link{attribute.combination}} for details.}
+}
+\value{
+A new graph object.
+}
+\description{
+This function creates a new graph, by merging several vertices into one. The
+vertices in the new graph correspond to sets of vertices in the input graph.
+}
+\details{
+The attributes of the graph are kept. Graph and edge attributes are
+unchanged, vertex attributes are combined, according to the
+\code{vertex.attr.comb} parameter.
+}
+\examples{
+g <- make_ring(10)
+g$name <- "Ring"
+V(g)$name <- letters[1:vcount(g)]
+E(g)$weight <- runif(ecount(g))
+
+g2 <- contract(g, rep(1:5, each=2),
+                        vertex.attr.comb=toString)
+
+## graph and edge attributes are kept, vertex attributes are
+## combined using the 'toString' function.
+print(g2, g=TRUE, v=TRUE, e=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/contract.vertices.Rd b/man/contract.vertices.Rd
deleted file mode 100644
index 44e9c47..0000000
--- a/man/contract.vertices.Rd
+++ /dev/null
@@ -1,51 +0,0 @@
-\name{contract.vertices}
-\alias{contract.vertices}
-\title{Contract several vertices into a single one}
-\description{
-  This function creates a new graph, by merging several 
-  vertices into one. The vertices in the new graph correspond
-  to sets of vertices in the input graph.
-}
-\usage{
-contract.vertices(graph, mapping,
-                  vertex.attr.comb=getIgraphOpt("vertex.attr.comb"))
-}
-\arguments{
-  \item{graph}{The input graph, it can be directed or undirected.}
-  \item{mapping}{A numeric vector that specifies the mapping. Its
-    elements correspond to the vertices, and for each element the id in
-    the new graph is given.}
-  \item{vertex.attr.comb}{Specifies how to combine the vertex attributes
-    in the new graph. Please see \code{\link{attribute.combination}} for
-    details.
-  }
-}
-\details{
-  The attributes of the graph are kept. Graph and edge attributes are
-  unchanged, vertex attributes are combined, according to the
-  \code{vertex.attr.comb} parameter.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g <- graph.ring(10)
-g$name <- "Ring"
-V(g)$name <- letters[1:vcount(g)]
-E(g)$weight <- runif(ecount(g))
-
-g2 <- contract.vertices(g, rep(1:5, each=2),
-                        vertex.attr.comb=toString)
-
-## graph and edge attributes are kept, vertex attributes are
-## combined using the 'toString' function.
-print(g2, g=TRUE, v=TRUE, e=TRUE)
-
-}
-\keyword{graphs}
-
-  
-  
\ No newline at end of file
diff --git a/man/conversion.Rd b/man/conversion.Rd
deleted file mode 100644
index 4d06c40..0000000
--- a/man/conversion.Rd
+++ /dev/null
@@ -1,82 +0,0 @@
-\name{conversion}
-\alias{get.adjacency}
-\alias{get.edgelist}
-\concept{Edge list}
-\concept{Adjacency list}
-\title{Convert a graph to an adjacency matrix or an edge list}
-\description{Sometimes it is useful to have a standard representation of
-  a graph, like an adjacency matrix or an edge list.}
-\usage{
-get.adjacency(graph, type=c("both", "upper", "lower"),
-       attr=NULL, edges=FALSE, names=TRUE,
-       sparse=getIgraphOpt("sparsematrices"))
-get.edgelist(graph, names=TRUE)
-}
-\arguments{
-  \item{graph}{The graph to convert.}
-  \item{type}{Gives how to create the adjacency matrix for undirected
-    graphs. It is ignored for directed graphs. Possible values:
-    \code{upper}: the upper right triangle of the matrix is used,
-    \code{lower}: the lower left triangle of the matrix is
-    used. \code{both}: the whole matrix is used, a symmetric matrix is
-    returned.}
-  \item{attr}{Either \code{NULL} or a character string giving an edge
-    attribute name. If \code{NULL} a traditional adjacency matrix is
-    returned. If not \code{NULL} then the values of the given edge
-    attribute are included in the adjacency matrix. If the graph has
-    multiple edges, the edge attribute of an arbitrarily chosen edge
-    (for the multiple edges) is included. This argument is ignored if
-    \code{edges} is \code{TRUE}.
-
-    Note that this works only for certain attribute types. If the
-    \code{sparse} argumen is \code{TRUE}, then the attribute must be
-    either logical or numeric. If the \code{sparse} argument is
-    \code{FALSE}, then character is also allowed. The reason for the
-    difference is that the \code{Matrix} package does not support
-    character sparse matrices yet.
-  }
-  \item{edges}{Logical scalar, whether to return the edge ids in the
-    matrix. For non-existant edges zero is returned.}
-  \item{names}{Logical constant.
-
-    For \code{graph.adjacenct} it gives whether to assign row and column names
-    to the matrix. These are only assigned if the \code{name} vertex
-    attribute is present in the graph.
-
-    for \code{get.edgelist} it gives whether to return a character
-    matrix containing vertex names (ie. the \code{name} vertex
-    attribute) if they exist or numeric vertex ids.
-  }
-  \item{sparse}{Logical scalar, whether to create a sparse matrix. The
-    \sQuote{\code{Matrix}} package must be installed for creating sparse
-    matrices.}
-}
-\details{
-  \code{get.adjacency} returns the adjacency matrix of a graph, a
-  regular \R matrix if \code{sparse} is \code{FALSE}, or a sparse
-  matrix, as defined in the \sQuote{\code{Matrix}} package, if
-  \code{sparse} if \code{TRUE}.
-  
-  \code{get.edgelist} returns the list of edges in a graph.  
-}
-\value{
-  A \code{vcount(graph)} by \code{vcount(graph)} (usually) numeric
-  matrix for \code{get.adjacency}. (This can be huge!) Note that a
-  non-numeric matrix might be returned if \code{attr} is a non-numeric
-  edge attribute.
-
-  A \code{ecount(graph)} by 2 numeric matrix for \code{get.edgelist}.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.adjacency}}, \code{\link{read.graph}}}
-\examples{
-g <- erdos.renyi.game(10, 2/10)
-get.edgelist(g)
-get.adjacency(g)
-V(g)$name <- letters[1:vcount(g)]
-get.adjacency(g)
-E(g)$weight <- runif(ecount(g))
-get.adjacency(g, attr="weight")
-}
-\keyword{graphs}
diff --git a/man/convex.hull.Rd b/man/convex.hull.Rd
deleted file mode 100644
index fe696d4..0000000
--- a/man/convex.hull.Rd
+++ /dev/null
@@ -1,34 +0,0 @@
-\name{convex.hull}
-\alias{convex.hull}
-\concept{Convex hull}
-\title{Convex hull of a set of vertices}
-\description{
-  Calculate the convex hull of a set of points, i.e. the covering
-  polygon that has the smallest area.
-}
-\usage{
-convex.hull(data)
-}
-\arguments{
-  \item{data}{The data points, a numeric matrix with two columns.}
-}
-%\details{}
-\value{
-  A named list with components:
-  \item{resverts}{The indices of the input vertices that constritute the
-    convex hull.}
-  \item{rescoords}{The coordinates of the corners of the convex hull.}
-}
-\references{
- Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford
- Stein. Introduction to Algorithms, Second Edition. MIT Press and
- McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3:
- Finding the convex hull.
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com}}
-% \seealso
-\examples{
-M <- cbind( runif(100), runif(100) )
-convex.hull(M)
-}
-\keyword{graphs}
diff --git a/man/convex_hull.Rd b/man/convex_hull.Rd
new file mode 100644
index 0000000..9af4781
--- /dev/null
+++ b/man/convex_hull.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/other.R
+\name{convex_hull}
+\alias{convex.hull}
+\alias{convex_hull}
+\title{Convex hull of a set of vertices}
+\usage{
+convex_hull(data)
+}
+\arguments{
+\item{data}{The data points, a numeric matrix with two columns.}
+}
+\value{
+A named list with components: \item{resverts}{The indices of the
+input vertices that constritute the convex hull.} \item{rescoords}{The
+coordinates of the corners of the convex hull.}
+}
+\description{
+Calculate the convex hull of a set of points, i.e. the covering polygon that
+has the smallest area.
+}
+\examples{
+M <- cbind( runif(100), runif(100) )
+convex_hull(M)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and
+Clifford Stein. Introduction to Algorithms, Second Edition. MIT Press and
+McGraw-Hill, 2001. ISBN 0262032937. Pages 949-955 of section 33.3: Finding
+the convex hull.
+}
+\keyword{graphs}
+
diff --git a/man/coreness.Rd b/man/coreness.Rd
new file mode 100644
index 0000000..e80a4a6
--- /dev/null
+++ b/man/coreness.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{coreness}
+\alias{coreness}
+\alias{graph.coreness}
+\title{K-core decomposition of graphs}
+\usage{
+coreness(graph, mode = c("all", "out", "in"))
+}
+\arguments{
+\item{graph}{The input graph, it can be directed or undirected}
+
+\item{mode}{The type of the core in directed graphs. Character constant,
+possible values: \code{in}: in-cores are computed, \code{out}: out-cores are
+computed, \code{all}: the corresponding undirected graph is considered. This
+argument is ignored for undirected graphs.}
+}
+\value{
+Numeric vector of integer numbers giving the coreness of each
+vertex.
+}
+\description{
+The k-core of graph is a maximal subgraph in which each vertex has at least
+degree k. The coreness of a vertex is k if it belongs to the k-core but not
+to the (k+1)-core.
+}
+\details{
+The k-core of a graph is the maximal subgraph in which every vertex has at
+least degree k. The cores of a graph form layers: the (k+1)-core is always a
+subgraph of the k-core.
+
+This function calculates the coreness for each vertex.
+}
+\examples{
+g <- make_ring(10)
+g <- add_edges(g, c(1,2, 2,3, 1,3))
+coreness(g) 		# small core triangle in a ring
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Vladimir Batagelj, Matjaz Zaversnik: An O(m) Algorithm for Cores
+Decomposition of Networks, 2002
+
+Seidman S. B. (1983) Network structure and minimum degree, \emph{Social
+Networks}, 5, 269--287.
+}
+\seealso{
+\code{\link{degree}}
+}
+\keyword{graphs}
+
diff --git a/man/count_isomorphisms.Rd b/man/count_isomorphisms.Rd
new file mode 100644
index 0000000..85053df
--- /dev/null
+++ b/man/count_isomorphisms.Rd
@@ -0,0 +1,67 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{count_isomorphisms}
+\alias{count_isomorphisms}
+\alias{graph.count.isomorphisms.vf2}
+\title{Count the number of isomorphic mappings between two graphs}
+\usage{
+count_isomorphisms(graph1, graph2, method = "vf2", ...)
+}
+\arguments{
+\item{graph1}{The first graph.}
+
+\item{graph2}{The second graph.}
+
+\item{method}{Currently only \sQuote{vf2} is supported, see
+\code{\link{isomorphic}} for details about it and extra arguments.}
+
+\item{...}{Passed to the individual methods.}
+}
+\value{
+Number of isomirphic mappings between the two graphs.
+}
+\description{
+Count the number of isomorphic mappings between two graphs
+}
+\examples{
+# colored graph isomorphism
+g1 <- make_ring(10)
+g2 <- make_ring(10)
+isomorphic(g1, g2)
+
+V(g1)$color <- rep(1:2, length = vcount(g1))
+V(g2)$color <- rep(2:1, length = vcount(g2))
+# consider colors by default
+count_isomorphisms(g1, g2)
+# ignore colors
+count_isomorphisms(g1, g2, vertex.color1 = NULL,
+    vertex.color2 = NULL)
+}
+\references{
+LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+ for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+ on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/count_motifs.Rd b/man/count_motifs.Rd
new file mode 100644
index 0000000..90f8bf4
--- /dev/null
+++ b/man/count_motifs.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/motifs.R
+\name{count_motifs}
+\alias{count_motifs}
+\alias{graph.motifs.no}
+\title{Graph motifs}
+\usage{
+count_motifs(graph, size = 3, cut.prob = rep(0, size))
+}
+\arguments{
+\item{graph}{Graph object, the input graph.}
+
+\item{size}{The size of the motif, currently 3 and 4 are supported only.}
+
+\item{cut.prob}{Numeric vector giving the probabilities that the search
+graph is cut at a certain level. Its length should be the same as the size
+of the motif (the \code{size} argument). By default no cuts are made.}
+}
+\value{
+\code{count_motifs} returns  a numeric scalar.
+}
+\description{
+Graph motifs are small connected subgraphs with a well-defined
+structure.  These functions search a graph for various motifs.
+}
+\details{
+\code{count_motifs} calculates the total number of motifs of a given
+size in graph.
+}
+\examples{
+g <- barabasi.game(100)
+motifs(g, 3)
+count_motifs(g, 3)
+sample_motifs(g, 3)
+}
+\seealso{
+\code{\link{isomorphism_class}}
+
+Other graph motifs: \code{\link{graph.motifs.est}},
+  \code{\link{sample_motifs}}; \code{\link{graph.motifs}},
+  \code{\link{motifs}}
+}
+
diff --git a/man/count_subgraph_isomorphisms.Rd b/man/count_subgraph_isomorphisms.Rd
new file mode 100644
index 0000000..f81f1f3
--- /dev/null
+++ b/man/count_subgraph_isomorphisms.Rd
@@ -0,0 +1,100 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{count_subgraph_isomorphisms}
+\alias{count_subgraph_isomorphisms}
+\alias{graph.count.subisomorphisms.vf2}
+\title{Count the isomorphic mappings between a graph and the subgraphs of
+another graph}
+\usage{
+count_subgraph_isomorphisms(pattern, target, method = c("lad", "vf2"), ...)
+}
+\arguments{
+\item{pattern}{The smaller graph, it might be directed or
+undirected. Undirected graphs are treated as directed graphs with
+mutual edges.}
+
+\item{target}{The bigger graph, it might be directed or
+undirected. Undirected graphs are treated as directed graphs with
+mutual edges.}
+
+\item{method}{The method to use. Possible values:
+\sQuote{lad}, \sQuote{vf2}. See their details below.}
+
+\item{...}{Additional arguments, passed to the various methods.}
+}
+\value{
+Logical scalar, \code{TRUE} if the \code{pattern} is
+  isomorphic to a (possibly induced) subgraph of \code{target}.
+}
+\description{
+Count the isomorphic mappings between a graph and the subgraphs of
+another graph
+}
+\section{\sQuote{lad} method}{
+
+This is the LAD algorithm by Solnon, see the reference below. It has
+the following extra arguments:
+\describe{
+  \item{domains}{If not \code{NULL}, then it specifies matching
+    restrictions. It must be a list of \code{target} vertex sets, given
+    as numeric vertex ids or symbolic vertex names. The length of the
+    list must be \code{vcount(pattern)} and for each vertex in
+    \code{pattern} it gives the allowed matching vertices in
+    \code{target}. Defaults to \code{NULL}.}
+  \item{induced}{Logical scalar, whether to search for an induced
+    subgraph. It is \code{FALSE} by default.}
+  \item{time.limit}{The processor time limit for the computation, in
+    seconds. It defaults to \code{Inf}, which means no limit.}
+}
+}
+
+\section{\sQuote{vf2} method}{
+
+This method uses the VF2 algorithm by Cordella, Foggia et al., see
+references below. It supports vertex and edge colors and have the
+following extra arguments:
+\describe{
+  \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+    colors of the vertices for colored graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} vertex attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments. See also examples
+    below.}
+  \item{edge.color1, edge.color2}{Optional integer vectors giving the
+    colors of the edges for edge-colored (sub)graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} edge attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments.}
+}
+}
+\references{
+LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+ for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+ on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+
+ C. Solnon: AllDifferent-based Filtering for Subgraph Isomorphism,
+ \emph{Artificial Intelligence} 174(12-13):850--864, 2010.
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/count_triangles.Rd b/man/count_triangles.Rd
new file mode 100644
index 0000000..7cc1fd1
--- /dev/null
+++ b/man/count_triangles.Rd
@@ -0,0 +1,63 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/triangles.R
+\name{count_triangles}
+\alias{adjacent.triangles}
+\alias{count_triangles}
+\alias{triangles}
+\title{Find triangles in graphs}
+\usage{
+count_triangles(graph, vids = V(graph))
+}
+\arguments{
+\item{graph}{The input graph. It might be directed, but edge directions are
+ignored.}
+
+\item{vids}{The vertices to query, all of them by default. This might be a
+vector of numeric ids, or a character vector of symbolic vertex names for
+named graphs.}
+}
+\value{
+For \code{triangles} a numeric vector of vertex ids, the first three
+vertices belong to the first triangle found, etc.
+
+For \code{triangles} a numeric vector, the number of triangles for all
+vertices queried.
+}
+\description{
+Count how many triangles a vertex is part of, in a graph, or just list the
+triangles of a graph.
+}
+\details{
+\code{triangles} lists all triangles of a graph. For efficiency, all
+triangles are returned in a single vector. The first three vertices belong
+to the first triangle, etc.
+
+\code{count_triangles} counts how many triangles a vertex is part of.
+}
+\examples{
+## A small graph
+kite <- make_graph("Krackhardt_Kite")
+plot(kite)
+matrix(triangles(kite), nrow=3)
+
+## Adjacenct triangles
+atri <- count_triangles(kite)
+plot(kite, vertex.label=atri)
+
+## Always true
+sum(count_triangles(kite)) == length(triangles(kite))
+
+## Should match, local transitivity is the
+## number of adjacent triangles divided by the number
+## of adjacency triples
+transitivity(kite, type="local")
+count_triangles(kite) / (degree(kite) * (degree(kite)-1)/2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{transitivity}}
+}
+\keyword{graphs}
+
diff --git a/man/curve_multiple.Rd b/man/curve_multiple.Rd
new file mode 100644
index 0000000..0340a01
--- /dev/null
+++ b/man/curve_multiple.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/plot.common.R
+\name{curve_multiple}
+\alias{autocurve.edges}
+\alias{curve_multiple}
+\title{Optimal edge curvature when plotting graphs}
+\usage{
+curve_multiple(graph, start = 0.5)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{start}{The curvature at the two extreme edges. All edges will have a
+curvature between \code{-start} and \code{start}, spaced equally.}
+}
+\value{
+A numeric vector, its length is the number of edges in the graph.
+}
+\description{
+If graphs have multiple edges, then drawing them as straight lines does not
+show them when plotting the graphs; they will be on top of each other. One
+solution is to bend the edges, with diffenent curvature, so that all of them
+are visible.
+}
+\details{
+\code{curve_multiple} calculates the optimal \code{edge.curved} vector for
+plotting a graph with multiple edges, so that all edges are visible.
+}
+\examples{
+g <- graph( c(0,1,1,0,1,2,1,3,1,3,1,3,
+              2,3,2,3,2,3,2,3,0,1)+1 )
+
+curve_multiple(g)
+
+\dontrun{
+set.seed(42)
+plot(g)
+}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{igraph.plotting}} for all plotting parameters,
+\code{\link{plot.igraph}}, \code{\link{tkplot}} and \code{\link{rglplot}}
+for plotting functions.
+}
+\keyword{graphs}
+
diff --git a/man/decompose.Rd b/man/decompose.Rd
new file mode 100644
index 0000000..615f816
--- /dev/null
+++ b/man/decompose.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/components.R
+\name{decompose}
+\alias{decompose}
+\alias{decompose.graph}
+\title{Decompose a graph into components}
+\usage{
+decompose(graph, mode = c("weak", "strong"), max.comps = NA,
+  min.vertices = 0)
+}
+\arguments{
+\item{graph}{The original graph.}
+
+\item{mode}{Character constant giving the type of the components, wither
+\code{weak} for weakly connected components or \code{strong} for strongly
+connected components.}
+
+\item{max.comps}{The maximum number of components to return. The first
+\code{max.comps} components will be returned (which hold at least
+\code{min.vertices} vertices, see the next parameter), the others will be
+ignored. Supply \code{NA} here if you don't want to limit the number of
+components.}
+
+\item{min.vertices}{The minimum number of vertices a component should
+contain in order to place it in the result list. Eg. supply 2 here to ignore
+isolate vertices.}
+}
+\value{
+A list of graph objects.
+}
+\description{
+Creates a separate graph for each component of a graph.
+}
+\examples{
+# the diameter of each component in a random graph
+g <- sample_gnp(1000, 1/1000)
+components <- decompose(g, min.vertices=2)
+sapply(components, diameter)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{is_connected}} to decide whether a graph is connected,
+\code{\link{components}} to calculate the connected components of a graph.
+}
+\keyword{graphs}
+
diff --git a/man/decompose.graph.Rd b/man/decompose.graph.Rd
deleted file mode 100644
index 15d59fb..0000000
--- a/man/decompose.graph.Rd
+++ /dev/null
@@ -1,40 +0,0 @@
-\name{decompose.graph}
-\alias{decompose.graph}
-\concept{Graph decomposition}
-\concept{Graph component}
-\title{Decompose a graph into components}
-\description{Creates a separate graph for each component of a graph.}
-\usage{
-decompose.graph(graph, mode = c("weak", "strong"),
-       max.comps = NA, min.vertices = 0) 
-}
-\arguments{
-  \item{graph}{The original graph.}
-  \item{mode}{Character constant giving the type of the components,
-    wither \code{weak} for weakly connected components or \code{strong}
-    for strongly connected components.}
-  \item{max.comps}{The maximum number of components to return. The first
-    \code{max.comps} components will be returned (which hold at least
-    \code{min.vertices} vertices, see the next parameter), the others
-    will be ignored. Supply \code{NA} here if you don't want to limit
-    the number of components.}
-  \item{min.vertices}{The minimum number of vertices a component should
-    contain in order to place it in the result list. Eg. supply 2
-    here to ignore isolate vertices.}
-}
-% \details{}
-\value{
-  A list of graph objects.
-}
-%\references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{is.connected}} to decide whether a graph is
-  connected, \code{\link{clusters}} to calculate the connected
-  components of a graph.}
-\examples{
-# the diameter of each component in a random graph
-g <- erdos.renyi.game(1000, 1/1000)
-comps <- decompose.graph(g, min.vertices=2)
-sapply(comps, diameter)
-}
-\keyword{graphs}
diff --git a/man/degree.Rd b/man/degree.Rd
index db268d2..9a118a0 100644
--- a/man/degree.Rd
+++ b/man/degree.Rd
@@ -1,50 +1,57 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{degree}
 \alias{degree}
-\concept{Vertex degree}
-\concept{Degree distribution}
 \alias{degree.distribution}
+\alias{degree_distribution}
 \title{Degree and degree distribution of the vertices}
-\description{The degree of a vertex is its most basic structural
-  property, the number of its adjacent edges.}
 \usage{
-degree(graph, v=V(graph), mode = c("all", "out", "in", "total"),
-       loops = TRUE, normalized = FALSE) 
-degree.distribution(graph, cumulative = FALSE, \dots) 
+degree(graph, v = V(graph), mode = c("all", "out", "in", "total"),
+  loops = TRUE, normalized = FALSE)
+
+degree_distribution(graph, cumulative = FALSE, ...)
 }
 \arguments{
-  \item{graph}{The graph to analyze.}
-  \item{v}{The ids of vertices of which the degree will be calculated.}
-  \item{mode}{Character string, \dQuote{out} for out-degree, \dQuote{in} for
-    in-degree or \dQuote{total} for the sum of the two. For undirected
-    graphs this argument is ignored. \dQuote{all} is a synonym of
-    \dQuote{total}.}
-  \item{loops}{Logical; whether the loop edges are also counted.}
-  \item{normalized}{Logical scalar, whether to normalize the degree.
-    If \code{TRUE} then the result is divided by \eqn{n-1}, where
-    \eqn{n} is the number of vertices in the graph.}
-  \item{cumulative}{Logical; whether the cumulative degree distribution
-    is to be calculated.}
-  \item{\dots}{Additional arguments to pass to \code{degree},
-    eg. \code{mode} is useful but also \code{v} and \code{loops} make
-    sense.}
+\item{graph}{The graph to analyze.}
+
+\item{v}{The ids of vertices of which the degree will be calculated.}
+
+\item{mode}{Character string, \dQuote{out} for out-degree, \dQuote{in} for
+in-degree or \dQuote{total} for the sum of the two. For undirected graphs
+this argument is ignored. \dQuote{all} is a synonym of \dQuote{total}.}
+
+\item{loops}{Logical; whether the loop edges are also counted.}
+
+\item{normalized}{Logical scalar, whether to normalize the degree.  If
+\code{TRUE} then the result is divided by \eqn{n-1}, where \eqn{n} is the
+number of vertices in the graph.}
+
+\item{cumulative}{Logical; whether the cumulative degree distribution is to
+be calculated.}
+
+\item{\dots}{Additional arguments to pass to \code{degree}, eg. \code{mode}
+is useful but also \code{v} and \code{loops} make sense.}
 }
-% \details{}
 \value{
-  For \code{degree} a numeric vector of the same length as argument
-  \code{v}.
+For \code{degree} a numeric vector of the same length as argument
+\code{v}.
 
-  For \code{degree.distribution} a numeric vector of the same length as
-  the maximum degree plus one. The first element is the relative
-  frequency zero degree vertices, the second vertices with degree one, 
-  etc. 
+For \code{degree_distribution} a numeric vector of the same length as the
+maximum degree plus one. The first element is the relative frequency zero
+degree vertices, the second vertices with degree one, etc.
+}
+\description{
+The degree of a vertex is its most basic structural property, the number of
+its adjacent edges.
 }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 degree(g)
-g2 <- erdos.renyi.game(1000, 10/1000)
-degree.distribution(g2)
+g2 <- sample_gnp(1000, 10/1000)
+degree_distribution(g2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
 }
 \keyword{graphs}
+
diff --git a/man/degree.sequence.game.Rd b/man/degree.sequence.game.Rd
deleted file mode 100644
index 5e03a8f..0000000
--- a/man/degree.sequence.game.Rd
+++ /dev/null
@@ -1,86 +0,0 @@
-\name{degree.sequence.game}
-\alias{degree.sequence.game}
-\concept{Degree sequence}
-\concept{Configuration model}
-\title{Generate random graphs with a given degree sequence}
-\description{It is often useful to create a graph with given vertex
-  degrees. This is exactly what \code{degree.sequence.game} does.}
-\usage{
-degree.sequence.game(out.deg, in.deg = NULL,
-     method = c("simple", "vl", "simple.no.multiple"), \dots)
-}
-\arguments{
-  \item{out.deg}{Numeric vector, the sequence of degrees (for undirected
-  graphs) or out-degrees (for directed graphs). For undirected graphs
-  its sum should be even. For directed graphs its sum should be the same
-  as the sum of \code{in.deg}.}
-  \item{in.deg}{For directed graph, the in-degree sequence. By default
-    this is \code{NULL} and an undirected graph is created.}
-  \item{method}{Character, the method for generating the graph. Right
-    now the \dQuote{simple}, \dQuote{simple.no.multiple} and \dQuote{vl}
-    methods are implemented.}
-  \item{\dots}{Additional arguments, these are used as graph
-    attributes.}
-}
-\details{The \dQuote{simple} method connects the out-stubs of the
-  edges (undirected graphs) or the out-stubs and in-stubs
-  (directed graphs) together. This way loop edges and also multiple
-  edges may be generated. This method is not adequate if one needs to
-  generate simple graphs with a given degree sequence. The multiple and
-  loop edges can be deleted, but then the degree sequence is distorted
-  and there is nothing to ensure that the graphs are sampled uniformly.
-
-  The \dQuote{simple.no.multiple} method is similar to \dQuote{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
-  eventually succeed if the provided degree sequence is graphical,
-  but there is no upper bound on the number of iterations.
-  
-  The \dQuote{vl} method is a more sophisticated generator. The
-  algorithm and the implementation was done by Fabien Viger and Matthieu
-  Latapy. This generator always generates undirected, connected simple
-  graphs, it is an error to pass the \code{in.deg} argument to it.
-  The algorithm relies on first creating an initial (possibly
-  unconnected) simple undirected graph with the given degree sequence
-  (if this is possible at all). Then some rewiring is done to make the
-  graph connected. Finally a Monte-Carlo algorithm is used to randomize
-  the graph. The \dQuote{vl} samples from the undirected, connected
-  simple graphs unformly. See
-  \url{http://www-rp.lip6.fr/~latapy/FV/generation.html} for details.
-}
-\value{The new graph object.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{erdos.renyi.game}}, \code{\link{barabasi.game}},
-  \code{\link{simplify}} to get rid of the multiple and/or loops edges.}
-\examples{
-## The simple generator
-g <- degree.sequence.game(rep(2,100))
-degree(g)
-is.simple(g)   # sometimes TRUE, but can be FALSE
-g2 <- degree.sequence.game(1:10, 10:1)
-degree(g2, mode="out")
-degree(g2, mode="in")
-
-## The vl generator
-g3 <- degree.sequence.game(rep(2,100), method="vl")
-degree(g3)
-is.simple(g3)  # always TRUE
-
-## Exponential degree distribution
-## Note, that we correct the degree sequence if its sum is odd
-degs <- sample(1:100, 100, replace=TRUE, prob=exp(-0.5*(1:100)))
-if (sum(degs) \%\% 2 != 0) { degs[1] <- degs[1] + 1 }
-g4 <- degree.sequence.game(degs, method="vl")
-all(degree(g4) == degs)
-
-## Power-law degree distribution
-## Note, that we correct the degree sequence if its sum is odd
-degs <- sample(1:100, 100, replace=TRUE, prob=(1:100)^-2)
-if (sum(degs) \%\% 2 != 0) { degs[1] <- degs[1] + 1 }
-g5 <- degree.sequence.game(degs, method="vl")
-all(degree(g5) == degs)
-}
-\keyword{graphs}
diff --git a/man/delete_edge_attr.Rd b/man/delete_edge_attr.Rd
new file mode 100644
index 0000000..8f90f26
--- /dev/null
+++ b/man/delete_edge_attr.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{delete_edge_attr}
+\alias{delete_edge_attr}
+\alias{remove.edge.attribute}
+\title{Delete an edge attribute}
+\usage{
+delete_edge_attr(graph, name)
+}
+\arguments{
+\item{graph}{The graph}
+
+\item{name}{The name of the edge attribute to delete.}
+}
+\value{
+The graph, with the specified edge attribute removed.
+}
+\description{
+Delete an edge attribute
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_edge_attr("name", value = LETTERS[1:10])
+edge_attr_names(g)
+g2 <- delete_edge_attr(g, "name")
+edge_attr_names(g2)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/delete_edges.Rd b/man/delete_edges.Rd
new file mode 100644
index 0000000..740fcca
--- /dev/null
+++ b/man/delete_edges.Rd
@@ -0,0 +1,40 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{delete_edges}
+\alias{delete.edges}
+\alias{delete_edges}
+\title{Delete edges from a graph}
+\usage{
+delete_edges(graph, edges)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{edges}{The edges to remove, specified as an edge sequence.}
+}
+\value{
+The graph, with the edges removed.
+}
+\description{
+Delete edges from a graph
+}
+\examples{
+g <- make_ring(10) \%>\%
+  delete_edges(seq(1, 9, by = 2))
+g
+
+g <- make_ring(10) \%>\%
+  delete_edges("10|1")
+g
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{path}};
+  \code{\link{vertex}}, \code{\link{vertices}}
+}
+
diff --git a/man/delete_graph_attr.Rd b/man/delete_graph_attr.Rd
new file mode 100644
index 0000000..7300323
--- /dev/null
+++ b/man/delete_graph_attr.Rd
@@ -0,0 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{delete_graph_attr}
+\alias{delete_graph_attr}
+\alias{remove.graph.attribute}
+\title{Delete a graph attribute}
+\usage{
+delete_graph_attr(graph, name)
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{Name of the attribute to delete.}
+}
+\value{
+The graph, with the specified attribute removed.
+}
+\description{
+Delete a graph attribute
+}
+\examples{
+g <- make_ring(10)
+graph_attr_names(g)
+g2 <- delete_graph_attr(g, "name")
+graph_attr_names(g2)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/delete_vertex_attr.Rd b/man/delete_vertex_attr.Rd
new file mode 100644
index 0000000..7de8766
--- /dev/null
+++ b/man/delete_vertex_attr.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{delete_vertex_attr}
+\alias{delete_vertex_attr}
+\alias{remove.vertex.attribute}
+\title{Delete a vertex attribute}
+\usage{
+delete_vertex_attr(graph, name)
+}
+\arguments{
+\item{graph}{The graph}
+
+\item{name}{The name of the vertex attribute to delete.}
+}
+\value{
+The graph, with the specified vertex attribute removed.
+}
+\description{
+Delete a vertex attribute
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10])
+vertex_attr_names(g)
+g2 <- delete_vertex_attr(g, "name")
+vertex_attr_names(g2)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/delete_vertices.Rd b/man/delete_vertices.Rd
new file mode 100644
index 0000000..53fb0e3
--- /dev/null
+++ b/man/delete_vertices.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{delete_vertices}
+\alias{delete.vertices}
+\alias{delete_vertices}
+\title{Delete vertices from a graph}
+\usage{
+delete_vertices(graph, v)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{v}{The vertices to remove, a vertex sequence.}
+}
+\value{
+The graph, with the vertices removed.
+}
+\description{
+Delete vertices from a graph
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10])
+g
+V(g)
+
+g2 <- delete_vertices(g, c(1,5)) \%>\%
+  delete_vertices("B")
+g2
+V(g2)
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{edge}}, \code{\link{edges}};
+  \code{\link{path}}; \code{\link{vertex}},
+  \code{\link{vertices}}
+}
+
diff --git a/man/dendPlot.Rd b/man/dendPlot.Rd
deleted file mode 100644
index d4eb89e..0000000
--- a/man/dendPlot.Rd
+++ /dev/null
@@ -1,24 +0,0 @@
-\name{dendPlot}
-\alias{dendPlot}
-\concept{Dendrograms}
-\title{Plot dendrograms}
-\description{
-  This is generic function that can plot various objects as dendrograms.
-}
-% \usage
-% \arguments{}
-\details{
-  Currently the function is defined for \code{communities} (see
-  \code{\link{dendPlot.communities}}) and \code{igraphHRG}
-  (see \code{\link{dendPlot.igraphHRG}}) objects.
-}
-% \value{}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-karate <- graph.famous("Zachary")
-fc <- fastgreedy.community(karate)
-dendPlot(fc)
-}
-\keyword{graphs}
diff --git a/man/dendPlot.communities.Rd b/man/dendPlot.communities.Rd
deleted file mode 100644
index 43035c0..0000000
--- a/man/dendPlot.communities.Rd
+++ /dev/null
@@ -1,95 +0,0 @@
-\name{dendPlot.communities}
-\alias{dendPlot.communities}
-\concept{Dendrograms}
-\concept{Community structure}
-\title{Community structure dendrogram plots}
-\description{Plot a hierarchical community structure as a dendrogram.}
-\usage{
-\method{dendPlot}{communities}(x, mode = getIgraphOpt("dend.plot.type"),
-   \dots, use.modularity = FALSE)
-}
-\arguments{
-  \item{x}{An object containing the community structure of a graph. See
-    \code{\link{communities}} for details.}
-  \item{mode}{Which dendrogram plotting function to use. See details
-    below.}
-  \item{\dots}{Additional arguments to supply to the dendrogram plotting
-    function.}
- \item{use.modularity}{Logical scalar, whether to use the modularity
-   values to define the height of the branches.}
-}
-\details{
-  \code{dendPlot} supports three different plotting functions, selected
-  via the \code{mode} argument. By default the plotting function is
-  taken from the \code{dend.plot.type} igraph option, and it has for
-  possible values: \itemize{
-  \item \code{auto} Choose automatically between the plotting
-    functions. As \code{plot.phylo} is the most sophisticated, that is
-    choosen, whenever the \code{ape} package is available. Otherwise
-    \code{plot.hclust} is used.
-  \item \code{phylo} Use \code{plot.phylo} from the \code{ape}
-    package.
-  \item \code{hclust} Use \code{plot.hclust} from the \code{stats}
-    package.
-  \item \code{dendrogram} Use \code{plot.dendrogram} from the
-    \code{stats} package.
-  }
-
-  The different plotting functions take different sets of
-  arguments. When using \code{plot.phylo} (\code{mode="phylo"}), we have
-  the following syntax: \preformatted{
-    dendPlot(x, mode="phylo",
-         colbar = rainbow(11, start=0.7, end=0.1),
-	 edge.color = NULL, use.edge.length = FALSE, \dots)
-  } The extra arguments not documented above: \itemize{
-    \item \code{colbar} Color bar for the edges. 
-    \item \code{edge.color} Edge colors. If \code{NULL}, then the
-    \code{colbar} argument is used.
-    \item \code{use.edge.length} Passed to \code{plot.phylo}.
-    \item \code{dots} Attitional arguments to pass to
-    \code{plot.phylo}.
-  }
-
-  The syntax for \code{plot.hclust} (\code{mode="hclust"}): \preformatted{
-    dendPlot(x, mode="hclust", rect = 0, colbar = rainbow(rect),
-         hang = 0.01, ann = FALSE, main = "", sub = "", xlab = "",
-	 ylab = "", \dots)
-  } The extra arguments not documented above: \itemize{
-    \item \code{rect} A numeric scalar, the number of groups to mark on
-    the dendrogram. The dendrogram is cut into exactly \code{rect}
-    groups and they are marked via the \code{rect.hclust} command. Set
-    this to zero if you don't want to mark any groups.
-    \item \code{colbar} The colors of the rectanges that mark the
-    vertex groups via the \code{rect} argument.
-    \item \code{hang} Where to put the leaf nodes, this corresponds to the
-    \code{hang} argument of \code{plot.hclust}.
-    \item \code{ann} Whether to annotate the plot, the \code{ann} argument
-    of \code{plot.hclust}.
-    \item \code{main} The main title of the plot, the \code{main} argument
-    of \code{plot.hclust}.
-    \item \code{sub} The sub-title of the plot, the \code{sub} argument
-    of \code{plot.hclust}.
-    \item \code{xlab} The label on the horizontal axis, passed to
-    \code{plot.hclust}. 
-    \item \code{ylab} The label on the vertical axis, passed to
-    \code{plot.hclust}. 
-    \item \code{dots} Attitional arguments to pass to \code{plot.hclust}.
-  }
-
-  The syntax for \code{plot.dendrogram} (\code{mode="dendrogram"}): \preformatted{
-    dendPlot(x, \dots)
-  } The extra arguments are simply passed to \code{as.dendrogram}.  
-}
-\value{
-  Returns whatever the return value was from the plotting function,
-  \code{plot.phylo}, \code{plot.dendrogram} or \code{plot.hclust}.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-% \seealso{}
-\examples{
-karate <- graph.famous("Zachary")
-fc <- fastgreedy.community(karate)
-dendPlot(fc)
-}
-\keyword{graphs}
diff --git a/man/dendPlot.igraphHRG.Rd b/man/dendPlot.igraphHRG.Rd
deleted file mode 100644
index bd4e21b..0000000
--- a/man/dendPlot.igraphHRG.Rd
+++ /dev/null
@@ -1,94 +0,0 @@
-\name{dendPlot.igraphHRG}
-\alias{dendPlot.igraphHRG}
-\concept{Dendrograms}
-\concept{Hierarchical random graphs}
-\title{HRG dendrogram plot}
-\description{Plot a hierarchical random graph as a dendrogram.}
-\usage{
-\method{dendPlot}{igraphHRG}(x, mode = getIgraphOpt("dend.plot.type"),
-        \dots)
-}
-\arguments{
-  \item{x}{An \code{igraphHRG}, a hierarchical random graph,
-    as returned by the \code{\link{hrg.fit}} function.}
-  \item{mode}{Which dendrogram plotting function to use. See details
-    below.}
-  \item{\dots}{Additional arguments to supply to the dendrogram plotting
-    function.}
-}
-\details{
-  \code{dendPlot} supports three different plotting functions, selected
-  via the \code{mode} argument. By default the plotting function is
-  taken from the \code{dend.plot.type} igraph option, and it has for
-  possible values: \itemize{
-  \item \code{auto} Choose automatically between the plotting
-    functions. As \code{plot.phylo} is the most sophisticated, that is
-    choosen, whenever the \code{ape} package is available. Otherwise
-    \code{plot.hclust} is used.
-  \item \code{phylo} Use \code{plot.phylo} from the \code{ape}
-    package.
-  \item \code{hclust} Use \code{plot.hclust} from the \code{stats}
-    package.
-  \item \code{dendrogram} Use \code{plot.dendrogram} from the
-    \code{stats} package.
-  }
-
-  The different plotting functions take different sets of
-  arguments. When using \code{plot.phylo} (\code{mode="phylo"}), we have
-  the following syntax: \preformatted{
-    dendPlot(x, mode="phylo",
-         colbar = rainbow(11, start=0.7, end=0.1),
-	 edge.color = NULL, use.edge.length = FALSE, \dots)
-  } The extra arguments not documented above: \itemize{
-    \item \code{colbar} Color bar for the edges. 
-    \item \code{edge.color} Edge colors. If \code{NULL}, then the
-    \code{colbar} argument is used.
-    \item \code{use.edge.length} Passed to \code{plot.phylo}.
-    \item \code{dots} Attitional arguments to pass to
-    \code{plot.phylo}.
-  }
-
-  The syntax for \code{plot.hclust} (\code{mode="hclust"}): \preformatted{
-    dendPlot(x, mode="hclust", rect = 0, colbar = rainbow(rect),
-         hang = 0.01, ann = FALSE, main = "", sub = "", xlab = "",
-	 ylab = "", \dots)
-  } The extra arguments not documented above: \itemize{
-    \item \code{rect} A numeric scalar, the number of groups to mark on
-    the dendrogram. The dendrogram is cut into exactly \code{rect}
-    groups and they are marked via the \code{rect.hclust} command. Set
-    this to zero if you don't want to mark any groups.
-    \item \code{colbar} The colors of the rectanges that mark the
-    vertex groups via the \code{rect} argument.
-    \item \code{hang} Where to put the leaf nodes, this corresponds to the
-    \code{hang} argument of \code{plot.hclust}.
-    \item \code{ann} Whether to annotate the plot, the \code{ann} argument
-    of \code{plot.hclust}.
-    \item \code{main} The main title of the plot, the \code{main} argument
-    of \code{plot.hclust}.
-    \item \code{sub} The sub-title of the plot, the \code{sub} argument
-    of \code{plot.hclust}.
-    \item \code{xlab} The label on the horizontal axis, passed to
-    \code{plot.hclust}. 
-    \item \code{ylab} The label on the vertical axis, passed to
-    \code{plot.hclust}. 
-    \item \code{dots} Attitional arguments to pass to \code{plot.hclust}.
-  }
-
-  The syntax for \code{plot.dendrogram} (\code{mode="dendrogram"}): \preformatted{
-    dendPlot(x, \dots)
-  } The extra arguments are simply passed to \code{as.dendrogram}.
-  
-}
-\value{
-  Returns whatever the return value was from the plotting function,
-  \code{plot.phylo}, \code{plot.dendrogram} or \code{plot.hclust}.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g <- graph.full(5) + graph.full(5)
-hrg <- hrg.fit(g)
-dendPlot(hrg)
-}
-\keyword{graphs}
diff --git a/man/dfs.Rd b/man/dfs.Rd
new file mode 100644
index 0000000..69e8c54
--- /dev/null
+++ b/man/dfs.Rd
@@ -0,0 +1,109 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{dfs}
+\alias{dfs}
+\alias{graph.dfs}
+\title{Depth-first search}
+\usage{
+dfs(graph, root, neimode = c("out", "in", "all", "total"),
+  unreachable = TRUE, order = TRUE, order.out = FALSE, father = FALSE,
+  dist = FALSE, in.callback = NULL, out.callback = NULL, extra = NULL,
+  rho = parent.frame())
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{root}{The single root vertex to start the search from.}
+
+\item{neimode}{For directed graphs specifies the type of edges to follow.
+\sQuote{out} follows outgoing, \sQuote{in} incoming edges. \sQuote{all}
+ignores edge directions completely. \sQuote{total} is a synonym for
+\sQuote{all}. This argument is ignored for undirected graphs.}
+
+\item{unreachable}{Logical scalar, whether the search should visit the
+vertices that are unreachable from the given root vertex (or vertices). If
+\code{TRUE}, then additional searches are performed until all vertices are
+visited.}
+
+\item{order}{Logical scalar, whether to return the DFS ordering of the
+vertices.}
+
+\item{order.out}{Logical scalar, whether to return the ordering based on
+leaving the subtree of the vertex.}
+
+\item{father}{Logical scalar, whether to return the father of the vertices.}
+
+\item{dist}{Logical scalar, whether to return the distance from the root of
+the search tree.}
+
+\item{in.callback}{If not \code{NULL}, then it must be callback function.
+This is called whenever a vertex is visited. See details below.}
+
+\item{out.callback}{If not \code{NULL}, then it must be callback function.
+This is called whenever the subtree of a vertex is completed by the
+algorithm. See details below.}
+
+\item{extra}{Additional argument to supply to the callback function.}
+
+\item{rho}{The environment in which the callback function is evaluated.}
+}
+\value{
+A named list with the following entries: \item{root}{Numeric scalar.
+The root vertex that was used as the starting point of the search.}
+\item{neimode}{Character scalar. The \code{neimode} argument of the function
+call. Note that for undirected graphs this is always \sQuote{all},
+irrespectively of the supplied value.} \item{order}{Numeric vector. The
+vertex ids, in the order in which they were visited by the search.}
+\item{order.out}{Numeric vector, the vertex ids, in the order of the
+completion of their subtree.} \item{father}{Numeric vector. The father of
+each vertex, i.e. the vertex it was discovered from.} \item{dist}{Numeric
+vector, for each vertex its distance from the root of the search tree.}
+
+Note that \code{order}, \code{order.out}, \code{father}, and \code{dist}
+might be \code{NULL} if their corresponding argument is \code{FALSE}, i.e.
+if their calculation is not requested.
+}
+\description{
+Depth-first search is an algorithm to traverse a graph. It starts from a
+root vertex and tries to go quickly as far from as possible.
+}
+\details{
+The callback functions must have the following arguments: \describe{
+\item{graph}{The input graph is passed to the callback function here.}
+\item{data}{A named numeric vector, with the following entries:
+\sQuote{vid}, the vertex that was just visited and \sQuote{dist}, its
+distance from the root of the search tree.} \item{extra}{The extra
+argument.} } See examples below on how to use the callback functions.
+}
+\examples{
+## A graph with two separate trees
+dfs(make_tree(10) \%du\% make_tree(10), root=1, "out",
+          TRUE, TRUE, TRUE, TRUE)
+
+## How to use a callback
+f.in <- function(graph, data, extra) {
+  cat("in:", paste(collapse=", ", data), "\\n")
+  FALSE
+}
+f.out <- function(graph, data, extra) {
+  cat("out:", paste(collapse=", ", data), "\\n")
+  FALSE
+}
+tmp <- dfs(make_tree(10), root=1, "out",
+                 in.callback=f.in, out.callback=f.out)
+
+## Terminate after the first component, using a callback
+f.out <- function(graph, data, extra) {
+ data['vid'] == 1
+}
+tmp <- dfs(make_tree(10) \%du\% make_tree(10), root=1,
+                 out.callback=f.out)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{bfs}} for breadth-first search.
+}
+\keyword{graphs}
+
diff --git a/man/diameter.Rd b/man/diameter.Rd
index 0acb1ce..7fe56cf 100644
--- a/man/diameter.Rd
+++ b/man/diameter.Rd
@@ -1,59 +1,72 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{diameter}
 \alias{diameter}
-\alias{get.diameter}
 \alias{farthest.nodes}
-\concept{Diameter}
+\alias{farthest_vertices}
+\alias{get.diameter}
+\alias{get_diameter}
 \title{Diameter of a graph}
-\description{The diameter of a graph is the length of the longest
-  geodesic.}
 \usage{
 diameter(graph, directed = TRUE, unconnected = TRUE, weights = NULL)
-get.diameter (graph, directed = TRUE, unconnected = TRUE, weights = NULL) 
-farthest.nodes (graph, directed = TRUE, unconnected = TRUE, weights = NULL) 
 }
 \arguments{
-  \item{graph}{The graph to analyze.}
-  \item{directed}{Logical, whether directed or undirected paths are to
-    be considered. This is ignored for undirected graphs.}
-  \item{unconnected}{Logical, what to do if the graph is unconnected. If
-    FALSE, the function will return a number that is one larger the
-    largest possible diameter, which is always the number of
-    vertices. If TRUE, the diameters of the connected components will be
-    calculated and the largest one will be returned.}
-  \item{weights}{Optional positive weight vector for calculating
-    weighted distances. If the graph has a \code{weight} edge
-    attribute, then this is used by default.}
-}
-\details{The diameter is calculated by using a breadth-first search like
-  method.
+\item{graph}{The graph to analyze.}
+
+\item{directed}{Logical, whether directed or undirected paths are to be
+considered. This is ignored for undirected graphs.}
 
-  \code{get.diameter} returns a path with the actual diameter. If there
-  are many shortest paths of the length of the diameter, then it returns
-  the first one found.
+\item{unconnected}{Logical, what to do if the graph is unconnected. If
+FALSE, the function will return a number that is one larger the largest
+possible diameter, which is always the number of vertices. If TRUE, the
+diameters of the connected components will be calculated and the largest one
+will be returned.}
 
-  \code{farthest.points} returns two vertex ids, the vertices which are
-  connected by the diameter path.
+\item{weights}{Optional positive weight vector for calculating weighted
+distances. If the graph has a \code{weight} edge attribute, then this is
+used by default.}
 }
-\value{A numeric constant for \code{diameter}, a numeric vector for
-  \code{get.diameter} and a numeric vector of length two for
-  \code{farthest.nodes}.
+\value{
+A numeric constant for \code{diameter}, a numeric vector for
+\code{get_diameter}. \code{farthest_vertices} returns a list with two
+entries: \itemize{
+  \item \code{vertices} The two vertices that are the farthest.
+  \item \code{distnace} Their distance.
+}
+}
+\description{
+The diameter of a graph is the length of the longest geodesic.
+}
+\details{
+The diameter is calculated by using a breadth-first search like method.
+
+\code{get_diameter} returns a path with the actual diameter. If there are
+many shortest paths of the length of the diameter, then it returns the first
+one found.
+
+\code{farthest_vertices} returns two vertex ids, the vertices which are
+connected by the diameter path.
 }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{shortest.paths}}}
 \examples{
-g <- graph.ring(10)
-g2 <- delete.edges(g, c(1,2,1,10))
+g <- make_ring(10)
+g2 <- delete_edges(g, c(1,2,1,10))
 diameter(g2, unconnected=TRUE)
 diameter(g2, unconnected=FALSE)
 
 ## Weighted diameter
 set.seed(1)
-g <- graph.ring(10)
+g <- make_ring(10)
 E(g)$weight <- sample(seq_len(ecount(g)))
 diameter(g)
-get.diameter(g)
+get_diameter(g)
 diameter(g, weights=NA)
-get.diameter(g, weights=NA)
+get_diameter(g, weights=NA)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{distances}}
 }
 \keyword{graphs}
+
diff --git a/man/difference.Rd b/man/difference.Rd
new file mode 100644
index 0000000..e410df6
--- /dev/null
+++ b/man/difference.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{difference}
+\alias{difference}
+\title{Difference of two sets}
+\usage{
+difference(...)
+}
+\arguments{
+\item{...}{Arguments, their number and interpretation depends on
+the function that implements \code{difference}.}
+}
+\value{
+Depends on the function that implements this method.
+}
+\description{
+This is an S3 generic function. See \code{methods("difference")}
+for the actual implementations for various S3 classes. Initially
+it is implemented for igraph graphs (difference of edges in two graphs),
+and igraph vertex and edge sequences. See
+\code{\link{difference.igraph}}, and
+\code{\link{difference.igraph.vs}}.
+}
+
diff --git a/man/difference.igraph.Rd b/man/difference.igraph.Rd
new file mode 100644
index 0000000..1c63530
--- /dev/null
+++ b/man/difference.igraph.Rd
@@ -0,0 +1,64 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{difference.igraph}
+\alias{\%m\%}
+\alias{difference.igraph}
+\alias{graph.difference}
+\title{Difference of graphs}
+\usage{
+\method{difference}{igraph}(big, small, byname = "auto", ...)
+}
+\arguments{
+\item{big}{The left hand side argument of the minus operator. A directed or
+undirected graph.}
+
+\item{small}{The right hand side argument of the minus operator. A directed
+ot undirected graph.}
+
+\item{byname}{A logical scalar, or the character scalar \code{auto}. Whether
+to perform the operation based on symbolic vertex names. If it is
+\code{auto}, that means \code{TRUE} if both graphs are named and
+\code{FALSE} otherwise. A warning is generated if \code{auto} and one graph,
+but not both graphs are named.}
+
+\item{...}{Ignored, included for S3 compatibility.}
+}
+\value{
+A new graph object.
+}
+\description{
+The difference of two graphs are created.
+}
+\details{
+\code{difference} creates the difference of two graphs. Only edges
+present in the first graph but not in the second will be be included in the
+new graph. The corresponding operator is \%m\%.
+
+If the \code{byname} argument is \code{TRUE} (or \code{auto} and the graphs
+are all named), then the operation is performed based on symbolic vertex
+names. Otherwise numeric vertex ids are used.
+
+\code{difference} keeps all attributes (graph, vertex and edge) of the
+first graph.
+
+Note that \code{big} and \code{small} must both be directed or both be
+undirected, otherwise an error message is given.
+}
+\examples{
+## Create a wheel graph
+wheel <- union(make_ring(10),
+                     make_star(11, center=11, mode="undirected"))
+V(wheel)$name <- letters[seq_len(vcount(wheel))]
+
+## Subtract a star graph from it
+sstar <- make_star(6, center=6, mode="undirected")
+V(sstar)$name <- letters[c(1,3,5,7,9,11)]
+G <- wheel \%m\% sstar
+str(G)
+plot(G, layout=layout_nicely(wheel))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/difference.igraph.es.Rd b/man/difference.igraph.es.Rd
new file mode 100644
index 0000000..f985506
--- /dev/null
+++ b/man/difference.igraph.es.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{difference.igraph.es}
+\alias{difference.igraph.es}
+\title{Difference of edge sequences}
+\usage{
+\method{difference}{igraph.es}(big, small, ...)
+}
+\arguments{
+\item{big}{The \sQuote{big} edge sequence.}
+
+\item{small}{The \sQuote{small} edge sequence.}
+
+\item{...}{Ignored, included for S3 signature compatibility.}
+}
+\value{
+An edge sequence that contains only edges that are part of
+\code{big}, but not part of \code{small}.
+}
+\description{
+Difference of edge sequences
+}
+\details{
+They must belong to the same graph. Note that this function has
+\sQuote{set} semantics and the multiplicity of edges is lost in the
+result.
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+difference(V(g), V(g)[6:10])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/difference.igraph.vs.Rd b/man/difference.igraph.vs.Rd
new file mode 100644
index 0000000..a2eb22d
--- /dev/null
+++ b/man/difference.igraph.vs.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{difference.igraph.vs}
+\alias{difference.igraph.vs}
+\title{Difference of vertex sequences}
+\usage{
+\method{difference}{igraph.vs}(big, small, ...)
+}
+\arguments{
+\item{big}{The \sQuote{big} vertex sequence.}
+
+\item{small}{The \sQuote{small} vertex sequence.}
+
+\item{...}{Ignored, included for S3 signature compatibility.}
+}
+\value{
+A vertex sequence that contains only vertices that are part of
+\code{big}, but not part of \code{small}.
+}
+\description{
+Difference of vertex sequences
+}
+\details{
+They must belong to the same graph. Note that this function has
+\sQuote{set} semantics and the multiplicity of vertices is lost in the
+result.
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+difference(V(g), V(g)[6:10])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/dim_select.Rd b/man/dim_select.Rd
new file mode 100644
index 0000000..3cd5c8f
--- /dev/null
+++ b/man/dim_select.Rd
@@ -0,0 +1,72 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/embedding.R
+\name{dim_select}
+\alias{dim_select}
+\title{Dimensionality selection for singular values using profile likelihood.}
+\usage{
+dim_select(sv)
+}
+\arguments{
+\item{sv}{A numeric vector, the ordered singular values.}
+}
+\value{
+A numeric scalar, the estimate of \eqn{d}.
+}
+\description{
+Select the number of significant singular values, by finding the
+\sQuote{elbow} of the scree plot, in a principled way.
+}
+\details{
+The input of the function is a numeric vector which contains the measure of
+\sQuote{importance} for each dimension.
+
+For spectral embedding, these are the singular values of the adjacency
+matrix. The singular values are assumed to be generated from a Gaussian
+mixture distribution with two components that have different means and same
+variance. The dimensionality \eqn{d} is chosen to maximize the likelihood
+when the \eqn{d} largest singular values are assigned to one component of
+the mixture and the rest of the singular values assigned to the other
+component.
+
+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 to know their border. See
+examples below.
+}
+\examples{
+# Generate the two groups of singular values with
+# Gaussian mixture of two components that have different means
+sing.vals  <- c( rnorm (10, mean=1, sd=1), rnorm(10, mean=3, sd=1) )
+dim.chosen <- dim_select(sing.vals)
+dim.chosen
+
+# Sample random vectors with multivariate normal distribution
+# and normalize to unit length
+lpvs <- matrix(rnorm(200), 10, 20)
+lpvs <- apply(lpvs, 2, function(x) { (abs(x) / sqrt(sum(x^2))) })
+RDP.graph  <- sample_dot_product(lpvs)
+dim_select( embed_adjacency_matrix(RDP.graph, 10)$D )
+
+# Sample random vectors with the Dirichlet distribution
+lpvs.dir    <- sample_dirichlet(n=20, rep(1, 10))
+RDP.graph.2 <- sample_dot_product(lpvs.dir)
+dim_select( embed_adjacency_matrix(RDP.graph.2, 10)$D )
+
+# Sample random vectors from hypersphere with radius 1.
+lpvs.sph    <- sample_sphere_surface(dim=10, n=20, radius=1)
+RDP.graph.3 <- sample_dot_product(lpvs.sph)
+dim_select( embed_adjacency_matrix(RDP.graph.3, 10)$D )
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+M. Zhu, and A. Ghodsi (2006). Automatic dimensionality selection
+from the scree plot via the use of profile likelihood. \emph{Computational
+Statistics and Data Analysis}, Vol. 51, 918--930.
+}
+\seealso{
+\code{\link{embed_adjacency_matrix}}
+}
+\keyword{graphs}
+
diff --git a/man/disjoint_union.Rd b/man/disjoint_union.Rd
new file mode 100644
index 0000000..2ec5ee1
--- /dev/null
+++ b/man/disjoint_union.Rd
@@ -0,0 +1,57 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{disjoint_union}
+\alias{\%du\%}
+\alias{disjoint_union}
+\alias{graph.disjoint.union}
+\title{Disjoint union of graphs}
+\usage{
+disjoint_union(...)
+
+x \%du\% y
+}
+\arguments{
+\item{x,y}{Graph objects.}
+
+\item{\dots}{Graph objects or lists of graph objects.}
+}
+\value{
+A new graph object.
+}
+\description{
+The union of two or more graphs are created. The graphs are assumed to have
+disjoint vertex sets.
+}
+\details{
+\code{disjoint_union} creates a union of two or more disjoint graphs.
+Thus first the vertices in the second, third, etc. graphs are relabeled to
+have completely disjoint graphs. Then a simple union is created. This
+function can also be used via the \%du\% operator.
+
+\code{graph.disjont.union} handles graph, vertex and edge attributes.  In
+particular, it merges vertex and edge attributes using the basic \code{c()}
+function. For graphs that lack some vertex/edge attribute, the corresponding
+values in the new graph are set to \code{NA}. Graph attributes are simply
+copied to the result. If this would result a name clash, then they are
+renamed by adding suffixes: _1, _2, etc.
+
+Note that if both graphs have vertex names (ie. a \code{name} vertex
+attribute), then the concatenated vertex names might be non-unique in the
+result. A warning is given if this happens.
+
+An error is generated if some input graphs are directed and others are
+undirected.
+}
+\examples{
+## A star and a ring
+g1 <- make_star(10, mode="undirected")
+V(g1)$name <- letters[1:10]
+g2 <- make_ring(10)
+V(g2)$name <- letters[11:20]
+str(g1 \%du\% g2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/distances.Rd b/man/distances.Rd
new file mode 100644
index 0000000..07259fc
--- /dev/null
+++ b/man/distances.Rd
@@ -0,0 +1,207 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/paths.R, R/structural.properties.R
+\name{distance_table}
+\alias{all_shortest_paths}
+\alias{average.path.length}
+\alias{distance_table}
+\alias{distances}
+\alias{get.all.shortest.paths}
+\alias{get.shortest.paths}
+\alias{mean_distance}
+\alias{path.length.hist}
+\alias{shortest.paths}
+\alias{shortest_paths}
+\title{Shortest (directed or undirected) paths between vertices}
+\usage{
+distance_table(graph, directed = TRUE)
+
+mean_distance(graph, directed = TRUE, unconnected = TRUE)
+
+distances(graph, v = V(graph), to = V(graph), mode = c("all", "out",
+  "in"), weights = NULL, algorithm = c("automatic", "unweighted",
+  "dijkstra", "bellman-ford", "johnson"))
+
+shortest_paths(graph, from, to = V(graph), mode = c("out", "all", "in"),
+  weights = NULL, output = c("vpath", "epath", "both"),
+  predecessors = FALSE, inbound.edges = FALSE)
+
+all_shortest_paths(graph, from, to = V(graph), mode = c("out", "all", "in"),
+  weights = NULL)
+}
+\arguments{
+\item{graph}{The graph to work on.}
+
+\item{directed}{Whether to consider directed paths in directed graphs,
+this argument is ignored for undirected graphs.}
+
+\item{unconnected}{What to do if the graph is unconnected (not
+strongly connected if directed paths are considered). If TRUE only
+the lengths of the existing paths are considered and averaged; if
+FALSE the length of the missing paths are counted having length
+\code{vcount(graph)}, one longer than the longest possible geodesic
+in the network.}
+
+\item{v}{Numeric vector, the vertices from which the shortest paths will be
+calculated.}
+
+\item{to}{Numeric vector, the vertices to which the shortest paths will be
+calculated. By default it includes all vertices. Note that for
+\code{distances} every vertex must be included here at most once. (This
+is not required for \code{shortest_paths}.}
+
+\item{mode}{Character constant, gives whether the shortest paths to or from
+the given vertices should be calculated for directed graphs. If \code{out}
+then the shortest paths \emph{from} the vertex, if \code{in} then \emph{to}
+it will be considered. If \code{all}, the default, then the corresponding
+undirected graph will be used, ie. not directed paths are searched. This
+argument is ignored for undirected graphs.}
+
+\item{weights}{Possibly a numeric vector giving edge weights. If this is
+\code{NULL} and the graph has a \code{weight} edge attribute, then the
+attribute is used. If this is \code{NA} then no weights are used (even if
+the graph has a \code{weight} attribute).}
+
+\item{algorithm}{Which algorithm to use for the calculation. By default
+igraph tries to select the fastest suitable algorithm. If there are no
+weights, then an unweighted breadth-first search is used, otherwise if all
+weights are positive, then Dijkstra's algorithm is used. If there are
+negative weights and we do the calculation for more than 100 sources, then
+Johnson's algorithm is used. Otherwise the Bellman-Ford algorithm is used.
+You can override igraph's choice by explicitly giving this parameter. Note
+that the igraph C core might still override your choice in obvious cases,
+i.e. if there are no edge weights, then the unweighted algorithm will be
+used, regardless of this argument.}
+
+\item{from}{Numeric constant, the vertex from or to the shortest paths will
+be calculated. Note that right now this is not a vector of vertex ids, but
+only a single vertex.}
+
+\item{output}{Character scalar, defines how to report the shortest paths.
+\dQuote{vpath} means that the vertices along the paths are reported, this
+form was used prior to igraph version 0.6. \dQuote{epath} means that the
+edges along the paths are reported. \dQuote{both} means that both forms are
+returned, in a named list with components \dQuote{vpath} and \dQuote{epath}.}
+
+\item{predecessors}{Logical scalar, whether to return the predecessor vertex
+for each vertex. The predecessor of vertex \code{i} in the tree is the
+vertex from which vertex \code{i} was reached. The predecessor of the start
+vertex (in the \code{from} argument) is itself by definition. If the
+predecessor is zero, it means that the given vertex was not reached from the
+source during the search. Note that the search terminates if all the
+vertices in \code{to} are reached.}
+
+\item{inbound.edges}{Logical scalar, whether to return the inbound edge for
+each vertex. The inbound edge of vertex \code{i} in the tree is the edge via
+which vertex \code{i} was reached. The start vertex and vertices that were
+not reached during the search will have zero in the corresponding entry of
+the vector. Note that the search terminates if all the vertices in \code{to}
+are reached.}
+}
+\value{
+For \code{distances} a numeric matrix with \code{length(to)}
+columns and \code{length(v)} rows. The shortest path length from a vertex to
+itself is always zero. For unreachable vertices \code{Inf} is included.
+
+For \code{shortest_paths} a named list with four entries is returned:
+\item{vpath}{This itself is a list, of length \code{length(to)}; list
+element \code{i} contains the vertex ids on the path from vertex \code{from}
+to vertex \code{to[i]} (or the other way for directed graphs depending on
+the \code{mode} argument). The vector also contains \code{from} and \code{i}
+as the first and last elements. If \code{from} is the same as \code{i} then
+it is only included once. If there is no path between two vertices then a
+numeric vector of length zero is returned as the list element. If this
+output is not requested in the \code{output} argument, then it will be
+\code{NULL}.} \item{epath}{This is a list similar to \code{vpath}, but the
+vectors of the list contain the edge ids along the shortest paths, instead
+of the vertex ids. This entry is set to \code{NULL} if it is not requested
+in the \code{output} argument.} \item{predecessors}{Numeric vector, the
+predecessor of each vertex in the \code{to} argument, or \code{NULL} if it
+was not requested.} \item{inbound_edges}{Numeric vector, the inbound edge
+for each vertex, or \code{NULL}, if it was not requested.}
+
+For \code{all_shortest_paths} a list is returned, each list element
+contains a shortest path from \code{from} to a vertex in \code{to}. The
+shortest paths to the same vertex are collected into consecutive elements of
+the list.
+
+For \code{mean_distance} a single number is returned.
+
+\code{distance_table} returns a named list with two entries: \code{res} is
+a numeric vector, the histogram of distances, \code{unconnected} is a
+numeric scalar, the number of pairs for which the first vertex is not
+reachable from the second. The sum of the two entries is always \eqn{n(n-1)}
+for directed graphs and \eqn{n(n-1)/2} for undirected graphs.
+}
+\description{
+\code{distances} calculates the length of all the shortest paths from
+or to the vertices in the network. \code{shortest_paths} calculates one
+shortest path (the path itself, and not just its length) from or to the
+given vertex.
+}
+\details{
+The shortest path, or geodesic between two pair of vertices is a path with
+the minimal number of vertices. The functions documented in this manual page
+all calculate shortest paths between vertex pairs.
+
+\code{distances} calculates the lengths of pairwise shortest paths from
+a set of vertices (\code{from}) to another set of vertices (\code{to}). It
+uses different algorithms, depending on the \code{argorithm} argument and
+the \code{weight} edge attribute of the graph. The implemented algorithms
+are breadth-first search (\sQuote{\code{unweighted}}), this only works for
+unweighted graphs; the Dijkstra algorithm (\sQuote{\code{dijkstra}}), this
+works for graphs with non-negative edge weights; the Bellman-Ford algorithm
+(\sQuote{\code{bellman-ford}}), and Johnson's algorithm
+(\sQuote{\code{"johnson"}}). The latter two algorithms work with arbitrary
+edge weights, but (naturally) only for graphs that don't have a negative
+cycle.
+
+igraph can choose automatically between algorithms, and chooses the most
+efficient one that is appropriate for the supplied weights (if any). For
+automatic algorithm selection, supply \sQuote{\code{automatic}} as the
+\code{algorithm} argument. (This is also the default.)
+
+\code{shortest_paths} calculates a single shortest path (i.e. the path
+itself, not just its length) between the source vertex given in \code{from},
+to the target vertices given in \code{to}. \code{shortest_paths} uses
+breadth-first search for unweighted graphs and Dijkstra's algorithm for
+weighted graphs. The latter only works if the edge weights are non-negative.
+
+\code{all_shortest_paths} calculates \emph{all} shortest paths between
+pairs of vertices. More precisely, between the \code{from} vertex to the
+vertices given in \code{to}. It uses a breadth-first search for unweighted
+graphs and Dijkstra's algorithm for weighted ones. The latter only supports
+non-negative edge weights.
+
+\code{mean_distance} calculates the average path length in a graph, by
+calculating the shortest paths between all pairs of vertices (both ways for
+directed graphs). This function does not consider edge weights currently and
+uses a breadth-first search.
+
+\code{distance_table} calculates a histogram, by calculating the shortest
+path length between each pair of vertices. For directed graphs both
+directions are considered, so every pair of vertices appears twice in the
+histogram.
+}
+\examples{
+g <- make_ring(10)
+distances(g)
+shortest_paths(g, 5)
+all_shortest_paths(g, 1, 6:8)
+mean_distance(g)
+## Weighted shortest paths
+el <- matrix(nc=3, byrow=TRUE,
+             c(1,2,0, 1,3,2, 1,4,1, 2,3,0, 2,5,5, 2,6,2, 3,2,1, 3,4,1,
+               3,7,1, 4,3,0, 4,7,2, 5,6,2, 5,8,8, 6,3,2, 6,7,1, 6,9,1,
+               6,10,3, 8,6,1, 8,9,1, 9,10,4) )
+g2 <- add_edges(make_empty_graph(10), t(el[,1:2]), weight=el[,3])
+distances(g2, mode="out")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+West, D.B. (1996). \emph{Introduction to Graph Theory.} Upper
+Saddle River, N.J.: Prentice Hall.
+}
+\keyword{graphs}
+
diff --git a/man/diverging_pal.Rd b/man/diverging_pal.Rd
new file mode 100644
index 0000000..4417d41
--- /dev/null
+++ b/man/diverging_pal.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/palette.R
+\name{diverging_pal}
+\alias{diverging_pal}
+\title{Diverging palette}
+\usage{
+diverging_pal(n)
+}
+\arguments{
+\item{n}{The number of colors in the palette. The maximum is eleven
+currently.}
+}
+\value{
+A character vector of RGB color codes.
+}
+\description{
+This is the \sQuote{PuOr} palette from \url{http://colorbrewer2.org}.
+It has at most eleven colors.
+}
+\details{
+This is similar to \code{\link{sequential_pal}}, but it also puts
+emphasis on the mid-range values, plus the the two extreme ends.
+Use this palette, if you have such a quantity to mark with vertex
+colors.
+}
+\examples{
+\dontrun{
+library(igraphdata)
+data(foodwebs)
+fw <- foodwebs[[1]] \%>\%
+  induced_subgraph(V(.)[ECO == 1]) \%>\%
+  add_layout_(with_fr()) \%>\%
+  set_vertex_attr("label", value = seq_len(gorder(.))) \%>\%
+  set_vertex_attr("size", value = 10) \%>\%
+  set_edge_attr("arrow.size", value = 0.3)
+
+V(fw)$color <- scales::dscale(V(fw)$Biomass \%>\% cut(10), diverging_pal)
+plot(fw)
+
+data(karate)
+karate <- karate \%>\%
+  add_layout_(with_kk()) \%>\%
+  set_vertex_attr("size", value = 10)
+
+V(karate)$color <- scales::dscale(degree(karate) \%>\% cut(5), diverging_pal)
+plot(karate)
+}
+}
+\seealso{
+Other palettes: \code{\link{categorical_pal}};
+  \code{\link{r_pal}}; \code{\link{sequential_pal}}
+}
+
diff --git a/man/diversity.Rd b/man/diversity.Rd
new file mode 100644
index 0000000..24d8ee9
--- /dev/null
+++ b/man/diversity.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{diversity}
+\alias{diversity}
+\alias{graph.diversity}
+\title{Graph diversity}
+\usage{
+diversity(graph, weights = NULL, vids = V(graph))
+}
+\arguments{
+\item{graph}{The input graph. Edge directions are ignored.}
+
+\item{weights}{\code{NULL}, or the vector of edge weights to use for the
+computation. If \code{NULL}, then the \sQuote{weight} attibute is used. Note
+that this measure is not defined for unweighted graphs.}
+
+\item{vids}{The vertex ids for which to calculate the measure.}
+}
+\value{
+A numeric vector, its length is the number of vertices.
+}
+\description{
+Calculates a measure of diversity for all vertices.
+}
+\details{
+The diversity of a vertex is defined as the (scaled) Shannon entropy of the
+weights of its incident edges:
+\deqn{D(i)=\frac{H(i)}{\log k_i}}{D(i)=H(i)/log(k[i])}
+and
+\deqn{H(i)=-\sum_{j=1}^{k_i} p_{ij}\log p_{ij},}{H(i) =
+  -sum(p[i,j] log(p[i,j]), j=1..k[i]),} where
+\deqn{p_{ij}=\frac{w_{ij}}{\sum_{l=1}^{k_i}}V_{il},}{p[i,j] = w[i,j] /
+sum(w[i,l], l=1..k[i]),} and \eqn{k_i}{k[i]} is the (total) degree of vertex
+\eqn{i}, \eqn{w_{ij}}{w[i,j]} is the weight of the edge(s) between vertices
+\eqn{i} and \eqn{j}.
+
+For vertices with degree less than two the function returns \code{NaN}.
+}
+\examples{
+g1 <- sample_gnp(20, 2/20)
+g2 <- sample_gnp(20, 2/20)
+g3 <- sample_gnp(20, 5/20)
+E(g1)$weight <- 1
+E(g2)$weight <- runif(ecount(g2))
+E(g3)$weight <- runif(ecount(g3))
+diversity(g1)
+diversity(g2)
+diversity(g3)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Nathan Eagle, Michael Macy and Rob Claxton: Network Diversity
+and Economic Development, \emph{Science} \bold{328}, 1029--1031, 2010.
+}
+\keyword{graphs}
+
diff --git a/man/dominator.tree.Rd b/man/dominator.tree.Rd
deleted file mode 100644
index 21ed1e5..0000000
--- a/man/dominator.tree.Rd
+++ /dev/null
@@ -1,75 +0,0 @@
-\name{dominator.tree}
-\alias{dominator.tree}
-\concept{Domintor tree}
-\title{Dominator tree}
-\description{Dominator tree of a directed graph.
-}
-\usage{
-dominator.tree (graph, root, mode = c("out", "in"))
-}
-\arguments{
-  \item{graph}{A directed graph. If it is not a flowgraph, and it
-    contains some vertices not reachable from the root vertex,
-    then these vertices will be collected and returned as part of the
-    result.}
-  \item{root}{The id of the root (or source) vertex, this will be the
-    root of the tree.}
-  \item{mode}{Constant, must be \sQuote{\code{in}} or
-    \sQuote{\code{out}}. If it is \sQuote{\code{in}}, then all
-    directions are considered as opposite to the original one in the
-    input graph.}
-}
-\details{
- A flowgraph is a directed graph with a distinguished start (or
- root) vertex \eqn{r}, such that for any vertex \eqn{v}, there is a path
- from \eqn{r} to \eqn{v}. A vertex \eqn{v} dominates another vertex
- \eqn{w} (not equal to \eqn{v}), if every path from \eqn{r} to \eqn{w}
- contains \eqn{v}. Vertex \eqn{v} is the immediate dominator or \eqn{w},
- \eqn{v=\textrm{idom}(w)}{v=idom(w)}, if \eqn{v} dominates \eqn{w} and
- every other dominator of \eqn{w} dominates \eqn{v}. The edges
- \eqn{{(\textrm{idom}(w), w)| w \ne r}}{{(idom(w),w)| w is not r}}
- form a directed tree, rooted at \eqn{r}, called the dominator tree of
- the graph. Vertex \eqn{v} dominates vertex \eqn{w} if and only if
- \eqn{v} is an ancestor of \eqn{w} in the dominator tree.
-
- This function implements the Lengauer-Tarjan algorithm
- to construct the dominator tree of a directed graph. For details see
- the reference below.
-}
-\value{
-  A list with components:
-  \item{dom}{
-    A numeric vector giving the immediate dominators for each
-    vertex. For vertices that are unreachable from the root, it contains
-    \code{NaN}. For the root vertex itself it contains minus one.
-  }
-  \item{domtree}{
-    A graph object, the dominator tree. Its vertex ids are the as the
-    vertex ids of the input graph. Isolate vertices are the ones that
-    are unreachable from the root.
-  }
-  \item{leftout}{
-    A numeric vector containing the vertex ids that are unreachable from
-    the root.
-  }
-}
-\references{
-  Thomas Lengauer, Robert Endre Tarjan: A fast algorithm
-  for finding dominators in a flowgraph, \emph{ACM Transactions on
-  Programming Languages and Systems (TOPLAS)} I/1, 121--141, 1979.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## The example from the paper
-g <- graph.formula(R-+A:B:C, A-+D, B-+A:D:E, C-+F:G, D-+L,
-                   E-+H, F-+I, G-+I:J, H-+E:K, I-+K, J-+I,
-                   K-+I:R, L-+H)
-dtree <- dominator.tree(g, root="R")
-layout <- layout.reingold.tilford(dtree$domtree, root="R")
-layout[,2] <- -layout[,2]
-if (interactive()) {
-  plot(dtree$domtree, layout=layout, vertex.label=V(dtree$domtree)$name)
-}
-}
-\keyword{graphs}
diff --git a/man/dominator_tree.Rd b/man/dominator_tree.Rd
new file mode 100644
index 0000000..5acd2ab
--- /dev/null
+++ b/man/dominator_tree.Rd
@@ -0,0 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{dominator_tree}
+\alias{dominator.tree}
+\alias{dominator_tree}
+\title{Dominator tree}
+\usage{
+dominator_tree(graph, root, mode = c("out", "in"))
+}
+\arguments{
+\item{graph}{A directed graph. If it is not a flowgraph, and it contains
+some vertices not reachable from the root vertex, then these vertices will
+be collected and returned as part of the result.}
+
+\item{root}{The id of the root (or source) vertex, this will be the root of
+the tree.}
+
+\item{mode}{Constant, must be \sQuote{\code{in}} or \sQuote{\code{out}}. If
+it is \sQuote{\code{in}}, then all directions are considered as opposite to
+the original one in the input graph.}
+}
+\value{
+A list with components: \item{dom}{ A numeric vector giving the
+immediate dominators for each vertex. For vertices that are unreachable from
+the root, it contains \code{NaN}. For the root vertex itself it contains
+minus one.  } \item{domtree}{ A graph object, the dominator tree. Its vertex
+ids are the as the vertex ids of the input graph. Isolate vertices are the
+ones that are unreachable from the root.  } \item{leftout}{ A numeric vector
+containing the vertex ids that are unreachable from the root.  }
+}
+\description{
+Dominator tree of a directed graph.
+}
+\details{
+A flowgraph is a directed graph with a distinguished start (or root) vertex
+\eqn{r}, such that for any vertex \eqn{v}, there is a path from \eqn{r} to
+\eqn{v}. A vertex \eqn{v} dominates another vertex \eqn{w} (not equal to
+\eqn{v}), if every path from \eqn{r} to \eqn{w} contains \eqn{v}. Vertex
+\eqn{v} is the immediate dominator or \eqn{w},
+\eqn{v=\textrm{idom}(w)}{v=idom(w)}, if \eqn{v} dominates \eqn{w} and every
+other dominator of \eqn{w} dominates \eqn{v}. The edges
+\eqn{{(\textrm{idom}(w), w)| w \ne r}}{{(idom(w),w)| w is not r}} form a
+directed tree, rooted at \eqn{r}, called the dominator tree of the graph.
+Vertex \eqn{v} dominates vertex \eqn{w} if and only if \eqn{v} is an
+ancestor of \eqn{w} in the dominator tree.
+
+This function implements the Lengauer-Tarjan algorithm to construct the
+dominator tree of a directed graph. For details see the reference below.
+}
+\examples{
+## The example from the paper
+g <- graph_from_literal(R-+A:B:C, A-+D, B-+A:D:E, C-+F:G, D-+L,
+               E-+H, F-+I, G-+I:J, H-+E:K, I-+K, J-+I,
+               K-+I:R, L-+H)
+dtree <- dominator_tree(g, root="R")
+layout <- layout_as_tree(dtree$domtree, root="R")
+layout[,2] <- -layout[,2]
+plot(dtree$domtree, layout=layout, vertex.label=V(dtree$domtree)$name)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Thomas Lengauer, Robert Endre Tarjan: A fast algorithm for
+finding dominators in a flowgraph, \emph{ACM Transactions on Programming
+Languages and Systems (TOPLAS)} I/1, 121--141, 1979.
+}
+\keyword{graphs}
+
diff --git a/man/dyad.census.Rd b/man/dyad.census.Rd
deleted file mode 100644
index d7d2950..0000000
--- a/man/dyad.census.Rd
+++ /dev/null
@@ -1,38 +0,0 @@
-\name{dyad.census}
-\alias{dyad.census}
-\concept{Dyad census}
-\title{Dyad census of a graph}
-\description{Classify dyads in a directed graphs. The relationship
-  between each pair of vertices is measured. It can be in three states:
-  mutual, asymmetric or non-existent.}
-\usage{
-dyad.census(graph)
-}
-\arguments{
-  \item{graph}{The input graph. A warning is given if it is not directed.}
-}
-%\details{}
-\value{A named numeric vector with three elements:
-  \item{mut}{The number of pairs with mutual connections.}
-  \item{asym}{The number of pairs with non-mutual connections.}
-  \item{null}{The number of pairs with no connection between them.}
-}
-\references{
-  Holland, P.W. and Leinhardt, S. A Method for Detecting
-  Structure in Sociometric Data. \emph{American Journal of Sociology}, 76,
-  492--513. 1970.
-
-  Wasserman, S., and Faust, K. \emph{Social Network Analysis: Methods
-  and Applications.} Cambridge: Cambridge University Press. 1994.
-}
-\author{
-  Gabor Csardi \email{csardi.gabor at gmail.com}
-}
-\seealso{
-  \code{\link{triad.census}} for the same classification, but with triples.
-}
-\examples{
-g <- ba.game(100)
-dyad.census(g)
-}
-\keyword{graphs}
diff --git a/man/dyad_census.Rd b/man/dyad_census.Rd
new file mode 100644
index 0000000..c470bf6
--- /dev/null
+++ b/man/dyad_census.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/motifs.R
+\name{dyad_census}
+\alias{dyad.census}
+\alias{dyad_census}
+\title{Dyad census of a graph}
+\usage{
+dyad_census(graph)
+}
+\arguments{
+\item{graph}{The input graph. A warning is given if it is not directed.}
+}
+\value{
+A named numeric vector with three elements: \item{mut}{The number of
+pairs with mutual connections.} \item{asym}{The number of pairs with
+non-mutual connections.} \item{null}{The number of pairs with no connection
+between them.}
+}
+\description{
+Classify dyads in a directed graphs. The relationship between each pair of
+vertices is measured. It can be in three states: mutual, asymmetric or
+non-existent.
+}
+\examples{
+g <- sample_pa(100)
+dyad_census(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Holland, P.W. and Leinhardt, S. A Method for Detecting Structure
+in Sociometric Data. \emph{American Journal of Sociology}, 76, 492--513.
+1970.
+
+Wasserman, S., and Faust, K. \emph{Social Network Analysis: Methods and
+Applications.} Cambridge: Cambridge University Press. 1994.
+}
+\seealso{
+\code{\link{triad_census}} for the same classification, but with
+triples.
+}
+\keyword{graphs}
+
diff --git a/man/each_edge.Rd b/man/each_edge.Rd
new file mode 100644
index 0000000..4f867c5
--- /dev/null
+++ b/man/each_edge.Rd
@@ -0,0 +1,41 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/rewire.R
+\name{each_edge}
+\alias{each_edge}
+\title{Rewires the endpoints of the edges of a graph to a random vertex}
+\usage{
+each_edge(prob, loops = FALSE, multiple = FALSE)
+}
+\arguments{
+\item{prob}{The rewiring probability, a real number between zero and one.}
+
+\item{loops}{Logical scalar, whether loop edges are allowed in the rewired
+graph.}
+
+\item{multiple}{Logical scalar, whether multiple edges are allowed int the
+  generated graph.}
+}
+\description{
+This function can be used together with \code{\link{rewire}}.
+This method rewires the endpoints of the edges with a constant probability
+uniformly randomly to a new vertex in a graph.
+}
+\details{
+Note that this method might create graphs with multiple and/or loop edges.
+}
+\examples{
+# Some random shortcuts shorten the distances on a lattice
+g <- make_lattice(length = 100, dim = 1, nei = 5)
+mean_distance(g)
+g <- rewire(g, each_edge(prob = 0.05))
+mean_distance(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other rewiring functions: \code{\link{keeping_degseq}};
+  \code{\link{rewire}}
+}
+\keyword{graphs}
+
diff --git a/man/eccentricity.Rd b/man/eccentricity.Rd
index 5c20ef1..f907529 100644
--- a/man/eccentricity.Rd
+++ b/man/eccentricity.Rd
@@ -1,50 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/paths.R
 \name{eccentricity}
 \alias{eccentricity}
-\alias{radius}
-\concept{Eccentricity}
-\concept{Radius}
-\title{Eccentricity and radius}
-\description{The eccentricity of a vertex is its shortest path distance
-  from the farthest other node in the graph. The smallest eccentricity
-  in a graph is called its radius}
+\title{Eccentricity of the vertices in a graph}
 \usage{
-eccentricity(graph, vids=V(graph), mode=c("all", "out", "in", "total"))
-radius(graph, mode=c("all", "out", "in", "total"))
+eccentricity(graph, vids = V(graph), mode = c("all", "out", "in", "total"))
 }
 \arguments{
-  \item{graph}{The input graph, it can be directed or undirected.}
-  \item{vids}{The vertices for which the eccentricity is calculated.}
-  \item{mode}{Character constant, gives whether the shortest paths to or
-    from the given vertices should be calculated for directed graphs. If
-    \code{out} then the shortest paths \emph{from} the vertex, if
-    \code{in} then \emph{to} it will be considered. If \code{all}, the
-    default, then the corresponding undirected graph will be used, edge
-    directions will be ignored. This argument is ignored for
-    undirected graphs.}
-}
-\details{
- The eccentricity of a vertex is calculated by measuring the shortest
- distance from (or to) the vertex, to (or from) all vertices in the
- graph, and taking the maximum.
+\item{graph}{The input graph, it can be directed or undirected.}
+
+\item{vids}{The vertices for which the eccentricity is calculated.}
 
- This implementation ignores vertex pairs that are in different
- components. Isolate vertices have eccentricity zero.  
+\item{mode}{Character constant, gives whether the shortest paths to or from
+the given vertices should be calculated for directed graphs. If \code{out}
+then the shortest paths \emph{from} the vertex, if \code{in} then \emph{to}
+it will be considered. If \code{all}, the default, then the corresponding
+undirected graph will be used, edge directions will be ignored. This
+argument is ignored for undirected graphs.}
 }
 \value{
-  \code{eccentricity} returns a numeric vector, containing the
-  eccentricity score of each given vertex.
-
-  \code{radius} returns a numeric scalar.
+\code{eccentricity} returns a numeric vector, containing the
+eccentricity score of each given vertex.
 }
-\references{
-  Harary, F. Graph Theory. Reading, MA: Addison-Wesley, p. 35, 1994.
+\description{
+The eccentricity of a vertex is its shortest path distance from the farthest
+other node in the graph.
+}
+\details{
+The eccentricity of a vertex is calculated by measuring the shortest
+distance from (or to) the vertex, to (or from) all vertices in the graph,
+and taking the maximum.
+
+This implementation ignores vertex pairs that are in different components.
+Isolate vertices have eccentricity zero.
 }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{shortest.paths}} for general shortest path
-  calculations.}
 \examples{
-g <- graph.star(10, mode="undirected")
+g <- make_star(10, mode="undirected")
 eccentricity(g)
-radius(g)
 }
-\keyword{graphs}
+\references{
+Harary, F. Graph Theory. Reading, MA: Addison-Wesley, p. 35,
+1994.
+}
+\seealso{
+\code{\link{radius}} for a related concept,
+  \code{\link{distances}} for general shortest path calculations.
+}
+
diff --git a/man/edge.Rd b/man/edge.Rd
new file mode 100644
index 0000000..59bd717
--- /dev/null
+++ b/man/edge.Rd
@@ -0,0 +1,63 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{edge}
+\alias{edge}
+\alias{edges}
+\title{Helper function for adding and deleting edges}
+\usage{
+edge(...)
+
+edges(...)
+}
+\arguments{
+\item{...}{See details below.}
+}
+\value{
+A special object that can be used with together with
+  igraph graphs and the plus and minus operators.
+}
+\description{
+This is a helper function that simplifies adding and deleting
+edges to/from graphs.
+}
+\details{
+\code{edges} is an alias for \code{edge}.
+
+When adding edges via \code{+}, all unnamed arguments of
+\code{edge} (or \code{edges}) are concatenated, and then passed to
+\code{\link{add_edges}}. They are interpreted as pairs of vertex ids,
+and an edge will added between each pair. Named arguments will be
+used as edge attributes for the new edges.
+
+When deleting edges via \code{-}, all arguments of \code{edge} (or
+\code{edges}) are concatenated via \code{c()} and passed to
+\code{\link{delete_edges}}.
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_edge_attr("color", value = "red")
+
+g <- g + edge(1, 5, color = "green") +
+  edge(2, 6, color = "blue") -
+  edge("8|9")
+
+E(g)[[]]
+
+g \%>\%
+  add_layout_(in_circle()) \%>\%
+  plot()
+
+g <- make_ring(10) + edges(1:10)
+plot(g)
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{path}};
+  \code{\link{vertex}}, \code{\link{vertices}}
+}
+
diff --git a/man/edge.connectivity.Rd b/man/edge.connectivity.Rd
deleted file mode 100644
index e84b073..0000000
--- a/man/edge.connectivity.Rd
+++ /dev/null
@@ -1,80 +0,0 @@
-\name{edge.connectivity}
-\alias{edge.connectivity}
-\alias{edge.disjoint.paths}
-\alias{graph.adhesion}
-\concept{Edge connectivity}
-\concept{Edge-disjoint paths}
-\concept{Graph adhesion}
-\title{Edge connectivity.}
-\description{The edge connectivity of a graph or two vertices, this is
-  recently also called group adhesion.}
-\usage{
-edge.connectivity(graph, source=NULL, target=NULL, checks=TRUE)
-edge.disjoint.paths(graph, source, target)
-graph.adhesion(graph, checks=TRUE)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{source}{The id of the source vertex, for
-    \code{edge.connectivity} it can be \code{NULL}, see details below.}
-  \item{target}{The id of the target vertex, for
-    \code{edge.connectivity} it can be \code{NULL}, see details below.}
-  \item{checks}{Logical constant. Whether to check that the graph is
-    connected and also the degree of the vertices. If the graph is
-    not (strongly) connected then the connectivity is obviously zero. Otherwise
-    if the minimum degree is one then the edge connectivity is also
-    one. It is a good idea to perform these checks, as they can be
-    done quickly compared to the connectivity calculation itself. 
-    They were suggested by Peter McMahan, thanks Peter.
-  }
-}
-\details{
-  The edge connectivity of a pair of vertices (\code{source} and
-  \code{target}) is the minimum number of edges needed to remove to
-  eliminate all (directed) paths from \code{source} to \code{target}.
-  \code{edge.connectivity} calculates this quantity if both the
-  \code{source} and \code{target} arguments are given (and not
-  \code{NULL}). 
-
-  The edge connectivity of a graph is the minimum of the edge
-  connectivity of every (ordered) pair of vertices in the graph.
-  \code{edge.connectivity} calculates this quantity if neither the
-  \code{source} nor the \code{target} arguments are given (ie. they are
-  both \code{NULL}).
-
-  A set of edge disjoint paths between two vertices is a set of paths
-  between them containing no common edges. The maximum number of edge
-  disjoint paths between two vertices is the same as their edge
-  connectivity.
-
-  The adhesion of a graph is the minimum number of edges needed to
-  remove to obtain a graph which is not strongly connected. This is the
-  same as the edge connectivity of the graph.
-
-  The three functions documented on this page calculate similar
-  properties, more precisely the most general is
-  \code{edge.connectivity}, the others are included only for having more
-  descriptive function names.
-}
-\value{
-  A scalar real value.
-}
-\references{Douglas R. White and Frank Harary: The cohesiveness of
-  blocks in social networks: node connectivity and conditional
-  density, TODO: citation}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.maxflow}}, \code{\link{vertex.connectivity}},
-  \code{\link{vertex.disjoint.paths}}, \code{\link{graph.cohesion}}}
-\examples{
-g <- barabasi.game(100, m=1)
-g2 <- barabasi.game(100, m=5)
-edge.connectivity(g, 100, 1)
-edge.connectivity(g2, 100, 1)
-edge.disjoint.paths(g2, 100, 1)
-
-g <- erdos.renyi.game(50, 5/50)
-g <- as.directed(g)
-g <- induced.subgraph(g, subcomponent(g, 1))
-graph.adhesion(g)
-}
-\keyword{graphs}
diff --git a/man/edge_attr-set.Rd b/man/edge_attr-set.Rd
new file mode 100644
index 0000000..1e4e28a
--- /dev/null
+++ b/man/edge_attr-set.Rd
@@ -0,0 +1,79 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{edge_attr<-}
+\alias{edge.attributes<-}
+\alias{edge_attr<-}
+\title{Set one or more edge attributes}
+\usage{
+edge_attr(graph, name, index = E(graph)) <- value
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{The name of the edge attribute to set. If missing,
+then \code{value} must be a named list, and its entries are
+set as edge attributes.}
+
+\item{index}{An optional edge sequence to set the attributes
+of a subset of edges.}
+
+\item{value}{The new value of the attribute(s) for all
+(or \code{index}) edges.}
+}
+\value{
+The graph, with the edge attribute(s) added or set.
+}
+\description{
+Set one or more edge attributes
+}
+\examples{
+g <- make_ring(10)
+edge_attr(g) <- list(name = LETTERS[1:10],
+                      color = rep("green", gsize(g)))
+edge_attr(g, "label") <- E(g)$name
+g
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes}}, \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/edge_attr.Rd b/man/edge_attr.Rd
new file mode 100644
index 0000000..3c2f7aa
--- /dev/null
+++ b/man/edge_attr.Rd
@@ -0,0 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{edge_attr}
+\alias{edge.attributes}
+\alias{edge_attr}
+\alias{get.edge.attribute}
+\title{Query edge attributes of a graph}
+\usage{
+edge_attr(graph, name, index = E(graph))
+}
+\arguments{
+\item{graph}{The graph}
+
+\item{name}{The name of the attribute to query. If missing, then
+all edge attributes are returned in a list.}
+
+\item{index}{An optional edge sequence, to query edge attributes
+for a subset of edges.}
+}
+\value{
+The value of the edge attribute, or the list of all
+  edge attributes if \code{name} is missing.
+}
+\description{
+Query edge attributes of a graph
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_edge_attr("weight", value = 1:10) \%>\%
+  set_edge_attr("color", value = "red")
+g
+plot(g, edge.width = E(g)$weight)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/edge_attr_names.Rd b/man/edge_attr_names.Rd
new file mode 100644
index 0000000..e688cf7
--- /dev/null
+++ b/man/edge_attr_names.Rd
@@ -0,0 +1,67 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{edge_attr_names}
+\alias{edge_attr_names}
+\alias{list.edge.attributes}
+\title{List names of edge attributes}
+\usage{
+edge_attr_names(graph)
+}
+\arguments{
+\item{graph}{The graph.}
+}
+\value{
+Character vector, the names of the edge attributes.
+}
+\description{
+List names of edge attributes
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_edge_attr("label", value = letters[1:10])
+edge_attr_names(g)
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/edge_connectivity.Rd b/man/edge_connectivity.Rd
new file mode 100644
index 0000000..5b86c5e
--- /dev/null
+++ b/man/edge_connectivity.Rd
@@ -0,0 +1,86 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{edge_connectivity}
+\alias{adhesion}
+\alias{edge.connectivity}
+\alias{edge.disjoint.paths}
+\alias{edge_connectivity}
+\alias{edge_disjoint_paths}
+\alias{graph.adhesion}
+\title{Edge connectivity.}
+\usage{
+edge_connectivity(graph, source = NULL, target = NULL, checks = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{source}{The id of the source vertex, for \code{edge_connectivity} it
+can be \code{NULL}, see details below.}
+
+\item{target}{The id of the target vertex, for \code{edge_connectivity} it
+can be \code{NULL}, see details below.}
+
+\item{checks}{Logical constant. Whether to check that the graph is connected
+and also the degree of the vertices. If the graph is not (strongly)
+connected then the connectivity is obviously zero. Otherwise if the minimum
+degree is one then the edge connectivity is also one. It is a good idea to
+perform these checks, as they can be done quickly compared to the
+connectivity calculation itself.  They were suggested by Peter McMahan,
+thanks Peter.}
+}
+\value{
+A scalar real value.
+}
+\description{
+The edge connectivity of a graph or two vertices, this is recently also
+called group adhesion.
+}
+\details{
+The edge connectivity of a pair of vertices (\code{source} and
+\code{target}) is the minimum number of edges needed to remove to eliminate
+all (directed) paths from \code{source} to \code{target}.
+\code{edge_connectivity} calculates this quantity if both the \code{source}
+and \code{target} arguments are given (and not \code{NULL}).
+
+The edge connectivity of a graph is the minimum of the edge connectivity of
+every (ordered) pair of vertices in the graph.  \code{edge_connectivity}
+calculates this quantity if neither the \code{source} nor the \code{target}
+arguments are given (ie. they are both \code{NULL}).
+
+A set of edge disjoint paths between two vertices is a set of paths between
+them containing no common edges. The maximum number of edge disjoint paths
+between two vertices is the same as their edge connectivity.
+
+The adhesion of a graph is the minimum number of edges needed to remove to
+obtain a graph which is not strongly connected. This is the same as the edge
+connectivity of the graph.
+
+The three functions documented on this page calculate similar properties,
+more precisely the most general is \code{edge_connectivity}, the others are
+included only for having more descriptive function names.
+}
+\examples{
+g <- barabasi.game(100, m=1)
+g2 <- barabasi.game(100, m=5)
+edge_connectivity(g, 100, 1)
+edge_connectivity(g2, 100, 1)
+edge_disjoint_paths(g2, 100, 1)
+
+g <- sample_gnp(50, 5/50)
+g <- as.directed(g)
+g <- induced_subgraph(g, subcomponent(g, 1))
+adhesion(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Douglas R. White and Frank Harary: The cohesiveness of blocks in
+social networks: node connectivity and conditional density, TODO: citation
+}
+\seealso{
+\code{\link{max_flow}}, \code{\link{vertex_connectivity}},
+\code{\link{vertex_disjoint_paths}}, \code{\link{cohesion}}
+}
+\keyword{graphs}
+
diff --git a/man/edge_density.Rd b/man/edge_density.Rd
new file mode 100644
index 0000000..42388bc
--- /dev/null
+++ b/man/edge_density.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{edge_density}
+\alias{edge_density}
+\alias{graph.density}
+\title{Graph density}
+\usage{
+edge_density(graph, loops = FALSE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{loops}{Logical constant, whether to allow loop edges in the graph. If
+this is TRUE then self loops are considered to be possible. If this is FALSE
+then we assume that the graph does not contain any loop edges and that loop
+edges are not meaningful.}
+}
+\value{
+A real constant. This function returns \code{NaN} (=0.0/0.0) for an
+empty graph with zero vertices.
+}
+\description{
+The density of a graph is the ratio of the number of edges and the number of
+possible edges.
+}
+\details{
+Note that this function may return strange results for graph with multiple
+edges, density is ill-defined for graphs with multiple edges.
+}
+\examples{
+g1 <- make_empty_graph(n=10)
+g2 <- make_full_graph(n=10)
+g3 <- sample_gnp(n=10, 0.4)
+
+# loop edges
+g <- graph( c(1,2, 2,2, 2,3) )
+edge_density(g, loops=FALSE)              # this is wrong!!!
+edge_density(g, loops=TRUE)               # this is right!!!
+edge_density(simplify(g), loops=FALSE)    # this is also right, but different
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Wasserman, S., and Faust, K.  (1994).  Social Network Analysis:
+Methods and Applications.  Cambridge: Cambridge University Press.
+}
+\seealso{
+\code{\link{vcount}}, \code{\link{ecount}}, \code{\link{simplify}}
+to get rid of the multiple and/or loop edges.
+}
+\keyword{graphs}
+
diff --git a/man/ego.Rd b/man/ego.Rd
new file mode 100644
index 0000000..2b02381
--- /dev/null
+++ b/man/ego.Rd
@@ -0,0 +1,92 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{ego}
+\alias{connect}
+\alias{connect.neighborhood}
+\alias{ego}
+\alias{ego_graph}
+\alias{ego_size}
+\alias{graph.neighborhood}
+\alias{make_ego_graph}
+\alias{neighborhood}
+\alias{neighborhood.size}
+\title{Neighborhood of graph vertices}
+\usage{
+ego(graph, order, nodes = V(graph), mode = c("all", "out", "in"),
+  mindist = 0)
+
+make_ego_graph(graph, order, nodes = V(graph), mode = c("all", "out", "in"),
+  mindist = 0)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{order}{Integer giving the order of the neighborhood.}
+
+\item{nodes}{The vertices for which the calculation is performed.}
+
+\item{mode}{Character constatnt, it specifies how to use the direction of
+the edges if a directed graph is analyzed. For \sQuote{out} only the
+outgoing edges are followed, so all vertices reachable from the source
+vertex in at most \code{order} steps are counted. For \sQuote{"in"} all
+vertices from which the source vertex is reachable in at most \code{order}
+steps are counted. \sQuote{"all"} ignores the direction of the edges. This
+argument is ignored for undirected graphs.}
+
+\item{mindist}{The minimum distance to include the vertex in the result.}
+}
+\value{
+\code{ego_size} returns with an integer vector.
+
+\code{ego} returns with a list of integer vectors.
+
+\code{make_ego_graph} returns with a list of graphs.
+
+\code{connect} returns with a new graph object.
+}
+\description{
+These functions find the vertices not farther than a given limit from
+another fixed vertex, these are called the neighborhood of the vertex.
+}
+\details{
+The neighborhood of a given order \code{o} of a vertex \code{v} includes all
+vertices which are closer to \code{v} than the order. Ie. order 0 is always
+\code{v} itself, order 1 is \code{v} plus its immediate neighbors, order 2
+is order 1 plus the immediate neighbors of the vertices in order 1, etc.
+
+\code{ego_size} calculates the size of the neighborhoods for the
+given vertices with the given order.
+
+\code{ego} calculates the neighborhoods of the given vertices with
+the given order parameter.
+
+\code{make_ego_graph} is creates (sub)graphs from all neighborhoods of
+the given vertices with the given order parameter. This function preserves
+the vertex, edge and graph attributes.
+
+\code{connect} creates a new graph by connecting each vertex to
+all other vertices in its neighborhood.
+}
+\examples{
+g <- make_ring(10)
+ego_size(g, 0, 1:3)
+ego_size(g, 1, 1:3)
+ego_size(g, 2, 1:3)
+ego(g, 0, 1:3)
+ego(g, 1, 1:3)
+ego(g, 2, 1:3)
+
+# attributes are preserved
+V(g)$name <- c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")
+make_ego_graph(g, 2, 1:3)
+
+# connecting to the neighborhood
+g <- make_ring(10)
+g <- connect(g, 2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}, the first version was
+done by Vincent Matossian
+}
+\keyword{graphs}
+
diff --git a/man/eigen_centrality.Rd b/man/eigen_centrality.Rd
new file mode 100644
index 0000000..0aeeee2
--- /dev/null
+++ b/man/eigen_centrality.Rd
@@ -0,0 +1,85 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{eigen_centrality}
+\alias{eigen_centrality}
+\alias{evcent}
+\title{Find Eigenvector Centrality Scores of Network Positions}
+\usage{
+eigen_centrality(graph, directed = FALSE, scale = TRUE, weights = NULL,
+  options = arpack_defaults)
+}
+\arguments{
+\item{graph}{Graph to be analyzed.}
+
+\item{directed}{Logical scalar, whether to consider direction of the edges
+in directed graphs. It is ignored for undirected graphs.}
+
+\item{scale}{Logical scalar, whether to scale the result to have a maximum
+score of one. If no scaling is used then the result vector has unit length
+in the Euclidean norm.}
+
+\item{weights}{A numerical vector or \code{NULL}. This argument can be used
+to give edge weights for calculating the weighted eigenvector centrality of
+vertices. If this is \code{NULL} and the graph has a \code{weight} edge
+attribute then that is used. If \code{weights} is a numerical vector then it
+used, even if the graph has a \code{weights} edge attribute. If this is
+\code{NA}, then no edge weights are used (even if the graph has a
+\code{weight} edge attribute. Note that if there are negative edge weights
+and the direction of the edges is considered, then the eigenvector might be
+complex. In this case only the real part is reported.}
+
+\item{options}{A named list, to override some ARPACK options. See
+\code{\link{arpack}} for details.}
+}
+\value{
+A named list with components: \item{vector}{A vector containing the
+centrality scores.} \item{value}{The eigenvalue corresponding to the
+calculated eigenvector, i.e. the centrality scores.} \item{options}{A named
+list, information about the underlying ARPACK computation. See
+\code{\link{arpack}} for the details.  }
+}
+\description{
+\code{eigen_centrality} takes a graph (\code{graph}) and returns the
+eigenvector centralities of positions \code{v} within it
+}
+\details{
+Eigenvector centrality scores correspond to the values of the first
+eigenvector of the graph adjacency matrix; these scores may, in turn, be
+interpreted as arising from a reciprocal process in which the centrality of
+each actor is proportional to the sum of the centralities of those actors to
+whom he or she is connected.  In general, vertices with high eigenvector
+centralities are those which are connected to many other vertices which are,
+in turn, connected to many others (and so on).  (The perceptive may realize
+that this implies that the largest values will be obtained by individuals in
+large cliques (or high-density substructures).  This is also intelligible
+from an algebraic point of view, with the first eigenvector being closely
+related to the best rank-1 approximation of the adjacency matrix (a
+relationship which is easy to see in the special case of a diagonalizable
+symmetric real matrix via the \eqn{SLS^-1}{$S \Lambda S^{-1}$}
+decomposition).)
+
+From igraph version 0.5 this function uses ARPACK for the underlying
+computation, see \code{\link{arpack}} for more about ARPACK in igraph.
+}
+\section{WARNING }{
+ \code{eigen_centrality} will not symmetrize your data
+before extracting eigenvectors; don't send this routine asymmetric matrices
+unless you really mean to do so.
+}
+\examples{
+#Generate some test data
+g <- make_ring(10, directed=FALSE)
+#Compute eigenvector centrality scores
+eigen_centrality(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com} and Carter T. Butts
+(\url{http://www.faculty.uci.edu/profile.cfm?faculty_id=5057}) for the
+manual page.
+}
+\references{
+Bonacich, P.  (1987).  Power and Centrality: A Family of
+Measures. \emph{American Journal of Sociology}, 92, 1170-1182.
+}
+\keyword{graphs}
+
diff --git a/man/embed_adjacency_matrix.Rd b/man/embed_adjacency_matrix.Rd
new file mode 100644
index 0000000..0a856c3
--- /dev/null
+++ b/man/embed_adjacency_matrix.Rd
@@ -0,0 +1,88 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/embedding.R
+\name{embed_adjacency_matrix}
+\alias{embed_adjacency_matrix}
+\title{Spectral Embedding of Adjacency Matrices}
+\usage{
+embed_adjacency_matrix(graph, no, weights = NULL, which = c("lm", "la",
+  "sa"), scaled = TRUE, cvec = graph.strength(graph, weights =
+  weights)/(vcount(graph) - 1), options = igraph.arpack.default)
+}
+\arguments{
+\item{graph}{The input graph, directed or undirected.}
+
+\item{no}{An integer scalar. This value is the embedding dimension of the
+spectral embedding. Should be smaller than the number of vertices. The
+largest \code{no}-dimensional non-zero singular values are used for the
+spectral embedding.}
+
+\item{weights}{Optional positive weight vector for calculating weighted
+closeness. If the graph has a \code{weight} edge attribute, then this is
+used by default.}
+
+\item{which}{Which eigenvalues (or singular values, for directed graphs) to
+use. \sQuote{lm} means the ones with the largest magnitude, \sQuote{la} is
+the ones (algebraic) largest, and \sQuote{sa} is the (algebraic) smallest
+eigenvalues. The default is \sQuote{lm}. Note that for directed graphs
+\sQuote{la} and \sQuote{lm} are the equivalent, because the singular values
+are used for the ordering.}
+
+\item{scaled}{Logical scalar, if \code{FALSE}, then \eqn{U} and \eqn{V} are
+returned instead of \eqn{X} and \eqn{Y}.}
+
+\item{cvec}{A numeric vector, its length is the number vertices in the
+graph. This vector is added to the diagonal of the adjacency matrix.}
+
+\item{options}{A named list containing the parameters for the SVD
+computation algorithm in ARPACK. By default, the list of values is assigned
+the values given by \code{\link{igraph.arpack.default}}.}
+}
+\value{
+A list containing with entries: \item{X}{Estimated latent positions,
+an \code{n} times \code{no} matrix, \code{n} is the number of vertices.}
+\item{Y}{\code{NULL} for undirected graphs, the second half of the latent
+positions for directed graphs, an \code{n} times \code{no} matrix, \code{n}
+is the number of vertices.} \item{D}{The eigenvalues (for undirected graphs)
+or the singular values (for directed graphs) calculated by the algorithm.}
+\item{options}{A named list, information about the underlying ARPACK
+computation. See \code{\link{arpack}} for the details.}
+}
+\description{
+Spectral decomposition of the adjacency matrices of graphs.
+}
+\details{
+This function computes a \code{no}-dimensional Euclidean representation of
+the graph based on its adjacency matrix, \eqn{A}. This representation is
+computed via the singular value decomposition of the adjacency matrix,
+\eqn{A=UDV^T}.In the case, where the graph is a random dot product graph
+generated using latent position vectors in \eqn{R^{no}} for each vertex, the
+embedding will provide an estimate of these latent vectors.
+
+For undirected graphs the latent positions are calculated as
+\eqn{X=U^{no}D^{1/2}}{U[no] sqrt(D[no])}, where \eqn{U^{no}}{U[no]} equals
+to the first \code{no} columns of \eqn{U}, and \eqn{D^{1/2}}{sqrt(D[no])} is
+a diagonal matrix containing the top \code{no} singular values on the
+diagonal.
+
+For directed graphs the embedding is defined as the pair
+\eqn{X=U^{no}D^{1/2}}{U[no] sqrt(D[no])} and \eqn{Y=V^{no}D^{1/2}}{V[no]
+sqrt(D[no])}. (For undirected graphs \eqn{U=V}, so it is enough to keep one
+of them.)
+}
+\examples{
+## A small graph
+lpvs <- matrix(rnorm(200), 20, 10)
+lpvs <- apply(lpvs, 2, function(x) { return (abs(x)/sqrt(sum(x^2))) })
+RDP <- sample_dot_product(lpvs)
+embed <- embed_adjacency_matrix(RDP, 5)
+}
+\references{
+Sussman, D.L., Tang, M., Fishkind, D.E., Priebe, C.E.  A
+Consistent Adjacency Spectral Embedding for Stochastic Blockmodel Graphs,
+\emph{Journal of the American Statistical Association}, Vol. 107(499), 2012
+}
+\seealso{
+\code{\link{sample_dot_product}}
+}
+\keyword{graphs}
+
diff --git a/man/embed_laplacian_matrix.Rd b/man/embed_laplacian_matrix.Rd
new file mode 100644
index 0000000..4809273
--- /dev/null
+++ b/man/embed_laplacian_matrix.Rd
@@ -0,0 +1,100 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/embedding.R
+\name{embed_laplacian_matrix}
+\alias{embed_laplacian_matrix}
+\title{Spectral Embedding of the Laplacian of a Graph}
+\usage{
+embed_laplacian_matrix(graph, no, weights = NULL, which = c("lm", "la",
+  "sa"), degmode = c("out", "in", "all", "total"), type = c("default",
+  "D-A", "DAD", "I-DAD", "OAP"), scaled = TRUE,
+  options = igraph.arpack.default)
+}
+\arguments{
+\item{graph}{The input graph, directed or undirected.}
+
+\item{no}{An integer scalar. This value is the embedding dimension of the
+spectral embedding. Should be smaller than the number of vertices. The
+largest \code{no}-dimensional non-zero singular values are used for the
+spectral embedding.}
+
+\item{weights}{Optional positive weight vector for calculating weighted
+closeness. If the graph has a \code{weight} edge attribute, then this is
+used by default.}
+
+\item{which}{Which eigenvalues (or singular values, for directed graphs) to
+use. \sQuote{lm} means the ones with the largest magnitude, \sQuote{la} is
+the ones (algebraic) largest, and \sQuote{sa} is the (algebraic) smallest
+eigenvalues. The default is \sQuote{lm}. Note that for directed graphs
+\sQuote{la} and \sQuote{lm} are the equivalent, because the singular values
+are used for the ordering.}
+
+\item{degmode}{TODO}
+
+\item{type}{The type of the Laplacian to use. Various definitions exist for
+the Laplacian of a graph, and one can choose between them with this
+argument.
+
+Possible values: \code{D-A} means \eqn{D-A} where \eqn{D} is the degree
+matrix and \eqn{A} is the adjacency matrix; \code{DAD} means
+\eqn{D^{1/2}}{D^1/2} times \eqn{A} times \eqn{D^{1/2}{D^1/2}},
+\eqn{D^{1/2}}{D^1/2} is the inverse of the square root of the degree matrix;
+\code{I-DAD} means \eqn{I-D^{1/2}}{I-D^1/2}, where \eqn{I} is the identity
+matrix.  \code{OAP} is \eqn{O^{1/2}AP^{1/2}}{O^1/2 A P^1/2}, where
+\eqn{O^{1/2}}{O^1/2} is the inverse of the square root of the out-degree
+matrix and \eqn{P^{1/2}}{P^1/2} is the same for the in-degree matrix.
+
+\code{OAP} is not defined for undireted graphs, and is the only defined type
+for directed graphs.
+
+The default (i.e. type \code{default}) is to use \code{D-A} for undirected
+graphs and \code{OAP} for directed graphs.}
+
+\item{scaled}{Logical scalar, if \code{FALSE}, then \eqn{U} and \eqn{V} are
+returned instead of \eqn{X} and \eqn{Y}.}
+
+\item{options}{A named list containing the parameters for the SVD
+computation algorithm in ARPACK. By default, the list of values is assigned
+the values given by \code{\link{igraph.arpack.default}}.}
+}
+\value{
+A list containing with entries: \item{X}{Estimated latent positions,
+an \code{n} times \code{no} matrix, \code{n} is the number of vertices.}
+\item{Y}{\code{NULL} for undirected graphs, the second half of the latent
+positions for directed graphs, an \code{n} times \code{no} matrix, \code{n}
+is the number of vertices.} \item{D}{The eigenvalues (for undirected graphs)
+or the singular values (for directed graphs) calculated by the algorithm.}
+\item{options}{A named list, information about the underlying ARPACK
+computation. See \code{\link{arpack}} for the details.}
+}
+\description{
+Spectral decomposition of Laplacian matrices of graphs.
+}
+\details{
+This function computes a \code{no}-dimensional Euclidean representation of
+the graph based on its Laplacian matrix, \eqn{L}. This representation is
+computed via the singular value decomposition of the Laplacian matrix.
+
+They are essentially doing the same as \code{\link{embed_adjacency_matrix}},
+but work on the Laplacian matrix, instead of the adjacency matrix.
+}
+\examples{
+## A small graph
+lpvs <- matrix(rnorm(200), 20, 10)
+lpvs <- apply(lpvs, 2, function(x) { return (abs(x)/sqrt(sum(x^2))) })
+RDP <- sample_dot_product(lpvs)
+embed <- embed_laplacian_matrix(RDP, 5)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Sussman, D.L., Tang, M., Fishkind, D.E., Priebe, C.E.  A
+Consistent Adjacency Spectral Embedding for Stochastic Blockmodel Graphs,
+\emph{Journal of the American Statistical Association}, Vol. 107(499), 2012
+}
+\seealso{
+\code{\link{embed_adjacency_matrix}},
+\code{\link{sample_dot_product}}
+}
+\keyword{graphs}
+
diff --git a/man/ends.Rd b/man/ends.Rd
new file mode 100644
index 0000000..3974127
--- /dev/null
+++ b/man/ends.Rd
@@ -0,0 +1,40 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{ends}
+\alias{ends}
+\alias{get.edge}
+\alias{get.edges}
+\title{Incident vertices of some graph edges}
+\usage{
+ends(graph, es, names = TRUE)
+}
+\arguments{
+\item{graph}{The input graph}
+
+\item{es}{The sequence of edges to query}
+
+\item{names}{Whether to return vertex names or
+numeric vertex ids. By default vertex names are used.}
+}
+\value{
+A two column matrix of vertex names or vertex ids.
+}
+\description{
+Incident vertices of some graph edges
+}
+\examples{
+g <- make_ring(5)
+ends(g, E(g))
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{get.edge.ids}}; \code{\link{gorder}},
+  \code{\link{vcount}}; \code{\link{head_of}};
+  \code{\link{incident_edges}}; \code{\link{incident}};
+  \code{\link{is.directed}}, \code{\link{is_directed}};
+  \code{\link{neighbors}}; \code{\link{tail_of}}
+}
+
diff --git a/man/erdos.renyi.game.Rd b/man/erdos.renyi.game.Rd
index f7e825b..5543c1a 100644
--- a/man/erdos.renyi.game.Rd
+++ b/man/erdos.renyi.game.Rd
@@ -1,46 +1,68 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
 \name{erdos.renyi.game}
 \alias{erdos.renyi.game}
 \alias{random.graph.game}
-\concept{Random graph model}
-\concept{Erdos-Renyi graph}
 \title{Generate random graphs according to the Erdos-Renyi model}
-\description{This model is very simple, every possible edge is created
-  with the same constant probability. }
 \usage{
-erdos.renyi.game(n, p.or.m, type=c("gnp", "gnm"),
-                 directed = FALSE, loops = FALSE, \dots)
+erdos.renyi.game(n, p.or.m, type = c("gnp", "gnm"), directed = FALSE,
+  loops = FALSE, ...)
 }
 \arguments{
-  \item{n}{The number of vertices in the graph.}
-  \item{p.or.m}{Either the probability for drawing an edge between two
-    arbitrary vertices (G(n,p) graph), or the number of edges in the
-    graph (for G(n,m) graphs).}
-  \item{type}{The type of the random graph to create, either \code{gnp}
-    (G(n,p) graph) or \code{gnm} (G(n,m) graph).}
-  \item{directed}{Logical, whether the graph will be directed, defaults
-    to FALSE.}
-  \item{loops}{Logical, whether to add loop edges, defaults to FALSE.}
-  \item{\dots}{Additional arguments, ignored.}
+\item{n}{The number of vertices in the graph.}
+
+\item{p.or.m}{Either the probability for drawing an edge between two
+arbitrary vertices (G(n,p) graph), or the number of edges in the graph (for
+G(n,m) graphs).}
+
+\item{type}{The type of the random graph to create, either \code{gnp}
+(G(n,p) graph) or \code{gnm} (G(n,m) graph).}
+
+\item{directed}{Logical, whether the graph will be directed, defaults to
+FALSE.}
+
+\item{loops}{Logical, whether to add loop edges, defaults to FALSE.}
+
+\item{\dots}{Additional arguments, ignored.}
+}
+\value{
+A graph object.
+}
+\description{
+This model is very simple, every possible edge is created with the same
+constant probability.
 }
 \details{
-  In G(n,p) graphs, the graph has \sQuote{n} vertices and for each edge
-  the probability that it is present in the graph is \sQuote{p}.
-
-  In G(n,m) graphs, the graph has \sQuote{n} vertices and \sQuote{m}
-  edges, and the \sQuote{m} edges are chosen uniformly randomly from the
-  set of all possible edges. This set includes loop edges as well if the
-  \code{loops} parameter is TRUE.
-  
-  \code{random.graph.game} is an alias to this function.
-}
-\value{A graph object.}
-\references{ Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
-  Mathematicae} 6, 290--297 (1959).
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{barabasi.game}}}
+In G(n,p) graphs, the graph has \sQuote{n} vertices and for each edge the
+probability that it is present in the graph is \sQuote{p}.
+
+In G(n,m) graphs, the graph has \sQuote{n} vertices and \sQuote{m} edges,
+and the \sQuote{m} edges are chosen uniformly randomly from the set of all
+possible edges. This set includes loop edges as well if the \code{loops}
+parameter is TRUE.
+
+\code{random.graph.game} is an alias to this function.
+}
+\section{Deprecated}{
+
+
+Since igraph version 0.8.0, both \code{erdos.renyi.game} and
+\code{random.graph.game} are deprecated, and \code{\link{sample_gnp}} and
+\code{\link{sample_gnm}} should be used instead.
+}
 \examples{
 g <- erdos.renyi.game(1000, 1/1000)
-degree.distribution(g)
+degree_distribution(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
+Mathematicae} 6, 290--297 (1959).
+}
+\seealso{
+\code{\link{sample_pa}}
 }
 \keyword{graphs}
+
diff --git a/man/evcent.Rd b/man/evcent.Rd
deleted file mode 100644
index 25b4f9c..0000000
--- a/man/evcent.Rd
+++ /dev/null
@@ -1,76 +0,0 @@
-\name{evcent}
-\alias{evcent}
-\concept{Eigenvector centrality}
-\title{Find Eigenvector Centrality Scores of Network Positions}
-\description{
-  \code{evcent} takes a graph (\code{graph}) and returns the
-  eigenvector centralities of positions \code{v} within it
-}
-\usage{
-evcent (graph, directed = FALSE, scale = TRUE, weights = NULL,
-     options = igraph.arpack.default) 
-}
-\arguments{
-  \item{graph}{Graph to be analyzed.}
-  \item{directed}{Logical scalar, whether to consider direction of the
-    edges in directed graphs. It is ignored for undirected graphs.}
-  \item{scale}{Logical scalar, whether to scale the result to have a
-    maximum score of one. If no scaling is used then the result vector
-    has unit length in the Euclidean norm.}
-  \item{weights}{A numerical vector or \code{NULL}. This argument can be
-    used to give edge weights for calculating the weighted eigenvector
-    centrality of vertices. If this is \code{NULL} and the graph has a
-    \code{weight} edge attribute then that is used. If \code{weights} is
-    a numerical vector then it used, even if the graph has a
-    \code{weights} edge attribute. If this is \code{NA}, then no edge
-    weights are used (even if the graph has a \code{weight} edge
-    attribute. Note that if there are negative edge weights and the
-    direction of the edges is considered, then the eigenvector might be
-    complex. In this case only the real part is reported.}
-  \item{options}{A named list, to override some ARPACK options. See
-    \code{\link{arpack}} for details.}
-}
-\details{
-Eigenvector centrality scores correspond to the values of the first
-eigenvector of the graph adjacency matrix; these scores may, in turn, be
-interpreted as arising from a reciprocal process in which the centrality
-of each actor is proportional to the sum of the centralities of those
-actors to whom he or she is connected.  In general, vertices with high
-eigenvector centralities are those which are connected to many other
-vertices which are, in turn, connected to many others (and so on).  (The
-perceptive may realize that this implies that the largest values will be
-obtained by individuals in large cliques (or high-density
-substructures).  This is also intelligible from an algebraic point of
-view, with the first eigenvector being closely related to the best
-rank-1 approximation of the adjacency matrix (a relationship which is
-easy to see in the special case of a diagonalizable symmetric real
-matrix via the \eqn{SLS^-1}{$S \Lambda S^{-1}$} decomposition).)
-
-From igraph version 0.5 this function uses ARPACK for the underlying
-computation, see \code{\link{arpack}} for more about ARPACK in igraph.
-}
-\value{
-  A named list with components:
-  \item{vector}{A vector containing the centrality scores.}
-  \item{value}{The eigenvalue corresponding to the calculated
-    eigenvector, i.e. the centrality scores.}
-  \item{options}{A named list, information about the underlying ARPACK
-    computation. See \code{\link{arpack}} for the details.
-  }
-}
-\references{ Bonacich, P.  (1987).  Power and Centrality: A Family of
-Measures. \emph{American Journal of Sociology}, 92, 1170-1182. }
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} and Carter T. Butts
-  (\url{http://www.faculty.uci.edu/profile.cfm?faculty_id=5057})
-  for the manual page.}
-\section{WARNING }{\code{evcent} will not symmetrize your data before
-extracting eigenvectors; don't send this routine asymmetric matrices
-unless you really mean to do so.}
-% \seealso{}
-\examples{
-#Generate some test data
-g <- graph.ring(10, directed=FALSE)
-#Compute eigenvector centrality scores
-evcent(g)
-}
-\keyword{graphs}
diff --git a/man/evolver.Rd b/man/evolver.Rd
deleted file mode 100644
index bdc51e8..0000000
--- a/man/evolver.Rd
+++ /dev/null
@@ -1,243 +0,0 @@
-\name{revolver}
-\alias{evolver}
-\alias{revolver}
-\alias{evolver.d}
-\alias{revolver.d}
-\alias{revolver.ad}
-\alias{revolver.ade}
-\alias{revolver.adi}
-\alias{revolver.air}
-\alias{revolver.ar}
-\alias{revolver.de}
-\alias{revolver.di}
-\alias{revolver.dl}
-\alias{revolver.e}
-\alias{revolver.el}
-\alias{revolver.il}
-\alias{revolver.ir}
-\alias{revolver.l}
-\alias{revolver.r}
-\alias{revolver.error.d}
-\alias{revolver.error.ad}
-\alias{revolver.error.ade}
-\alias{revolver.error.adi}
-\alias{revolver.error.air}
-\alias{revolver.error.ar}
-\alias{revolver.error.de}
-\alias{revolver.error.di}
-\alias{revolver.error.dl}
-\alias{revolver.error.e}
-\alias{revolver.error.el}
-\alias{revolver.error.il}
-\alias{revolver.error.ir}
-\alias{revolver.error.l}
-\alias{revolver.error.r}
-\alias{revolver.d.d}
-\alias{revolver.p.p}
-\alias{revolver.ml.AD.alpha.a.beta}
-\alias{revolver.ml.AD.dpareto}
-\alias{revolver.ml.AD.dpareto.eval}
-\alias{revolver.ml.ad}
-\alias{revolver.ml.ade}
-\alias{revolver.ml.ADE.alpha.a.beta}
-\alias{revolver.ml.ADE.dpareto}
-\alias{revolver.ml.ADE.dpareto.eval}
-\alias{revolver.ml.ADE.dpareto.evalf}
-\alias{revolver.ml.d}
-\alias{revolver.ml.D.alpha}
-\alias{revolver.ml.D.alpha.a}
-\alias{revolver.ml.de}
-\alias{revolver.ml.DE.alpha.a}
-\alias{revolver.ml.df}
-\alias{revolver.ml.f}
-\alias{revolver.ml.l}
-\alias{revolver.probs.ad}
-\alias{revolver.probs.ade}
-\alias{revolver.probs.ADE.dpareto}
-\alias{revolver.probs.d}
-\alias{revolver.probs.de}
-\title{Measuring the driving force in evolving networks}
-\description{These functions assume a simple evolving network model and
-  measure the functional form of a so-called \emph{attractiveness
-    function} governing the evolution of the network.
-}
-\usage{
-evolver.d (nodes, kernel, outseq = NULL, outdist = NULL, m = 1, 
-           directed = TRUE)
-
-revolver.d (graph, niter=5, sd=FALSE, norm=FALSE,
-           cites=FALSE, expected=FALSE, error=TRUE, debug=numeric())
-revolver.ad (graph, niter=5, agebins=max(vcount(graph)/7100, 10),
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE, error=TRUE,
-            debug=matrix(ncol=2, nrow=0))
-revolver.ade (graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-             sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-             error=TRUE, debug=matrix(ncol=2, nrow=0))
-revolver.e (graph, cats, niter=5, st=FALSE,
-           sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-           error=TRUE, debug=numeric())
-revolver.de (graph, cats, niter=5,
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-            error=TRUE, debug=numeric())
-revolver.l (graph, niter=5, agebins=max(vcount(graph)/7100, 10),
-           sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-           error=TRUE, debug=numeric())
-revolver.dl (graph, niter=5, agebins=max(vcount(graph)/7100, 10),
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-            error=TRUE, debug=numeric())
-revolver.el (graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-            error=TRUE, debug=numeric())
-revolver.r (graph, window, niter=5, sd=FALSE, norm=FALSE,
-           cites=FALSE, expected=FALSE, error=TRUE, debug=numeric())
-revolver.ar (graph, window, niter=5, agebins=max(vcount(graph)/7100, 10),
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE, error=TRUE,
-            debug=matrix(ncol=2, nrow=0))
-revolver.di (graph, cats, niter=5,
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-            error=TRUE, debug=numeric())
-revolver.adi (graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-             sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-             error=TRUE, debug=matrix(ncol=2, nrow=0))
-revolver.il (graph, cats, niter=5, agebins=max(vcount(graph)/7100, 10),
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-            error=TRUE, debug=numeric())
-revolver.ir (graph, cats, window, niter=5,
-            sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-            error=TRUE, debug=numeric())
-revolver.air (graph, cats, window,
-             niter=5, agebins=max(vcount(graph)/7100, 10),
-             sd=FALSE, norm=FALSE, cites=FALSE, expected=FALSE,
-             error=TRUE, debug=matrix(ncol=2, nrow=0))
-revolver.d.d (graph, vtime = V(graph)$time, etime = E(graph)$time, niter = 5, 
-             sd = FALSE, norm = FALSE, cites = FALSE, expected = FALSE, 
-             error = TRUE, debug = matrix(ncol = 2, nrow = 0))
-revolver.p.p (graph, events = get.graph.attribute(graph, "events"), 
-             vtime = V(graph)$time, etime = E(graph)$time, niter = 5, sd = FALSE, 
-             norm = FALSE, cites = FALSE, expected = FALSE, error = TRUE, 
-             debug = matrix(ncol = 2, nrow = 0)) 
-revolver.error.d (graph, kernel)
-revolver.error.ad (graph, kernel)
-revolver.error.ade (graph, kernel, cats)
-revolver.error.adi (graph, kernel, cats)
-revolver.error.air (graph, kernel, cats, window)
-revolver.error.ar (graph, kernel, window)
-revolver.error.de (graph, kernel, cats)
-revolver.error.di (graph, kernel, cats)
-revolver.error.dl (graph, kernel)
-revolver.error.e (graph, kernel, cats)
-revolver.error.el (graph, kernel, cats)
-revolver.error.il (graph, kernel, cats)
-revolver.error.ir (graph, kernel, cats, window)
-revolver.error.l (graph, kernel)
-revolver.error.r (graph, kernel, window)
-
-revolver.ml.ade (graph, niter, cats, agebins = 300, delta = 1e-10,
-    filter = NULL)
-revolver.ml.d (graph, niter, delta = 1e-10, filter = NULL)
-revolver.ml.de (graph, niter, cats, delta = 1e-10, filter = NULL)
-revolver.ml.df (graph, niter, delta = 1e-10)
-revolver.ml.f (graph, niter, delta = 1e-10)
-revolver.ml.l (graph, niter, agebins = 300, delta = 1e-10)
-
-revolver.ml.AD.alpha.a.beta (graph, alpha, a, beta, abstol = 1e-08,
-    reltol = 1e-08, maxit = 1000, agebins = 300, filter = NULL)
-revolver.ml.AD.dpareto (graph, alpha, a, paralpha, parbeta, parscale,
-    abstol = 1e-08, reltol = 1e-08, maxit = 1000, agebins = 300, filter
-    = NULL)
-revolver.ml.ADE.alpha.a.beta (graph, cats, alpha, a, beta, coeffs,
-    abstol = 1e-08, reltol = 1e-08, maxit = 1000, agebins = 300, filter
-    = NULL)
-revolver.ml.ADE.dpareto (graph, cats, alpha, a, paralpha, parbeta, parscale, 
-    coeffs, abstol = 1e-08, reltol = 1e-08, maxit = 1000, agebins = 300, 
-    filter = NULL)
-revolver.ml.D.alpha (graph, alpha, abstol = 1e-08, reltol = 1e-08, maxit
-    = 1000, filter = NULL)
-revolver.ml.D.alpha.a (graph, alpha, a, abstol = 1e-08, reltol = 1e-08,
-    maxit = 1000, filter = NULL)
-revolver.ml.DE.alpha.a (graph, cats, alpha, a, coeffs, abstol = 1e-08,
-    reltol = 1e-08, maxit = 1000, filter = NULL)
-
-revolver.ml.AD.dpareto.eval (graph, alpha, a, paralpha, parbeta,
-    parscale, agebins = 300, filter = NULL) 
-revolver.ml.ADE.dpareto.eval (graph, cats, alpha, a, paralpha, parbeta,
-    parscale, coeffs, agebins = 300, filter = NULL) 
-revolver.ml.ADE.dpareto.evalf (graph, cats, par, agebins, filter = NULL)
-
-revolver.probs.ad (graph, kernel, ntk = FALSE)
-revolver.probs.ade (graph, kernel, cats)
-revolver.probs.d (graph, kernel, ntk = FALSE)
-revolver.probs.de (graph, kernel, cats)
-revolver.probs.ADE.dpareto (graph, par, cats, gcats, agebins)
-}
-\arguments{
-  \item{nodes}{The number of vertices in the generated network.}
-  \item{kernel}{The kernel function, a vector, matrix or array,
-    depending on the number of model parameters.}
-  \item{outseq}{The out-degree sequence, or \code{NULL} if no out-degree
-    sequence is used.}
-  \item{outdist}{The out-degree distribution, or \code{NULL} if all
-    vertices have the same out-degree. This argument is ignored if the
-    \code{outseq} argument is not \code{NULL}.}
-  \item{m}{Numeric scalar, the out-degree of the verticec. It is ignored
-    if at least one of \code{outseq} and \code{outdist} is not
-    \code{NULL}.}
-  \item{directed}{Logical scalar, whether to create a directed graph.}
-  \item{graph}{The input graph.}
-  \item{niter}{The number of iterations to perform.}
-  \item{sd}{Logical scalar, whether to return the standard deviation of
-    the estimates.}
-  \item{norm}{Logical scalar, whether to return the normalizing factors.}
-  \item{cites}{Logical scalar, whether to return the number of citations
-    to the different vertex types.}
-  \item{expected}{Logical scalar, whether to return the expected number
-    of citations for the different vertex types.}
-  \item{error}{Logical scalar, whether to return the error of the fit.}
-  \item{debug}{Currently not used.}
-  \item{agebins}{The number of bins for vertex age.}
-  \item{cats}{The number of categories to use.}
-  \item{window}{The width of the time window to use, measured in number
-    of vertices.}
-  \item{vtime}{Numeric vector, the time steps when the vertices where
-    added to the network.}
-  \item{etime}{Numeric vector, the time steps when the edges where added
-    to the network.}
-  \item{events}{A list of numeric vectors, each vector represents an
-    event, with the participation of the listed vertices.}
-  \item{delta}{Real scalar, the error margin that is allowed for the
-    convergence.}
-  \item{filter}{Logical vector, length is the number of vertices. Only
-    vertices corresponding to \code{TRUE} entries are used in the
-    fitting.}
-  \item{alpha}{Starting value for the \sQuote{\code{alpha}} parameter.}
-  \item{a}{Starting value for the \sQuote{\code{a}} parameter.}
-  \item{paralpha}{Starting value for the \sQuote{\code{paralpha}}
-    (Pareto alpha) parameter.}
-  \item{parbeta}{Starting value for the \sQuote{\code{parbeta}} (Pareto
-    beta) parameter.}
-  \item{parscale}{Starting value for the \sQuote{\code{parscale}}
-    (Pareto scale) parameter.}
-  \item{abstol}{Real scalar, absolute tolerance for the ML fitting.}
-  \item{reltol}{Real scalar, relative tolerance for the ML fitting.}
-  \item{maxit}{Numeric scalar, the maximum number of iterations.}
-  \item{beta}{Real scalar, starting value for the \sQuote{\code{beta}}
-    parameter.}
-  \item{coeffs}{Numeric vector, starting values for the coefficients.}
-  \item{par}{Pareto parameters for the different vertex types, in a
-    matrix.}
-  \item{ntk}{Logical scalar, whether to return the Ntk values.}
-  \item{gcats}{Numeric vector, the vertex types.}
-  \item{st}{Logical scalar, whether to return the S(t) values.}
-}
-\details{
-  The functions should be considered as experimental, so no
-  detailed documentation yet. Sorry.
-}
-\value{
-  A named list.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% seealso{}
-% \examples{}
-\keyword{graphs}
diff --git a/man/fastgreedy.community.Rd b/man/fastgreedy.community.Rd
deleted file mode 100644
index f78c115..0000000
--- a/man/fastgreedy.community.Rd
+++ /dev/null
@@ -1,63 +0,0 @@
-\name{fastgreedy.community}
-\alias{fastgreedy.community}
-\concept{Community structure}
-\concept{Fast greedy community detection}
-\title{Community structure via greedy optimization of modularity}
-\description{
-  This function tries to find dense subgraph, also called communities in
-  graphs via directly optimizing a modularity score.
-}
-\usage{
-fastgreedy.community(graph, merges=TRUE, modularity=TRUE,
-      membership=TRUE, weights=E(graph)$weight)
-}
-\arguments{
-  \item{graph}{The input graph}
-  \item{merges}{Logical scalar, whether to return the merge matrix.}
-  \item{modularity}{Logical scalar, whether to return a vector containing
-    the modularity after each merge.}
-  \item{membership}{Logical scalar, whether to calculate the membership
-    vector corresponding to the maximum modularity score, considering
-    all possible community structures along the merges.}
-  \item{weights}{If not \code{NULL}, then a numeric vector of edge
-    weights. The length must match the number of edges in the graph.
-    By default the \sQuote{\code{weight}} edge attribute is used as
-    weights. If it is not present, then all edges are considered to have
-    the same weight.
-  }
-}
-\details{
- This function implements the fast greedy modularity optimization
- algorithm for finding community structure, see 
- A Clauset, MEJ Newman, C Moore: Finding community structure in very
- large networks, http://www.arxiv.org/abs/cond-mat/0408187 for the
- details.
-}
-\value{
-  \code{fastgreedy.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\references{
-  A Clauset, MEJ Newman, C Moore: Finding community structure in very
-  large networks, http://www.arxiv.org/abs/cond-mat/0408187
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
-  \email{csardi.gabor at gmail.com} for the R interface.
-}
-\seealso{
-  \code{\link{communities}} for extracting the results.
-  
-  See also \code{\link{walktrap.community}},
-  \code{\link{spinglass.community}},
-  \code{\link{leading.eigenvector.community}} and 
-  \code{\link{edge.betweenness.community}} for other methods.
-}
-\examples{
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
-fc <- fastgreedy.community(g)
-membership(fc)
-sizes(fc)
-}
-\keyword{graphs}
diff --git a/man/fit_hrg.Rd b/man/fit_hrg.Rd
new file mode 100644
index 0000000..0bd7add
--- /dev/null
+++ b/man/fit_hrg.Rd
@@ -0,0 +1,90 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{fit_hrg}
+\alias{fit_hrg}
+\alias{hrg.fit}
+\title{Fit a hierarchical random graph model}
+\usage{
+fit_hrg(graph, hrg = NULL, start = FALSE, steps = 0)
+}
+\arguments{
+\item{graph}{The graph to fit the model to. Edge directions are ignored in
+directed graphs.}
+
+\item{hrg}{A hierarchical random graph model, in the form of an
+\code{igraphHRG} object. \code{fit_hrg} allows this to be \code{NULL}, in
+which case a random starting point is used for the fitting.}
+
+\item{start}{Logical, whether to start the fitting/sampling from the
+supplied \code{igraphHRG} object, or from a random starting point.}
+
+\item{steps}{The number of MCMC steps to make. If this is zero, then the
+MCMC procedure is performed until convergence.}
+}
+\value{
+\code{fit_hrg} returns an \code{igraphHRG} object. This is a list
+with the following members:
+  \item{left}{Vector that contains the left children of the internal
+    tree vertices. The first vertex is always the root vertex, so the
+    first element of the vector is the left child of the root
+    vertex. Internal vertices are denoted with negative numbers, starting
+    from -1 and going down, i.e. the root vertex is -1. Leaf vertices
+    are denoted by non-negative number, starting from zero and up.}
+  \item{right}{Vector that contains the right children of the vertices,
+    with the same encoding as the \code{left} vector.}
+  \item{prob}{The connection probabilities attached to the internal
+    vertices, the first number belongs to the root vertex (i.e. internal
+    vertex -1), the second to internal vertex -2, etc.}
+  \item{edges}{The number of edges in the subtree below the given
+    internal vertex.}
+  \item{vertices}{The number of vertices in the subtree below the
+    given internal vertex, including itself.}
+}
+\description{
+\code{fit_hrg} fits a HRG to a given graph. It takes the specified
+\code{steps} number of MCMC steps to perform the fitting, or a convergence
+criteria if the specified number of steps is zero. \code{fit_hrg} can start
+from a given HRG, if this is given in the \code{hrg} argument and the
+\code{start} argument is \code{TRUE}.
+}
+\examples{
+## We are not running these examples any more, because they
+## take a long time (~15 seconds) to run and this is against the CRAN
+## repository policy. Copy and paste them by hand to your R prompt if
+## you want to run them.
+
+\dontrun{
+## A graph with two dense groups
+g <- sample_gnp(10, p=1/2) + sample_gnp(10, p=1/2)
+hrg <- fit_hrg(g)
+hrg
+
+## The consensus tree for it
+consensus_tree(g, hrg=hrg, start=TRUE)
+
+## Prediction of missing edges
+g2 <- make_full_graph(4) + (make_full_graph(4) - path(1,2))
+predict_edges(g2)
+}
+}
+\references{
+A. Clauset, C. Moore, and M.E.J. Newman. Hierarchical structure
+and the prediction of missing links in networks. \emph{Nature} 453, 98--101
+(2008);
+
+A. Clauset, C. Moore, and M.E.J. Newman. Structural Inference of Hierarchies
+in Networks. In E. M. Airoldi et al. (Eds.): ICML 2006 Ws, \emph{Lecture
+Notes in Computer Science} 4503, 1--13. Springer-Verlag, Berlin Heidelberg
+(2007).
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg_tree}}; \code{\link{hrg}},
+  \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/fit_power_law.Rd b/man/fit_power_law.Rd
new file mode 100644
index 0000000..68a5f67
--- /dev/null
+++ b/man/fit_power_law.Rd
@@ -0,0 +1,119 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/fit.R
+\name{fit_power_law}
+\alias{fit_power_law}
+\alias{power.law.fit}
+\title{Fitting a power-law distribution function to discrete data}
+\usage{
+fit_power_law(x, xmin = NULL, start = 2, force.continuous = FALSE,
+  implementation = c("plfit", "R.mle"), ...)
+}
+\arguments{
+\item{x}{The data to fit, a numeric vector. For implementation
+\sQuote{\code{R.mle}} the data must be integer values. For the
+\sQuote{\code{plfit}} implementation non-integer values might be present and
+then a continuous power-law distribution is fitted.}
+
+\item{xmin}{Numeric scalar, or \code{NULL}. The lower bound for fitting the
+power-law. If \code{NULL}, the smallest value in \code{x} will be used for
+the \sQuote{\code{R.mle}} implementation, and its value will be
+automatically determined for the \sQuote{\code{plfit}} implementation. This
+argument makes it possible to fit only the tail of the distribution.}
+
+\item{start}{Numeric scalar. The initial value of the exponent for the
+minimizing function, for the \sQuote{\code{R.mle}} implementation. Ususally
+it is safe to leave this untouched.}
+
+\item{force.continuous}{Logical scalar. Whether to force a continuous
+distribution for the \sQuote{\code{plfit}} implementation, even if the
+sample vector contains integer values only (by chance). If this argument is
+false, igraph will assume a continuous distribution if at least one sample
+is non-integer and assume a discrete distribution otherwise.}
+
+\item{implementation}{Character scalar. Which implementation to use. See
+details below.}
+
+\item{\dots}{Additional arguments, passed to the maximum likelihood
+optimizing function, \code{\link[stats4]{mle}}, if the \sQuote{\code{R.mle}}
+implementation is chosen. It is ignored by the \sQuote{\code{plfit}}
+implementation.}
+}
+\value{
+Depends on the \code{implementation} argument. If it is
+\sQuote{\code{R.mle}}, then an object with class \sQuote{\code{mle}}. It can
+be used to calculate confidence intervals and log-likelihood. See
+\code{\link[stats4]{mle-class}} for details.
+
+If \code{implementation} is \sQuote{\code{plfit}}, then the result is a
+named list with entries: \item{continuous}{Logical scalar, whether the
+fitted power-law distribution was continuous or discrete.}
+\item{alpha}{Numeric scalar, the exponent of the fitted power-law
+distribution.} \item{xmin}{Numeric scalar, the minimum value from which the
+power-law distribution was fitted. In other words, only the values larger
+than \code{xmin} were used from the input vector.} \item{logLik}{Numeric
+scalar, the log-likelihood of the fitted parameters.} \item{KS.stat}{Numeric
+scalar, the test statistic of a Kolmogorov-Smirnov test that compares the
+fitted distribution with the input vector. Smaller scores denote better
+fit.} \item{KS.p}{Numeric scalar, the p-value of the Kolmogorov-Smirnov
+test. Small p-values (less than 0.05) indicate that the test rejected the
+hypothesis that the original data could have been drawn from the fitted
+power-law distribution.}
+}
+\description{
+\code{fit_power_law} fits a power-law distribution to a data set.
+}
+\details{
+This function fits a power-law distribution to a vector containing samples
+from a distribution (that is assumed to follow a power-law of course). In a
+power-law distribution, it is generally assumed that \eqn{P(X=x)} is
+proportional to \eqn{x^{-alpha}}{x^-alpha}, where \eqn{x} is a positive
+number and \eqn{\alpha}{alpha} is greater than 1. In many real-world cases,
+the power-law behaviour kicks in only above a threshold value
+\eqn{x_{min}}{xmin}. The goal of this function is to determine
+\eqn{\alpha}{alpha} if \eqn{x_{min}}{xmin} is given, or to determine
+\eqn{x_{min}}{xmin} and the corresponding value of \eqn{\alpha}{alpha}.
+
+\code{fit_power_law} provides two maximum likelihood implementations.  If
+the \code{implementation} argument is \sQuote{\code{R.mle}}, then the BFGS
+optimization (see \link[stats4]{mle}) algorithm is applied.  The additional
+arguments are passed to the mle function, so it is possible to change the
+optimization method and/or its parameters.  This implementation can
+\emph{not} to fit the \eqn{x_{min}}{xmin} argument, so use the
+\sQuote{\code{plfit}} implementation if you want to do that.
+
+The \sQuote{\code{plfit}} implementation also uses the maximum likelihood
+principle to determine \eqn{\alpha}{alpha} for a given \eqn{x_{min}}{xmin};
+When \eqn{x_{min}}{xmin} is not given in advance, the algorithm will attempt
+to find itsoptimal value for which the \eqn{p}-value of a Kolmogorov-Smirnov
+test between the fitted distribution and the original sample is the largest.
+The function uses the method of Clauset, Shalizi and Newman to calculate the
+parameters of the fitted distribution. See references below for the details.
+}
+\examples{
+# This should approximately yield the correct exponent 3
+g <- barabasi.game(1000) # increase this number to have a better estimate
+d <- degree(g, mode="in")
+fit1 <- fit_power_law(d+1, 10)
+fit2 <- fit_power_law(d+1, 10, implementation="R.mle")
+
+fit1$alpha
+stats4::coef(fit2)
+fit1$logLik
+stats4::logLik(fit2)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
+\references{
+Power laws, Pareto distributions and Zipf's law, M. E. J.
+Newman, \emph{Contemporary Physics}, 46, 323-351, 2005.
+
+Aaron Clauset, Cosma R .Shalizi and Mark E.J. Newman: Power-law
+distributions in empirical data. SIAM Review 51(4):661-703, 2009.
+}
+\seealso{
+\code{\link[stats4]{mle}}
+}
+\keyword{graphs}
+
diff --git a/man/forest.fire.game.Rd b/man/forest.fire.game.Rd
deleted file mode 100644
index f7946d1..0000000
--- a/man/forest.fire.game.Rd
+++ /dev/null
@@ -1,79 +0,0 @@
-\name{forest.fire.game}
-\alias{forest.fire.game}
-\concept{Random graph model}
-\concept{Forest fire model}
-\title{Forest Fire Network Model}
-\description{This is a growing network model, which resembles of how the
-  forest fire spreads by igniting trees close by.}
-\usage{
-forest.fire.game (nodes, fw.prob, bw.factor = 1, ambs = 1, directed = TRUE)
-}
-\arguments{
-  \item{nodes}{The number of vertices in the graph.}
-  \item{fw.prob}{The forward burning probability, see details below.}
-  \item{bw.factor}{The backward burning ratio. The backward burning
-    probability is calculated as \code{bw.factor*fw.prob}.}
-  \item{ambs}{The number of ambassador vertices.}
-  \item{directed}{Logical scalar, whether to create a directed graph.}
-}
-\details{
-  The forest fire model intends to reproduce the following network
-  characteristics, observed in real networks:
-  \itemize{
-    \item Heavy-tailed in-degree distribution. 
-    \item Heavy-tailed out-degree distribution.
-    \item Communities.
-    \item Densification power-law. The network is densifying in time,
-      according to a power-law rule.
-    \item Shrinking diameter. The diameter of the network decreases in
-      time.
-  }
-
-  The network is generated in the following way. One vertex is added at
-  a time. This vertex connects to (cites) \code{ambs} vertices already
-  present in the network, chosen uniformly random. Now, for each cited
-  vertex \eqn{v} we do the following procedure:
-  \enumerate{
-    \item We generate two random number, \eqn{x} and \eqn{y}, that are
-      geometrically distributed with means \eqn{p/(1-p)} and
-      \eqn{rp(1-rp)}. (\eqn{p} is \code{fw.prob}, \eqn{r} is
-      \code{bw.factor}.) The new vertex cites \eqn{x} outgoing neighbors
-      and \eqn{y} incoming neighbors of \eqn{v}, from those which are
-      not yet cited by the new vertex. If there are less than \eqn{x} or
-      \eqn{y} such vertices available then we cite all of them.
-    \item The same procedure is applied to all the newly cited
-      vertices.
-  }
-}
-\note{
-  The version of the model in the published paper is incorrect
-  in the sense that it cannot generate the kind of graphs the authors
-  claim. A corrected version is available from
-  \url{http://www.cs.cmu.edu/~jure/pubs/powergrowth-tkdd.pdf}, our
-  implementation is based on this.
-}
-\value{A simple graph, possibly directed if the \code{directed} argument
-  is \code{TRUE}.}
-\references{
-  Jure Leskovec, Jon Kleinberg and Christos Faloutsos. Graphs over time:
-  densification laws, shrinking diameters and possible explanations.
-  \emph{KDD '05: Proceeding of the eleventh ACM SIGKDD international
-    conference on Knowledge discovery in data mining}, 177--187, 2005.
-}
-\author{
-  Gabor Csardi \email{csardi.gabor at gmail.com}
-}
-\seealso{
-  \code{\link{barabasi.game}} for the basic preferential attachment
-  model.
-}
-\examples{
-g <- forest.fire.game(10000, fw.prob=0.37, bw.factor=0.32/0.37)
-dd1 <- degree.distribution(g, mode="in")
-dd2 <- degree.distribution(g, mode="out")
-if (interactive()) {
-  plot(seq(along=dd1)-1, dd1, log="xy")
-  points(seq(along=dd2)-1, dd2, col=2, pch=2)
-}
-}
-\keyword{graphs}
diff --git a/man/gclust.app.Rd b/man/gclust.app.Rd
new file mode 100644
index 0000000..ed27870
--- /dev/null
+++ b/man/gclust.app.Rd
@@ -0,0 +1,29 @@
+\name{gclust.app}
+\alias{gclust.app}
+\concept{Graph Clustering}
+\title{Graph Clustering Using NMF (and no SVT) -- Apparent Clusters}
+\description{Performs Clustering of Graphs using Non-negative Factorization.}
+
+\usage{
+    gclust.app(glist, r=1,nmfout=FALSE,maxit=10000, nmfmethod='lee')
+}
+
+\arguments{
+    \item{glist}{List of \code{igraph} Objects}
+    \item{r}{Maximum Number of Clusters Allowed}
+    \item{nmfout}{T/F indicating if the output from nmf should be returned; Default is FALSE}
+    \item{maxit}{A number passed to irlba or svd function limiting the number of iteration; Default is 10000}
+    \item{nmfmethod}{A number passed to irlba or svd, limiting the number of iterations; Default is 'lee'}
+}
+
+\value{
+    \item{nmf}{An NMF object}
+    \item{W}{Basis Graphs} 
+    \item{H}{Probability Vector for Cluster Weights timeseries of graphs}
+    \item{Xorigin}{Input Data in the matrix form}
+    }
+
+\author{Nam Lee \email{nhlee at jhu.edu}}
+
+% \examples{
+% }
diff --git a/man/gclust.rsvt.Rd b/man/gclust.rsvt.Rd
new file mode 100644
index 0000000..357169a
--- /dev/null
+++ b/man/gclust.rsvt.Rd
@@ -0,0 +1,33 @@
+\name{gclust.rsvt}
+\alias{gclust.rsvt}
+\concept{Graph Clustering}
+\title{Graph Clustering Using SVT and NMF -- Clusters Implied by Singular Value Thresholding}
+\description{Performs Clustering of Graphs using Singular Value Thresholding and Non-negative Factorization.}
+
+\usage{
+    gclust.rsvt(glist, r=1,maxsvt=10,nmfout=FALSE,maxit=10000, nmfmethod='lee') 
+}
+
+\arguments{
+    \item{glist}{List of \code{igraph} Objects}
+    \item{r}{Maximum Number of Clusters Allowed}
+    \item{maxsvt}{Maximum Number of Singular Value Thresholding; Default is 10}
+    \item{nmfout}{T/F indicating if the output from nmf should be returned; Default is FALSE}
+    \item{maxit}{A number passed to irlba or svd function limiting the number of iteration; Default is 10000}
+    \item{nmfmethod}{A number passed to irlba or svd, limiting the number of iterations; Default is 'lee'}
+}
+
+\value{
+    \item{nmf}{An NMF object}
+    \item{W}{Basis Graphs} 
+    \item{H}{Probability Vector for Cluster Weights timeseries of graphs}
+    \item{Xorigin}{Input Data in the matrix form}
+    }
+
+\author{Nam Lee \email{nhlee at jhu.edu}}
+
+\examples{ 
+require(NMF)
+require(irlba)
+require(igraph)
+}
diff --git a/man/get.adjlist.Rd b/man/get.adjlist.Rd
deleted file mode 100644
index 476d33e..0000000
--- a/man/get.adjlist.Rd
+++ /dev/null
@@ -1,41 +0,0 @@
-\name{get.adjlist}
-\alias{get.adjlist}
-\alias{get.adjedgelist}
-\concept{Adjacency list}
-\title{Adjacency lists}
-\description{Create adjacency lists from a graph, either for adjacent
-  edges or for neighboring vertices
-}
-\usage{
-get.adjlist(graph, mode = c("all", "out", "in", "total"))
-get.adjedgelist(graph, mode = c("all", "out", "in", "total"))
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{mode}{Character scalar, it gives what kind of adjacent
-    edges/vertices to include in the lists. \sQuote{\code{out}} is for
-    outgoing edges/vertices, \sQuote{\code{in}} is for incoming
-    edges/vertices, \sQuote{\code{all}} is for both. This argument is
-    ignored for undirected graphs.}
-}
-\details{
-  \code{get.adjlist} returns a list of numeric vectors, which include
-  the ids of neighbor vertices (according to the \code{mode} argument) of all
-  vertices.
-
-  \code{get.adjedgelist} returns a list of numeric vectors, which
-  include the ids of adjacent edgs (according to the \code{mode}
-  argument) of all vertices.
-}
-\value{
-  A list of numeric vectors.
-}
-%\references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{get.edgelist}}, \code{\link{get.adjacency}}}
-\examples{
-g <- graph.ring(10)
-get.adjlist(g)
-get.adjedgelist(g)
-}
-\keyword{graphs}
diff --git a/man/get.edge.ids.Rd b/man/get.edge.ids.Rd
index 4044baf..1a18f88 100644
--- a/man/get.edge.ids.Rd
+++ b/man/get.edge.ids.Rd
@@ -1,50 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
 \name{get.edge.ids}
 \alias{get.edge.ids}
 \title{Find the edge ids based on the incident vertices of the edges}
-\description{
-  Find the edges in an igraph graph that have the specified end
-  points. This function handles multi-graph (graphs with multiple edges)
-  and can consider or ignore the edge directions in directed graphs.
-}
 \usage{
 get.edge.ids(graph, vp, directed = TRUE, error = FALSE, multi = FALSE)
 }
 \arguments{
-  \item{graph}{The input graph.}
-  \item{vp}{The indicent vertices, given as vertex ids or symbolic
-    vertex names. They are interpreted pairwise, i.e. the first and
-    second are used for the first edge, the third and fourth for the
-    second, etc.}
-  \item{directed}{Logical scalar, whether to consider edge directions in
-    directed graphs. This argument is ignored for undirected graphs.}
-  \item{error}{Logical scalar, whether to report an error if an edge is
-    not found in the graph. If \code{FALSE}, then no error is reported,
-    and zero is returned for the non-existant edge(s).}
-  \item{multi}{Logical scalar, whether to handle multiple edges
-    properly. If \code{FALSE}, and a pair of vertices are given twice
-    (or more), then always the same edge id is reported back for
-    them. If \code{TRUE}, then the edge ids of multiple edges are
-    correctly reported.}
+\item{graph}{The input graph.}
+
+\item{vp}{The indicent vertices, given as vertex ids or symbolic vertex
+names. They are interpreted pairwise, i.e. the first and second are used for
+the first edge, the third and fourth for the second, etc.}
+
+\item{directed}{Logical scalar, whether to consider edge directions in
+directed graphs. This argument is ignored for undirected graphs.}
+
+\item{error}{Logical scalar, whether to report an error if an edge is not
+found in the graph. If \code{FALSE}, then no error is reported, and zero is
+returned for the non-existant edge(s).}
+
+\item{multi}{Logical scalar, whether to handle multiple edges properly. If
+\code{FALSE}, and a pair of vertices are given twice (or more), then always
+the same edge id is reported back for them. If \code{TRUE}, then the edge
+ids of multiple edges are correctly reported.}
+}
+\value{
+A numeric vector of edge ids, one for each pair of input vertices.
+If there is no edge in the input graph for a given pair of vertices, then
+zero is reported. (If the \code{error} argument is \code{FALSE}.)
+}
+\description{
+Find the edges in an igraph graph that have the specified end points. This
+function handles multi-graph (graphs with multiple edges) and can consider
+or ignore the edge directions in directed graphs.
 }
 \details{
-  igraph vertex ids are natural numbers, starting from one, up to the
-  number of vertices in the graph. Similarly, edges are also numbered
-  from one, up to the number of edges.
+igraph vertex ids are natural numbers, starting from one, up to the number
+of vertices in the graph. Similarly, edges are also numbered from one, up to
+the number of edges.
 
-  This function allows finding the edges of the graph, via their
-  incident vertices.
-}
-\value{A numeric vector of edge ids, one for each pair of input
-  vertices. If there is no edge in the input graph for a given pair of
-  vertices, then zero is reported. (If the \code{error} argument is
-  \code{FALSE}.) }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
+This function allows finding the edges of the graph, via their incident
+vertices.
+}
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 ei <- get.edge.ids(g, c(1,2, 4,5))
 E(g)[ei]
 
 ## non-existant edge
 get.edge.ids(g, c(2,1, 1,4, 5,4))
 }
-\keyword{graphs}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{gorder}},
+  \code{\link{vcount}}; \code{\link{head_of}};
+  \code{\link{incident_edges}}; \code{\link{incident}};
+  \code{\link{is.directed}}, \code{\link{is_directed}};
+  \code{\link{neighbors}}; \code{\link{tail_of}}
+}
+
diff --git a/man/get.incidence.Rd b/man/get.incidence.Rd
deleted file mode 100644
index 0003756..0000000
--- a/man/get.incidence.Rd
+++ /dev/null
@@ -1,48 +0,0 @@
-\name{get.incidence}
-\alias{get.incidence}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\concept{Incidence matrix}
-\title{Incidence matrix of a bipartite graph}
-\description{This function can return a sparse or dense incidence matrix
-of a bipartite network. The incidence matrix is an \eqn{n} times \eqn{m}
-matrix, \eqn{n} and \eqn{m} are the number of vertices of the two kinds.}
-\usage{
-get.incidence(graph, types=NULL, attr=NULL, names=TRUE, sparse=FALSE)
-}
-\arguments{
-  \item{graph}{The input graph. The direction of the edges is ignored in
-  directed graphs.}
-  \item{types}{An optional vertex type vector to use instead of the
-    \code{type} vertex attribute. You must supply this argument
-    if the graph has no \code{type} vertex attribute.}
-  \item{attr}{Either \code{NULL} or a character string giving an edge
-    attribute name. If \code{NULL}, then a traditional incidence matrix is
-    returned. If not \code{NULL} then the values of the given edge
-    attribute are included in the incidence matrix. If the graph has
-    multiple edges, the edge attribute of an arbitrarily chosen edge
-    (for the multiple edges) is included.}
-  \item{names}{Logical scalar, if \code{TRUE} and the vertices in the
-    graph are named (i.e. the graph has a vertex attribute called
-    \code{name}), then vertex names will be added to the result
-    as row and column names. Otherwise the ids of the vertices are used
-    as row and column names.}
-  \item{sparse}{Logical scalar, if it is \code{TRUE} then a sparse
-    matrix is created, you will need the \code{Matrix} package for this.}
-}
-\details{
-  Bipartite graphs have a \code{type} vertex attribute in
-  igraph, this is boolean and \code{FALSE} for the vertices of the first
-  kind and \code{TRUE} for vertices of the second kind.
-}
-\value{
-  A sparse or dense matrix.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{\code{\link{graph.incidence}} for the opposite operation.}
-\examples{
-g <- graph.bipartite( c(0,1,0,1,0,0), c(1,2,2,3,3,4) )
-get.incidence(g)
-}
-\keyword{graphs}
diff --git a/man/getAICc.Rd b/man/getAICc.Rd
new file mode 100644
index 0000000..18e7411
--- /dev/null
+++ b/man/getAICc.Rd
@@ -0,0 +1,28 @@
+\name{getAICc}
+\alias{getAICc}
+\concept{Compute Information Criteria Value Using a Poisson Approximation}
+\title{Compute AIC based on a Poisson Approximation using the output from \code{gclust}}
+\description{
+    Compute and Extract information Criteria Value from \code{gclust} using a Poisson
+    approximation, where the penality term is adjusted for small sample cases.  
+}
+\usage{ getAICc(gfit) }
+\arguments{
+    \item{gfit}{The output from a call to \code{gclust.rsvt} or \code{gclust.app}}
+}
+
+\value{
+    \item{nclust}{Number of clusters being considered}
+    \item{negloglikpart}{Negative log likelihood part}
+    \item{parampart}{Parameter penalty term}
+    \item{AIC}{AIC Value Using a Possion approximation}
+}
+
+\author{ Nam Lee \email{nhlee at jhu.edu}}
+
+\examples{
+require(NMF)
+require(irlba)
+require(igraph)
+}
+
diff --git a/man/girth.Rd b/man/girth.Rd
index 1a0e626..4f6332a 100644
--- a/man/girth.Rd
+++ b/man/girth.Rd
@@ -1,55 +1,55 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{girth}
 \alias{girth}
-\concept{Girth}
 \title{Girth of a graph}
-\description{The girth of a graph is the length of the shortest circle
-  in it.}
 \usage{
-girth(graph, circle=TRUE)
+girth(graph, circle = TRUE)
 }
 \arguments{
-  \item{graph}{The input graph. It may be directed, but the algorithm
-    searches for undirected circles anyway.}
-  \item{circle}{Logical scalar, whether to return the shortest circle
-    itself.}
-}
-\details{
-  The current implementation works for undirected graphs only, 
-  directed graphs are treated as undirected graphs. Loop edges and
-  multiple edges are ignored.
-  If the graph is a forest (ie. acyclic), then zero is returned.
+\item{graph}{The input graph. It may be directed, but the algorithm searches
+for undirected circles anyway.}
 
-  This implementation is based on Alon Itai and Michael Rodeh:
-  Finding a minimum circuit in a graph
-  \emph{Proceedings of the ninth annual ACM symposium on Theory of
-    computing}, 1-10, 1977. The first implementation of this
-  function was done by Keith Briggs, thanks Keith.
+\item{circle}{Logical scalar, whether to return the shortest circle itself.}
 }
 \value{
-  A named list with two components:
-  \item{girth}{Integer constant, the girth of the graph, or 0 if the
-    graph is acyclic.}
-  \item{circle}{Numeric vector with the vertex ids in the shortest
-    circle.}
+A named list with two components: \item{girth}{Integer constant, the
+girth of the graph, or 0 if the graph is acyclic.} \item{circle}{Numeric
+vector with the vertex ids in the shortest circle.}
 }
-\references{
-  Alon Itai and Michael Rodeh: Finding a minimum circuit in a graph 
-  \emph{Proceedings of the ninth annual ACM symposium on Theory of 
-    computing}, 1-10, 1977
+\description{
+The girth of a graph is the length of the shortest circle in it.
+}
+\details{
+The current implementation works for undirected graphs only, directed graphs
+are treated as undirected graphs. Loop edges and multiple edges are ignored.
+If the graph is a forest (ie. acyclic), then zero is returned.
+
+This implementation is based on Alon Itai and Michael Rodeh: Finding a
+minimum circuit in a graph \emph{Proceedings of the ninth annual ACM
+symposium on Theory of computing}, 1-10, 1977. The first implementation of
+this function was done by Keith Briggs, thanks Keith.
 }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
 \examples{
 # No circle in a tree
-g <- graph.tree(1000, 3)
+g <- make_tree(1000, 3)
 girth(g)
 
 # The worst case running time is for a ring
-g <- graph.ring(100)
+g <- make_ring(100)
 girth(g)
 
 # What about a random graph?
-g <- erdos.renyi.game(1000, 1/1000)
+g <- sample_gnp(1000, 1/1000)
 girth(g)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Alon Itai and Michael Rodeh: Finding a minimum circuit in a
+graph \emph{Proceedings of the ninth annual ACM symposium on Theory of
+computing}, 1-10, 1977
+}
 \keyword{graphs}
 
diff --git a/man/gorder.Rd b/man/gorder.Rd
new file mode 100644
index 0000000..6039503
--- /dev/null
+++ b/man/gorder.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{gorder}
+\alias{gorder}
+\alias{vcount}
+\title{Order (number of vertices) of a graph}
+\usage{
+gorder(graph)
+}
+\arguments{
+\item{graph}{The graph}
+}
+\value{
+Number of vertices, numeric scalar.
+}
+\description{
+Order (number of vertices) of a graph
+}
+\examples{
+g <- make_ring(10)
+gorder(g)
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{neighbors}};
+  \code{\link{tail_of}}
+}
+
diff --git a/man/graph.adjacency.Rd b/man/graph.adjacency.Rd
deleted file mode 100644
index c672bcf..0000000
--- a/man/graph.adjacency.Rd
+++ /dev/null
@@ -1,156 +0,0 @@
-\name{graph.adjacency}
-\alias{graph.adjacency}
-\concept{Adjacency matrix}
-\concept{Sparse matrix}
-\title{Create graphs from adjacency matrices}
-\description{\code{graph.adjacency} is a flexible function for creating
-  \code{igraph} graphs from adjacency matrices.}
-\usage{
-graph.adjacency(adjmatrix, mode=c("directed", "undirected", "max",
-        "min", "upper", "lower", "plus"), weighted=NULL, diag=TRUE,
-        add.colnames=NULL, add.rownames=NA)
-}
-\arguments{
-  \item{adjmatrix}{A square adjacency matrix. From igraph version 0.5.1
-    this can be a sparse matrix created with the \code{Matrix} package.}
-  \item{mode}{
-    Character scalar, specifies how igraph should interpret the supplied
-    matrix. See also the \code{weighted} argument, the interpretation
-    depends on that too. Possible values are: \code{directed},
-    \code{undirected}, \code{upper}, \code{lower}, \code{max},
-    \code{min}, \code{plus}. See details below.
-  }
-  \item{weighted}{This argument specifies whether to create a weighted
-    graph from an adjacency matrix. If it is \code{NULL} then an
-    unweighted graph is created and the elements of the adjacency matrix
-    gives the number of edges between the vertices. If it is a character
-    constant then for every non-zero matrix entry an edge is created and
-    the value of the entry is added as an edge attribute named by the
-    \code{weighted} argument. If it is \code{TRUE} then a weighted graph
-    is created and the name of the edge attribute will be
-    \code{weight}. See also details below.
-  }
-  \item{diag}{Logical scalar, whether to include the diagonal of the
-    matrix in the calculation. If this is \code{FALSE} then the diagonal
-    is zerod out first.
-  }
-  \item{add.colnames}{Character scalar, whether to add the column names as
-    vertex attributes. If it is \sQuote{\code{NULL}} (the default)
-    then, if present, column names are added as vertex attribute
-    \sQuote{name}. If \sQuote{\code{NA}} then they will not be added.
-    If a character constant, then it gives the name of the vertex
-    attribute to add.}
-  \item{add.rownames}{Character scalar, whether to add the row names as
-    vertex attributes. Possible values the same as the previous
-    argument. By default row names are not added. If
-    \sQuote{\code{add.rownames}} and \sQuote{\code{add.colnames}} specify the
-    same vertex attribute, then the former is ignored. }
-}
-\details{
-  \code{graph.adjacency} creates a graph from an adjacency matrix.
-
-  The order of the vertices are preserved, i.e. the vertex corresponding
-  to the first row will be vertex 0 in the graph, etc.
-
-  \code{graph.adjacency} operates in two main modes, depending on the
-  \code{weighted} argument.
-
-  If this argument is \code{NULL} then an unweighted graph is
-  created and an element of the adjacency matrix gives the number
-  of edges to create between the two corresponding vertices.
-  The details depend on the value of the \code{mode} argument:
-  \describe{
-    \item{\code{directed}}{The graph will be directed and a matrix
-      element gives the number of edges between two vertices.}
-    \item{\code{undirected}}{This is exactly the same as \code{max},
-      for convenience. Note that it is \emph{not} checked whether the
-      matrix is symmetric.} 
-    \item{\code{max}}{An undirected graph will be created and
-      \code{max(A(i,j), A(j,i))} gives the number of edges.}
-    \item{\code{upper}}{An undirected graph will be created, only the
-      upper right triangle (including the diagonal) is used for the
-      number of edges.}
-    \item{\code{lower}}{An undirected graph will be created, only the
-      lower left triangle (including the diagonal) is used for
-      creating the edges.}
-    \item{\code{min}}{undirected graph will be created with
-      \code{min(A(i,j), A(j,i))} edges between vertex \code{i} and
-      \code{j}.}
-    \item{\code{plus}}{ undirected graph will be created with
-      \code{A(i,j)+A(j,i)} edges between vertex \code{i} and
-      \code{j}.}  
-  }
-
-  If the \code{weighted} argument is not \code{NULL} then the elements
-  of the matrix give the weights of the edges (if they are not zero).
-  The details depend on the value of the \code{mode} argument:
-  \describe{
-    \item{\code{directed}}{The graph will be directed and a matrix
-      element gives the edge weights.}
-    \item{\code{undirected}}{First we check that the matrix is
-      symmetric. It is an error if not. Then only the upper triangle is
-      used to create a weighted undirected graph.}
-    \item{\code{max}}{An undirected graph will be created and
-      \code{max(A(i,j), A(j,i))} gives the edge weights.}
-    \item{\code{upper}}{An undirected graph will be created, only the
-      upper right triangle (including the diagonal) is used (for the
-      edge weights).}
-    \item{\code{lower}}{An undirected graph will be created, only the
-      lower left triangle (including the diagonal) is used for
-      creating the edges.}
-    \item{\code{min}}{An undirected graph will be created,
-      \code{min(A(i,j), A(j,i))} gives the edge weights.}
-    \item{\code{plus}}{An undirected graph will be created,
-      \code{A(i,j)+A(j,i)} gives the edge weights.}
-  }
-  
-}
-\value{
-  An igraph graph object.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\link{graph} and \code{\link{graph.formula}} for
-  other ways to create graphs.
-}
-\examples{
-adjm <- matrix(sample(0:1, 100, replace=TRUE, prob=c(0.9,0.1)), nc=10)
-g1 <- graph.adjacency( adjm )
-adjm <- matrix(sample(0:5, 100, replace=TRUE,
-                      prob=c(0.9,0.02,0.02,0.02,0.02,0.02)), nc=10)
-g2 <- graph.adjacency(adjm, weighted=TRUE)
-E(g2)$weight
-
-## various modes for weighted graphs, with some tests
-nzs <- function(x) sort(x [x!=0])
-adjm <- matrix(runif(100), 10)
-adjm[ adjm<0.5 ] <- 0
-g3 <- graph.adjacency((adjm + t(adjm))/2, weighted=TRUE,
-                      mode="undirected") 
-
-g4 <- graph.adjacency(adjm, weighted=TRUE, mode="max")
-all(nzs(pmax(adjm, t(adjm))[upper.tri(adjm)]) == sort(E(g4)$weight))
-
-g5 <- graph.adjacency(adjm, weighted=TRUE, mode="min")
-all(nzs(pmin(adjm, t(adjm))[upper.tri(adjm)]) == sort(E(g5)$weight))
-
-g6 <- graph.adjacency(adjm, weighted=TRUE, mode="upper")
-all(nzs(adjm[upper.tri(adjm)]) == sort(E(g6)$weight))
-
-g7 <- graph.adjacency(adjm, weighted=TRUE, mode="lower")
-all(nzs(adjm[lower.tri(adjm)]) == sort(E(g7)$weight))
-
-g8 <- graph.adjacency(adjm, weighted=TRUE, mode="plus")
-d2 <- function(x) { diag(x) <- diag(x)/2; x }
-all(nzs((d2(adjm+t(adjm)))[lower.tri(adjm)]) == sort(E(g8)$weight))
-
-g9 <- graph.adjacency(adjm, weighted=TRUE, mode="plus", diag=FALSE)
-d0 <- function(x) { diag(x) <- 0 }
-all(nzs((d0(adjm+t(adjm)))[lower.tri(adjm)]) == sort(E(g9)$weight))
-
-## row/column names
-rownames(adjm) <- sample(letters, nrow(adjm))
-colnames(adjm) <- seq(ncol(adjm))
-g10 <- graph.adjacency(adjm, weighted=TRUE, add.rownames="code")
-summary(g10)
-}
-\keyword{graphs}
diff --git a/man/graph.adjlist.Rd b/man/graph.adjlist.Rd
deleted file mode 100644
index e325016..0000000
--- a/man/graph.adjlist.Rd
+++ /dev/null
@@ -1,62 +0,0 @@
-\name{Graphs from adjacency lists}
-\alias{graph.adjlist}
-\title{Create graphs from adjacency lists}
-\description{An adjacency list is a list of numeric vectors, containing
-  the neighbor vertices for each vertex. This function creates an igraph
-  graph object from such a list.
-}
-\usage{
-graph.adjlist(adjlist, mode = c("out", "in", "all", "total"),
-              duplicate = TRUE)
-}
-\arguments{
-  \item{adjlist}{The adjacency list. It should be consistent, i.e. the
-    maximum throughout all vectors in the list must be less than the
-    number of vectors (=the number of vertices in the graph). Note that
-    the list is expected to be 0-indexed.}
-  \item{mode}{Character scalar, it specifies whether the graph to create
-    is undirected (\sQuote{all} or \sQuote{total}) or directed; and in
-    the latter case, whether it contains the outgoing (\sQuote{out}) or
-    the incoming (\sQuote{in}) neighbors of the vertices.}
-  \item{duplicate}{Logical scalar. For undirected graphs it gives
-    whether edges are included in the list twice. E.g. if it is
-    \code{TRUE} then for an undirected \code{{A,B}} edge
-    \code{graph.adjlist} expects \code{A} included in the neighbors of
-    \code{B} and \code{B} to be included in the neighbors of \code{A}.
-
-    This argument is ignored if \code{mode} is \code{out} or \code{in}.
-  }
-}
-\details{
-  Adjacency lists are handy if you intend to do many (small)
-  modifications to a graph. In this case adjacency lists are more
-  efficient than igraph graphs.
-
-  The idea is that you convert your graph to an adjacency list by
-  \code{\link{get.adjlist}}, do your modifications to the graphs and
-  finally create again an igraph graph by calling \code{graph.adjlist}.
-}
-\value{
-  An igraph graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{get.edgelist}} }
-\examples{
-## Directed
-g <- graph.ring(10, dir=TRUE)
-al <- get.adjlist(g, mode="out")
-g2 <- graph.adjlist(al)
-graph.isomorphic(g, g2)
-
-## Undirected
-g <- graph.ring(10)
-al <- get.adjlist(g)
-g2 <- graph.adjlist(al, mode="all")
-graph.isomorphic(g, g2)
-ecount(g2)
-g3 <- graph.adjlist(al, mode="all", duplicate=FALSE)
-ecount(g3)
-is.multiple(g3)
-}
-\keyword{graphs}
diff --git a/man/graph.automorphisms.Rd b/man/graph.automorphisms.Rd
deleted file mode 100644
index 5b472ae..0000000
--- a/man/graph.automorphisms.Rd
+++ /dev/null
@@ -1,58 +0,0 @@
-\name{graph.automorphisms}
-\alias{graph.automorphisms}
-\concept{Graph automorphism}
-\title{Number of automorphisms}
-\description{Calculate the number of automorphisms of a graph,
-  i.e. the number of isomorphisms to itself.}
-\usage{
-graph.automorphisms(graph, sh="fm")
-}
-\arguments{
-  \item{graph}{The input graph, it is treated as undirected.}
-  \item{sh}{The splitting heuristics for the BLISS algorithm. Possible
-    values are: \sQuote{\code{f}}: first non-singleton cell,
-    \sQuote{\code{fl}}: first largest non-singleton cell,
-    \sQuote{\code{fs}}: first smallest non-singleton cell,
-    \sQuote{\code{fm}}: first maximally non-trivially connected
-    non-singleton cell, \sQuote{\code{flm}}: first largest maximally
-    non-trivially connected non-singleton cell, \sQuote{\code{fsm}}:
-    first smallest maximally non-trivially connected non-singleton
-    cell.}
-}
-\details{
-  An automorphism of a graph is a permutation of its vertices which
-  brings the graph into itself.
-
-  This function calculates the number of automorphism of a graph using
-  the BLISS algorithm. See also the BLISS homepage at 
-  \url{http://www.tcs.hut.fi/Software/bliss/index.html}.
-}
-\value{
-  A named list with the following members:
-  \item{group_size}{The size of the automorphism group of the
-    input graph, as a string. This number is exact if igraph was
-    compiled with the GMP library, and approximate otherwise.}
-  \item{nof_nodes}{The number of nodes in the search tree.}
-  \item{nof_leaf_nodes}{The number of leaf nodes in the search
-    tree.}
-  \item{nof_bad_nodes}{Number of bad nodes.}
-  \item{nof_canupdates}{Number of canrep updates.}
-  \item{max_level}{Maximum level.}
-}
-\references{
-  Tommi Junttila and Petteri Kaski: Engineering an Efficient Canonical
-  Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of the
-    Ninth Workshop on Algorithm Engineering and Experiments and the
-    Fourth Workshop on Analytic Algorithms and Combinatorics.} 2007.
-}
-\author{ Tommi Juntilla (\url{http://users.ics.aalto.fi/tjunttil/)}
-  for BLISS and Gabor Csardi \email{csardi.gabor at gmail.com} for the
-  igraph glue code and this manual page.} 
-\seealso{\code{\link{canonical.permutation}}, \code{\link{permute.vertices}}}
-\examples{
-## A ring has n*2 automorphisms, you can "turn" it by 0-9 vertices
-## and each of these graphs can be "flipped"
-g <- graph.ring(10)
-graph.automorphisms(g)
-}
-\keyword{graphs}
diff --git a/man/graph.bfs.Rd b/man/graph.bfs.Rd
deleted file mode 100644
index fdffa1a..0000000
--- a/man/graph.bfs.Rd
+++ /dev/null
@@ -1,113 +0,0 @@
-\name{graph.bfs}
-\alias{graph.bfs}
-\title{Breadth-first search}
-\description{Breadth-first search is an algorithm to traverse a
-  graph. We start from a root vertex and spread along every edge
-  \dQuote{simultaneously}. }
-\usage{
-graph.bfs (graph, root, neimode = c("out", "in", "all", "total"), 
-    unreachable = TRUE, restricted = NULL, order = TRUE,
-    rank = FALSE, father = FALSE, pred = FALSE, succ = FALSE,
-    dist = FALSE, callback = NULL, extra = NULL, 
-    rho = parent.frame()) 
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{root}{Numeric vector, usually of length one. The root vertex, or
-    root vertices to start the search from.}
-  \item{neimode}{For directed graphs specifies the type of edges to
-    follow. \sQuote{out} follows outgoing, \sQuote{in} incoming
-    edges. \sQuote{all} ignores edge directions
-    completely. \sQuote{total} is a synonym for \sQuote{all}. This
-    argument is ignored for undirected graphs.}
-  \item{unreachable}{Logical scalar, whether the search should visit
-    the vertices that are unreachable from the given root
-    vertex (or vertices). If \code{TRUE}, then additional searches are
-    performed until all vertices are visited.}
-  \item{restricted}{\code{NULL} (=no restriction), or a vector of
-    vertices (ids or symbolic names). In the latter case, the search is
-    restricted to the given vertices.}
-  \item{order}{Logical scalar, whether to return the ordering of the
-    vertices.}
-  \item{rank}{Logical scalar, whether to return the rank of the
-    vertices.}
-  \item{father}{Logical scalar, whether to return the father of the
-    vertices.}
-  \item{pred}{Logical scalar, whether to return the predecessors of the
-    vertices.}
-  \item{succ}{Logical scalar, whether to return the successors of the
-    vertices.}
-  \item{dist}{Logical scalar, whether to return the distance from the
-    root of the search tree.}
-  \item{callback}{If not \code{NULL}, then it must be callback
-    function. This is called whenever a vertex is visited. See details
-    below.}
-  \item{extra}{Additional argument to supply to the callback function.}
-  \item{rho}{The environment in which the callback function is
-    evaluated.}
-}
-\details{
-  
-  The callback function must have the following arguments:
-  \describe{
-    \item{graph}{The input graph is passed to the callback function
-      here.}
-    \item{data}{A named numeric vector, with the following entries:
-      \sQuote{vid}, the vertex that was just visited, \sQuote{pred}, its
-      predecessor, \sQuote{succ}, its successor, \sQuote{rank}, the rank
-      of the current vertex, \sQuote{dist}, its distance from the root
-      of the search tree.}
-    \item{extra}{The extra argument.}
-  }
-  See examples below on how to use the callback function.
-}
-\value{
-  A named list with the following entries:
-  \item{root}{Numeric scalar. The root vertex that was used as the
-    starting point of the search.}
-  \item{neimode}{Character scalar. The \code{neimode} argument of the
-    function call. Note that for undirected graphs this is always
-    \sQuote{all}, irrespectively of the supplied value.}
-  \item{order}{Numeric vector. The vertex ids, in the order in which
-    they were visited by the search.}
-  \item{rank}{Numeric vector. The rank for each vertex.}
-  \item{father}{Numeric vector. The father of each vertex, i.e. the
-    vertex it was discovered from.}
-  \item{pred}{Numeric vector. The previously visited vertex for each
-    vertex, or 0 if there was no such vertex.}
-  \item{succ}{Numeric vector. The next vertex that was visited after the
-    current one, or 0 if there was no such vertex.}
-  \item{dist}{Numeric vector, for each vertex its distance from the root
-    of the search tree.}
-  
-  Note that \code{order}, \code{rank}, \code{father}, \code{pred},
-  \code{succ} and \code{dist} might be \code{NULL} if their
-  corresponding argument is \code{FALSE}, i.e. if their calculation is
-  not requested.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{ \code{\link{graph.dfs}} for depth-first search.}
-\examples{
-## Two rings
-graph.bfs(graph.ring(10) \%du\% graph.ring(10), root=1, "out",
-          order=TRUE, rank=TRUE, father=TRUE, pred=TRUE,
-          succ=TRUE, dist=TRUE)
-
-## How to use a callback
-f <- function(graph, data, extra) {
-  print(data)
-  FALSE
-}
-tmp <- graph.bfs(graph.ring(10) \%du\% graph.ring(10), root=1, "out",
-                 callback=f)
-
-## How to use a callback to stop the search
-## We stop after visiting all vertices in the initial component
-f <- function(graph, data, extra) {
- data['succ'] == -1
-}
-graph.bfs(graph.ring(10) \%du\% graph.ring(10), root=1, callback=f)
-
-}
-\keyword{graphs}
diff --git a/man/graph.bipartite.Rd b/man/graph.bipartite.Rd
deleted file mode 100644
index ed6760a..0000000
--- a/man/graph.bipartite.Rd
+++ /dev/null
@@ -1,54 +0,0 @@
-\name{graph.bipartite}
-\alias{graph.bipartite}
-\alias{is.bipartite}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\title{Create a bipartite graph}
-\description{A bipartite graph has two kinds of vertices and connections
-  are only allowed between different kinds.
-}
-\usage{
-graph.bipartite(types, edges, directed=FALSE)
-is.bipartite(graph)
-}
-\arguments{
-  \item{types}{A vector giving the vertex types. It will be coerced into
-  boolean. The length of the vector gives the number of vertices in the
-  graph.}
-  \item{edges}{A vector giving the edges of the graph, the same way as
-    for the regular \code{\link{graph}} function. It is checked that the
-    edges indeed connect vertices of different kind, accoding to the
-    supplied \code{types} vector.}
-  \item{directed}{Whether to create a directed graph, boolean
-    constant. Note that by default undirected graphs are created, as
-    this is more common for bipartite graphs.}
-  \item{graph}{The input graph.}
-}
-\details{
-  Bipartite graphs have a \code{type} vertex attribute in
-  igraph, this is boolean and \code{FALSE} for the vertices of the first
-  kind and \code{TRUE} for vertices of the second kind.
-
-  \code{graph.bipartite} basically does three things. First it checks
-  tha \code{edges} vector against the vertex \code{types}. Then it
-  creates a graph using the \code{edges} vector and finally it adds the
-  \code{types} vector as a vertex attribute called \code{type}.
-
-  \code{is.bipartite} checks whether the graph is bipartite or not. It
-  just checks whether the graph has a vertex attribute called
-  \code{type}.
-}
-\value{
-  \code{graph.bipartite} returns a bipartite igraph graph. In other
-  words, an igraph graph that has a vertex attribute named \code{type}.
-
-  \code{is.bipartite} returns a logical scalar.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph}} to create one-mode networks}
-\examples{
-g <- graph.bipartite( rep(0:1,length=10), c(1:10))
-print(g, v=TRUE)
-}
-\keyword{graphs}
diff --git a/man/graph.complementer.Rd b/man/graph.complementer.Rd
deleted file mode 100644
index 0fc8dab..0000000
--- a/man/graph.complementer.Rd
+++ /dev/null
@@ -1,40 +0,0 @@
-\name{graph.complementer}
-\alias{graph.complementer}
-\concept{Graph operators}
-\title{Complementer of a graph}
-\description{A complementer graph contains all edges that were not
-  present in the input graph.}
-\usage{
-graph.complementer(graph, loops=FALSE)
-}
-\arguments{
-  \item{graph}{The input graph, can be directed or undirected.}
-  \item{loops}{Logical constant, whether to generate loop edges.}
-}
-\details{
-  \code{graph.complementer} creates the complementer of a graph. Only
-  edges which are \emph{not} present in the original graph will be
-  included in the new graph.
-
-  \code{graph.complementer} keeps graph and vertex attriubutes, edge
-  attributes are lost.  
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## Complementer of a ring
-g <- graph.ring(10)
-graph.complementer(g)
-
-## A graph and its complementer give together the full graph
-g <- graph.ring(10)
-gc <- graph.complementer(g)
-gu <- graph.union(g, gc)
-gu
-graph.isomorphic(gu, graph.full(vcount(g)))
-}
-\keyword{graphs}
diff --git a/man/graph.compose.Rd b/man/graph.compose.Rd
deleted file mode 100644
index a234631..0000000
--- a/man/graph.compose.Rd
+++ /dev/null
@@ -1,72 +0,0 @@
-\name{graph.compose}
-\alias{graph.compose}
-\alias{\%c\%}
-\concept{Graph operators}
-\title{Compose two graphs as binary relations}
-\description{Relational composition of two graph.}
-\usage{
-graph.compose(g1, g2, byname = "auto")
-}
-\arguments{
-  \item{g1}{The first input graph.}
-  \item{g2}{The second input graph.}
-  \item{byname}{A logical scalar, or the character scalar
-    \code{auto}. Whether to perform the operation based on symbolic
-    vertex names. If it is \code{auto}, that means \code{TRUE} if both
-    graphs are named and \code{FALSE} otherwise. A warning is generated
-    if \code{auto} and one graph, but not both graphs are named.}
-}
-\details{
-  \code{graph.compose} creates the relational composition of two
-  graphs. The new graph will contain an (a,b) edge only if there is a
-  vertex c, such that edge (a,c) is included in the first graph and
-  (c,b) is included in the second graph. The corresponding operator is
-  \%c\%.
-
-  The function gives an error if one of the input graphs is directed and
-  the other is undirected.
-
-  If the \code{byname} argument is \code{TRUE} (or \code{auto} and the
-  graphs are all named), then the operation is performed based on
-  symbolic vertex names. Otherwise numeric vertex ids are used.
-
-  \code{graph.compose} keeps the attributes of both graphs. All
-  graph, vertex and edge attributes are copied to the result. If an
-  attribute is present in multiple graphs and would result a name clash,
-  then this attribute is renamed by adding suffixes: _1, _2, etc.
-
-  The \code{name} vertex attribute is treated specially if the operation
-  is performed based on symbolic vertex names. In this case \code{name}
-  must be present in both graphs, and it is not renamed in the result
-  graph.
-
-  Note that an edge in the result graph corresponds to two edges in the
-  input, one in the first graph, one in the second. This mapping is not
-  injective and several edges in the result might correspond to the same
-  edge in the first (and/or the second) graph. The edge attributes in
-  the result graph are updated accordingly.
-
-  Also note that the function may generate multigraphs, if there are more
-  than one way to find edges (a,b) in g1 and (b,c) in g2 for an edge
-  (a,c) in the result. See \code{\link{simplify}} if you want to get rid
-  of the multiple edges.
-
-  The function may create loop edges, if edges (a,b) and (b,a) are
-  present in g1 and g2, respectively, then (a,a) is included in the
-  result. See \code{\link{simplify}} if you want to get rid of the
-  self-loops.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g1 <- graph.ring(10)
-g2 <- graph.star(10, mode="undirected")
-gc <- graph.compose(g1, g2)
-str(gc)
-str(simplify(gc))
-}
-\keyword{graphs}
diff --git a/man/graph.constructors.Rd b/man/graph.constructors.Rd
deleted file mode 100644
index 77a0a0a..0000000
--- a/man/graph.constructors.Rd
+++ /dev/null
@@ -1,176 +0,0 @@
-\name{graph.constructors}
-\alias{graph.constructors}
-\alias{graph.empty}
-\alias{graph}
-\alias{graph.star}
-\alias{graph.lattice}
-\alias{graph.ring}
-\alias{graph.tree}
-\alias{graph.full}
-\alias{graph.full.citation}
-\alias{graph.atlas}
-\alias{graph.edgelist}
-\alias{graph.extended.chordal.ring}
-\concept{Tree}
-\concept{Lattice}
-\concept{Star graph}
-\concept{Graph Atlas}
-\concept{Empty graph}
-\concept{Full graph}
-\title{Various methods for creating graphs}
-\description{These method can create various (mostly regular) graphs:
-  empty graphs, graphs with the given edges, graphs from adjacency
-  matrices, star graphs, lattices, rings, trees.}
-\usage{
-graph.empty(n=0, directed=TRUE)
-graph(edges, n=max(edges), directed=TRUE)
-graph.star(n, mode = c("in", "out", "mutual", "undirected"), center = 1)
-graph.lattice(dimvector = NULL, length = NULL, dim = NULL, nei = 1,
-              directed = FALSE, mutual = FALSE, circular = FALSE, \dots)
-graph.ring(n, directed = FALSE, mutual = FALSE, circular=TRUE)
-graph.tree(n, children = 2, mode=c("out", "in", "undirected"))
-graph.full(n, directed = FALSE, loops = FALSE)
-graph.full.citation(n, directed = TRUE)
-graph.atlas(n)
-graph.edgelist(el, directed=TRUE)
-graph.extended.chordal.ring(n, w)
-}
-\arguments{
-  \item{edges}{Numeric vector defining the edges, the first edge points
-    from the first element to the second, the second edge from the third
-  to the fourth, etc.}
-  \item{directed}{Logical, if TRUE a directed graph will be
-    created. Note that for while most constructors the default is TRUE,
-    for \code{graph.lattice} and \code{graph.ring} it is FALSE. For
-    \code{graph.star} the \code{mode} argument should be used for
-    creating an undirected graph.}
-  \item{n}{The number of vertices in the graph for most functions.
-
-    For \code{graph} this parameter is ignored if there is a bigger
-    vertex id in \code{edges}. This means that for this function it is
-    safe to supply zero here if the vertex with the largest id is not an
-    isolate.
-
-    For \code{graph.atlas} this is the number (id) of the graph to
-    create. 
-  }
-  \item{mode}{
-    For \code{graph.star} it defines the direction of the
-    edges, \code{in}: the edges point \emph{to} the center, \code{out}:
-    the edges point \emph{from} the center, \code{mutual}: a directed
-    star is created with mutual edges, \code{undirected}: the edges
-    are undirected.
-
-    For \code{igraph.tree} this parameter defines the direction of the
-    edges. \code{out} indicates that the edges point from the parent to
-    the children, \code{in} indicates that they point from the children
-    to their parents, while \code{undirected} creates an undirected
-    graph. 
-  }
-  \item{center}{For \code{graph.star} the center vertex of the graph, by
-    default the first vertex.}
-  \item{dimvector}{A vector giving the size of the lattice in each
-    dimension, for \code{graph.lattice}.}
-  \item{nei}{The distance within which (inclusive) the neighbors on the
-    lattice will be connected. This parameter is not used right now.}
-  \item{mutual}{Logical, if TRUE directed lattices will be mutually
-    connected.} 
-  \item{circular}{Logical, if TRUE the lattice or ring will be circular.}
-  \item{length}{Integer constant, for regular lattices, the size of the
-    lattice in each dimension.}
-  \item{dim}{Integer constant, the dimension of the lattice.}
-  \item{children}{Integer constant, the number of children of a vertex
-    (except for leafs) for \code{graph.tree}.}
-  \item{loops}{If TRUE also loops edges (self edges) are added.}
-  \item{graph}{An object.}
-  \item{el}{An edge list, a two column matrix, character or numeric. See
-    details below.}
-  \item{w}{A matrix which specifies the extended chordal ring. See
-    details below.}
-  \item{\dots}{Currently ignored.}
-}
-\details{All these functions create graphs in a deterministic way.
-
-  \code{graph.empty} is the simplest one, this creates an empty graph.
-
-  \code{graph} creates a graph with the given edges.
-
-  \code{graph.star} creates a star graph, in this every single vertex is
-  connected to the center vertex and nobody else.
-
-  \code{graph.lattice} is a flexible function, it can create lattices of
-  arbitrary dimensions, periodic or unperiodic ones. It has two
-  forms. In the first form you only supply \code{dimvector}, but not
-  \code{length} and \code{dim}. In the second form you omit
-  \code{dimvector} and supply \code{length} and \code{dim}.
-
-  \code{graph.ring} is actually a special case of \code{graph.lattice},
-  it creates a one dimensional circular lattice.
-
-  \code{graph.tree} creates regular trees.
-
-  \code{graph.full} simply creates full graphs.
-
-  \code{graph.full.citation} creates a full citation graph. This is a
-  directed graph, where every i->j edge is present if and only if j<i.
-  If \code{directed=FALSE} then the graph is just a full graph.
-  
-  \code{graph.atlas} creates graphs from the book An Atlas of Graphs by
-  Roland C. Read and Robin J. Wilson. The atlas contains all undirected
-  graphs with up to seven vertices, numbered from 0 up to 1252. The
-  graphs are listed: 
-  \enumerate{
-    \item in increasing order of number of nodes;
-    \item for a fixed number of nodes, in increasing order of the number
-      of edges;
-    \item for fixed numbers of nodes and edges, in increasing order of
-      the degree sequence, for example 111223 < 112222;
-    \item for fixed degree sequence, in increasing number of
-      automorphisms.
-  }
-
-  \code{graph.edgelist} creates a graph from an edge list. Its argument
-  is a two-column matrix, each row defines one edge. If it is 
-  a numeric matrix then its elements are interpreted as vertex ids. If
-  it is a character matrix then it is interpreted as symbolic vertex
-  names and a vertex id will be assigned to each name, and also a
-  \code{name} vertex attribute will be added.
-  
-  \code{graph.extended.chordal.ring} creates an extended chordal ring.
-  An extended chordal ring is regular graph, each node has the same
-  degree. It can be obtained from a simple ring by adding some extra
-  edges specified by a matrix. Let p denote the number of columns in
-  the \sQuote{\code{W}} matrix. The extra edges of vertex \code{i}
-  are added according to column \code{i mod p} in
-  \sQuote{\code{W}}. The number of extra edges is the number
-  of rows in \sQuote{\code{W}}: for each row \code{j} an edge
-  \code{i->i+w[ij]} is added if \code{i+w[ij]} is less than the number
-  of total nodes. See also Kotsis, G: Interconnection Topologies for
-  Parallel Processing Systems, PARS Mitteilungen 11, 1-6, 1993.
-
-  
-}
-\value{Every function documented here returns a \code{graph} object.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.adjacency}} to create graphs from adjacency
-  matrices, \code{\link{graph.formula}} for a handy way to create small
-  graphs, \code{\link{graph.data.frame}} for an easy way to create
-  graphs with many edge/vertex attributes.
-}
-\examples{
-g1 <- graph.empty()
-g2 <- graph( c(1,2,2,3,3,4,5,6), directed=FALSE )
-g5 <- graph.star(10, mode="out")
-g6 <- graph.lattice(c(5,5,5))
-g7 <- graph.lattice(length=5, dim=3)
-g8 <- graph.ring(10)
-g9 <- graph.tree(10, 2)
-g10 <- graph.full(5, loops=TRUE)
-g11 <- graph.full.citation(10)
-g12 <- graph.atlas(sample(0:1252, 1))
-el <- matrix( c("foo", "bar", "bar", "foobar"), nc=2, byrow=TRUE)
-g13 <- graph.edgelist(el)
-g15 <- graph.extended.chordal.ring(15, matrix(c(3,12,4,7,8,11), nr=2))
-}
-\keyword{graphs}
diff --git a/man/graph.data.frame.Rd b/man/graph.data.frame.Rd
deleted file mode 100644
index 719521b..0000000
--- a/man/graph.data.frame.Rd
+++ /dev/null
@@ -1,110 +0,0 @@
-\name{graph.data.frame}
-\alias{graph.data.frame}
-\alias{get.data.frame}
-\concept{Data frame}
-\title{Creating igraph graphs from data frames or vice-versa}
-\description{
-  This function creates an igraph graph from one or two data frames
-  containing the (symbolic) edge list and edge/vertex attributes.
-}
-\usage{
-graph.data.frame(d, directed=TRUE, vertices=NULL)
-get.data.frame(x, what=c("edges", "vertices", "both"))
-}
-\arguments{
-  \item{d}{A data frame containing a symbolic edge list in the first two
-    columns. Additional columns are considered as edge attributes.
-    Since version 0.7 this argument is coerced to a data frame with
-    \code{as.data.frame}.}
-  \item{directed}{Logical scalar, whether or not to create a directed graph.}
-  \item{vertices}{A data frame with vertex metadata, or \code{NULL}. See
-    details below. Since version 0.7 this argument is coerced to a data
-    frame with \code{as.data.frame}, if not \code{NULL}.}
-  \item{x}{An igraph object.}
-  \item{what}{Character constant, whether to return info about vertices,
-    edges, or both. The default is \sQuote{edges}.}
-}
-\details{
-  \code{graph.data.frame} creates igraph graphs from one or two data
-  frames. It has two modes of operatation, depending whether the
-  \code{vertices} argument is \code{NULL} or not.
-
-  If \code{vertices} is \code{NULL}, then the first two columns of
-  \code{d} are used as a symbolic edge list and additional columns as
-  edge attributes. The names of the attributes are taken from the names
-  of the columns.
-
-  If \code{vertices} is not \code{NULL}, then it must be a data frame
-  giving vertex metadata. The first column of \code{vertices} is assumed
-  to contain symbolic vertex names, this will be added to the graphs as
-  the \sQuote{\code{name}} vertex attribute. Other columns will be added
-  as additional vertex attributes. If \code{vertices} is not \code{NULL}
-  then the symbolic edge list given in \code{d} is checked to contain
-  only vertex names listed in \code{vertices}.
-
-  Typically, the data frames are exported from some speadsheat software
-  like Excel and are imported into R via \code{\link{read.table}},
-  \code{\link{read.delim}} or \code{\link{read.csv}}.
-
-  \code{get.data.frame} converts the igraph graph into one or more data
-  frames, depending on the \code{what} argument.
-
-  If the \code{what} argument is \code{edges} (the default), then the
-  edges of the graph and also the edge attributes are returned. The
-  edges will be in the first two columns, named \code{from} and
-  \code{to}. (This also denotes edge direction for directed graphs.)
-  For named graphs, the vertex names will be included in these columns,
-  for other graphs, the numeric vertex ids. The edge attributes will be
-  in the other columns. It is not a good idea to have an edge attribute
-  named \code{from} or \code{to}, because then the column named in the
-  data frame will not be unique. The edges are listed in the order of
-  their numeric ids.
-
-  If the \code{what} argument is \code{vertices}, then vertex attributes
-  are returned. Vertices are listed in the order of their numeric vertex
-  ids.
-
-  If the \code{what} argument is \code{both}, then both vertex and edge
-  data is returned, in a list with named entries \code{vertices} and
-  \code{edges}.
-}
-\note{
-  For \code{graph.data.frame} \code{NA} elements in the first two
-  columns \sQuote{d} are replaced by the string \dQuote{NA} before
-  creating the graph. This means that all \code{NA}s will correspond to
-  a single vertex. 
-
-  \code{NA} elements in the first column of \sQuote{vertices} are also
-  replaced by the string \dQuote{NA}, but the rest of \sQuote{vertices}
-  is not touched. In other words, vertex names (=the first column)
-  cannot be \code{NA}, but other vertex attributes can.
-}
-\value{
-  An igraph graph object for \code{graph.data.frame}, and either a data
-  frame or a list of two data frames named \code{edges} and
-  \code{vertices} for \code{as.data.frame}.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{graph.constructors}} and
-  \code{\link{graph.formula}} for other ways to create graphs,
-  \code{\link{read.table}} to read in tables from files.}
-\examples{
-## A simple example with a couple of actors
-## The typical case is that these tables are read in from files....
-actors <- data.frame(name=c("Alice", "Bob", "Cecil", "David",
-                            "Esmeralda"),
-                     age=c(48,33,45,34,21),
-                     gender=c("F","M","F","M","F"))
-relations <- data.frame(from=c("Bob", "Cecil", "Cecil", "David",
-                               "David", "Esmeralda"),
-                        to=c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"),
-                        same.dept=c(FALSE,FALSE,TRUE,FALSE,FALSE,TRUE),
-                        friendship=c(4,5,5,2,1,1), advice=c(4,5,5,4,2,3))
-g <- graph.data.frame(relations, directed=TRUE, vertices=actors)
-print(g, e=TRUE, v=TRUE)
-
-## The opposite operation
-get.data.frame(g, what="vertices")
-get.data.frame(g, what="edges")
-}
-\keyword{graphs}
diff --git a/man/graph.de.bruijn.Rd b/man/graph.de.bruijn.Rd
deleted file mode 100644
index 25e335c..0000000
--- a/man/graph.de.bruijn.Rd
+++ /dev/null
@@ -1,38 +0,0 @@
-\name{graph.de.bruijn}
-\alias{graph.de.bruijn}
-\concept{De Bruijn graph}
-\title{De Bruijn graphs.}
-\description{De Bruijn graphs are labeled graphs representing the
-  overlap of strings. }
-\usage{
-graph.de.bruijn(m,n)
-}
-\arguments{
-  \item{m}{Integer scalar, the size of the alphabet. See details below.}
-  \item{n}{Integer scalar, the length of the labels. See details below.}
-}
-\details{
- A de Bruijn graph represents relationships between strings. An alphabet
- of \code{m} letters are used and strings of length \code{n} are considered. 
- A vertex corresponds to every possible string and there is a directed edge
- from vertex \code{v} to vertex \code{w} if the string of \code{v} can
- be transformed into the string of \code{w} by removing its first letter
- and appending a letter to it.
- 
- Please note that the graph will have \code{m} to the power \code{n}
- vertices and even more edges, so probably you don't want to supply too
- big numbers for \code{m} and \code{n}.
- 
- De Bruijn graphs have some interesting properties, please see another source,
- eg. Wikipedia for details.   
-}
-\value{A graph object.}
-\author{Gabor Csardi <csardi.gabor at gmail.com>}
-\seealso{\code{\link{graph.kautz}}, \code{\link{line.graph}}}
-\examples{
-# de Bruijn graphs can be created recursively by line graphs as well 
-g <- graph.de.bruijn(2,1)
-graph.de.bruijn(2,2)
-line.graph(g)
-}
-\keyword{graphs}
diff --git a/man/graph.density.Rd b/man/graph.density.Rd
deleted file mode 100644
index 6a6dee8..0000000
--- a/man/graph.density.Rd
+++ /dev/null
@@ -1,44 +0,0 @@
-\name{graph.density}
-\alias{graph.density}
-\concept{Graph density}
-\title{Graph density}
-\description{The density of a graph is the ratio of the number of edges
-  and the number of possible edges.}
-\usage{
-graph.density(graph, loops=FALSE)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{loops}{Logical constant, whether to allow loop edges in the
-    graph. If this is TRUE then self loops are considered to be possible. If
-    this is FALSE then we assume that the graph does not contain any
-    loop edges and that loop edges are not meaningful.}
-}
-\details{
-  Note that this function may return strange results for graph with
-  multiple edges, density is ill-defined for graphs with multiple
-  edges. 
-}
-\value{
-  A real constant. This function returns \code{NaN} (=0.0/0.0) for an
-  empty graph with zero vertices.
-}
-\references{
-  Wasserman, S., and Faust, K.  (1994).  Social Network Analysis:
-  Methods and Applications.  Cambridge: Cambridge University Press.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{vcount}}, \code{\link{ecount}},
-  \code{\link{simplify}} to get rid of the multiple and/or loop edges.}
-\examples{
-g1 <- graph.empty(n=10)
-g2 <- graph.full(n=10)
-g3 <- erdos.renyi.game(n=10, 0.4)
-
-# loop edges
-g <- graph( c(1,2, 2,2, 2,3) )
-graph.density(g, loops=FALSE)              # this is wrong!!!
-graph.density(g, loops=TRUE)               # this is right!!!
-graph.density(simplify(g), loops=FALSE)    # this is also right, but different
-}
-\keyword{graphs}
diff --git a/man/graph.dfs.Rd b/man/graph.dfs.Rd
deleted file mode 100644
index fac1253..0000000
--- a/man/graph.dfs.Rd
+++ /dev/null
@@ -1,102 +0,0 @@
-\name{graph.dfs}
-\alias{graph.dfs}
-\title{Depth-first search}
-\description{Depth-first search is an algorithm to traverse a graph. It
-  starts from a root vertex and tries to go quickly as far from as possible.}
-\usage{
-graph.dfs (graph, root, neimode = c("out", "in", "all", "total"), 
-    unreachable = TRUE, order = TRUE, order.out = FALSE,
-    father = FALSE, dist = FALSE, in.callback = NULL,
-    out.callback = NULL, extra = NULL, rho = parent.frame()) 
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{root}{The single root vertex to start the search from. }
-  \item{neimode}{For directed graphs specifies the type of edges to
-    follow. \sQuote{out} follows outgoing, \sQuote{in} incoming
-    edges. \sQuote{all} ignores edge directions
-    completely. \sQuote{total} is a synonym for \sQuote{all}. This
-    argument is ignored for undirected graphs.}
-  \item{unreachable}{Logical scalar, whether the search should visit
-    the vertices that are unreachable from the given root
-    vertex (or vertices). If \code{TRUE}, then additional searches are
-    performed until all vertices are visited.}
-  \item{order}{Logical scalar, whether to return the DFS ordering of the
-    vertices.}
-  \item{order.out}{Logical scalar, whether to return the ordering based
-    on leaving the subtree of the vertex.}
-  \item{father}{Logical scalar, whether to return the father of the
-    vertices.}
-  \item{dist}{Logical scalar, whether to return the distance from the
-    root of the search tree.}
-  \item{in.callback}{If not \code{NULL}, then it must be callback
-    function. This is called whenever a vertex is visited. See details
-    below.}
-  \item{out.callback}{If not \code{NULL}, then it must be callback
-    function. This is called whenever the subtree of a vertex is
-    completed by the algorithm. See details below.}
-  \item{extra}{Additional argument to supply to the callback function.}
-  \item{rho}{The environment in which the callback function is
-    evaluated.}
-}
-\details{
-  The callback functions must have the following arguments:
-  \describe{
-    \item{graph}{The input graph is passed to the callback function
-      here.}
-    \item{data}{A named numeric vector, with the following entries:
-      \sQuote{vid}, the vertex that was just visited and \sQuote{dist},
-      its distance from the root of the search tree.}
-    \item{extra}{The extra argument.}
-  }
-  See examples below on how to use the callback functions.
-}
-\value{
-  A named list with the following entries:
-  \item{root}{Numeric scalar. The root vertex that was used as the
-    starting point of the search.}
-  \item{neimode}{Character scalar. The \code{neimode} argument of the
-    function call. Note that for undirected graphs this is always
-    \sQuote{all}, irrespectively of the supplied value.}
-  \item{order}{Numeric vector. The vertex ids, in the order in which
-    they were visited by the search.}
-  \item{order.out}{Numeric vector, the vertex ids, in the order of the
-    completion of their subtree.}
-  \item{father}{Numeric vector. The father of each vertex, i.e. the
-    vertex it was discovered from.}
-  \item{dist}{Numeric vector, for each vertex its distance from the root
-    of the search tree.}
-
-  Note that \code{order}, \code{order.out}, \code{father}, and
-  \code{dist} might be \code{NULL} if their corresponding argument is
-  \code{FALSE}, i.e. if their calculation is not requested.  
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{ \code{\link{graph.bfs}} for breadth-first search.}
-\examples{
-## A graph with two separate trees
-graph.dfs(graph.tree(10) \%du\% graph.tree(10), root=1, "out",
-          TRUE, TRUE, TRUE, TRUE)
-
-## How to use a callback
-f.in <- function(graph, data, extra) {
-  cat("in:", paste(collapse=", ", data), "\n")
-  FALSE
-}
-f.out <- function(graph, data, extra) {
-  cat("out:", paste(collapse=", ", data), "\n")
-  FALSE
-}
-tmp <- graph.dfs(graph.tree(10), root=1, "out",
-                 in.callback=f.in, out.callback=f.out)
-
-## Terminate after the first component, using a callback
-f.out <- function(graph, data, extra) {
- data['vid'] == 1
-}
-tmp <- graph.dfs(graph.tree(10) \%du\% graph.tree(10), root=1,
-                 out.callback=f.out)
-
-}
-\keyword{graphs}
diff --git a/man/graph.difference.Rd b/man/graph.difference.Rd
deleted file mode 100644
index 6579e2a..0000000
--- a/man/graph.difference.Rd
+++ /dev/null
@@ -1,55 +0,0 @@
-\name{graph.difference}
-\alias{graph.difference}
-\alias{\%m\%}
-\concept{Graph operators}
-\title{Difference of graphs}
-\description{The difference of two graphs are created.}
-\usage{
-graph.difference(big, small, byname = "auto")
-}
-\arguments{
-  \item{big}{The left hand side argument of the minus operator. A
-    directed or undirected graph.}
-  \item{small}{The right hand side argument of the minus operator. A
-    directed ot undirected graph.}
-  \item{byname}{A logical scalar, or the character scalar
-    \code{auto}. Whether to perform the operation based on symbolic
-    vertex names. If it is \code{auto}, that means \code{TRUE} if both
-    graphs are named and \code{FALSE} otherwise. A warning is generated
-    if \code{auto} and one graph, but not both graphs are named.}
-}
-\details{
-  \code{graph.difference} creates the difference of two graphs. Only
-  edges present in the first graph but not in the second will be be
-  included in the new graph. The corresponding operator is \%m\%.
-
-  If the \code{byname} argument is \code{TRUE} (or \code{auto} and the
-  graphs are all named), then the operation is performed based on
-  symbolic vertex names. Otherwise numeric vertex ids are used.
-  
-  \code{graph.difference} keeps all attributes
-  (graph, vertex and edge) of the first graph.
-
-  Note that \code{big} and \code{small} must both be directed or both be
-  undirected, otherwise an error message is given.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## Create a wheel graph
-wheel <- graph.union(graph.ring(10),
-                     graph.star(11, center=11, mode="undirected"))
-V(wheel)$name <- letters[seq_len(vcount(wheel))]
-
-## Subtract a star graph from it
-sstar <- graph.star(6, center=6, mode="undirected")
-V(sstar)$name <- letters[c(1,3,5,7,9,11)]
-G <- wheel \%m\% sstar
-str(G)
-plot(G, layout=layout.auto(wheel))
-}
-\keyword{graphs}
diff --git a/man/graph.disjoint.union.Rd b/man/graph.disjoint.union.Rd
deleted file mode 100644
index 87eca95..0000000
--- a/man/graph.disjoint.union.Rd
+++ /dev/null
@@ -1,49 +0,0 @@
-\name{graph.disjoint.union}
-\alias{graph.disjoint.union}
-\alias{\%du\%}
-\concept{Graph operators}
-\title{Disjoint union of graphs}
-\description{The union of two or more graphs are created. The graphs are
-  assumed to have disjoint vertex sets.}
-\usage{
-graph.disjoint.union(\dots)
-}
-\arguments{
-  \item{\dots}{Graph objects or lists of graph objects.}
-}
-\details{
-  \code{graph.disjoint.union} creates a union of two or more disjoint
-  graphs. Thus first the vertices in the second, third, etc. graphs are
-  relabeled to have completely disjoint graphs. Then a simple union is
-  created. This function can also be used via the \%du\% operator.  
-  
-  \code{graph.disjont.union} handles graph, vertex and edge attributes.
-  In particular, it merges vertex and edge
-  attributes using the basic \code{c()} function. For graphs that lack
-  some vertex/edge attribute, the corresponding values in the new graph
-  are set to \code{NA}. Graph attributes are simply copied to the
-  result. If this would result a name clash, then they are renamed by
-  adding suffixes: _1, _2, etc.
-
-  Note that if both graphs have vertex names (ie. a \code{name} vertex
-  attribute), then the concatenated vertex names might be non-unique
-  in the result. A warning is given if this happens.
-  
-  An error is generated if some input graphs are directed and others are
-  undirected.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## A star and a ring
-g1 <- graph.star(10, mode="undirected")
-V(g1)$name <- letters[1:10]
-g2 <- graph.ring(10)
-V(g2)$name <- letters[11:20]
-str(g1 \%du\% g2)
-}
-\keyword{graphs}
diff --git a/man/graph.diversity.Rd b/man/graph.diversity.Rd
deleted file mode 100644
index e9c15a1..0000000
--- a/man/graph.diversity.Rd
+++ /dev/null
@@ -1,57 +0,0 @@
-\name{graph.diversity}
-\alias{graph.diversity}
-\concept{Entropy}
-\title{Graph diversity}
-\description{
-  Calculates a measure of diversity for all vertices.
-}
-\usage{
-graph.diversity(graph, weights = NULL, vids = V(graph))
-}
-\arguments{
-  \item{graph}{The input graph. Edge directions are ignored.}
-  \item{weights}{\code{NULL}, or the vector of edge weights to use for
-    the computation. If \code{NULL}, then the \sQuote{weight} attibute
-    is used. Note that this measure is not defined for unweighted
-    graphs.}
-  \item{vids}{The vertex ids for which to calculate the measure.}
-}
-\details{
-  The diversity of a vertex is defined as the (scaled) Shannon entropy
-  of the weights of its incident edges:
-  \deqn{D(i)=\frac{H(i)}{\log k_i}}{D(i)=H(i)/log(k[i])}
-  and
-  \deqn{H(i)=-\sum_{j=1}^{k_i} p_{ij}\log p_{ij},}{%
-    H(i) = -sum(p[i,j] log(p[i,j]), j=1..k[i]),}
-  where
-  \deqn{p_{ij}=\frac{w_{ij}}{\sum_{l=1}^{k_i}}V_{il},}{%
-    p[i,j] = w[i,j] / sum(w[i,l], l=1..k[i]),}
-  and \eqn{k_i}{k[i]} is the (total) degree of vertex \eqn{i},
-  \eqn{w_{ij}}{w[i,j]} is the weight of the edge(s) between vertices
-  \eqn{i} and \eqn{j}.
-
-  For vertices with degree less than two the function returns
-  \code{NaN}.  
-}
-\value{
-  A numeric vector, its length is the number of vertices.
-}
-\references{
-  Nathan Eagle, Michael Macy and Rob Claxton: Network Diversity and
-  Economic Development, \emph{Science} \bold{328}, 1029--1031, 2010.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g1 <- erdos.renyi.game(20, 2/20)
-g2 <- erdos.renyi.game(20, 2/20)
-g3 <- erdos.renyi.game(20, 5/20)
-E(g1)$weight <- 1
-E(g2)$weight <- runif(ecount(g2))
-E(g3)$weight <- runif(ecount(g3))
-graph.diversity(g1)
-graph.diversity(g2)
-graph.diversity(g3)
-}
-\keyword{graphs}
-
diff --git a/man/graph.eigen.Rd b/man/graph.eigen.Rd
deleted file mode 100644
index 01e0c20..0000000
--- a/man/graph.eigen.Rd
+++ /dev/null
@@ -1,81 +0,0 @@
-\name{graph.eigen}
-\alias{graph.eigen}
-\alias{igraph.eigen.default}
-\concept{Eigenvalues}
-\concept{Eigenvectors}
-\title{Eigenvalues and eigenvectors of the adjacency matrix of a graph}
-\description{
-  Calculate selected eigenvalues and eigenvectors of a (supposedly
-  sparse) graph.
-}
-\usage{
-graph.eigen (graph, algorithm = c("arpack", "auto", "lapack", "comp_auto", 
-    "comp_lapack", "comp_arpack"), which = list(),
-    options = igraph.arpack.default)
-igraph.eigen.default
-}
-\arguments{
-  \item{graph}{The input graph, can be directed or undirected.}
-  \item{algorithm}{The algorithm to use. Currently only \code{arpack} is
-    implemented, which uses the ARPACK solver. See also
-    \code{\link{arpack}}.}
-  \item{which}{A list to specify which eigenvalues and eigenvectors to
-    calculate. By default the leading (i.e. largest magnitude)
-    eigenvalue and the corresponding eigenvector is calculated.}
-  \item{options}{Options for the ARPACK solver. See
-    \code{\link{igraph.arpack.default}}.}
-}
-\details{
-  The \code{which} argument is a list and it specifies which eigenvalues
-  and corresponding eigenvectors to calculate: There are eight options:
-  \enumerate{
-    \item Eigenvalues with the largest magnitude. Set \code{pos} to
-    \code{LM}, and \code{howmany} to the number of eigenvalues you
-    want.
-    \item Eigenvalues with the smallest magnitude. Set \code{pos} to
-    \code{SM} and \code{howmany} to the number of eigenvalues you want.
-    \item Largest eigenvalues. Set \code{pos} to \code{LA} and
-    \code{howmany} to the number of eigenvalues you want.
-    \item Smallest eigenvalues. Set \code{pos} to \code{SA} and
-    \code{howmany} to the number of eigenvalues you want.
-    \item Eigenvalues from both ends of the spectrum. Set \code{pos} to
-    \code{BE} and \code{howmany} to the number of eigenvalues you
-    want. If \code{howmany} is odd, then one more eigenvalue is returned
-    from the larger end.
-    \item Selected eigenvalues. This is not (yet) implemented currently.
-    \item Eigenvalues in an interval. This is not (yet) implemented.
-    \item All eigenvalues. This is not implemented yet. The standard
-    \code{eigen} function does a better job at this, anyway.
-  }
-  
-  Note that ARPACK might be unstable for graphs with multiple
-  components, e.g. graphs with isolate vertices.
-}
-\value{
-  Depends on the algorithm used.
-
-  For \code{arpack} a list with three entries is returned:
-  \item{options}{See the return value for \code{arpack} for a complete
-    description.}
-  \item{values}{Numeric vector, the eigenvalues.}
-  \item{vectors}{Numeric matrix, with the eigenvectors as columns.}
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{\code{\link{get.adjacency}} to create a (sparse) adjacency
-  matrix.}
-\examples{
-## Small example graph, leading eigenvector by default
-kite <- graph.famous("Krackhardt_kite")
-graph.eigen(kite)[c("values", "vectors")]
-
-## Double check
-eigen(get.adjacency(kite, sparse=FALSE))$vectors[,1]
-
-## Should be the same as 'evcent' (but rescaled)
-cor(evcent(kite)$vector, graph.eigen(kite)$vectors)
-
-## Smallest eigenvalues
-graph.eigen(kite, which=list(pos="SM", howmany=2))$values
-}
-\keyword{graphs}
diff --git a/man/graph.famous.Rd b/man/graph.famous.Rd
deleted file mode 100644
index fc08faa..0000000
--- a/man/graph.famous.Rd
+++ /dev/null
@@ -1,133 +0,0 @@
-\encoding{UTF-8}
-\name{graph.famous}
-\alias{graph.famous}
-\title{Creating named graphs}
-\description{There are some famous, named graphs, sometimes
-  counterexamples to some conjecture or unique graphs with given
-  features. These can be created with this function}
-\usage{
-graph.famous(name)
-}
-\arguments{
-  \item{name}{Character constant giving the name of the graph. It is
-    case insensitive.}
-}
-\details{
-  \code{graph.famous} knows the following graphs:
-  \describe{
-    \item{Bull}{The bull graph, 5 vertices, 5 edges, resembles to the
-      head of a bull if drawn properly.}
-    \item{Chvatal}{This is the smallest triangle-free graph that is
-      both 4-chromatic and 4-regular. According to the Grunbaum
-      conjecture there exists an m-regular, m-chromatic graph
-      with n vertices for every m>1 and n>2. The Chvatal graph
-      is an example for m=4 and n=12. It has 24 edges.}
-    \item{Coxeter}{A non-Hamiltonian cubic symmetric graph with 28
-      vertices and 42 edges.}
-    \item{Cubical}{The Platonic graph of the cube. A convex regular
-      polyhedron with 8 vertices and 12 edges.}
-    \item{Diamond}{A graph with 4 vertices and 5 edges, resembles to a
-      schematic diamond if drawn properly.}
-    \item{Dodecahedral, Dodecahedron}{Another Platonic solid
-      with 20 vertices and 30 edges.}
-    \item{Folkman}{The semisymmetric graph with minimum number of
-      vertices, 20 and 40 edges. A semisymmetric graph is
-      regular, edge transitive and not vertex transitive.}
-    \item{Franklin}{This is a graph whose embedding to the Klein
-      bottle can be colored with six colors, it is a
-      counterexample to the neccessity of the Heawood
-      conjecture on a Klein bottle. It has 12 vertices and 18
-      edges.}
-    \item{Frucht}{The Frucht Graph is the smallest cubical graph
-      whose automorphism group consists only of the identity
-      element. It has 12 vertices and 18 edges.}
-    \item{Grotzsch}{The Grötzsch graph is a triangle-free graph with
-      11 vertices, 20 edges, and chromatic number 4. It is named after
-      German mathematician Herbert Grötzsch, and its existence
-      demonstrates that the assumption of planarity is necessary in
-      Grötzsch's theorem that every triangle-free planar
-      graph is 3-colorable.}
-    \item{Heawood}{The Heawood graph is an undirected graph with 14
-      vertices and 21 edges. The graph is cubic, and all cycles in the
-      graph have six or more edges. Every smaller cubic graph has shorter
-      cycles, so this graph is the 6-cage, the smallest cubic graph of
-      girth 6.}
-    \item{Herschel}{The Herschel graph is the smallest
-      nonhamiltonian polyhedral graph. It is the
-      unique such graph on 11 nodes, and has 18 edges.}
-    \item{House}{The house graph is a 5-vertex, 6-edge graph, the
-      schematic draw of a house if drawn properly, basicly a 
-      triangle of the top of a square.}
-    \item{HouseX}{The same as the house graph with an X in the square. 5
-      vertices and 8 edges.}
-    \item{Icosahedral, Icosahedron}{A Platonic solid with 12
-      vertices and 30 edges.}
-    \item{Krackhardt\_Kite}{A social network with 10 vertices and 18 edges.
-      Krackhardt, D. Assessing the Political Landscape:
-      Structure, Cognition, and Power in Organizations.
-      Admin. Sci. Quart. 35, 342-369, 1990.}
-    \item{Levi}{The graph is a 4-arc transitive cubic graph, it has
-      30 vertices and 45 edges.}
-    \item{McGee}{The McGee graph is the unique 3-regular 7-cage
-      graph, it has 24 vertices and 36 edges.}
-    \item{Meredith}{The Meredith graph is a quartic graph on 70
-      nodes and 140 edges that is a counterexample to the conjecture that
-      every 4-regular 4-connected graph is Hamiltonian.}
-    \item{Noperfectmatching}{A connected graph with 16 vertices and
-      27 edges containing no perfect matching. A matching in a graph
-      is a set of pairwise non-adjacent edges; that is, no two edges
-      share a common vertex. A perfect matching is a matching
-      which covers all vertices of the graph.}
-    \item{Nonline}{A graph whose connected components are the 9
-      graphs whose presence as a vertex-induced subgraph in a
-      graph makes a nonline graph. It has 50 vertices and 72 edges.}
-    \item{Octahedral, Octahedron}{Platonic solid with 6
-      vertices and 12 edges.} 
-    \item{Petersen}{A 3-regular graph with 10 vertices and 15 edges. It is
-      the smallest hypohamiltonian graph, ie. it is
-      non-hamiltonian but removing any single vertex from it makes it
-      Hamiltonian.}
-    \item{Robertson}{The unique (4,5)-cage graph, ie. a 4-regular
-      graph of girth 5. It has 19 vertices and 38 edges.}
-    \item{Smallestcyclicgroup}{A smallest nontrivial graph
-      whose automorphism group is cyclic. It has 9 vertices and
-      15 edges.}
-    \item{Tetrahedral, Tetrahedron}{Platonic solid with 4
-      vertices and 6 edges.}
-    \item{Thomassen}{The smallest hypotraceable graph,
-      on 34 vertices and 52 edges. A hypotracable graph does
-      not contain a Hamiltonian path but after removing any
-      single vertex from it the remainder always contains a
-      Hamiltonian path. A graph containing a Hamiltonian path
-      is called tracable.}
-    \item{Tutte}{Tait's Hamiltonian graph conjecture states that
-      every 3-connected 3-regular planar graph is Hamiltonian.
-      This graph is a counterexample. It has 46 vertices and 69
-      edges.}
-    \item{Uniquely3colorable}{Returns a 12-vertex, triangle-free
-      graph with chromatic number 3 that is uniquely
-      3-colorable.}
-    \item{Walther}{An identity graph with 25 vertices and 31
-      edges. An identity graph has a single graph automorphism,
-      the trivial one.}
-    \item{Zachary}{Social network of friendships between 34 members of a
-      karate club at a US university in the 1970s. See
-      W. W. Zachary, An information flow model for conflict and
-      fission in small groups, Journal of Anthropological
-      Research 33, 452-473 (1977).
-    }
-  }
-}
-\value{A graph object.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{graph}} can create arbitrary graphs, see also the other
-  functions on the its manual page for creating special graphs.
-}
-\examples{
-solids <- list(graph.famous("Tetrahedron"),
-               graph.famous("Cubical"),
-               graph.famous("Octahedron"),
-               graph.famous("Dodecahedron"),
-               graph.famous("Icosahedron"))
-}
-\keyword{graphs}
diff --git a/man/graph.formula.Rd b/man/graph.formula.Rd
deleted file mode 100644
index f45fbaa..0000000
--- a/man/graph.formula.Rd
+++ /dev/null
@@ -1,125 +0,0 @@
-\name{graph.formula}
-\alias{graph.formula}
-\title{Creating (small) graphs via a simple interface}
-\description{
-  This function is useful if you want to create a small (named) graph
-  quickly, it works for both directed and undirected graphs.
-}
-\usage{
-graph.formula(..., simplify = TRUE)
-}
-\arguments{
-  \item{...}{The formulae giving the structure of the graph, see details
-    below.}
-  \item{simplify}{Logical scalar, whether to call \code{\link{simplify}}
-    on the created graph. By default the graph is simplified, loop and
-    multiple edges are removed.}
-}
-\details{
-  \code{graph.formula} is very handy for creating small graphs quickly.
-  You need to supply one or more R expressions giving the structure of
-  the graph. The expressions consist of vertex names and edge
-  operators. An edge operator is a sequence of \sQuote{\code{-}} and
-  \sQuote{\code{+}} characters, the former is for the edges and the
-  latter is used for arrow heads. The edges can be arbitrarily long,
-  ie. you may use as many \sQuote{\code{-}} characters to \dQuote{draw}
-  them as you like.
-
-  If all edge operators consist of only \sQuote{\code{-}} characters
-  then the graph will be undirected, whereas a single \sQuote{\code{+}}
-  character implies a directed graph.
-
-  Let us see some simple examples. Without arguments the function
-  creates an empty graph:
-  \preformatted{
-    graph.formula()
-  }
-
-  A simple undirected graph with two vertices called \sQuote{A} and
-  \sQuote{B} and one edge only:
-  \preformatted{
-    graph.formula(A-B)
-  }
-
-  Remember that the length of the edges does not matter, so we could
-  have written the following, this creates the same graph:
-  \preformatted{
-    graph.formula( A-----B )
-  }
-
-  If you have many disconnected components in the graph, separate them
-  with commas. You can also give isolate vertices.
-  \preformatted{
-    graph.formula( A--B, C--D, E--F, G--H, I, J, K )
-  }
-
-  The \sQuote{\code{:}} operator can be used to define vertex sets. If
-  an edge operator connects two vertex sets then every vertex from the
-  first set will be connected to every vertex in the second set. The
-  following form creates a full graph, including loop edges:
-  \preformatted{
-    graph.formula( A:B:C:D -- A:B:C:D )
-  }
-
-  In directed graphs, edges will be created only if the edge operator
-  includes a arrow head (\sQuote{+}) \emph{at the end} of the edge:
-  \preformatted{
-    graph.formula( A -+ B -+ C )
-    graph.formula( A +- B -+ C )
-    graph.formula( A +- B -- C )
-  }
-  Thus in the third example no edge is created between vertices \code{B}
-  and \code{C}.
-
-  Mutual edges can be also created with a simple edge operator:
-  \preformatted{
-    graph.formula( A +-+ B +---+ C ++ D + E)
-  }
-  Note again that the length of the edge operators is arbitrary,
-  \sQuote{\code{+}}, \sQuote{\code{++}} and \sQuote{\code{+-----+}} have
-  exactly the same meaning.
-
-  If the vertex names include spaces or other special characters then
-  you need to quote them:
-  \preformatted{
-    graph.formula( "this is" +- "a silly" -+ "graph here" )
-  }
-  You can include any character in the vertex names this way, even
-  \sQuote{+} and \sQuote{-} characters.
-
-  See more examples below.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph}} for more general graph creation methods.}
-\examples{
-# A simple undirected graph
-g <- graph.formula( Alice-Bob-Cecil-Alice, Daniel-Cecil-Eugene, Cecil-Gordon )
-g
-
-# Another undirected graph, ":" notation
-g2 <- graph.formula( Alice-Bob:Cecil:Daniel, Cecil:Daniel-Eugene:Gordon )
-g2
-
-# A directed graph
-g3 <- graph.formula( Alice +-+ Bob --+ Cecil +-- Daniel,
-                     Eugene --+ Gordon:Helen )
-g3
-
-# A graph with isolate vertices
-g4 <- graph.formula( Alice -- Bob -- Daniel, Cecil:Gordon, Helen )
-g4
-V(g4)$name
-
-# "Arrows" can be arbitrarily long
-g5 <- graph.formula( Alice +---------+ Bob )
-g5
-
-# Special vertex names
-g6 <- graph.formula( "+" -- "-", "*" -- "/", "\%\%" -- "\%/\%" )
-g6
-}
-\keyword{graphs}
diff --git a/man/graph.full.bipartite.Rd b/man/graph.full.bipartite.Rd
deleted file mode 100644
index 73f2670..0000000
--- a/man/graph.full.bipartite.Rd
+++ /dev/null
@@ -1,39 +0,0 @@
-\name{graph.full.bipartite}
-\alias{graph.full.bipartite}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\title{Create a full bipartite graph}
-\description{Bipartite graphs are also called two-mode by some. This
-  function creates a bipartite graph in which every possible edge is
-  present.}
-\usage{
-graph.full.bipartite (n1, n2, directed = FALSE, mode = c("all", "out", "in")) 
-}
-\arguments{
-  \item{n1}{The number of vertices of the first kind.}
-  \item{n2}{The number of vertices of the second kind.}
-  \item{directed}{Logical scalar, whether the graphs is directed.}
-  \item{mode}{Scalar giving the kind of edges to create for directed
-    graphs. If this is \sQuote{\code{out}} then all vertices of the
-    first kind are connected to the others; \sQuote{\code{in}} specifies
-    the opposite direction; \sQuote{\code{all}} creates mutual
-    edges. This argument is ignored for undirected graphs.x}
-}
-\details{
-  Bipartite graphs have a \sQuote{\code{type}} vertex attribute in
-  igraph, this is boolean and \code{FALSE} for the vertices of the first
-  kind and \code{TRUE} for vertices of the second kind.
-}
-\value{
-  An igraph graph, with the \sQuote{\code{type}} vertex attribute set.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.full}} for creating one-mode full graphs}
-\examples{
-g <- graph.full.bipartite(2, 3)
-g2 <- graph.full.bipartite(2, 3, dir=TRUE)
-g3 <- graph.full.bipartite(2, 3, dir=TRUE, mode="in")
-g4 <- graph.full.bipartite(2, 3, dir=TRUE, mode="all")
-}
-\keyword{graphs}
diff --git a/man/graph.graphdb.Rd b/man/graph.graphdb.Rd
deleted file mode 100644
index 73f9b3c..0000000
--- a/man/graph.graphdb.Rd
+++ /dev/null
@@ -1,78 +0,0 @@
-\name{graph.graphdb}
-\alias{graph.graphdb}
-\concept{Graph database}
-\title{Load a graph from the graph database for testing graph
-  isomorphism.}
-\description{This function downloads a graph from a database created for
-  the evaluation of graph isomorphism testing algothitms.}
-\usage{
-graph.graphdb (url = NULL, prefix = "iso", type = "r001", nodes = NULL, 
-    pair = "A", which = 0, base = "http://cneurocvs.rmki.kfki.hu/graphdb/gzip", 
-    compressed = TRUE, directed = TRUE) 
-}
-\arguments{
-  \item{url}{If not \code{NULL} it is a complete URL with the file to import.}
-  \item{prefix}{Gives the prefix. See details below. Possible values:
-    \code{iso}, \code{i2}, \code{si4}, \code{si6}, \code{mcs10},
-    \code{mcs30}, \code{mcs50}, \code{mcs70}, \code{mcs90}.
-  }
-  \item{type}{Gives the graph type identifier. See details
-    below. Possible values: \code{r001}, \code{r005}, \code{r01},
-    \code{r02}, \code{m2D}, \code{m2Dr2}, \code{m2Dr4}, \code{m2Dr6}
-    \code{m3D}, \code{m3Dr2}, \code{m3Dr4}, \code{m3Dr6}, \code{m4D},
-    \code{m4Dr2}, \code{m4Dr4}, \code{m4Dr6}, \code{b03}, 
-    \code{b03m}, \code{b06}, \code{b06m}, \code{b09}, \code{b09m}.
-  }
-  \item{nodes}{The number of vertices in the graph.}
-  \item{pair}{Specifies which graph of the pair to read. Possible
-    values: \code{A} and \code{B}.}
-  \item{which}{Gives the number of the graph to read. For every graph
-    type there are a number of actual graphs in the database. This
-    argument specifies which one to read.}
-  \item{base}{The base address of the database. See details below.}
-  \item{compressed}{Logical constant, if TRUE than the file is expected
-    to be compressed by gzip. If \code{url} is \code{NULL} then a
-    \sQuote{\code{.gz}} suffix is added to the filename.}
-  \item{directed}{Logical constant, whether to create a directed graph.}
-}
-\details{
-  \code{graph.graphdb} reads a graph from the graph database from an FTP
-  or HTTP server or from a local copy. It has two modes of operation:
-
-  If the \code{url} argument is specified then it should the complete
-  path to a local or remote graph database file. In this case
-  we simply call \code{\link{read.graph}} with the proper arguments to
-  read the file.
-
-  If \code{url} is \code{NULL}, and this is the default, then the
-  filename is assembled from the \code{base}, \code{prefix}, \code{type},
-  \code{nodes}, \code{pair} and \code{which} arguments.
-
-  Unfortunately the original graph database homepage is now defunct,
-  but see its old version at
-  \url{http://web.archive.org/web/20090215182331/http://amalfi.dis.unina.it/graph/db/doc/graphdbat.html}
-  for the actual format of a graph database file and other information.
-}
-\value{
-  A new graph object.
-}
-\references{M. De Santo, P. Foggia, C. Sansone, M. Vento:
-  A large database of graphs and its use for benchmarking graph
-  isomorphism algorithms, \emph{Pattern Recognition Letters},
-  Volume 24, Issue 8 (May 2003)
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{read.graph}}, \code{\link{graph.isomorphic.vf2}}}
-\examples{
-\dontrun{
-g <- graph.graphdb(prefix="iso", type="r001", nodes=20, pair="A",
-  which=10, compressed=TRUE)
-g2 <- graph.graphdb(prefix="iso", type="r001", nodes=20, pair="B",
-  which=10, compressed=TRUE)
-graph.isomorphic.vf2(g, g2)	% should be TRUE
-g3 <- graph.graphdb(url=paste(sep="/",
-                              "http://cneurocvs.rmki.kfki.hu",
-                              "graphdb/gzip/iso/bvg/b06m",
-                              "iso_b06m_m200.A09.gz"))
-}}
-\keyword{graphs}
diff --git a/man/graph.incidence.Rd b/man/graph.incidence.Rd
deleted file mode 100644
index 915f176..0000000
--- a/man/graph.incidence.Rd
+++ /dev/null
@@ -1,73 +0,0 @@
-\name{graph.incidence}
-\alias{graph.incidence}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\title{Create graphs from an incidence matrix}
-\description{\code{graph.incidence} creates a bipartite igraph graph
-  from an incidence matrix.}
-\usage{
-graph.incidence(incidence, directed = FALSE, mode = c("all", "out", 
-    "in", "total"), multiple = FALSE, weighted = NULL, add.names = NULL)
-}
-\arguments{
-  \item{incidence}{The input incidence matrix. It can also be a sparse
-    matrix from the \code{Matrix} package.}
-  \item{directed}{Logical scalar, whether to create a directed graph.}
-  \item{mode}{A character constant, defines the direction of the edges
-    in directed graphs, ignored for undirected graphs. If
-    \sQuote{\code{out}}, then edges go from vertices of the first kind
-    (corresponding to rows in the incidence matrix) to vertices of the
-    second kind (columns in the incidence matrix). If
-    \sQuote{\code{in}}, then the opposite direction is used. If
-    \sQuote{\code{all}} or \sQuote{\code{total}}, then mutual edges are
-    created. }
-  \item{multiple}{Logical scalar, specifies how to interpret the matrix
-    elements. See details below.}
-  \item{weighted}{This argument specifies whether to create a weighted
-    graph from the incidence matrix. If it is \code{NULL} then an
-    unweighted graph is created and the \code{multiple} argument is used
-    to determine the edges of the graph. If it is a character
-    constant then for every non-zero matrix entry an edge is created and
-    the value of the entry is added as an edge attribute named by the
-    \code{weighted} argument. If it is \code{TRUE} then a weighted graph
-    is created and the name of the edge attribute will be
-    \sQuote{\code{weight}}.
-  }
-  \item{add.names}{A character constant, \code{NA} or
-    \code{NULL}. \code{graph.incidence} can add the row and column names
-    of the incidence matrix as vertex attributes. If this argument is
-    \code{NULL} (the default) and the incidence matrix has both row and
-    column names, then these are added as the \sQuote{\code{name}} vertex
-    attribute. If you want a different vertex attribute for this, then
-    give the name of the attributes as a character string. If this
-    argument is \code{NA}, then no vertex attributes (other than type)
-    will be added.
-  }
-}
-\details{
-  Bipartite graphs have a \sQuote{\code{type}} vertex attribute in
-  igraph, this is boolean and \code{FALSE} for the vertices of the first
-  kind and \code{TRUE} for vertices of the second kind.
-
- \code{graph.incidence} can operate in two modes, depending on the
- \code{multiple} argument. If it is \code{FALSE} then a single edge is
- created for every non-zero element in the incidence matrix. If
- \code{multiple} is \code{TRUE}, then the matrix elements are rounded up
- to the closest non-negative integer to get the number of edges to
- create between a pair of vertices.
-}
-\value{
-  A bipartite igraph graph. In other words, an igraph graph that has a
-  vertex attribute \code{type}. 
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.bipartite}} for another way to create
-  bipartite graphs}
-\examples{
-inc <- matrix(sample(0:1, 15, repl=TRUE), 3, 5)
-colnames(inc) <- letters[1:5]
-rownames(inc) <- LETTERS[1:3]
-graph.incidence(inc)
-}
-\keyword{graphs}
diff --git a/man/graph.intersection.Rd b/man/graph.intersection.Rd
deleted file mode 100644
index d4cfb13..0000000
--- a/man/graph.intersection.Rd
+++ /dev/null
@@ -1,56 +0,0 @@
-\name{graph.intersection}
-\alias{graph.intersection}
-\alias{\%s\%}
-\concept{Graph operators}
-\title{Intersection of graphs}
-\description{The intersection of two or more graphs are created.
-  The graphs may have identical or overlapping vertex sets.}
-\usage{
-graph.intersection(\dots, byname = "auto", keep.all.vertices = TRUE)
-}
-\arguments{
-  \item{\dots}{Graph objects or lists of graph objects.}
-  \item{byname}{A logical scalar, or the character scalar
-    \code{auto}. Whether to perform the operation based on symbolic
-    vertex names. If it is \code{auto}, that means \code{TRUE} if all
-    graphs are named and \code{FALSE} otherwise. A warning is generated
-    if \code{auto} and some (but not all) graphs are named.}
-  \item{keep.all.vertices}{Logical scalar, whether to keep vertices that
-    only appear in a subset of the input graphs.}
-}
-\details{
-  \code{graph.intersection} creates the intersection of two or more
-  graphs: only edges present in all graphs will be included.
-  The corresponding operator is \%s\%.
-
-  If the \code{byname} argument is \code{TRUE} (or \code{auto} and all
-  graphs are named), then the operation is performed on symbolic vertex
-  names instead of the internal numeric vertex ids.
-
-  \code{graph.intersection} keeps the attributes of all graphs. All
-  graph, vertex and edge attributes are copied to the result. If an
-  attribute is present in multiple graphs and would result a name clash,
-  then this attribute is renamed by adding suffixes: _1, _2, etc.
-
-  The \code{name} vertex attribute is treated specially if the operation
-  is performed based on symbolic vertex names. In this case \code{name}
-  must be present in all graphs, and it is not renamed in the result
-  graph.  
-
-  An error is generated if some input graphs are directed and others are
-  undirected.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## Common part of two social networks
-net1 <- graph.formula(D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G,
-                      H-F:G, H-I-J)
-net2 <- graph.formula(D-A:F:Y, B-A-X-F-H-Z, F-Y)
-str(net1 \%s\% net2)
-}
-\keyword{graphs}
diff --git a/man/graph.isomorphism.Rd b/man/graph.isomorphism.Rd
deleted file mode 100644
index 7233e90..0000000
--- a/man/graph.isomorphism.Rd
+++ /dev/null
@@ -1,329 +0,0 @@
-\name{graph-isomorphism}
-\alias{graph.isoclass}
-\alias{graph.isocreate}
-\alias{graph.isomorphic}
-\alias{graph.isomorphic.vf2}
-\alias{graph.count.isomorphisms.vf2}
-\alias{graph.count.subisomorphisms.vf2}
-\alias{graph.get.isomorphisms.vf2}
-\alias{graph.get.subisomorphisms.vf2}
-\alias{graph.isoclass.subgraph}
-\alias{graph.isomorphic.34}
-\alias{graph.isomorphic.bliss}
-\alias{graph.subisomorphic.vf2}
-\alias{graph.subisomorphic.lad}
-\concept{Graph isomorphism}
-\concept{Subgraph isomorphism}
-\concept{VF2 algorithm}
-\concept{BLISS algorithm}
-\title{Graph Isomorphism}
-\description{These functions deal with graph isomorphism.}
-\usage{
-graph.isomorphic(graph1, graph2)
-graph.isomorphic.34(graph1, graph2)
-graph.isomorphic.bliss(graph1, graph2, sh1="fm", sh2="fm")
-graph.isomorphic.vf2(graph1, graph2, vertex.color1, vertex.color2,
-     edge.color1, edge.color2)
-
-graph.count.isomorphisms.vf2(graph1, graph2,
-     vertex.color1, vertex.color2,
-     edge.color1, edge.color2)
-graph.get.isomorphisms.vf2(graph1, graph2,
-     vertex.color1, vertex.color2,
-     edge.color1, edge.color2)
-
-graph.subisomorphic.vf2(graph1, graph2,
-     vertex.color1, vertex.color2,
-     edge.color1, edge.color2)
-graph.count.subisomorphisms.vf2(graph1, graph2,
-     vertex.color1, vertex.color2,
-     edge.color1, edge.color2)
-graph.get.subisomorphisms.vf2(graph1, graph2,
-     vertex.color1, vertex.color2,
-     edge.color1, edge.color2)
-
-graph.subisomorphic.lad (pattern, target, domains = NULL, 
-                         induced = FALSE, map = TRUE, all.maps = FALSE,
-                         time.limit = Inf)
-
-graph.isoclass(graph)
-graph.isoclass.subgraph(graph, vids)
-graph.isocreate(size, number, directed=TRUE)
-}
-\arguments{
-  \item{graph}{A graph object.}
-  \item{graph1,graph2}{Graph objects}
-  \item{vertex.color1,vertex.color2}{
-    Optional integer vectors giving the colors of the
-    vertices for colored (sub)graph isomorphism. If they are not given,
-    but the graph has a \dQuote{color} vertex attribute, then it will be
-    used. If you want to ignore these attributes, then supply
-    \code{NULL} for both of these arguments. See also examples below.}
-  \item{edge.color1,edge.color2}{
-    Optional integer vectors giving the colors of the edges
-    for edge-colored (sub)graph isomorphism. If they are not given,
-    but the graph has a \dQuote{color} edge attribute, then it will be
-    used. If you want to ignore these attributes, then supply
-    \code{NULL} for both of these arguments.}
-  \item{size}{A numeric integer giving the number of vertices in the
-    graph to create. Only three or four are suppported right now.}
-  \item{number}{The number of the isomorphism class of the graph to be
-    created.}
-  \item{directed}{Whether to create a directed graph.}
-  \item{sh1}{Character constant, the heuristics to use in the BLISS
-    algorithm, for \code{graph1}. See the \code{sh} argument of
-    \code{\link{canonical.permutation}} for possible values.}
-  \item{sh2}{Character constant, the heuristics to use in the BLISS
-    algorithm, for \code{graph2}. See the \code{sh} argument of
-    \code{\link{canonical.permutation}} for possible values.}
-  \item{vids}{Numeric vector, the vertex ids of vertices to form the
-    induced subgraph for determining the isomorphism class.}
-  \item{pattern}{The smaller graph, it might be directed or
-    undirected. Undirected graphs are treated as directed graphs with
-    mutual edges.}
-  \item{target}{The bigger graph, it might be directed or
-    undirected. Undirected graphs are treated as directed graphs with
-    mutual edges.}
-  \item{domains}{If not \code{NULL}, then it specifies matching
-    restrictions. It must be a list of \code{target} vertex sets, given
-    as numeric vertex ids or symbolic vertex names. The length of the
-    list must be \code{vcount(pattern)} and for each vertex in
-    \code{pattern} it gives the allowed matching vertices in
-    \code{target}.}
-  \item{induced}{Logical scalar, whether to search for an induced
-    subgraph. It is \code{FALSE} by default.}
-  \item{map}{Logical scalar, whether to return a mapping between
-    \code{pattern} and \code{target}. Defaults to \code{TRUE}.}
-  \item{all.maps}{Logical scalar, whether to return all mappings between
-    \code{pattern} and \code{target}. Defaults to \code{FALSE}.}
-  \item{time.limit}{The processor time limit for the computation, in
-    seconds. It defaults to \code{Inf}, which means no limit. }
-}
-\details{
-  \code{graph.isomorphic} decides whether two graphs are isomorphic.
-  The input graphs must be both directed or both undirected.
-  This function is a higher level interface to the other graph
-  isomorphism decision functions. Currently it does the following:
-  \enumerate{
-    \item If the two graphs do not agree in the number of vertices and
-    the number of edges then \code{FALSE} is returned.
-    \item Otherwise if the graphs have 3 or 4 vertices, then
-    \code{igraph.isomorphic.34} is called.
-    \item Otherwise if the graphs are directed, then
-    \code{igraph.isomorphic.vf2} is called.
-    \item Otherwise \code{igraph.isomorphic.bliss} is called.
-  }
-
-  \code{igraph.isomorphic.34} decides whether two graphs, both of which
-  contains only 3 or 4 vertices, are isomorphic. It works based on a
-  precalculated and stored table.
-
-  \code{igraph.isomorphic.bliss} uses the BLISS algorithm by Junttila
-  and Kaski, and it works for undirected graphs. For both graphs the
-  \code{\link{canonical.permutation}} and then the
-  \code{\link{permute.vertices}} function is called to transfer them
-  into canonical form; finally the canonical forms are compared.
-
-  \code{graph.isomorphic.vf2} decides whethe two graphs are isomorphic,
-  it implements the VF2 algorithm, by Cordella, Foggia et al., see
-  references.
-
-  \code{graph.count.isomorphisms.vf2} counts the different isomorphic
-  mappings between \code{graph1} and \code{graph2}. (To count
-  automorphisms you can supply the same graph twice, but it is better to
-  call \code{\link{graph.automorphisms}}.) It uses the VF2 algorithm.
-
-  \code{graph.get.isomorphisms.vf2} calculates all isomorphic mappings
-  between \code{graph1} and \code{graph2}. It uses the VF2 algorithm.
-
-  \code{graph.subisomorphic.vf2} decides whether \code{graph2} is
-  isomorphic to some subgraph of \code{graph1}. It uses the VF2 algorithm.
-
-  \code{graph.count.subisomorphisms.vf2} counts the different isomorphic
-  mappings between \code{graph2} and the subgraphs of \code{graph1}. It
-  uses the VF2 algorithm.
-
-  \code{graph.get.subisomorphisms.vf2} calculates all isomorphic
-  mappings between \code{graph2} and the subgraphs of \code{graph1}. It
-  uses the VF2 algorithm.
-
-  \code{graph.subisomorphic.lad} checks whether \code{pattern} is
-  isomorphic to a subgraph or induced subgraph of \code{target}. It can
-  also optionally return a mapping, or all possible mappings between the
-  two graphs. Its \code{domains} argument allows for a flexible way to
-  restrict the matching to a subset of allowed vertices, individually
-  for each vertex in \code{pattern}.
-  
-  \code{graph.isoclass} returns the isomorphism class of a graph, a
-  non-negative integer number. Graphs (with the same number of vertices)
-  having the same isomorphism class are isomorphic and isomorphic graphs
-  always have the same isomorphism class. Currently it can handle only
-  graphs with 3 or 4 vertices.
-
-  \code{graph.isoclass.subgraph} calculates the isomorphism class of a
-  subgraph of the input graph. Currently it only works for subgraphs
-  with 3 or 4 vertices.
-  
-  \code{graph.isocreate} create a graph from the given isomorphic
-  class. Currently it can handle only graphs with 3 or 4 vertices.
-}
-\note{
-  Functions \code{graph.isoclass}, \code{graph.isoclass.subgraph} and
-  \code{graph.isocreate} are considered experimental and might be
-  reorganized/rewritten later.
-}
-\value{
-  \code{graph.isomorphic} and \code{graph.isomorphic.34} return a
-  logical scalar, \code{TRUE} if the input graphs are isomorphic,
-  \code{FALSE} otherwise.
-
-  \code{graph.isomorphic.bliss} returns a named list with elements:
-  \item{iso}{A logical scalar, whether the two graphs are isomorphic.}
-  \item{map12}{A numeric vector, an mapping from \code{graph1} to
-    \code{graph2} if \code{iso} is \code{TRUE}, an empty numeric
-    vector otherwise.}
-  \item{map21}{A numeric vector, an mapping from \code{graph2} to
-    \code{graph1} if \code{iso} is \code{TRUE}, an empty numeric
-    vector otherwise.}
-  \item{info1}{Some information about the canonical form calculation
-    for \code{graph1}. A named list, see the return value of
-    \code{\link{canonical.permutation}} for details. Note that if the
-		two graphs have different number of vertices or edges, then the
-		BLISS algorithm is not run at all, and the contents of \code{info1}
-		is incorrect.}
-  \item{info2}{Some information about the canonical form calculation
-    for \code{graph2}. A named list, see the return value of
-    \code{\link{canonical.permutation}} for details. Note that if the
-		two graphs have different number of vertices or edges, then the
-		BLISS algorithm is not run at all, and the contents of \code{info2}
-		is incorrect.}
-
-  \code{graph.isomorphic.vf2} returns a names list with three elements:
-  \item{iso}{A logical scalar, whether the two graphs are isomorphic.}
-  \item{map12}{A numeric vector, an mapping from \code{graph1} to
-    \code{graph2} if \code{iso} is \code{TRUE}, an empty numeric
-    vector otherwise.}
-  \item{map21}{A numeric vector, an mapping from \code{graph2} to
-    \code{graph1} if \code{iso} is \code{TRUE}, an empty numeric
-    vector otherwise.}
-
-  \code{graph.count.isomorphisms.vf2} returns a numeric scalar, an
-  integer, the number of isomorphic mappings between the two input
-  graphs.
-
-  \code{graph.get.isomorphisms.vf2} returns a list of numeric
-  vectors. Every numeric vector is a permutation which takes
-  \code{graph2} into \code{graph1}.
-
-  \code{graph.subisomorphic.vf2} returns a named list with three
-  elements:
-  \item{iso}{Logical scalar, \code{TRUE} if a subgraph of
-    \code{graph1} is isomorphic to \code{graph2}.}
-  \item{map12}{Numeric vector, empty if \code{iso} is
-    \code{FALSE}. Otherwise a mapping from a subgraph of \code{graph1}
-    to \code{graph2}. -1 denotes the vertices which are not part of
-    the mapping.}
-  \item{map21}{Numeric vector, empty if \code{iso} is
-    \code{FALSE}. Otherwise a mapping from \code{graph2} into
-    \code{graph1}.}
-
-  \code{graph.count.subisomorphisms.vf2} returns a numeric scalar, an
-  integer.
-
-  \code{graph.get.subisomorphisms.vf2} returns a list of numeric
-  vectors, each numeric vector is an isomorphic mapping from
-  \code{graph2} to a subgraph of \code{graph1}.
-
-  \code{graph.subisomorphic.lad} return a named list with three entries:
-  \item{iso}{Logical scalar, whether the algorithm found a subgraph (or
-    induced subgraph is the \code{induced} argument in \code{TRUE}) in
-    \code{target} that is isomorphic to \code{pattern}.}
-  \item{map}{If a mapping is requested via the \code{map} argument, then
-    a numeric vector of vertex ids from \code{target}, the matching
-    vertices for each \code{pattern} vertex in \code{pattern} vertex id
-    order. Otherwise \code{NULL}.}
-  \item{maps}{If all mappings are requested via the \code{all.maps}
-    argument, then all possible mappings from \code{pattern} to
-    \code{target}, in a list of vectors, where each vector is in the
-    same format as \code{map} just above.}
-  
-  \code{graph.isoclass} and \code{graph.isoclass.subgraph} return a
-  non-negative integer number. 
-
-  \code{graph.isocreate} returns a graph object.
-}
-\references{
-  Tommi Junttila and Petteri Kaski: Engineering an Efficient Canonical
-  Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of the
-    Ninth Workshop on Algorithm Engineering and Experiments and the
-    Fourth Workshop on Analytic Algorithms and Combinatorics.} 2007.
-
-  LP Cordella,  P Foggia, C Sansone, and M Vento:
-  An improved algorithm for matching large graphs,
-  \emph{Proc. of the 3rd IAPR TC-15 Workshop on Graphbased
-    Representations in Pattern Recognition}, 149--159, 2001.
-
-  C. Solnon: AllDifferent-based Filtering for Subgraph Isomorphism,
-  \emph{Artificial Intelligence} 174(12-13):850--864, 2010.
-}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.motifs}}}
-\examples{
-# create some non-isomorphic graphs
-g1 <- graph.isocreate(3, 10)
-g2 <- graph.isocreate(3, 11)
-graph.isoclass(g1)
-graph.isoclass(g2)
-graph.isomorphic(g1, g2)
-
-# create two isomorphic graphs, by
-# permuting the vertices of the first 
-g1 <- barabasi.game(30, m=2, directed=FALSE)
-g2 <- permute.vertices(g1, sample(vcount(g1)))
-# should be TRUE
-graph.isomorphic(g1, g2)
-graph.isomorphic.bliss(g1, g2)
-graph.isomorphic.vf2(g1, g2)
-
-# colored graph isomorphism
-g1 <- graph.ring(10)
-g2 <- graph.ring(10)
-graph.isomorphic.vf2(g1, g2)
-
-V(g1)$color <- rep(1:2, length=vcount(g1))
-V(g2)$color <- rep(2:1, length=vcount(g2))
-graph.count.isomorphisms.vf2(g1, g2)
-graph.count.isomorphisms.vf2(g1, g2, vertex.color1=NULL,
-    vertex.color2=NULL)
-
-V(g1)$name <- letters[1:vcount(g1)]
-V(g2)$name <- LETTERS[1:vcount(g2)]
-graph.get.isomorphisms.vf2(g1, g2)
-
-V(g1)$color <- 1
-V(g2)$color <- 2
-graph.isomorphic.vf2(g1, g2)
-graph.isomorphic.vf2(g2, g2, vertex.color1=NULL,
-    vertex.color2=NULL)
-
-# The LAD example
-pattern <- graph.formula(1:2:3:4:5,
-                         1 - 2:5, 2 - 1:5:3, 3 - 2:4, 4 - 3:5, 5 - 4:2:1)
-target <- graph.formula(1:2:3:4:5:6:7:8:9,
-                        1 - 2:5:7, 2 - 1:5:3, 3 - 2:4, 4 - 3:5:6:8:9,
-                        5 - 1:2:4:6:7, 6 - 7:5:4:9, 7 - 1:5:6,
-                        8 - 4:9, 9 - 6:4:8)
-domains <- list(`1` = c(1,3,9), `2` = c(5,6,7,8), `3` = c(2,4,6,7,8,9),
-                `4` = c(1,3,9), `5` = c(2,4,8,9))
-graph.subisomorphic.lad(pattern, target, all.maps=TRUE)
-graph.subisomorphic.lad(pattern, target, induced=TRUE, all.maps=TRUE)
-graph.subisomorphic.lad(pattern, target, domains=domains, all.maps=TRUE)
-
-# Directed LAD example
-pattern <- graph.formula(1:2:3, 1 -+ 2:3)
-uring <- graph.ring(10)
-dring <- graph.ring(10, directed=TRUE)
-graph.subisomorphic.lad(pattern, uring)
-graph.subisomorphic.lad(pattern, dring)
-}
-\keyword{graphs}
diff --git a/man/graph.kautz.Rd b/man/graph.kautz.Rd
deleted file mode 100644
index 811df18..0000000
--- a/man/graph.kautz.Rd
+++ /dev/null
@@ -1,34 +0,0 @@
-\name{graph.kautz}
-\alias{graph.kautz}
-\concept{Kautz graph}
-\title{Kautz graphs}
-\description{Kautz graphs are labeled graphs representing the
-  overlap of strings. }
-\usage{
-graph.kautz(m,n)
-}
-\arguments{
-  \item{m}{Integer scalar, the size of the alphabet. See details below.}
-  \item{n}{Integer scalar, the length of the labels. See details below.}
-}
-\details{
-  A Kautz graph is a labeled graph, vertices are labeled by strings
-  of length \code{n+1} above an alphabet with \code{m+1} letters, with
-  the restriction that every two consecutive letters in the string
-  must be different. There is a directed edge from a vertex \code{v} to
-  another vertex \code{w} if it is possible to transform the string of
-  \code{v} into the string of \code{w} by removing the first letter and
-  appending a letter to it.
-  
-  Kautz graphs have some interesting properties, see eg. Wikipedia
-  for details.
-}
-\value{A graph object.}
-\author{Gabor Csardi <csardi.gabor at gmail.com>, the first version in R was
-  written by Vincent Matossian.}
-\seealso{\code{\link{graph.de.bruijn}}, \code{\link{line.graph}}}
-\examples{
-line.graph(graph.kautz(2,1))
-graph.kautz(2,2)
-}
-\keyword{graphs}
diff --git a/man/graph.kcores.Rd b/man/graph.kcores.Rd
deleted file mode 100644
index a2ce068..0000000
--- a/man/graph.kcores.Rd
+++ /dev/null
@@ -1,42 +0,0 @@
-\name{graph.coreness}
-\alias{graph.coreness}
-\concept{K-core}
-\title{K-core decomposition of graphs}
-\description{The k-core of graph is a maximal subgraph in which each
-  vertex has at least degree k. The coreness of a vertex is k if it
-  belongs to the k-core but not to the (k+1)-core.}
-\usage{
-graph.coreness(graph, mode=c("all", "out", "in"))
-}
-\arguments{
-  \item{graph}{The input graph, it can be directed or undirected}
-  \item{mode}{The type of the core in directed graphs. Character
-    constant, possible values: \code{in}: in-cores are computed,
-    \code{out}: out-cores are computed, \code{all}: the corresponding
-    undirected graph is considered. This argument is ignored for
-    undirected graphs.}
-}
-\details{
-  The k-core of a graph is the maximal subgraph in which every vertex
-  has at least degree k. The cores of a graph form layers: the (k+1)-core
-  is always a subgraph of the k-core.
-
-  This function calculates the coreness for each vertex.
-}
-\value{
-  Numeric vector of integer numbers giving the coreness of each vertex.
-}
-\references{Vladimir Batagelj, Matjaz Zaversnik: An O(m)
-  Algorithm for Cores Decomposition of Networks, 2002
-  
-  Seidman S. B. (1983) Network structure and minimum degree, \emph{Social
-    Networks}, 5, 269--287.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{degree}}}
-\examples{
-g <- graph.ring(10)
-g <- add.edges(g, c(1,2, 2,3, 1,3))
-graph.coreness(g) 		% small core triangle in a ring
-}
-\keyword{graphs}
\ No newline at end of file
diff --git a/man/graph.knn.Rd b/man/graph.knn.Rd
deleted file mode 100644
index 60e561b..0000000
--- a/man/graph.knn.Rd
+++ /dev/null
@@ -1,63 +0,0 @@
-\name{graph.knn}
-\alias{graph.knn}
-\title{Average nearest neighbor degree}
-\description{Calculate the average nearest neighbor degree of the given
-  vertices and the same quantity in the function of vertex degree}
-\usage{
-graph.knn(graph, vids=V(graph), weights=NULL)
-}
-\arguments{
-  \item{graph}{The input graph. It can be directed, but it will be
-    treated as undirected, i.e. the direction of the edges is ignored.}
-  \item{vids}{The vertices for which the calculation is
-    performed. Normally it includes all vertices. Note, that if not all
-    vertices are given here, then both \sQuote{\code{knn}} and
-    \sQuote{\code{knnk}} will be calculated based on the given vertices
-    only.}
-  \item{weights}{Weight vector. If the graph has a \code{weight} edge
-    attribute, then this is used by default. If this argument is given,
-    then vertex strength (see \code{\link{graph.strength}}) is used
-    instead of vertex degree. But note that \code{knnk} is still given
-    in the function of the normal vertex degree. }
-}
-\details{
-  Note that for zero degree vertices the answer in \sQuote{\code{knn}}
-  is \code{NaN} (zero divided by zero), the same is true for
-  \sQuote{\code{knnk}} if a given degree never appears in the network.
-}
-\value{
-  A list with two members:
-  \item{knn}{A numeric vector giving the average nearest neighbor
-    degree for all vertices in \code{vids}.}
-  \item{knnk}{A numeric vector, its length is the maximum (total)
-    vertex degree in the graph. The first element is the
-    average nearest neighbor degree of vertices with degree one, etc.
-  }
-}
-\references{
-  Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras, Alessandro
-  Vespignani: The architecture of complex weighted networks,
-  Proc. Natl. Acad. Sci. USA 101, 3747 (2004)
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\examples{
-# Some trivial ones
-g <- graph.ring(10)
-graph.knn(g)
-g2 <- graph.star(10)
-graph.knn(g2)
-
-# A scale-free one, try to plot 'knnk'
-g3 <- ba.game(1000, m=5)
-graph.knn(g3)
-
-# A random graph
-g4 <- random.graph.game(1000, p=5/1000)
-graph.knn(g4)
-
-# A weighted graph
-g5 <- graph.star(10)
-E(g5)$weight <- seq(ecount(g5))
-graph.knn(g5)
-}
-\keyword{graphs}
diff --git a/man/graph.laplacian.Rd b/man/graph.laplacian.Rd
deleted file mode 100644
index afe8fc9..0000000
--- a/man/graph.laplacian.Rd
+++ /dev/null
@@ -1,49 +0,0 @@
-\name{graph.laplacian}
-\alias{graph.laplacian}
-\concept{Graph Laplacian}
-\title{Graph Laplacian}
-\description{The Laplacian of a graph.}
-\usage{
-graph.laplacian(graph, normalized=FALSE, weights=NULL,
-   sparse=getIgraphOpt("sparsematrices"))
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{normalized}{Whether to calculate the normalized Laplacian. See
-    definitions below.}
-  \item{weights}{An optional vector giving edge weights for weighted
-    Laplacian matrix. If this is \code{NULL} and the graph has an edge
-    attribute called \code{weight}, then it will be used
-    automatically. Set this to \code{NA} if you want the unweighted
-    Laplacian on a graph that has a \code{weight} edge attribute.}
-  \item{sparse}{Logical scalar, whether to return the result as a sparse
-    matrix. The \code{Matrix} package is required for sparse matrices.}
-}
-\details{
-  The Laplacian Matrix of a graph is a symmetric matrix having
-  the same number of rows and columns as the number of vertices in the
-  graph and element (i,j) is d[i], the degree of vertex i if if i==j,
-  -1 if i!=j and there is an edge between vertices i and j and 0
-  otherwise.
-
-  A normalized version of the Laplacian Matrix is similar: element (i,j)
-  is 1 if i==j, -1/sqrt(d[i] d[j]) if i!=j and there is an edge between
-  vertices i and j and 0 otherwise.
-
-  The weighted version of the Laplacian simply works with the weighted
-  degree instead of the plain degree. I.e. (i,j) is d[i], the weighted
-  degree of vertex i if if i==j, -w if i!=j and there is an edge between
-  vertices i and j with weight w, and 0 otherwise. The weighted degree
-  of a vertex is the sum of the weights of its adjacent edges.
-}
-\value{A numeric matrix.}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g <- graph.ring(10)
-graph.laplacian(g)
-graph.laplacian(g, norm=TRUE)
-graph.laplacian(g, norm=TRUE, sparse=FALSE)
-}
-\keyword{graphs}
diff --git a/man/graph.lcf.Rd b/man/graph.lcf.Rd
deleted file mode 100644
index 508433e..0000000
--- a/man/graph.lcf.Rd
+++ /dev/null
@@ -1,31 +0,0 @@
-\name{graph.lcf}
-\alias{graph.lcf}
-\concept{LCF notation}
-\title{Creating a graph from LCF notation}
-\description{LCF is short for Lederberg-Coxeter-Frucht, it is a concise notation for
-  3-regular Hamiltonian graphs. It constists of three parameters, the
-  number of vertices in the graph, a list of shifts giving additional
-  edges to a cycle backbone and another integer giving how many times
-  the shifts should be performed. See
-  \url{http://mathworld.wolfram.com/LCFNotation.html} for details.}
-\usage{
-graph.lcf(n, shifts, repeats)
-}
-\arguments{
-  \item{n}{Integer, the number of vertices in the graph.}
-  \item{shifts}{Integer vector, the shifts.}
-  \item{repeats}{Integer constant, how many times to repeat the shifts.}
-}
-%\details{}
-\value{A graph object.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{graph}} can create arbitrary graphs, see also the other
-  functions on the its manual page for creating special graphs.
-}
-\examples{
-# This is the Franklin graph:
-g1 <- graph.lcf(12, c(5,-5), 6)
-g2 <- graph.famous("Franklin")
-graph.isomorphic.vf2(g1, g2)
-}
-\keyword{graphs}
diff --git a/man/graph.maxflow.Rd b/man/graph.maxflow.Rd
deleted file mode 100644
index c6f3d78..0000000
--- a/man/graph.maxflow.Rd
+++ /dev/null
@@ -1,128 +0,0 @@
-\name{graph.maxflow}
-\alias{graph.maxflow}
-\alias{graph.mincut}
-\concept{Maximum flow}
-\concept{Minimum cut}
-\title{Maximum flow in a network}
-\description{In a graph where each edge has a given flow capacity the
-  maximal flow between two vertices is calculated.}
-\usage{
-graph.maxflow(graph, source, target, capacity=NULL)
-graph.mincut(graph, source=NULL, target=NULL, capacity=NULL,
-       value.only = TRUE)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{source}{The id of the source vertex.}
-  \item{target}{The id of the target vertex (sometimes also called sink).}
-  \item{capacity}{Vector giving the capacity of the edges. If this is
-    \code{NULL} (the default) then the \code{capacity} edge attribute is
-    used.}
-  \item{value.only}{Logical scalar, if \code{TRUE} only the minumum cut
-    value is returned, if \code{FALSE} the edges in the cut and a the
-    two (or more) partitions are also returned.
-  }
-}
-\details{
-  \code{graph.maxflow} calculates the maximum flow between two vertices
-  in a weighted (ie. valued) graph. A flow from \code{source} to
-  \code{target} is an assignment of non-negative real numbers to the
-  edges of the graph, satisfying two properties: (1) for each edge the
-  flow (ie. the assigned number) is not more than the capacity of the
-  edge (the \code{capacity} parameter or edge attribute), (2) for every
-  vertex, except the source and the target the incoming flow is the same
-  as the outgoing flow. The value of the flow is the incoming flow of
-  the \code{target} vertex. The maximum flow is the flow of maximum
-  value.
-
-  \code{graph.mincut} calculates the minimum st-cut between two vertices
-  in a graph (if the \code{source} and \code{target} arguments are
-  given) or the minimum cut of the graph (if both \code{source} and
-  \code{target} are \code{NULL}).
-
-  The minimum st-cut between \code{source} and \code{target} is the
-  minimum total weight of edges needed to remove to eliminate all paths from
-  \code{source} to \code{target}.
-
-  The minimum cut of a graph is the minimum total weight of the edges
-  needed to remove to separate the graph into (at least) two
-  components. (Which is to make the graph \emph{not} strongly connected
-  in the directed case.)
-  
-  The maximum flow between two vertices in a graph is the same as the minimum
-  st-cut, so \code{graph.maxflow} and \code{graph.mincut} essentially
-  calculate the same quantity, the only difference is that
-  \code{graph.mincut} can be invoked without giving the \code{source}
-  and \code{target} arguments and then minimum of all possible minimum
-  cuts is calculated.
-
-  For undirected graphs the Stoer-Wagner algorithm (see reference below)
-  is used to calculate the minimum cut.
-}
-\value{
-  For \code{graph.maxflow} a named list with components:
-  \item{value}{A numeric scalar, the value of the maximum flow.}
-  \item{flow}{A numeric vector, the flow itself, one entry for each
-    edge. For undirected graphs this entry is bit trickier,
-    since for these the flow direction is not predetermined by
-    the edge direction. For these graphs the elements of the
-    this vector can be negative, this means that the flow
-    goes from the bigger vertex id to the smaller one. Positive
-    values mean that the flow goes from the smaller vertex id to
-    the bigger one.}
-  \item{cut}{A numeric vector of edge ids, the minimum cut corresponding
-    to the maximum flow.}
-  \item{partition1}{A numeric vector of vertex ids, the vertices in the
-    first partition of the minimum cut corresponding to the maximum
-    flow.}
-  \item{partition2}{A numeric vector of vertex ids, the vertices in the
-    second partition of the minimum cut corresponding to the maximum
-    flow.}
-  \item{stats}{A list with some statistics from the push-relabel
-    algorithm. Five integer values currently: \code{nopush} is the
-    number of push operations, \code{norelabel} the number of
-    relabelings, \code{nogap} is the number of times the gap heuristics
-    was used, \code{nogapnodes} is the total number of gap nodes omitted
-    because of the gap heuristics and \code{nobfs} is the number of
-    times a global breadth-first-search update was performed to assign
-    better height (=distance) values to the vertices.}
-  
-  For \code{graph.mincut} a numeric constant, the value of the minimum
-  cut, except if \code{value.only=FALSE}. In this case a named list with
-  components:
-  \item{value}{Numeric scalar, the cut value.}
-  \item{cut}{Numeric vector, the edges in the cut.}
-  \item{partition1}{The vertices in the first partition after the cut
-    edges are removed. Note that these vertices might be actually in
-    different components (after the cut edges are removed), as the
-    graph may fall apart into more than two components.}
-  \item{partition2}{The vertices in the second partition after the cut
-    edges are removed. Note that these vertices might be actually in
-    different components (after the cut edges are removed), as the
-    graph may fall apart into more than two components.}
-}
-\references{
-  A. V. Goldberg and R. E. Tarjan: A New Approach to the Maximum Flow
-  Problem \emph{Journal of the ACM} 35:921-940, 1988.
-  
-  M. Stoer and F. Wagner: A simple min-cut algorithm, \emph{Journal of
-  the ACM}, 44 585-591, 1997.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{shortest.paths}}, \code{\link{edge.connectivity}},
-  \code{\link{vertex.connectivity}}}
-\examples{
-E <- rbind( c(1,3,3), c(3,4,1), c(4,2,2), c(1,5,1), c(5,6,2), c(6,2,10))
-colnames(E) <- c("from", "to", "capacity")
-g1 <- graph.data.frame(as.data.frame(E))
-graph.maxflow(g1, source=V(g1)["1"], target=V(g1)["2"])
-
-g <- graph.ring(100)
-graph.mincut(g, capacity=rep(1,vcount(g)))
-graph.mincut(g, value.only=FALSE, capacity=rep(1,vcount(g)))
-
-g2 <- graph( c(1,2,2,3,3,4, 1,6,6,5,5,4, 4,1) )
-E(g2)$capacity <- c(3,1,2, 10,1,3, 2)
-graph.mincut(g2, value.only=FALSE)
-}
-\keyword{graphs}
diff --git a/man/graph.motifs.Rd b/man/graph.motifs.Rd
deleted file mode 100644
index 011bb66..0000000
--- a/man/graph.motifs.Rd
+++ /dev/null
@@ -1,62 +0,0 @@
-\name{graph-motifs}
-\alias{graph.motifs}
-\alias{graph.motifs.no}
-\alias{graph.motifs.est}
-\concept{Graph motif}
-\title{Graph motifs}
-\description{Graph motifs are small connected subgraphs with a
-  well-defined structure. These functions search a graph for various
-  motifs.}
-\usage{
-graph.motifs(graph, size = 3, cut.prob = rep(0, size)) 
-graph.motifs.no(graph, size = 3, cut.prob = rep(0, size)) 
-graph.motifs.est(graph, size = 3, cut.prob = rep(0, size), sample.size =
-    vcount(graph)/10, sample = NULL) 
-}
-\arguments{
-  \item{graph}{Graph object, the input graph.}
-  \item{size}{The size of the motif, currently 3 and 4 are supported
-    only.}
-  \item{cut.prob}{Numeric vector giving the probabilities that the
-    search graph is cut at a certain level. Its length should be the
-    same as the size of the motif (the \code{size} argument). By default
-    no cuts are made.}
-  \item{sample.size}{The number of vertices to use as a starting point
-    for finding motifs. Only used if the \code{sample} argument is
-    \code{NULL}.}
-  \item{sample}{If not \code{NULL} then it specifies the vertices to use
-    as a starting point for finding motifs.}
-}
-\details{
-  \code{graph.motifs} searches a graph for motifs of a given size and
-  returns a numeric vector containing the number of different
-  motifs. The order of the motifs is defined by their isomorphism class,
-  see \code{\link{graph.isoclass}}.
-
-  \code{graph.motifs.no} calculates the total number of motifs of a
-  given size in graph.
-
-  \code{graph.motifs.est} estimates the total number of motifs of a
-  given size in a graph based on a sample. 
-}
-\value{
-  \code{graph.motifs} returns a numeric vector, the number of occurences
-  of each motif in the graph. The motifs are ordered by their
-  isomorphism classes. Note that for unconnected subgraphs, which are
-  not considered to be motifs, the result will be \code{NA}.
-
-  \code{graph.motifs.no} and \code{graph.motifs.est} return a numeric
-  constant.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.isoclass}}}
-\examples{
-g <- barabasi.game(100)
-graph.motifs(g, 3)
-graph.motifs.no(g, 3)
-graph.motifs.est(g, 3)
-}
-\keyword{graphs}
-
-  
\ No newline at end of file
diff --git a/man/graph.strength.Rd b/man/graph.strength.Rd
deleted file mode 100644
index 315ec4d..0000000
--- a/man/graph.strength.Rd
+++ /dev/null
@@ -1,44 +0,0 @@
-\name{graph.strength}
-\alias{graph.strength}
-\title{Strength or weighted vertex degree}
-\description{Summing up the edge weights of the adjacent edges for each
-  vertex.}
-\usage{
-graph.strength (graph, vids = V(graph), mode = c("all", "out", "in", "total"),
-      loops = TRUE, weights = NULL)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{vids}{The vertices for which the strength will be calculated.}
-  \item{mode}{Character string, \dQuote{out} for out-degree, \dQuote{in} for
-    in-degree or \dQuote{all} for the sum of the two. For undirected
-    graphs this argument is ignored.}
-  \item{loops}{Logical; whether the loop edges are also counted.}
-  \item{weights}{Weight vector. If the graph has a \code{weight} edge
-    attribute, then this is used by default. If the graph does not have
-    a \code{weight} edge attribute and this argument is \code{NULL},
-    then a warning is given and \code{\link{degree}} is called.}
-}
-% \details{}
-\value{
-  A numeric vector giving the strength of the vertices.
-}
-\references{
-  Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras, Alessandro
-  Vespignani: The architecture of complex weighted networks,
-  Proc. Natl. Acad. Sci. USA 101, 3747 (2004)
-}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{\code{\link{degree}} for the unweighted version.}
-\examples{
-g <- graph.star(10)
-E(g)$weight <- seq(ecount(g))
-graph.strength(g)
-graph.strength(g, mode="out")
-graph.strength(g, mode="in")
-
-# No weights, a warning is given
-g <- graph.ring(10)
-graph.strength(g)
-}
-\keyword{graphs}
diff --git a/man/graph.structure.Rd b/man/graph.structure.Rd
deleted file mode 100644
index e801b3b..0000000
--- a/man/graph.structure.Rd
+++ /dev/null
@@ -1,351 +0,0 @@
-\name{graph.structure}
-\alias{add.edges}
-\alias{add.vertices}
-\alias{delete.edges}
-\alias{delete.vertices}
-\alias{[.igraph}
-\alias{[[.igraph}
-\alias{[<-.igraph}
-\alias{+.igraph}
-\alias{-.igraph}
-\alias{edge}
-\alias{edges}
-\alias{vertex}
-\alias{vertices}
-\alias{path}
-\title{Method for structural manipulation of graphs}
-\description{These are the methods for simple manipulation of graphs:
-  adding and deleting edges and vertices.}
-\usage{
-\method{[}{igraph}(x, i, j, \dots, from, to,
-                   sparse=getIgraphOpt("sparsematrices"),
-                   edges=FALSE, drop=TRUE,
-                   attr=if (is.weighted(x)) "weight" else NULL)
-\method{[[}{igraph}(x, i, j, \dots, directed=TRUE, edges=FALSE, exact=TRUE)
-\method{[}{igraph}(x, i, j, \dots, from, to,
-                   attr=if (is.weighted(x)) "weight" else NULL) <- value 
-
-\method{+}{igraph}(e1, e2)
-\method{-}{igraph}(e1, e2)
-vertex(\dots)
-vertices(\dots)
-edge(\dots)
-edges(\dots)
-path(\dots)
-
-add.edges(graph, edges, \dots, attr=list())
-add.vertices(graph, nv, \dots, attr=list())
-delete.edges(graph, edges)
-delete.vertices(graph, v)
-}
-\arguments{
-  \item{x,graph,e1}{The graph to work on.}
-  \item{i,j}{Vertex ids or names or logical vectors. See details below.}
-  \item{\dots}{These are currently ignored for the indexing operators.
-    For \code{vertex}, \code{vertices}, \code{edge}, \code{edges} and
-    \code{path} see details below.
-    For \code{add.edges} and \code{add.vertices} these additional
-    parameters will be added as edge/vertex attributes. Note that these
-    arguments have to be named.}
-  \item{from}{A numeric or character vector giving vertex ids or names.
-    Together with the \code{to} argument, it can be used to query/set
-    a sequence of edges. See details below.
-
-    This argument cannot be present together with any of the
-    \code{i} and \code{j} arguments and if it is present, then the
-    \code{to} argument must be present as well.}
-  \item{to}{A numeric or character vector giving vertex ids or names.
-    Together with the \code{from} argument, it can be used to query/set
-    a sequence of edges. See details below.
-
-    This argument cannot be present together with any of the
-    \code{i} and \code{j} arguments and if it is present, then the
-    \code{from} argument must be present as well.}
-  \item{sparse}{Logical scalar, whether to use sparse matrix.}
-  \item{directed}{Logical scalar, whether to consider edge directions
-    in directed graphs. It is ignored for undirected graphs.}
-  \item{edges}{Logical scalar, whether to return edge ids.}
-  \item{drop,exact}{These arguments are ignored.}
-  \item{value}{A logical or numeric scalar or \code{NULL}. If
-     \code{FALSE}, \code{NULL} or zero, then the specified edges will be
-     deleted. If \code{TRUE} or a non-zero numeric value, then the
-     specified edges will be added. (Only if they don't yet exist.)}
-  \item{e2}{See details below.}
-  \item{attr}{For the indexing operators: if not \code{NULL}, then it
-     should be the name of an edge attribute. This attribute is queried,
-     or updated to the given value. For \code{add.edges} and
-     \code{add.vertices}: additional edge/vertex attributes to add. This
-     will be concatenated to the other supplied attributes.}
-  \item{nv}{Numeric constant, the number of vertices to add.}
-  \item{v}{Vector sequence, the vertices to remove.}
-}
-\details{
-  There are, by and large, three ways to manipulate the structure
-  of a graph in igraph. The first way is using the \sQuote{\code{[}} and
-  \sQuote{\code{[[}} indexing operators on the graph object, very
-  much like the graph was an adjacency matrix (\code{[}) or an adjacency
-  list (\code{[}). The single bracket indexes the (possibly weighted)
-  adjacency matrix of the graph. The double bracket operator is
-  similar, but queries the adjacencly list of the graph. The details
-  on how to use the indexing operators are 
-  discussed below.
-
-  The addition (\sQuote{\code{+}}) and division (\sQuote{\code{-}})
-  operators can also be used to add and remove vertices and edges. This
-  form is sometimes more readable, and is usually the best if the user 
-  also wants to add attributes, together with the new vertices/edges.
-  Please see the details below.
-
-  In addition, the four functions, \code{add.vertices}, \code{add.edges},
-  \code{delete.vertices} and \code{delete.edges} can also be used
-  to manipulate the structure.
-}
-\section{The indexing operators}{
-  The one-bracket (\sQuote{\code{[}}) and two-brackets
-  (\sQuote{\code{[[}}) indexing operators allow relatively
-  straightforward query and update operations on graphs. The one bracket
-  operator works on the (imaginary) adjacency matrix of the graph.
-  Here is what you can do with it:
-
-  \enumerate{
-    \item Check whether there is an edge between two vertices (\eqn{v}
-      and \eqn{w}) in the graph: \preformatted{  graph[v, w]}
-      A numeric scalar is returned, one if the edge exists, zero
-      otherwise.
-    \item Extract the (sparse) adjacency matrix of the graph, or part of
-      it: \preformatted{  graph[]
-  graph[1:3,5:6]
-  graph[c(1,3,5),]}
-      The first variants returns the full adjacency matrix, the other
-      two return part of it.
-    \item The \code{from} and \code{to} arguments can be used to check
-      the existence of many edges. In this case, both \code{from} and
-      \code{to} must be present and they must have the same length. They
-      must contain vertex ids or names. A numeric vector is returned, of
-      the same length as \code{from} and \code{to}, it contains ones
-      for existing edges edges and zeros for non-existing ones.
-      Example: \preformatted{  graph[from=1:3, to=c(2,3,5)]}.
-    \item For weighted graphs, the \code{[} operator returns the edge
-      weights. For non-esistent edges zero weights are returned. Other
-      edge attributes can be queried as well, by giving the \code{attr}
-      argument. 
-    \item Querying edge ids instead of the existance of edges or edge
-      attributes. E.g. \preformatted{  graph[1, 2, edges=TRUE]}
-      returns the id of the edge between vertices 1 and 2, or zero if
-      there is no such edge.
-    \item Adding one or more edges to a graph. For this the element(s) of
-      the imaginary adjacency matrix must be set to a non-zero numeric
-      value (or \code{TRUE}): \preformatted{  graph[1, 2] <- 1
-  graph[1:3,1] <- 1
-  graph[from=1:3, to=c(2,3,5)] <- TRUE}
-      This does not affect edges that are already present in the graph,
-      i.e. no multiple edges are created.
-    \item Adding weighted edges to a graph. The \code{attr} argument
-      contains the name of the edge attribute to set, so it does not
-      have to be \sQuote{weight}: \preformatted{  graph[1, 2, attr="weight"]<- 5
-  graph[from=1:3, to=c(2,3,5)] <- c(1,-1,4)}
-      If an edge is already present in the network, then only its
-      weigths or other attribute are updated. If the graph is already
-      weighted, then the \code{attr="weight"} setting is implicit, and
-      one does not need to give it explicitly.
-    \item Deleting edges. The replacement syntax allow the deletion of
-      edges, by specifying \code{FALSE} or \code{NULL} as the
-      replacement value: \preformatted{  graph[v, w] <- FALSE}
-      removes the edge from vertex \eqn{v} to vertex \eqn{w}.
-      As this can be used to delete edges between two sets of vertices,
-      either pairwise: \preformatted{  graph[from=v, to=w] <- FALSE}
-      or not: \preformatted{  graph[v, w] <- FALSE }
-      if \eqn{v} and \eqn{w} are vectors of edge ids or names.
-  }
-
-  The double bracket operator indexes the (imaginary) adjacency list
-  of the graph. This can used for the following operations:
-  \enumerate{
-    \item Querying the adjacent vertices for one or more
-      vertices: \preformatted{  graph[[1:3,]]
-  graph[[,1:3]]}
-      The first form gives the successors, the second the predessors
-      or the 1:3 vertices. (For undirected graphs they are equivalent.)
-    \item Querying the incident edges for one or more vertices,
-      if the \code{edges} argument is set to
-      \code{TRUE}: \preformatted{  graph[[1:3, , edges=TRUE]]
-  graph[[, 1:3, edges=TRUE]]}
-    \item Querying the edge ids between two sets or vertices,
-      if both indices are used. E.g. \preformatted{  graph[[v, w, edges=TRUE]]}
-      gives the edge ids of all the edges that exist from vertices
-      \eqn{v} to vertices \eqn{w}.
-  }
-
-  Both the \sQuote{\code{[}} and \sQuote{\code{[[}} operators allow
-  logical indices and negative indices as well, with the usual R
-  semantics. E.g. \preformatted{  graph[degree(graph)==0, 1] <- 1}
-  adds an edge from every isolate vertex to vertex one,
-  and \preformatted{  G <- graph.empty(10)
-  G[-1,1] <- TRUE}
-  creates a star graph.
-
-  Of course, the indexing operators support vertex names,
-  so instead of a numeric vertex id a vertex can also be given to
-  \sQuote{\code{[}} and \sQuote{\code{[[}}.
-}
-\section{The plus operator for adding vertices and edges}{
-  The plus operator can be used to add vertices or edges to graph.
-  The actual operation that is performed depends on the type of the
-  right hand side argument.
-  \itemize{
-  \item If is is another igraph graph object and they are both
-    named graphs, then the union of the two graphs are calculated,
-    see \code{\link{graph.union}}.
-  \item If it is another igraph graph object, but either of the two
-    are not named, then the disjoint union of
-    the two graphs is calculated, see \code{\link{graph.disjoint.union}}.
-  \item If it is a numeric scalar, then the specified number of vertices
-    are added to the graph.
-  \item If it is a character scalar or vector, then it is interpreted as
-    the names of the vertices to add to the graph.
-  \item If it is an object created with the \code{vertex} or
-    \code{vertices} function, then new vertices are added to the
-    graph. This form is appropriate when one wants to add some vertex
-    attributes as well. The operands of the \code{vertices} function
-    specifies the number of vertices to add and their attributes as
-    well.
-
-    The unnamed arguments of \code{vertices} are concatenated and
-    used as the \sQuote{\code{name}} vertex attribute (i.e. vertex
-    names), the named arguments will be added as additional vertex
-    attributes. Examples: \preformatted{  g <- g + vertex(shape="circle", color="red")
-  g <- g + vertex("foo", color="blue")
-  g <- g + vertex("bar", "foobar")
-  g <- g + vertices("bar2", "foobar2", color=1:2, shape="rectangle")}
-    See more examples below.
-
-    \code{vertex} is just an alias to \code{vertices}, and it is
-    provided for readability. The user should use it if a single vertex
-    is added to the graph.
-
-  \item If it is an object created with the \code{edge} or \code{edges}
-    function, then new edges will be added to the graph. The new edges
-    and possibly their attributes can be specified as the arguments of
-    the \code{edges} function.
-
-    The unnamed arguments of \code{edges} are concatenated and used
-    as vertex ids of the end points of the new edges. The named
-    arguments will be added as edge attributes.
-
-    Examples: \preformatted{  g <- graph.empty() + vertices(letters[1:10]) +
-  vertices("foo", "bar", "bar2", "foobar2")
-  g <- g + edge("a", "b")
-  g <- g + edges("foo", "bar", "bar2", "foobar2")
-  g <- g + edges(c("bar", "foo", "foobar2", "bar2"), color="red", weight=1:2)}
-    See more examples below.
-
-    \code{edge} is just an alias to \code{edges} and it is provided
-    for readability. The user should use it if a single edge is added to
-    the graph.
-
-  \item If it is an object created with the \code{path} function, then
-    new edges that form a path are added. The edges and possibly their
-    attributes are specified as the arguments to the \code{path}
-    function. The non-named arguments are concatenated and interpreted
-    as the vertex ids along the path. The remaining arguments are added
-    as edge attributes.
-
-    Examples: \preformatted{  g <- graph.empty() + vertices(letters[1:10])
-  g <- g + path("a", "b", "c", "d")
-  g <- g + path("e", "f", "g", weight=1:2, color="red")
-  g <- g + path(c("f", "c", "j", "d"), width=1:3, color="green")}
-  }
-
-  It is important to note that, although the plus operator is
-  commutative, i.e. is possible to write \preformatted{  graph <- "foo" + graph.empty()}
-  it is not associative, e.g. \preformatted{  graph <- "foo" + "bar" + graph.empty()}
-  results a syntax error, unless parentheses are used: \preformatted{  graph <- "foo" + ( "bar" + graph.empty() )}
-  For clarity, we suggest to always put the graph object on the left
-  hand side of the operator: \preformatted{  graph <- graph.empty() + "foo" + "bar"}  
-}
-\section{The minus operator for deleting vertices and edges}{
-  The minus operator (\sQuote{\code{-}}) can be used to remove vertices
-  or edges from the graph. The operation performed is selected based on
-  the type of the right hand side argument:
-  \itemize{
-  \item If it is an igraph graph object, then the difference of the
-    two graphs is calculated, see \code{\link{graph.difference}}.
-  \item If it is a numeric or character vector, then it is interpreted
-    as a vector of vertex ids and the specified vertices will be
-    deleted from the graph. Example: \preformatted{  g <- graph.ring(10)
-  V(g)$name <- letters[1:10]
-  g <- g - c("a", "b")}
-  \item If \code{e2} is a vertex sequence (e.g. created by the
-    \code{\link{V}} function), then these vertices will be deleted from
-    the graph.
-  \item If it is an edge sequence (e.g. created by the \code{\link{E}}
-    function), then these edges will be deleted from the graph.
-  \item If it is an object created with the \code{vertex} (or the
-    \code{vertices}) function, then all arguments of \code{vertices} are
-    concatenated and the result is interpreted as a vector of vertex
-    ids. These vertices will be removed from the graph.
-  \item If it is an object created with the \code{edge} (or the
-    \code{edges}) function, then all arguments of \code{edges} are
-    concatenated and then interpreted as edges to be removed from the
-    graph.
-    Example: \preformatted{  g <- graph.ring(10)
-  V(g)$name <- letters[1:10]
-  E(g)$name <- LETTERS[1:10]
-  g <- g - edge("e|f")
-  g <- g - edge("H")}
-  \item If it is an object created with the \code{path} function,
-    then all \code{path} arguments are concatenated and then interpreted
-    as a path along which edges will be removed from the graph.
-    Example: \preformatted{  g <- graph.ring(10)
-  V(g)$name <- letters[1:10]
-  g <- g - path("a", "b", "c", "d")}
-  }
-}
-\section{More functions to manipulate graph structure}{
-  \code{add.edges} adds the specified edges to the graph. The ids of the
-  vertices are preserved. The additionally supplied named arguments will
-  be added as edge attributes for the new edges. If an attribute was not
-  present in the original graph, its value for the original edges will
-  be \code{NA}.
-
-  \code{add.vertices} adds the specified number of isolate vertices to
-  the graph. The ids of the old vertices are preserved. The additionally
-  supplied named arguments will be added as vertex attributes for the
-  new vertices. If an attribute was not present in the original graph,
-  its value is set to \code{NA} for the original vertices.
-
-  \code{delete.edges} removes the specified edges from the graph. If a
-  specified edge is not present, the function gives an error message,
-  and the original graph remains unchanged.
-  The ids of the vertices are preserved.
-
-  \code{delete.vertices} removes the specified vertices from the graph
-  together with their adjacent edges. The ids of the vertices are
-  \emph{not} preserved.
-}
-\value{For the indexing operators see the description above. The other
-  functions return a new graph.}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-# 10 vertices named a,b,c,... and no edges
-g <- graph.empty() + vertices(letters[1:10])
-
-# Add edges to make it a ring
-g <- g + path(letters[1:10], letters[1], color="grey")
-
-# Add some extra random edges
-g <- g + edges(sample(V(g), 10, replace=TRUE), color="red")
-g$layout <- layout.circle
-if (interactive()) {
-  plot(g)
-}
-
-# The old-style operations
-g <- graph.ring(10)
-add.edges(g, c(2,6,3,7) )
-delete.edges(g, E(g, P=c(1,10, 2,3)) )
-delete.vertices(g, c(2,7,8) )
-}
-\keyword{graphs}
diff --git a/man/graph.union.Rd b/man/graph.union.Rd
deleted file mode 100644
index 2a81c85..0000000
--- a/man/graph.union.Rd
+++ /dev/null
@@ -1,54 +0,0 @@
-\name{graph.union}
-\alias{graph.union}
-\alias{\%u\%}
-\concept{Graph operators}
-\title{Union of graphs}
-\description{The union of two or more graphs are created. The graphs may
-  have identical or overlapping vertex sets.}
-\usage{
-graph.union(\dots, byname = "auto")
-}
-\arguments{
-  \item{\dots}{Graph objects or lists of graph objects.}
-  \item{byname}{A logical scalar, or the character scalar
-    \code{auto}. Whether to perform the operation based on symbolic
-    vertex names. If it is \code{auto}, that means \code{TRUE} if all
-    graphs are named and \code{FALSE} otherwise. A warning is generated
-    if \code{auto} and some (but not all) graphs are named.}
-}
-\details{
-  \code{graph.union} creates the union of two or more graphs.
-  Edges which are included in at least one graph will be part of the new
-  graph. This function can be also used via the \%u\% operator.
-
-  If the \code{byname} argument is \code{TRUE} (or \code{auto} and all
-  graphs are named), then the operation is performed on symbolic vertex
-  names instead of the internal numeric vertex ids.
-
-  \code{graph.union} keeps the attributes of all graphs. All
-  graph, vertex and edge attributes are copied to the result. If an
-  attribute is present in multiple graphs and would result a name clash,
-  then this attribute is renamed by adding suffixes: _1, _2, etc.
-
-  The \code{name} vertex attribute is treated specially if the operation
-  is performed based on symbolic vertex names. In this case \code{name}
-  must be present in all graphs, and it is not renamed in the result
-  graph.
-
-  An error is generated if some input graphs are directed and others are
-  undirected.  
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-## Union of two social networks with overlapping sets of actors
-net1 <- graph.formula(D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G,
-                      H-F:G, H-I-J)
-net2 <- graph.formula(D-A:F:Y, B-A-X-F-H-Z, F-Y)
-str(net1 \%u\% net2)
-}
-\keyword{graphs}
diff --git a/man/graphNEL.Rd b/man/graphNEL.Rd
deleted file mode 100644
index 18969dd..0000000
--- a/man/graphNEL.Rd
+++ /dev/null
@@ -1,71 +0,0 @@
-\name{conversion between igraph and graphNEL graphs}
-\alias{igraph.from.graphNEL}
-\alias{igraph.to.graphNEL}
-\concept{Conversion}
-\concept{graph package}
-\concept{graphNEL object}
-\title{Convert igraph graphs to graphNEL objects or back}
-\description{The graphNEL class is defined in the \code{graph} package,
-  it is another way to represent graphs. These functions are provided to
-  convert between the igraph and the graphNEL objects.}
-\usage{
-igraph.from.graphNEL(graphNEL, name = TRUE, weight = TRUE,
-              unlist.attrs = TRUE)
-igraph.to.graphNEL(graph)
-}
-\arguments{
-  \item{graphNEL}{The graphNEL graph.}
-  \item{name}{Logical scalar, whether to add graphNEL vertex names as an
-    igraph vertex attribute called \sQuote{\code{name}}.}
-  \item{weight}{Logical scalar, whether to add graphNEL edge weights as
-    an igraph edge attribute called \sQuote{\code{weight}}. (graphNEL
-    graphs are always weighted.)}
-  \item{unlist.attrs}{Logical scalar. graphNEL attribute query functions
-    return the values of the attributes in R lists, if this argument is
-    \code{TRUE} (the default) these will be converted to atomic vectors,
-    whenever possible, before adding them to the igraph graph.}
-  \item{graph}{An igraph graph object.}
-}
-\details{
-  \code{igraph.from.graphNEL} takes a graphNEL graph and converts it to
-  an igraph graph. It handles all graph/vertex/edge attributes. If the
-  graphNEL graph has a vertex attribute called \sQuote{\code{name}} it
-  will be used as igraph vertex attribute \sQuote{\code{name}} and the
-  graphNEL vertex names will be ignored.
-
-  Because graphNEL graphs poorly support multiple edges, the edge
-  attributes of the multiple edges are lost: they are all replaced by
-  the attributes of the first of the multiple edges.
-  
-  \code{igraph.to.graphNEL} converts and igraph graph to a graphNEL
-  graph. It converts all graph/vertex/edge attributes. If the igraph
-  graph has a vertex attribute \sQuote{\code{name}}, then it will be
-  used to assign vertex names in the graphNEL graph. Otherwise igraph
-  vertex ids will be used for this purpose.
-}
-\value{
-  \code{igraph.from.graphNEL} returns an igraph graph object.
-
-  \code{igraph.to.graphNEL} returns a graphNEL graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{get.adjacency}}, \code{\link{graph.adjacency}},
-  \code{\link{get.adjlist}} and \code{\link{graph.adjlist}}.
-}
-\examples{
-## Undirected
-g <- graph.ring(10)
-V(g)$name <- letters[1:10]
-GNEL <- igraph.to.graphNEL(g)
-g2 <- igraph.from.graphNEL(GNEL)
-g2
-
-## Directed
-g3 <- graph.star(10, mode="in")
-V(g3)$name <- letters[1:10]
-GNEL2 <- igraph.to.graphNEL(g3)
-g4 <- igraph.from.graphNEL(GNEL2)
-g4
-}
-\keyword{graphs}
diff --git a/man/graph_.Rd b/man/graph_.Rd
new file mode 100644
index 0000000..3bbb780
--- /dev/null
+++ b/man/graph_.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{graph_}
+\alias{graph_}
+\title{Convert object to a graph}
+\usage{
+graph_(...)
+}
+\arguments{
+\item{...}{Parameters, see details below.}
+}
+\description{
+This is a generic function to convert R objects to igraph graphs.
+}
+\details{
+TODO
+}
+\examples{
+## These are equivalent
+graph_(cbind(1:5,2:6), from_edgelist(directed = FALSE))
+graph_(cbind(1:5,2:6), from_edgelist(), directed = FALSE)
+}
+
diff --git a/man/graph_attr-set.Rd b/man/graph_attr-set.Rd
new file mode 100644
index 0000000..98f08ae
--- /dev/null
+++ b/man/graph_attr-set.Rd
@@ -0,0 +1,76 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{graph_attr<-}
+\alias{graph.attributes<-}
+\alias{graph_attr<-}
+\title{Set all or some graph attributes}
+\usage{
+graph_attr(graph, name) <- value
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{The name of the attribute to set. If missing, then
+\code{value} should be a named list, and all list members
+are set as attributes.}
+
+\item{value}{The value of the attribute to set}
+}
+\value{
+The graph, with the attribute(s) added.
+}
+\description{
+Set all or some graph attributes
+}
+\examples{
+g <- make_graph(~ A - B:C:D)
+graph_attr(g, "name") <- "4-star"
+g
+
+graph_attr(g) <- list(layout = layout_with_fr(g),
+                       name = "4-star layed out")
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/graph_attr.Rd b/man/graph_attr.Rd
new file mode 100644
index 0000000..0ac9608
--- /dev/null
+++ b/man/graph_attr.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{graph_attr}
+\alias{get.graph.attribute}
+\alias{graph.attributes}
+\alias{graph_attr}
+\title{Graph attributes of a graph}
+\usage{
+graph_attr(graph, name)
+}
+\arguments{
+\item{graph}{Input graph.}
+
+\item{name}{The name of attribute to query. If missing, then all
+attributes are returned in a list.}
+}
+\value{
+A list of graph attributes, or a single graph attribute.
+}
+\description{
+Graph attributes of a graph
+}
+\examples{
+g <- make_ring(10)
+graph_attr(g)
+graph_attr(g, "name")
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/graph_attr_names.Rd b/man/graph_attr_names.Rd
new file mode 100644
index 0000000..71b8891
--- /dev/null
+++ b/man/graph_attr_names.Rd
@@ -0,0 +1,66 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{graph_attr_names}
+\alias{attributes}
+\alias{graph_attr_names}
+\alias{list.graph.attributes}
+\title{List names of graph attributes}
+\usage{
+graph_attr_names(graph)
+}
+\arguments{
+\item{graph}{The graph.}
+}
+\value{
+Character vector, the names of the graph attributes.
+}
+\description{
+List names of graph attributes
+}
+\examples{
+g <- make_ring(10)
+graph_attr_names(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/graph_from_adj_list.Rd b/man/graph_from_adj_list.Rd
new file mode 100644
index 0000000..ccdf6b6
--- /dev/null
+++ b/man/graph_from_adj_list.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{graph_from_adj_list}
+\alias{graph.adjlist}
+\alias{graph_from_adj_list}
+\title{Create graphs from adjacency lists}
+\usage{
+graph_from_adj_list(adjlist, mode = c("out", "in", "all", "total"),
+  duplicate = TRUE)
+}
+\arguments{
+\item{adjlist}{The adjacency list. It should be consistent, i.e. the maximum
+throughout all vectors in the list must be less than the number of vectors
+(=the number of vertices in the graph). Note that the list is expected to be
+0-indexed.}
+
+\item{mode}{Character scalar, it specifies whether the graph to create is
+undirected (\sQuote{all} or \sQuote{total}) or directed; and in the latter
+case, whether it contains the outgoing (\sQuote{out}) or the incoming
+(\sQuote{in}) neighbors of the vertices.}
+
+\item{duplicate}{Logical scalar. For undirected graphs it gives whether
+edges are included in the list twice. E.g. if it is \code{TRUE} then for an
+undirected \code{{A,B}} edge \code{graph_from_adj_list} expects \code{A}
+included in the neighbors of \code{B} and \code{B} to be included in the
+neighbors of \code{A}.
+
+This argument is ignored if \code{mode} is \code{out} or \code{in}.}
+}
+\value{
+An igraph graph object.
+}
+\description{
+An adjacency list is a list of numeric vectors, containing the neighbor
+vertices for each vertex. This function creates an igraph graph object from
+such a list.
+}
+\details{
+Adjacency lists are handy if you intend to do many (small) modifications to
+a graph. In this case adjacency lists are more efficient than igraph graphs.
+
+The idea is that you convert your graph to an adjacency list by
+\code{\link{as_adj_list}}, do your modifications to the graphs and finally
+create again an igraph graph by calling \code{graph_from_adj_list}.
+}
+\examples{
+## Directed
+g <- make_ring(10, dir=TRUE)
+al <- as_adj_list(g, mode="out")
+g2 <- graph_from_adj_list(al)
+graph.isomorphic(g, g2)
+
+## Undirected
+g <- make_ring(10)
+al <- as_adj_list(g)
+g2 <- graph_from_adj_list(al, mode="all")
+graph.isomorphic(g, g2)
+ecount(g2)
+g3 <- graph_from_adj_list(al, mode="all", duplicate=FALSE)
+ecount(g3)
+which_multiple(g3)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{as_edgelist}}
+}
+\keyword{graphs}
+
diff --git a/man/graph_from_adjacency_matrix.Rd b/man/graph_from_adjacency_matrix.Rd
new file mode 100644
index 0000000..747de90
--- /dev/null
+++ b/man/graph_from_adjacency_matrix.Rd
@@ -0,0 +1,150 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/adjacency.R
+\name{graph_from_adjacency_matrix}
+\alias{from_adjacency}
+\alias{graph.adjacency}
+\alias{graph_from_adjacency_matrix}
+\title{Create graphs from adjacency matrices}
+\usage{
+graph_from_adjacency_matrix(adjmatrix, mode = c("directed", "undirected",
+  "max", "min", "upper", "lower", "plus"), weighted = NULL, diag = TRUE,
+  add.colnames = NULL, add.rownames = NA)
+
+from_adjacency(...)
+}
+\arguments{
+\item{adjmatrix}{A square adjacency matrix. From igraph version 0.5.1 this
+can be a sparse matrix created with the \code{Matrix} package.}
+
+\item{mode}{Character scalar, specifies how igraph should interpret the
+supplied matrix. See also the \code{weighted} argument, the interpretation
+depends on that too. Possible values are: \code{directed},
+\code{undirected}, \code{upper}, \code{lower}, \code{max}, \code{min},
+\code{plus}. See details below.}
+
+\item{weighted}{This argument specifies whether to create a weighted graph
+from an adjacency matrix. If it is \code{NULL} then an unweighted graph is
+created and the elements of the adjacency matrix gives the number of edges
+between the vertices. If it is a character constant then for every non-zero
+matrix entry an edge is created and the value of the entry is added as an
+edge attribute named by the \code{weighted} argument. If it is \code{TRUE}
+then a weighted graph is created and the name of the edge attribute will be
+\code{weight}. See also details below.}
+
+\item{diag}{Logical scalar, whether to include the diagonal of the matrix in
+the calculation. If this is \code{FALSE} then the diagonal is zerod out
+first.}
+
+\item{add.colnames}{Character scalar, whether to add the column names as
+vertex attributes. If it is \sQuote{\code{NULL}} (the default) then, if
+present, column names are added as vertex attribute \sQuote{name}. If
+\sQuote{\code{NA}} then they will not be added.  If a character constant,
+then it gives the name of the vertex attribute to add.}
+
+\item{add.rownames}{Character scalar, whether to add the row names as vertex
+attributes. Possible values the same as the previous argument. By default
+row names are not added. If \sQuote{\code{add.rownames}} and
+\sQuote{\code{add.colnames}} specify the same vertex attribute, then the
+former is ignored.}
+
+\item{...}{Passed to \code{graph_from_adjacency_matrix}.}
+}
+\value{
+An igraph graph object.
+}
+\description{
+\code{graph_from_adjacency_matrix} is a flexible function for creating \code{igraph}
+graphs from adjacency matrices.
+}
+\details{
+The order of the vertices are preserved, i.e. the vertex corresponding to
+the first row will be vertex 0 in the graph, etc.
+
+\code{graph_from_adjacency_matrix} operates in two main modes, depending on the
+\code{weighted} argument.
+
+If this argument is \code{NULL} then an unweighted graph is created and an
+element of the adjacency matrix gives the number of edges to create between
+the two corresponding vertices.  The details depend on the value of the
+\code{mode} argument: \describe{ \item{"directed"}{The graph will be
+directed and a matrix element gives the number of edges between two
+vertices.} \item{"undirected"}{This is exactly the same as \code{max},
+for convenience. Note that it is \emph{not} checked whether the matrix is
+symmetric.} \item{"max"}{An undirected graph will be created and
+\code{max(A(i,j), A(j,i))} gives the number of edges.}
+\item{"upper"}{An undirected graph will be created, only the upper
+right triangle (including the diagonal) is used for the number of edges.}
+\item{"lower"}{An undirected graph will be created, only the lower
+left triangle (including the diagonal) is used for creating the edges.}
+\item{"min"}{undirected graph will be created with \code{min(A(i,j),
+A(j,i))} edges between vertex \code{i} and \code{j}.} \item{"plus"}{
+undirected graph will be created with \code{A(i,j)+A(j,i)} edges between
+vertex \code{i} and \code{j}.} }
+
+If the \code{weighted} argument is not \code{NULL} then the elements of the
+matrix give the weights of the edges (if they are not zero).  The details
+depend on the value of the \code{mode} argument: \describe{
+\item{"directed"}{The graph will be directed and a matrix element
+gives the edge weights.} \item{"undirected"}{First we check that the
+matrix is symmetric. It is an error if not. Then only the upper triangle is
+used to create a weighted undirected graph.} \item{"max"}{An
+undirected graph will be created and \code{max(A(i,j), A(j,i))} gives the
+edge weights.} \item{"upper"}{An undirected graph will be created,
+only the upper right triangle (including the diagonal) is used (for the edge
+weights).} \item{"lower"}{An undirected graph will be created, only
+the lower left triangle (including the diagonal) is used for creating the
+edges.} \item{"min"}{An undirected graph will be created,
+\code{min(A(i,j), A(j,i))} gives the edge weights.} \item{"plus"}{An
+undirected graph will be created, \code{A(i,j)+A(j,i)} gives the edge
+weights.} }
+}
+\examples{
+adjm <- matrix(sample(0:1, 100, replace=TRUE, prob=c(0.9,0.1)), nc=10)
+g1 <- graph_from_adjacency_matrix( adjm )
+adjm <- matrix(sample(0:5, 100, replace=TRUE,
+                      prob=c(0.9,0.02,0.02,0.02,0.02,0.02)), nc=10)
+g2 <- graph_from_adjacency_matrix(adjm, weighted=TRUE)
+E(g2)$weight
+
+## various modes for weighted graphs, with some tests
+nzs <- function(x) sort(x [x!=0])
+adjm <- matrix(runif(100), 10)
+adjm[ adjm<0.5 ] <- 0
+g3 <- graph_from_adjacency_matrix((adjm + t(adjm))/2, weighted=TRUE,
+                      mode="undirected")
+
+g4 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="max")
+all(nzs(pmax(adjm, t(adjm))[upper.tri(adjm)]) == sort(E(g4)$weight))
+
+g5 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="min")
+all(nzs(pmin(adjm, t(adjm))[upper.tri(adjm)]) == sort(E(g5)$weight))
+
+g6 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="upper")
+all(nzs(adjm[upper.tri(adjm)]) == sort(E(g6)$weight))
+
+g7 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="lower")
+all(nzs(adjm[lower.tri(adjm)]) == sort(E(g7)$weight))
+
+g8 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="plus")
+d2 <- function(x) { diag(x) <- diag(x)/2; x }
+all(nzs((d2(adjm+t(adjm)))[lower.tri(adjm)]) == sort(E(g8)$weight))
+
+g9 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, mode="plus", diag=FALSE)
+d0 <- function(x) { diag(x) <- 0 }
+all(nzs((d0(adjm+t(adjm)))[lower.tri(adjm)]) == sort(E(g9)$weight))
+
+## row/column names
+rownames(adjm) <- sample(letters, nrow(adjm))
+colnames(adjm) <- seq(ncol(adjm))
+g10 <- graph_from_adjacency_matrix(adjm, weighted=TRUE, add.rownames="code")
+summary(g10)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\link{graph} and \code{\link{graph_from_literal}} for other ways to
+create graphs.
+}
+\keyword{graphs}
+
diff --git a/man/graph_from_atlas.Rd b/man/graph_from_atlas.Rd
new file mode 100644
index 0000000..ebbeaa6
--- /dev/null
+++ b/man/graph_from_atlas.Rd
@@ -0,0 +1,74 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{graph_from_atlas}
+\alias{atlas}
+\alias{graph.atlas}
+\alias{graph_from_atlas}
+\title{Create a graph from the Graph Atlas}
+\usage{
+graph_from_atlas(n)
+
+atlas(...)
+}
+\arguments{
+\item{n}{The id of the graph to create.}
+
+\item{...}{Passed to \code{graph_from_atlas}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{graph_from_atlas} creates graphs from the book
+\sQuote{An Atlas of Graphs} by
+Roland C. Read and Robin J. Wilson. The atlas contains all undirected
+graphs with up to seven vertices, numbered from 0 up to 1252. The
+graphs are listed:
+\enumerate{
+   \item in increasing order of number of nodes;
+   \item for a fixed number of nodes, in increasing order of the number
+     of edges;
+   \item for fixed numbers of nodes and edges, in increasing order of
+     the degree sequence, for example 111223 < 112222;
+   \item for fixed degree sequence, in increasing number of
+     automorphisms.
+}
+}
+\examples{
+## Some randomly picked graphs from the atlas
+graph_from_atlas(sample(0:1252, 1))
+graph_from_atlas(sample(0:1252, 1))
+}
+\seealso{
+Other determimistic constructors: \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+\concept{
+Graph Atlas.
+}
+
diff --git a/man/graph_from_data_frame.Rd b/man/graph_from_data_frame.Rd
new file mode 100644
index 0000000..4ab1156
--- /dev/null
+++ b/man/graph_from_data_frame.Rd
@@ -0,0 +1,124 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R, R/data_frame.R
+\name{as_data_frame}
+\alias{as_data_frame}
+\alias{from_data_frame}
+\alias{get.data.frame}
+\alias{graph.data.frame}
+\alias{graph_from_data_frame}
+\title{Creating igraph graphs from data frames or vice-versa}
+\usage{
+as_data_frame(x, what = c("edges", "vertices", "both"))
+
+graph_from_data_frame(d, directed = TRUE, vertices = NULL)
+
+from_data_frame(...)
+}
+\arguments{
+\item{x}{An igraph object.}
+
+\item{what}{Character constant, whether to return info about vertices,
+edges, or both. The default is \sQuote{edges}.}
+
+\item{d}{A data frame containing a symbolic edge list in the first two
+columns. Additional columns are considered as edge attributes.  Since
+version 0.7 this argument is coerced to a data frame with
+\code{as.data.frame}.}
+
+\item{directed}{Logical scalar, whether or not to create a directed graph.}
+
+\item{vertices}{A data frame with vertex metadata, or \code{NULL}. See
+details below. Since version 0.7 this argument is coerced to a data frame
+with \code{as.data.frame}, if not \code{NULL}.}
+
+\item{...}{Passed to \code{graph_from_data_frame}.}
+}
+\value{
+An igraph graph object for \code{graph_from_data_frame}, and either a
+data frame or a list of two data frames named \code{edges} and
+\code{vertices} for \code{as.data.frame}.
+}
+\description{
+This function creates an igraph graph from one or two data frames containing
+the (symbolic) edge list and edge/vertex attributes.
+}
+\details{
+\code{graph_from_data_frame} creates igraph graphs from one or two data frames.
+It has two modes of operatation, depending whether the \code{vertices}
+argument is \code{NULL} or not.
+
+If \code{vertices} is \code{NULL}, then the first two columns of \code{d}
+are used as a symbolic edge list and additional columns as edge attributes.
+The names of the attributes are taken from the names of the columns.
+
+If \code{vertices} is not \code{NULL}, then it must be a data frame giving
+vertex metadata. The first column of \code{vertices} is assumed to contain
+symbolic vertex names, this will be added to the graphs as the
+\sQuote{\code{name}} vertex attribute. Other columns will be added as
+additional vertex attributes. If \code{vertices} is not \code{NULL} then the
+symbolic edge list given in \code{d} is checked to contain only vertex names
+listed in \code{vertices}.
+
+Typically, the data frames are exported from some speadsheat software like
+Excel and are imported into R via \code{\link{read.table}},
+\code{\link{read.delim}} or \code{\link{read.csv}}.
+
+\code{as_data_frame} converts the igraph graph into one or more data
+frames, depending on the \code{what} argument.
+
+If the \code{what} argument is \code{edges} (the default), then the edges of
+the graph and also the edge attributes are returned. The edges will be in
+the first two columns, named \code{from} and \code{to}. (This also denotes
+edge direction for directed graphs.)  For named graphs, the vertex names
+will be included in these columns, for other graphs, the numeric vertex ids.
+The edge attributes will be in the other columns. It is not a good idea to
+have an edge attribute named \code{from} or \code{to}, because then the
+column named in the data frame will not be unique. The edges are listed in
+the order of their numeric ids.
+
+If the \code{what} argument is \code{vertices}, then vertex attributes are
+returned. Vertices are listed in the order of their numeric vertex ids.
+
+If the \code{what} argument is \code{both}, then both vertex and edge data
+is returned, in a list with named entries \code{vertices} and \code{edges}.
+}
+\note{
+For \code{graph_from_data_frame} \code{NA} elements in the first two
+columns \sQuote{d} are replaced by the string \dQuote{NA} before creating
+the graph. This means that all \code{NA}s will correspond to a single
+vertex.
+
+\code{NA} elements in the first column of \sQuote{vertices} are also
+replaced by the string \dQuote{NA}, but the rest of \sQuote{vertices} is not
+touched. In other words, vertex names (=the first column) cannot be
+\code{NA}, but other vertex attributes can.
+}
+\examples{
+## A simple example with a couple of actors
+## The typical case is that these tables are read in from files....
+actors <- data.frame(name=c("Alice", "Bob", "Cecil", "David",
+                            "Esmeralda"),
+                     age=c(48,33,45,34,21),
+                     gender=c("F","M","F","M","F"))
+relations <- data.frame(from=c("Bob", "Cecil", "Cecil", "David",
+                               "David", "Esmeralda"),
+                        to=c("Alice", "Bob", "Alice", "Alice", "Bob", "Alice"),
+                        same.dept=c(FALSE,FALSE,TRUE,FALSE,FALSE,TRUE),
+                        friendship=c(4,5,5,2,1,1), advice=c(4,5,5,4,2,3))
+g <- graph_from_data_frame(relations, directed=TRUE, vertices=actors)
+print(g, e=TRUE, v=TRUE)
+
+## The opposite operation
+as_data_frame(g, what="vertices")
+as_data_frame(g, what="edges")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{graph_from_literal}}
+for another way to create graphs, \code{\link{read.table}} to read in tables
+from files.
+}
+\keyword{graphs}
+
diff --git a/man/graph_from_edgelist.Rd b/man/graph_from_edgelist.Rd
new file mode 100644
index 0000000..92c9939
--- /dev/null
+++ b/man/graph_from_edgelist.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/data_frame.R
+\name{graph_from_edgelist}
+\alias{from_edgelist}
+\alias{graph.edgelist}
+\alias{graph_from_edgelist}
+\title{Create a graph from an edge list matrix}
+\usage{
+graph_from_edgelist(el, directed = TRUE)
+
+from_edgelist(...)
+}
+\arguments{
+\item{el}{The edge list, a two column matrix, character or numeric.}
+
+\item{directed}{Whether to create a directed graph.}
+
+\item{...}{Passed to \code{graph_from_edgelist}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{graph_from_edgelist} creates a graph from an edge list. Its argument
+is a two-column matrix, each row defines one edge. If it is
+a numeric matrix then its elements are interpreted as vertex ids. If
+it is a character matrix then it is interpreted as symbolic vertex
+names and a vertex id will be assigned to each name, and also a
+\code{name} vertex attribute will be added.
+}
+\examples{
+el <- matrix( c("foo", "bar", "bar", "foobar"), nc = 2, byrow = TRUE)
+graph_from_edgelist(el)
+
+# Create a ring by hand
+graph_from_edgelist(cbind(1:10, c(2:10, 1)))
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+\concept{
+Edge list
+}
+
diff --git a/man/graph_from_graphdb.Rd b/man/graph_from_graphdb.Rd
new file mode 100644
index 0000000..98db9da
--- /dev/null
+++ b/man/graph_from_graphdb.Rd
@@ -0,0 +1,93 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/foreign.R
+\name{graph_from_graphdb}
+\alias{graph.graphdb}
+\alias{graph_from_graphdb}
+\title{Load a graph from the graph database for testing graph isomorphism.}
+\usage{
+graph_from_graphdb(url = NULL, prefix = "iso", type = "r001",
+  nodes = NULL, pair = "A", which = 0,
+  base = "http://cneurocvs.rmki.kfki.hu/graphdb/gzip", compressed = TRUE,
+  directed = TRUE)
+}
+\arguments{
+\item{url}{If not \code{NULL} it is a complete URL with the file to import.}
+
+\item{prefix}{Gives the prefix. See details below. Possible values:
+\code{iso}, \code{i2}, \code{si4}, \code{si6}, \code{mcs10}, \code{mcs30},
+\code{mcs50}, \code{mcs70}, \code{mcs90}.}
+
+\item{type}{Gives the graph type identifier. See details below. Possible
+values: \code{r001}, \code{r005}, \code{r01}, \code{r02}, \code{m2D},
+\code{m2Dr2}, \code{m2Dr4}, \code{m2Dr6} \code{m3D}, \code{m3Dr2},
+\code{m3Dr4}, \code{m3Dr6}, \code{m4D}, \code{m4Dr2}, \code{m4Dr4},
+\code{m4Dr6}, \code{b03}, \code{b03m}, \code{b06}, \code{b06m}, \code{b09},
+\code{b09m}.}
+
+\item{nodes}{The number of vertices in the graph.}
+
+\item{pair}{Specifies which graph of the pair to read. Possible values:
+\code{A} and \code{B}.}
+
+\item{which}{Gives the number of the graph to read. For every graph type
+there are a number of actual graphs in the database. This argument specifies
+which one to read.}
+
+\item{base}{The base address of the database. See details below.}
+
+\item{compressed}{Logical constant, if TRUE than the file is expected to be
+compressed by gzip. If \code{url} is \code{NULL} then a \sQuote{\code{.gz}}
+suffix is added to the filename.}
+
+\item{directed}{Logical constant, whether to create a directed graph.}
+}
+\value{
+A new graph object.
+}
+\description{
+This function downloads a graph from a database created for the evaluation
+of graph isomorphism testing algothitms.
+}
+\details{
+\code{graph_from_graphdb} reads a graph from the graph database from an FTP or
+HTTP server or from a local copy. It has two modes of operation:
+
+If the \code{url} argument is specified then it should the complete path to
+a local or remote graph database file. In this case we simply call
+\code{\link{read_graph}} with the proper arguments to read the file.
+
+If \code{url} is \code{NULL}, and this is the default, then the filename is
+assembled from the \code{base}, \code{prefix}, \code{type}, \code{nodes},
+\code{pair} and \code{which} arguments.
+
+Unfortunately the original graph database homepage is now defunct, but see
+its old version at
+\url{http://web.archive.org/web/20090215182331/http://amalfi.dis.unina.it/graph/db/doc/graphdbat.html}
+for the actual format of a graph database file and other information.
+}
+\examples{
+\dontrun{
+g <- graph_from_graphdb(prefix="iso", type="r001", nodes=20, pair="A",
+  which=10, compressed=TRUE)
+g2 <- graph_from_graphdb(prefix="iso", type="r001", nodes=20, pair="B",
+  which=10, compressed=TRUE)
+graph.isomorphic.vf2(g, g2)	\% should be TRUE
+g3 <- graph_from_graphdb(url=paste(sep="/",
+                              "http://cneurocvs.rmki.kfki.hu",
+                              "graphdb/gzip/iso/bvg/b06m",
+                              "iso_b06m_m200.A09.gz"))
+}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+M. De Santo, P. Foggia, C. Sansone, M. Vento: A large database
+of graphs and its use for benchmarking graph isomorphism algorithms,
+\emph{Pattern Recognition Letters}, Volume 24, Issue 8 (May 2003)
+}
+\seealso{
+\code{\link{read_graph}}, \code{\link{graph.isomorphic.vf2}}
+}
+\keyword{graphs}
+
diff --git a/man/graph_from_graphnel.Rd b/man/graph_from_graphnel.Rd
new file mode 100644
index 0000000..dc5e923
--- /dev/null
+++ b/man/graph_from_graphnel.Rd
@@ -0,0 +1,67 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/conversion.R
+\name{graph_from_graphnel}
+\alias{graph_from_graphnel}
+\alias{igraph.from.graphNEL}
+\title{Convert graphNEL objects from the graph package to igraph}
+\usage{
+graph_from_graphnel(graphNEL, name = TRUE, weight = TRUE,
+  unlist.attrs = TRUE)
+}
+\arguments{
+\item{graphNEL}{The graphNEL graph.}
+
+\item{name}{Logical scalar, whether to add graphNEL vertex names as an
+igraph vertex attribute called \sQuote{\code{name}}.}
+
+\item{weight}{Logical scalar, whether to add graphNEL edge weights as an
+igraph edge attribute called \sQuote{\code{weight}}. (graphNEL graphs are
+always weighted.)}
+
+\item{unlist.attrs}{Logical scalar. graphNEL attribute query functions
+return the values of the attributes in R lists, if this argument is
+\code{TRUE} (the default) these will be converted to atomic vectors,
+whenever possible, before adding them to the igraph graph.}
+}
+\value{
+\code{graph_from_graphnel} returns an igraph graph object.
+}
+\description{
+The graphNEL class is defined in the \code{graph} package, it is another
+way to represent graphs. \code{graph_from_graphnel} takes a graphNEL
+graph and converts it to an igraph graph. It handles all
+graph/vertex/edge attributes. If the graphNEL graph has a vertex
+attribute called \sQuote{\code{name}} it will be used as igraph vertex
+attribute \sQuote{\code{name}} and the graphNEL vertex names will be
+ignored.
+}
+\details{
+Because graphNEL graphs poorly support multiple edges, the edge
+attributes of the multiple edges are lost: they are all replaced by the
+attributes of the first of the multiple edges.
+}
+\examples{
+\dontrun{
+## Undirected
+g <- make_ring(10)
+V(g)$name <- letters[1:10]
+GNEL <- as_graphnel(g)
+g2 <- graph_from_graphnel(GNEL)
+g2
+
+## Directed
+g3 <- make_star(10, mode="in")
+V(g3)$name <- letters[1:10]
+GNEL2 <- as_graphnel(g3)
+g4 <- graph_from_graphnel(GNEL2)
+g4
+}
+#'
+}
+\seealso{
+\code{\link{as_graphnel}} for the other direction,
+\code{\link{as_adj}}, \code{\link{graph_from_adjacency_matrix}},
+\code{\link{as_adj_list}} and \code{\link{graph.adjlist}} for other
+graph representations.
+}
+
diff --git a/man/graph_from_incidence_matrix.Rd b/man/graph_from_incidence_matrix.Rd
new file mode 100644
index 0000000..327e24b
--- /dev/null
+++ b/man/graph_from_incidence_matrix.Rd
@@ -0,0 +1,85 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/incidence.R
+\name{graph_from_incidence_matrix}
+\alias{from_incidence_matrix}
+\alias{graph.incidence}
+\alias{graph_from_incidence_matrix}
+\title{Create graphs from an incidence matrix}
+\usage{
+graph_from_incidence_matrix(incidence, directed = FALSE, mode = c("all",
+  "out", "in", "total"), multiple = FALSE, weighted = NULL,
+  add.names = NULL)
+
+from_incidence_matrix(...)
+}
+\arguments{
+\item{incidence}{The input incidence matrix. It can also be a sparse matrix
+from the \code{Matrix} package.}
+
+\item{directed}{Logical scalar, whether to create a directed graph.}
+
+\item{mode}{A character constant, defines the direction of the edges in
+directed graphs, ignored for undirected graphs. If \sQuote{\code{out}}, then
+edges go from vertices of the first kind (corresponding to rows in the
+incidence matrix) to vertices of the second kind (columns in the incidence
+matrix). If \sQuote{\code{in}}, then the opposite direction is used. If
+\sQuote{\code{all}} or \sQuote{\code{total}}, then mutual edges are created.}
+
+\item{multiple}{Logical scalar, specifies how to interpret the matrix
+elements. See details below.}
+
+\item{weighted}{This argument specifies whether to create a weighted graph
+from the incidence matrix. If it is \code{NULL} then an unweighted graph is
+created and the \code{multiple} argument is used to determine the edges of
+the graph. If it is a character constant then for every non-zero matrix
+entry an edge is created and the value of the entry is added as an edge
+attribute named by the \code{weighted} argument. If it is \code{TRUE} then a
+weighted graph is created and the name of the edge attribute will be
+\sQuote{\code{weight}}.}
+
+\item{add.names}{A character constant, \code{NA} or \code{NULL}.
+\code{graph_from_incidence_matrix} can add the row and column names of the incidence
+matrix as vertex attributes. If this argument is \code{NULL} (the default)
+and the incidence matrix has both row and column names, then these are added
+as the \sQuote{\code{name}} vertex attribute. If you want a different vertex
+attribute for this, then give the name of the attributes as a character
+string. If this argument is \code{NA}, then no vertex attributes (other than
+type) will be added.}
+
+\item{...}{Passed to \code{graph_from_incidence_matrix}.}
+}
+\value{
+A bipartite igraph graph. In other words, an igraph graph that has a
+vertex attribute \code{type}.
+}
+\description{
+\code{graph_from_incidence_matrix} creates a bipartite igraph graph from an incidence
+matrix.
+}
+\details{
+Bipartite graphs have a \sQuote{\code{type}} vertex attribute in igraph,
+this is boolean and \code{FALSE} for the vertices of the first kind and
+\code{TRUE} for vertices of the second kind.
+
+\code{graph_from_incidence_matrix} can operate in two modes, depending on the
+\code{multiple} argument. If it is \code{FALSE} then a single edge is
+created for every non-zero element in the incidence matrix. If
+\code{multiple} is \code{TRUE}, then the matrix elements are rounded up to
+the closest non-negative integer to get the number of edges to create
+between a pair of vertices.
+}
+\examples{
+inc <- matrix(sample(0:1, 15, repl=TRUE), 3, 5)
+colnames(inc) <- letters[1:5]
+rownames(inc) <- LETTERS[1:3]
+graph_from_incidence_matrix(inc)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{make_bipartite_graph}} for another way to create bipartite
+graphs
+}
+\keyword{graphs}
+
diff --git a/man/graph_from_isomorphism_class.Rd b/man/graph_from_isomorphism_class.Rd
new file mode 100644
index 0000000..56a8624
--- /dev/null
+++ b/man/graph_from_isomorphism_class.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{graph_from_isomorphism_class}
+\alias{graph.isocreate}
+\alias{graph_from_isomorphism_class}
+\title{Create a graph from an isomorphism class}
+\usage{
+graph_from_isomorphism_class(size, number, directed = TRUE)
+}
+\arguments{
+\item{size}{The number of vertices in the graph.}
+
+\item{number}{The isomorphism class.}
+
+\item{directed}{Whether to create a directed graph (the default).}
+}
+\value{
+An igraph object, the graph of the given size, directedness
+  and isomorphism class.
+}
+\description{
+The isomorphism class is a non-negative integer number.
+Graphs (with the same number of vertices) having the same isomorphism
+class are isomorphic and isomorphic graphs always have the same
+isomorphism class. Currently it can handle only graphs with 3 or 4
+vertices.
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/graph_from_lcf.Rd b/man/graph_from_lcf.Rd
new file mode 100644
index 0000000..78f1061
--- /dev/null
+++ b/man/graph_from_lcf.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{graph_from_lcf}
+\alias{graph.lcf}
+\alias{graph_from_lcf}
+\title{Creating a graph from LCF notation}
+\usage{
+graph_from_lcf(n, shifts, repeats = 1)
+}
+\arguments{
+\item{n}{Integer, the number of vertices in the graph.}
+
+\item{shifts}{Integer vector, the shifts.}
+
+\item{repeats}{Integer constant, how many times to repeat the shifts.}
+}
+\value{
+A graph object.
+}
+\description{
+LCF is short for Lederberg-Coxeter-Frucht, it is a concise notation for
+3-regular Hamiltonian graphs. It constists of three parameters, the number
+of vertices in the graph, a list of shifts giving additional edges to a
+cycle backbone and another integer giving how many times the shifts should
+be performed. See \url{http://mathworld.wolfram.com/LCFNotation.html} for
+details.
+}
+\examples{
+# This is the Franklin graph:
+g1 <- graph_from_lcf(12, c(5,-5), 6)
+g2 <- make_graph("Franklin")
+isomorphic(g1, g2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{graph}} can create arbitrary graphs, see also the other
+functions on the its manual page for creating special graphs.
+}
+\keyword{graphs}
+
diff --git a/man/graph_from_literal.Rd b/man/graph_from_literal.Rd
new file mode 100644
index 0000000..52b3cf8
--- /dev/null
+++ b/man/graph_from_literal.Rd
@@ -0,0 +1,153 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{graph_from_literal}
+\alias{from_literal}
+\alias{graph.formula}
+\alias{graph_from_literal}
+\title{Creating (small) graphs via a simple interface}
+\usage{
+graph_from_literal(..., simplify = TRUE)
+
+from_literal(...)
+}
+\arguments{
+\item{...}{For \code{graph_from_literal} the formulae giving the
+structure of the graph, see details below. For \code{from_literal}
+all arguments are passed to \code{graph_from_literal}.}
+
+\item{simplify}{Logical scalar, whether to call \code{\link{simplify}}
+on the created graph. By default the graph is simplified, loop and
+multiple edges are removed.}
+}
+\value{
+An igraph graph
+}
+\description{
+This function is useful if you want to create a small (named) graph
+quickly, it works for both directed and undirected graphs.
+}
+\details{
+\code{graph_from_literal} is very handy for creating small graphs quickly.
+You need to supply one or more R expressions giving the structure of
+the graph. The expressions consist of vertex names and edge
+operators. An edge operator is a sequence of \sQuote{\code{-}} and
+\sQuote{\code{+}} characters, the former is for the edges and the
+latter is used for arrow heads. The edges can be arbitrarily long,
+ie. you may use as many \sQuote{\code{-}} characters to \dQuote{draw}
+them as you like.
+
+If all edge operators consist of only \sQuote{\code{-}} characters
+then the graph will be undirected, whereas a single \sQuote{\code{+}}
+character implies a directed graph.
+
+Let us see some simple examples. Without arguments the function
+creates an empty graph:
+\preformatted{  graph_from_literal()
+}
+
+A simple undirected graph with two vertices called \sQuote{A} and
+\sQuote{B} and one edge only:
+\preformatted{  graph_from_literal(A-B)
+}
+
+Remember that the length of the edges does not matter, so we could
+have written the following, this creates the same graph:
+\preformatted{  graph_from_literal( A-----B )
+}
+
+If you have many disconnected components in the graph, separate them
+with commas. You can also give isolate vertices.
+\preformatted{  graph_from_literal( A--B, C--D, E--F, G--H, I, J, K )
+}
+
+The \sQuote{\code{:}} operator can be used to define vertex sets. If
+an edge operator connects two vertex sets then every vertex from the
+first set will be connected to every vertex in the second set. The
+following form creates a full graph, including loop edges:
+\preformatted{  graph_from_literal( A:B:C:D -- A:B:C:D )
+}
+
+In directed graphs, edges will be created only if the edge operator
+includes a arrow head (\sQuote{+}) \emph{at the end} of the edge:
+\preformatted{  graph_from_literal( A -+ B -+ C )
+  graph_from_literal( A +- B -+ C )
+  graph_from_literal( A +- B -- C )
+}
+Thus in the third example no edge is created between vertices \code{B}
+and \code{C}.
+
+Mutual edges can be also created with a simple edge operator:
+\preformatted{  graph_from_literal( A +-+ B +---+ C ++ D + E)
+}
+Note again that the length of the edge operators is arbitrary,
+\sQuote{\code{+}}, \sQuote{\code{++}} and \sQuote{\code{+-----+}} have
+exactly the same meaning.
+
+If the vertex names include spaces or other special characters then
+you need to quote them:
+\preformatted{  graph_from_literal( "this is" +- "a silly" -+ "graph here" )
+}
+You can include any character in the vertex names this way, even
+\sQuote{+} and \sQuote{-} characters.
+
+See more examples below.
+}
+\examples{
+# A simple undirected graph
+g <- graph_from_literal( Alice-Bob-Cecil-Alice, Daniel-Cecil-Eugene,
+                     Cecil-Gordon )
+g
+
+# Another undirected graph, ":" notation
+g2 <- graph_from_literal( Alice-Bob:Cecil:Daniel, Cecil:Daniel-Eugene:Gordon )
+g2
+
+# A directed graph
+g3 <- graph_from_literal( Alice +-+ Bob --+ Cecil +-- Daniel,
+                     Eugene --+ Gordon:Helen )
+g3
+
+# A graph with isolate vertices
+g4 <- graph_from_literal( Alice -- Bob -- Daniel, Cecil:Gordon, Helen )
+g4
+V(g4)$name
+
+# "Arrows" can be arbitrarily long
+g5 <- graph_from_literal( Alice +---------+ Bob )
+g5
+
+# Special vertex names
+g6 <- graph_from_literal( "+" -- "-", "*" -- "/", "\%\%" -- "\%/\%" )
+g6
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+
diff --git a/man/graph_version.Rd b/man/graph_version.Rd
new file mode 100644
index 0000000..6adc4c6
--- /dev/null
+++ b/man/graph_version.Rd
@@ -0,0 +1,32 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/versions.R
+\name{graph_version}
+\alias{graph_version}
+\title{Igraph data structure versions}
+\usage{
+graph_version(graph)
+}
+\arguments{
+\item{graph}{The input graph. If it is missing, then
+the version number of the current data format is returned.}
+}
+\value{
+A character scalar.
+}
+\description{
+Igraph's internal data representation changes sometimes between
+versions. This means that it is not possible to use igraph objects
+that were created (and possibly saved to a file) with an older
+igraph version.
+}
+\details{
+\code{graph_version} queries the current data format,
+or the data format of a possibly older igraph graph.
+
+\code{\link{upgrade_graph}} can convert an older data format
+to the current one.
+}
+\seealso{
+upgrade_graph to convert the data format of a graph.
+}
+
diff --git a/man/graphlet_basis.Rd b/man/graphlet_basis.Rd
new file mode 100644
index 0000000..c395150
--- /dev/null
+++ b/man/graphlet_basis.Rd
@@ -0,0 +1,99 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/glet.R
+\name{graphlet_basis}
+\alias{graphlet_basis}
+\alias{graphlet_proj}
+\alias{graphlets}
+\alias{graphlets.candidate.basis}
+\alias{graphlets.project}
+\title{Graphlet decomposition of a graph}
+\usage{
+graphlet_basis(graph, weights = NULL)
+
+graphlet_proj(graph, weights = NULL, cliques, niter = 1000, Mu = rep(1,
+  length(cliques)))
+}
+\arguments{
+\item{graph}{The input graph, edge directions are ignored. Only simple graph
+(i.e. graphs without self-loops and multiple edges) are supported.}
+
+\item{weights}{Edge weights. If the graph has a \code{weight} edge attribute
+and this argument is \code{NULL} (the default), then the \code{weight} edge
+attribute is used.}
+
+\item{cliques}{A list of vertex ids, the graphlet basis to use for the
+projection.}
+
+\item{niter}{Integer scalar, the number of iterations to perform.}
+
+\item{Mu}{Starting weights for the projection.}
+}
+\value{
+\code{graphlets} returns a list with two members: \item{cliques}{A
+list of subgraphs, the candidate graphlet basis. Each subgraph is give by a
+vector of vertex ids.} \item{Mu}{The weights of the subgraphs in graphlet
+basis.}
+
+\code{graphlet_basis} returns a list of two elements: \item{cliques}{A list
+of subgraphs, the candidate graphlet basis. Each subgraph is give by a
+vector of vertex ids.} \item{thresholds}{The weight thresholds used for
+finding the subgraphs.}
+
+\code{graphlet_proj} return a numeric vector, the weights of the graphlet
+basis subgraphs.
+}
+\description{
+Graphlet decomposition models a weighted undirected graph via the union of
+potentially overlapping dense social groups.  This is done by a two-step
+algorithm. In the first step a candidate set of groups (a candidate basis)
+is created by finding cliques if the thresholded input graph. In the second
+step these the graph is projected on the candidate basis, resulting a weight
+coefficient for each clique in the candidate basis.
+}
+\details{
+igraph contains three functions for performing the graph decomponsition of a
+graph. The first is \code{graphlets}, which performed both steps on the
+method and returns a list of subgraphs, with their corresponding weights.
+The second and third functions correspond to the first and second steps of
+the algorithm, and they are useful if the user wishes to perform them
+individually: \code{graphlet_basis} and \code{graphlet_proj}.
+}
+\examples{
+## Create an example graph first
+D1 <- matrix(0, 5, 5)
+D2 <- matrix(0, 5, 5)
+D3 <- matrix(0, 5, 5)
+D1[1:3, 1:3] <- 2
+D2[3:5, 3:5] <- 3
+D3[2:5, 2:5] <- 1
+
+g <- simplify(graph_from_adjacency_matrix(D1 + D2 + D3,
+      mode="undirected", weighted=TRUE))
+V(g)$color <- "white"
+E(g)$label <- E(g)$weight
+E(g)$label.cex <- 2
+E(g)$color <- "black"
+layout(matrix(1:6, nrow=2, byrow=TRUE))
+co <- layout_with_kk(g)
+par(mar=c(1,1,1,1))
+plot(g, layout=co)
+
+## Calculate graphlets
+gl <- graphlets(g, niter=1000)
+
+## Plot graphlets
+for (i in 1:length(gl$cliques)) {
+  sel <- gl$cliques[[i]]
+  V(g)$color <- "white"
+  V(g)[sel]$color <- "#E495A5"
+  E(g)$width <- 1
+  E(g)[ V(g)[sel] \%--\% V(g)[sel] ]$width <- 2
+  E(g)$label <- ""
+  E(g)[ width == 2 ]$label <- round(gl$Mu[i], 2)
+  E(g)$color <- "black"
+  E(g)[ width == 2 ]$color <- "#E495A5"
+  plot(g, layout=co)
+}
+#'
+}
+
diff --git a/man/graphlets.Rd b/man/graphlets.Rd
deleted file mode 100644
index f446ada..0000000
--- a/man/graphlets.Rd
+++ /dev/null
@@ -1,100 +0,0 @@
-\name{Graphlets}
-\alias{graphlets}
-\alias{graphlets.project}
-\alias{graphlets.candidate.basis}
-\concept{Graphlets}
-\title{Graphlet decomposition of a graph}
-\description{
- Graphlet decomposition models a weighted undirected graph
- via the union of potentially overlapping dense social groups.
- This is done by a two-step algorithm. In the first step a candidate
- set of groups (a candidate basis) is created by finding cliques
- if the thresholded input graph. In the second step these 
- the graph is projected on the candidate basis, resulting a 
- weight coefficient for each clique in the candidate basis.
-}
-\usage{
-graphlets (graph, weights = NULL, niter = 1000)
-graphlets.candidate.basis (graph, weights = NULL)
-graphlets.project (graph, weights = NULL, cliques, niter = 1000,
-     Mu = rep(1, length(cliques))) 
-}
-\arguments{
-  \item{graph}{The input graph, edge directions are ignored. Only simple
-    graph (i.e. graphs without self-loops and multiple edges) are
-    supported.}
-  \item{weights}{Edge weights. If the graph has a \code{weight} edge
-    attribute and this argument is \code{NULL} (the default), then the
-    \code{weight} edge attribute is used.}
-  \item{niter}{Integer scalar, the number of iterations to perform.}
-  \item{cliques}{A list of vertex ids, the graphlet basis to use for the
-    projection.}
-  \item{Mu}{Starting weights for the projection.}
-}
-\details{
- igraph contains three functions for performing the graph 
- decomponsition of a graph. The first is \code{graphlets}, which 
- performed both steps on the method and returns a list of subgraphs,
- with their corresponding weights. The second and third functions 
- correspond to the first and second steps of the algorithm, and they are 
- useful if the user wishes to perform them individually: 
- \code{graphlets.candidate.basis} and 
- \code{graphlets.project}.
-}
-\value{
-  \code{graphlets} returns a list with two members:
-  \item{cliques}{A list of subgraphs, the candidate graphlet
-    basis. Each subgraph is give by a vector of vertex ids.}
-  \item{Mu}{The weights of the subgraphs in graphlet basis.}
-
-  \code{graphlets.candidate.basis} returns a list of two elements:
-  \item{cliques}{A list of subgraphs, the candidate graphlet
-    basis. Each subgraph is give by a vector of vertex ids.}
-  \item{thresholds}{The weight thresholds used for finding the
-    subgraphs.}
-
-  \code{graphlets.project} return a numeric vector, the weights
-  of the graphlet basis subgraphs.
-}
-% \references{}
-\author{
-  Gabor Csardi \email{csardi.gabor at gmail.com}
-}
-% \seealso{}
-\examples{
-## Create an example graph first
-D1 <- matrix(0, 5, 5)
-D2 <- matrix(0, 5, 5)
-D3 <- matrix(0, 5, 5)
-D1[1:3, 1:3] <- 2
-D2[3:5, 3:5] <- 3
-D3[2:5, 2:5] <- 1
-  
-g <- simplify(graph.adjacency(D1 + D2 + D3, mode="undirected", weighted=TRUE))
-V(g)$color <- "white"
-E(g)$label <- E(g)$weight
-E(g)$label.cex <- 2
-E(g)$color <- "black"
-layout(matrix(1:6, nrow=2, byrow=TRUE))
-co <- layout.kamada.kawai(g)
-par(mar=c(1,1,1,1))
-plot(g, layout=co)
-
-## Calculate graphlets
-gl <- graphlets(g, niter=1000)
-
-## Plot graphlets
-for (i in 1:length(gl$cliques)) {
-  sel <- gl$cliques[[i]]
-  V(g)$color <- "white"
-  V(g)[sel]$color <- "#E495A5"
-  E(g)$width <- 1
-  E(g)[ V(g)[sel] \%--\% V(g)[sel] ]$width <- 2
-  E(g)$label <- ""
-  E(g)[ width == 2 ]$label <- round(gl$Mu[i], 2)
-  E(g)$color <- "black"
-  E(g)[ width == 2 ]$color <- "#E495A5"
-  plot(g, layout=co)
-}
-}
-\keyword{graphs}
diff --git a/man/grg.game.Rd b/man/grg.game.Rd
deleted file mode 100644
index 352fed5..0000000
--- a/man/grg.game.Rd
+++ /dev/null
@@ -1,39 +0,0 @@
-\name{grg.game}
-\alias{grg.game}
-\concept{Geometric random graph}
-\title{Geometric random graphs}
-\description{Generate a random graph based on the distance of random
-  point on a unit square}
-\usage{
-grg.game(nodes, radius, torus = FALSE, coords = FALSE)
-}
-\arguments{
-  \item{nodes}{The number of vertices in the graph.}
-  \item{radius}{The radius within which the vertices will be connected
-    by an edge.}
-  \item{torus}{Logical constant, whether to use a torus instead of a
-    square.}
-  \item{coords}{Logical scalar, whether to add the positions of the
-    vertices as vertex attributes called \sQuote{\code{x}} and
-    \sQuote{\code{y}}.}
-}
-\details{
-  First a number of points are dropped on a unit square, these points
-  correspond to the vertices of the graph to create. Two points will be
-  connected with an undirected edge if they are closer to each other in
-  Euclidean norm than a given radius. If the \code{torus} argument is
-  \code{TRUE} then a unit area torus is used instead of a square.
-}
-\value{
-  A graph object. If \code{coords} is \code{TRUE} then with vertex
-  attributes \sQuote{\code{x}} and \sQuote{\code{y}}.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}, first version was
-  written by Keith Briggs (\url{http://keithbriggs.info/}).}
-\seealso{\code{\link{random.graph.game}}}
-\examples{
-g <- grg.game(1000, 0.05, torus=FALSE)
-g2 <- grg.game(1000, 0.05, torus=TRUE)
-}
-\keyword{graphs}
diff --git a/man/groups.Rd b/man/groups.Rd
new file mode 100644
index 0000000..cde49ac
--- /dev/null
+++ b/man/groups.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{groups}
+\alias{groups}
+\alias{groups.communities}
+\alias{groups.default}
+\title{Groups of a vertex partitioning}
+\usage{
+groups(x)
+}
+\arguments{
+\item{x}{Some object that represents a grouping of the vertices. See details
+below.}
+}
+\value{
+A named list of numeric or character vectors. The names are just
+numbers that refer to the groups. The vectors themselves are numeric or
+symbolic vertex ids.
+}
+\description{
+Create a list of vertex groups from some graph clustering or community
+structure.
+}
+\details{
+Currently two methods are defined for this function. The default method
+works on the output of \code{\link{components}}. (In fact it works on any
+object that is a list with an entry called \code{membership}.)
+
+The second method works on \code{\link{communities}} objects.
+}
+\examples{
+g <- make_graph("Zachary")
+fgc <- cluster_fast_greedy(g)
+groups(fgc)
+
+g2 <- make_ring(10) + make_full_graph(5)
+groups(components(g2))
+}
+\seealso{
+\code{\link{components}} and the various community finding
+functions.
+}
+
diff --git a/man/growing.random.game.Rd b/man/growing.random.game.Rd
deleted file mode 100644
index 9989cb4..0000000
--- a/man/growing.random.game.Rd
+++ /dev/null
@@ -1,35 +0,0 @@
-\name{growing.random.game}
-\alias{growing.random.game}
-\concept{Random graph model}
-\title{Growing random graph generation}
-\description{This function creates a random graph by simulating its
-  stochastic evolution.}
-\usage{
-growing.random.game(n, m = 1, directed = TRUE, citation = FALSE)
-}
-\arguments{
-  \item{n}{Numeric constant, number of vertices in the graph.}
-  \item{m}{Numeric constant, number of edges added in each time step.}
-  \item{directed}{Logical, whether to create a directed graph.}
-  \item{citation}{Logical. If \code{TRUE} a citation graph is created,
-    ie. in each time step the added edges are originating from the new
-    vertex. }
-}
-\details{
-  This is discrete time step model, in each time step a new vertex is
-  added to the graph and \code{m} new edges are created. If
-  \code{citation} is \code{FALSE} these edges are connecting two
-  uniformly randomly chosen vertices, otherwise the edges are connecting 
-  new vertex to uniformly randomly chosen old vertices.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{barabasi.game}}, \code{\link{erdos.renyi.game}}}
-\examples{
-g <- growing.random.game(500, citation=FALSE)
-g2 <- growing.random.game(500, citation=TRUE)
-}
-\keyword{graphs}
diff --git a/man/gsize.Rd b/man/gsize.Rd
new file mode 100644
index 0000000..1a2d2e3
--- /dev/null
+++ b/man/gsize.Rd
@@ -0,0 +1,40 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{gsize}
+\alias{ecount}
+\alias{gsize}
+\title{The size of the graph (number of edges)}
+\usage{
+gsize(graph)
+}
+\arguments{
+\item{graph}{The graph.}
+}
+\value{
+Numeric scalar, the number of edges.
+}
+\description{
+\code{ecount} of an alias of this function.
+}
+\examples{
+g <- sample_gnp(100, 2/100)
+gsize(g)
+
+# Number of edges in a G(n,p) graph
+replicate(100, sample_gnp(10, 1/2), simplify = FALSE) \%>\%
+  vapply(gsize, 0) \%>\%
+  hist()
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{neighbors}};
+  \code{\link{tail_of}}
+}
+
diff --git a/man/head_of.Rd b/man/head_of.Rd
new file mode 100644
index 0000000..cf7c90e
--- /dev/null
+++ b/man/head_of.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/basic.R
+\name{head_of}
+\alias{head_of}
+\title{Head of the edge(s) in a graph}
+\usage{
+head_of(graph, es)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{es}{The edges to query.}
+}
+\value{
+A vertex sequence with the head(s) of the edge(s).
+}
+\description{
+For undirected graphs, head and tail is not defined.  In this case
+\code{head_of} returns vertices incident to the supplied edges, and
+\code{tail_of} returns the other end(s) of the edge(s).
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{incident_edges}}; \code{\link{incident}};
+  \code{\link{is.directed}}, \code{\link{is_directed}};
+  \code{\link{neighbors}}; \code{\link{tail_of}}
+}
+
diff --git a/man/hrg-methods.Rd b/man/hrg-methods.Rd
new file mode 100644
index 0000000..74ebccf
--- /dev/null
+++ b/man/hrg-methods.Rd
@@ -0,0 +1,39 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{hrg-methods}
+\alias{hrg-methods}
+\title{Hierarchical random graphs}
+\description{
+Fitting and sampling hierarchical random graph models.
+}
+\details{
+A hierarchical random graph is an ensemble of undirected graphs with \eqn{n}
+vertices. It is defined via a binary tree with \eqn{n} leaf and \eqn{n-1}
+internal vertices, where the internal vertices are labeled with
+probabilities.  The probability that two vertices are connected in the
+random graph is given by the probability label at their closest common
+ancestor.
+
+Please see references below for more about hierarchical random graphs.
+
+igraph contains functions for fitting HRG models to a given network
+(\code{fit_hrg}, for generating networks from a given HRG ensemble
+(\code{sample_hrg}), converting an igraph graph to a HRG and back
+(\code{hrg}, \code{hrg_tree}), for calculating a consensus tree from a set
+of sampled HRGs (\code{consensus_tree}) and for predicting missing edges in
+a network based on its HRG models (\code{predict_edges}).
+
+The igraph HRG implementation is heavily based on the code published by
+Aaron Clauset, at his website (not functional any more).
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg.game}},
+  \code{\link{sample_hrg}}; \code{\link{hrg.predict}},
+  \code{\link{predict_edges}}; \code{\link{hrg_tree}};
+  \code{\link{hrg}}, \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/hrg.Rd b/man/hrg.Rd
index 4f99dbd..88b4a03 100644
--- a/man/hrg.Rd
+++ b/man/hrg.Rd
@@ -1,228 +1,35 @@
-\name{Hierarchical random graphs}
-\alias{HRG}
-\alias{hrg.consensus}
-\alias{hrg.game}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{hrg}
+\alias{hrg}
 \alias{hrg.create}
-\alias{hrg.predict}
-\alias{hrg.dendrogram}
-\alias{hrg.fit}
-\alias{print.igraphHRG}
-\alias{print.igraphHRGConsensus}
-\concept{Hierarchical random graphs}
-\title{Hierarchical random graphs}
-\description{Fitting and sampling hierarchical random graph models.}
+\title{Create a hierarchical random graph from an igraph graph}
 \usage{
-hrg.fit (graph, hrg = NULL, start = FALSE, steps = 0)
-hrg.consensus (graph, hrg = NULL, start = FALSE, num.samples = 10000)
-
-hrg.create (graph, prob)
-hrg.dendrogram (hrg)
-
-hrg.game (hrg)
-
-hrg.predict (graph, hrg = NULL, start = FALSE, num.samples = 10000,
-             num.bins = 25)
-
-\method{print}{igraphHRG}(x, type=c("auto", "tree", "plain"),
-           level = 3, \dots)
-\method{print}{igraphHRGConsensus}(x, \dots)
+hrg(graph, prob)
 }
 \arguments{
-  \item{graph}{The graph to fit the model to. Edge directions are
-    ignored in directed graphs.}
-  \item{hrg}{A hierarchical random graph model, in the form of an
-    \code{igraphHRG} object. \code{hrg.fit} allows this to be
-    \code{NULL}, in which case a random starting point is used for the
-    fitting. \code{hrg.consensus} and \code{hrg.predict} allow this to
-    be \code{NULL} as well, then a HRG is fitted to the graph first,
-    from a random starting point.}
-  \item{start}{Logical, whether to start the fitting/sampling from the
-    supplied \code{igraphHRG} object, or from a random starting point.}
-  \item{steps}{The number of MCMC steps to make. If this is zero, then
-    the MCMC procedure is performed until convergence.}
-  \item{num.samples}{Number of samples to use for consensus generation
-    or missing edge prediction.}
-  \item{prob}{A vector of probabilities, one for each vertex, in the
-    order of vertex ids.}
-  \item{num.bins}{Number of bins for the edge probabilities. Give a
-    higher number for a more accurate prediction.}
-  \item{x}{\code{igraphHRG} or \code{igraphHRGConsensus} object to
-    print.}
-  \item{type}{How to print the dendrogram, see details below.}
-  \item{level}{The number of top levels to print from the dendrogram.}
-  \item{\dots}{Additional arguments, not used currently.}
-}
-\details{
- A hierarchical random graph is an ensemble of undirected
- graphs with \eqn{n} vertices. It is defined via a binary tree with
- \eqn{n} leaf and \eqn{n-1} internal vertices, where the
- internal vertices are labeled with probabilities.
- The probability that two vertices are connected in the random graph
- is given by the probability label at their closest common
- ancestor.
-
- Please see references below for more about hierarchical random graphs. 
- 
- igraph contains functions for fitting HRG models to a given network
- (\code{hrg.fit}, for generating networks from a given HRG
- ensemble (\code{hrg.game}), converting an igraph graph to a
- HRG and back (\code{hrg.create}, \code{hrg.dendrogram}),
- for calculating a consensus tree from a set of sampled HRGs
- (\code{hrg.consensus}) and for predicting missing edges in a
- network based on its HRG models (\code{hrg.predict}). 
- 
- The igraph HRG implementation is heavily based on the code
- published by Aaron Clauset, at his website,
- \url{http://tuvalu.santafe.edu/~aaronc/hierarchy/}.
-
- \code{hrg.fit} fits a HRG to a given graph. It takes the specified
- \code{steps} number of MCMC steps to perform the fitting, or a
- convergence criteria if the specified number of steps is
- zero. \code{hrg.fit} can start from a given HRG, if this is given in
- the \code{hrg} argument and the \code{start} argument is \code{TRUE}.
-
- \code{hrg.consensus} creates a consensus tree from several fitted
- hierarchical random graph models, using phylogeny methods. If the
- \code{hrg} argument is given and \code{start} is set to \code{TRUE},
- then it starts sampling from the given HRG. Otherwise it optimizes the
- HRG log-likelihood first, and then samples starting from the optimum.
-
- \code{hrg.create} creates a HRG from an igraph graph. The igraph graph
- must be a directed binary tree, with \eqn{n-1} internal and \eqn{n}
- leaf vertices. The \code{prob} argument contains the HRG probability
- labels for each vertex; these are ignored for leaf vertices.
-
- \code{hrg.dendrogram} creates the corresponsing igraph tree of a
- hierarchical random graph model.
-
- \code{hrg.game} samples a graph from a given hierarchical random graph
- model.
-
- \code{hrg.predict} uses a hierarchical random graph model to predict
- missing edges from a network. This is done by sampling hierarchical
- models around the optimum model, proportionally to their
- likelihood. The MCMC sampling is stated from \code{hrg}, if it is given
- and the \code{start} argument is set to \code{TRUE}. Otherwise a HRG is
- fitted to the graph first.
-}
-\section{Printing HRGs to the screen}{
-  \code{igraphHRG} objects can be printed to the screen in two forms: as
-  a tree or as a list, depending on the \code{type} argument of the
-  print function. By default the \code{auto} type is used, which selects
-  \code{tree} for small graphs and \code{simple} (=list) for bigger
-  ones. The \code{tree} format looks like
-  this: \preformatted{Hierarchical random graph, at level 3:
-g1        p=   0  
-'- g15    p=0.33  1 
-   '- g13 p=0.88  6  3  9  4  2  10 7  5  8 
-'- g8     p= 0.5  
-   '- g16 p= 0.2  20 14 17 19 11 15 16 13
-   '- g5  p=   0  12 18  }
-  This is a graph with 20 vertices, and the
-  top three levels of the fitted hierarchical random graph are
-  printed. The root node of the HRG is always vertex group #1
-  (\sQuote{\code{g1}} in the the printout). Vertex pairs in the left
-  subtree of \code{g1} connect to vertices in the right subtree with
-  probability zero, according to the fitted model. \code{g1} has two
-  subgroups, \code{g15} and \code{g8}. \code{g15} has a subgroup of a
-  single vertex (vertex 1), and another larger subgroup that contains
-  vertices 6, 3, etc. on lower levels, etc.
-
-  The \code{plain} printing is simpler and faster to produce, but less
-  visual: \preformatted{Hierarchical random graph:
-g1  p=0.0 -> g12 g10   g2  p=1.0 -> 7 10      g3  p=1.0 -> g18 14    
-g4  p=1.0 -> g17 15    g5  p=0.4 -> g15 17    g6  p=0.0 -> 1 4       
-g7  p=1.0 -> 11 16     g8  p=0.1 -> g9 3      g9  p=0.3 -> g11 g16   
-g10 p=0.2 -> g4 g5     g11 p=1.0 -> g6 5      g12 p=0.8 -> g8 8      
-g13 p=0.0 -> g14 9     g14 p=1.0 -> 2 6       g15 p=0.2 -> g19 18    
-g16 p=1.0 -> g13 g2    g17 p=0.5 -> g7 13     g18 p=1.0 -> 12 19     
-g19 p=0.7 -> g3 20}
-  It lists the two subgroups of each internal node, in
-  as many columns as the screen width allows.
+\item{graph}{The igraph graph to create the HRG from.}
 
-  Consensus dendrograms (\code{igraphHRGConsensus} objects) are printed
-  simply by listing the children of each internal node of the
-  dendrogram: \preformatted{HRG consensus tree:
-g1 -> 11 12 13 14 15 16 17 18 19 20
-g2 -> 1  2  3  4  5  6  7  8  9  10   
-g3 -> g1 g2}
-  The root of the dendrogram is \code{g3} (because it has no incoming
-  edges), and it has two subgroups, \code{g1} and \code{g2}.
+\item{prob}{A vector of probabilities, one for each vertex, in the order of
+vertex ids.}
 }
 \value{
-  \code{hrg.fit} returns an \code{igraphHRG} object. This is a list with
-  the following members:
-  \item{left}{Vector that contains the left children of the internal
-    tree vertices. The first vertex is always the root vertex, so
-    the first element of the vector is the left child of the root
-    vertex. Internal vertices are denoted with negative numbers,
-    starting from -1 and going down, i.e. the root vertex is
-    -1. Leaf vertices are denoted by non-negative number, starting
-    from zero and up.}
-  \item{right}{Vector that contains the right children of the
-    vertices, with the same encoding as the \code{left} vector.}
-  \item{prob}{The connection probabilities attached to the internal
-    vertices, the first number belongs to the root vertex
-    (i.e. internal vertex -1), the second to internal vertex -2,
-    etc.}
-  \item{edges}{The number of edges in the subtree below the given
-    internal vertex.}
-  \item{vertices}{The number of vertices in the subtree below the
-    given internal vertex, including itself.}
-
-  \code{hrg.consensus} returns a list of two objects. The first is an
-  \code{igraphHRGConsensus} object, the second is an \code{igraphHRG}
-  object. The \code{igraphHRGConsensus} object has the following
-  members:
-  \item{parents}{For each vertex, the id of its parent vertex is stored,
-    or zero, if the vertex is the root vertex in the tree. The first n
-    vertex ids (from 0) refer to the original vertices of the graph,
-    the other ids refer to vertex groups.}
-  \item{weights}{Numeric vector, counts the number of times a given
-    tree split occured in the generated network samples, for each
-    internal vertices. The order is the same as in the \code{parents}
-    vector.}
-
-  \code{hrg.create} returns an \code{igraphHRG} object.
-
-  \code{hrg.dendrogram} returns an igraph graph.
-
-  \code{hrg.game} returns an igraph graph.
+\code{hrg} returns an \code{igraphHRG} object.
 }
-\references{
-  A. Clauset, C. Moore, and M.E.J. Newman. Hierarchical structure and the
-  prediction of missing links in networks. \emph{Nature} 453, 98--101
-  (2008); 
-
-  A. Clauset, C. Moore, and M.E.J. Newman. Structural Inference of
-  Hierarchies in Networks. In E. M. Airoldi  et al. (Eds.): ICML 2006 Ws,
-  \emph{Lecture Notes in Computer Science} 4503, 1--13. Springer-Verlag,
-  Berlin Heidelberg (2007). 
+\description{
+\code{hrg} creates a HRG from an igraph graph. The igraph graph must be
+a directed binary tree, with \eqn{n-1} internal and \eqn{n} leaf
+vertices. The \code{prob} argument contains the HRG probability labels
+for each vertex; these are ignored for leaf vertices.
 }
-\author{
-  Gabor Csardi \email{csardi.gabor at gmail.com}, based on code from Aaron
-  Clauset, thanks Aaron!
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg_tree}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
 }
-% \seealso{}
-\examples{
-
-## We are not running these examples any more, because they
-## take a long time (~15 seconds) to run and this is against the CRAN
-## repository policy. Copy and paste them by hand to your R prompt if
-## you want to run them.
-
-\dontrun{
-## A graph with two dense groups
-g <- erdos.renyi.game(10, p=1/2) + erdos.renyi.game(10, p=1/2)
-hrg <- hrg.fit(g)
-hrg
 
-## The consensus tree for it
-hrg.consensus(g, hrg=hrg, start=TRUE)
-
-## Prediction of missing edges
-g2 <- graph.full(4) + (graph.full(4) - path(1,2))
-hrg.predict(g2)
-}
-}
-\keyword{graphs}
diff --git a/man/hrg_tree.Rd b/man/hrg_tree.Rd
new file mode 100644
index 0000000..4e2b4d3
--- /dev/null
+++ b/man/hrg_tree.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{hrg_tree}
+\alias{hrg_tree}
+\title{Create an igraph graph from a hierarchical random graph model}
+\usage{
+hrg_tree(hrg)
+}
+\arguments{
+\item{hrg}{A hierarchical random graph model.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{hrg_tree} creates the corresponsing igraph tree of a hierarchical
+random graph model.
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg}}, \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/hub_score.Rd b/man/hub_score.Rd
new file mode 100644
index 0000000..afb999b
--- /dev/null
+++ b/man/hub_score.Rd
@@ -0,0 +1,64 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{hub_score}
+\alias{hub.score}
+\alias{hub_score}
+\title{Kleinberg's hub centrality scores.}
+\usage{
+hub_score(graph, scale = TRUE, weights = NULL, options = arpack_defaults)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{scale}{Logical scalar, whether to scale the result to have a maximum
+score of one. If no scaling is used then the result vector has unit length
+in the Euclidean norm.}
+
+\item{weights}{Optional positive weight vector for calculating weighted
+scores. If the graph has a \code{weight} edge attribute, then this is used
+by default.}
+
+\item{options}{A named list, to override some ARPACK options. See
+\code{\link{arpack}} for details.}
+}
+\value{
+A named list with members:
+  \item{vector}{The authority/hub scores of the vertices.}
+  \item{value}{The corresponding eigenvalue of the calculated
+    principal eigenvector.}
+  \item{options}{Some information about the ARPACK computation, it has
+    the same members as the \code{options} member returned
+    by \code{\link{arpack}}, see that for documentation.}
+}
+\description{
+The hub scores of the vertices are defined as the principal eigenvector
+of \eqn{A A^T}{A*t(A)}, where \eqn{A} is the adjacency matrix of the
+graph.
+}
+\details{
+For undirected matrices the adjacency matrix is symmetric and the hub
+scores are the same as authority scores, see
+\code{\link{authority_score}}.
+}
+\examples{
+## An in-star
+g <- make_star(10)
+hub_score(g)$vector
+
+## A ring
+g2 <- make_ring(10)
+hub_score(g2)$vector
+}
+\references{
+J. Kleinberg. Authoritative sources in a hyperlinked
+environment. \emph{Proc. 9th ACM-SIAM Symposium on Discrete Algorithms},
+1998. Extended version in \emph{Journal of the ACM} 46(1999). Also appears
+as IBM Research Report RJ 10076, May 1997.
+}
+\seealso{
+\code{\link{authority_score}},
+\code{\link{eigen_centrality}} for eigenvector centrality,
+\code{\link{page_rank}} for the Page Rank scores. \code{\link{arpack}} for
+the underlining machinery of the computation.
+}
+
diff --git a/man/identical_graphs.Rd b/man/identical_graphs.Rd
new file mode 100644
index 0000000..6a35a91
--- /dev/null
+++ b/man/identical_graphs.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{identical_graphs}
+\alias{identical_graphs}
+\title{Decide if two graphs are identical}
+\usage{
+identical_graphs(g1, g2)
+}
+\arguments{
+\item{g1,g2}{The two graphs}
+}
+\value{
+Logical scalar
+}
+\description{
+This is similar to \code{identical} in the \code{base} package,
+but ignores the mutable piece of igraph objects, that might be
+different, even if the two graphs are identical.
+}
+
diff --git a/man/igraph-attribute-combination.Rd b/man/igraph-attribute-combination.Rd
new file mode 100644
index 0000000..3891c8b
--- /dev/null
+++ b/man/igraph-attribute-combination.Rd
@@ -0,0 +1,109 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{igraph-attribute-combination}
+\alias{attribute.combination}
+\alias{igraph-attribute-combination}
+\title{How igraph functions handle attributes when the graph changes}
+\description{
+Many times, when the structure of a graph is modified, vertices/edges map of
+the original graph map to vertices/edges in the newly created (modified)
+graph. For example \code{\link{simplify}} maps multiple edges to single
+edges. igraph provides a flexible mechanism to specify what to do with the
+vertex/edge attributes in these cases.
+}
+\details{
+The functions that support the combination of attributes have one or two
+extra arguments called \code{vertex.attr.comb} and/or \code{edge.attr.comb}
+that specify how to perform the mapping of the attributes. E.g.
+\code{\link{contract}} contracts many vertices into a single one, the
+attributes of the vertices can be combined and stores as the vertex
+attributes of the new graph.
+
+The specification of the combination of (vertex or edge) attributes can be
+given as \enumerate{
+  \item a character scalar,
+  \item a function object or
+  \item a list of character scalars and/or function objects.
+}
+
+If it is a character scalar, then it refers to one of the predefined
+combinations, see their list below.
+
+If it is a function, then the given function is expected to perform the
+combination. It will be called once for each new vertex/edge in the graph,
+with a single argument: the attribute values of the vertices that map to
+that single vertex.
+
+The third option, a list can be used to specify different combination
+methods for different attributes. A named entry of the list corresponds to
+the attribute with the same name. An unnamed entry (i.e. if the name is the
+empty string) of the list specifies the default combination method. I.e.
+\preformatted{list(weight="sum", "ignore")} specifies that the weight of the
+new edge should be sum of the weights of the corresponding edges in the old
+graph; and that the rest of the attributes should be ignored (=dropped).
+}
+\section{Predefined combination functions}{
+ The following combination
+behaviors are predefined: \describe{ \item{"ignore"}{The attribute is
+ignored and dropped.} \item{"sum"}{The sum of the attributes is
+calculated. This does not work for character attributes and works for
+complex attributes only if they have a \code{sum} generic defined. (E.g. it
+works for sparse matrices from the \code{Matrix} package, because they have
+a \code{sum} method.)} \item{"prod"}{The product of the attributes is
+calculated. This does not work for character attributes and works for
+complex attributes only if they have a \code{prod} function defined.}
+\item{"min"}{The minimum of the attributes is calculated and returned.
+For character and complex attributes the standard R \code{min} function is
+used.} \item{"max"}{The maximum of the attributes is calculated and
+returned. For character and complex attributes the standard R \code{max}
+function is used.} \item{"random"}{Chooses one of the supplied
+attribute values, uniformly randomly. For character and complex attributes
+this is implemented by calling \code{sample}.} \item{"first"}{Always
+chooses the first attribute value. It is implemented by calling the
+\code{head} function.} \item{"last"}{Always chooses the last attribute
+value. It is implemented by calling the \code{tail} function.}
+\item{"mean"}{The mean of the attributes is calculated and returned.
+For character and complex attributes this simply calls the \code{mean}
+function.} \item{"median"}{The median of the attributes is selected.
+Calls the R \code{median} function for all attribute types.}
+\item{"concat"}{Concatenate the attributes, using the \code{c}
+function. This results almost always a complex attribute.} }
+}
+\examples{
+g <- graph( c(1,2, 1,2, 1,2, 2,3, 3,4) )
+E(g)$weight <- 1:5
+
+## print attribute values with the graph
+igraph_options(print.graph.attributes=TRUE)
+igraph_options(print.vertex.attributes=TRUE)
+igraph_options(print.edge.attributes=TRUE)
+
+## new attribute is the sum of the old ones
+simplify(g, edge.attr.comb="sum")
+
+## collect attributes into a string
+simplify(g, edge.attr.comb=toString)
+
+## concatenate them into a vector, this creates a complex
+## attribute
+simplify(g, edge.attr.comb="concat")
+
+E(g)$name <- letters[seq_len(ecount(g))]
+
+## both attributes are collected into strings
+simplify(g, edge.attr.comb=toString)
+
+## harmonic average of weights, names are dropped
+simplify(g, edge.attr.comb=list(weight=function(x) length(x)/sum(1/x),
+                                name="ignore"))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{graph_attr}}, \code{\link{vertex_attr}},
+  \code{\link{edge_attr}} on how to use graph/vertex/edge attributes in
+  general. \code{\link{igraph_options}} on igraph parameters.
+}
+\keyword{graphs}
+
diff --git a/man/igraph-dollar.Rd b/man/igraph-dollar.Rd
new file mode 100644
index 0000000..121b6fe
--- /dev/null
+++ b/man/igraph-dollar.Rd
@@ -0,0 +1,73 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{igraph-dollar}
+\alias{$.igraph}
+\alias{$<-.igraph}
+\alias{igraph-dollar}
+\title{Getting and setting graph attributes, shortcut}
+\usage{
+\method{$}{igraph}(x, name)
+
+\method{$}{igraph}(x, name) <- value
+}
+\arguments{
+\item{x}{An igraph graph}
+
+\item{name}{Name of the attribute to get/set.}
+
+\item{value}{New value of the graph attribute.}
+}
+\description{
+The \code{$} operator is a shortcut to get and and set
+graph attributes. It is shorter and just as readable as
+\code{\link{graph_attr}} and \code{\link{set_graph_attr}}.
+}
+\examples{
+g <- make_ring(10)
+g$name
+g$name <- "10-ring"
+g$name
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/igraph-es-attributes.Rd b/man/igraph-es-attributes.Rd
new file mode 100644
index 0000000..e8bd6bf
--- /dev/null
+++ b/man/igraph-es-attributes.Rd
@@ -0,0 +1,117 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{igraph-es-attributes}
+\alias{$.igraph.es}
+\alias{$<-.igraph.es}
+\alias{E<-}
+\alias{[<-.igraph.es}
+\alias{[[<-.igraph.es}
+\alias{igraph-es-attributes}
+\title{Query or set attributes of the edges in an edge sequence}
+\usage{
+\method{[[}{igraph.es}(x, i) <- value
+
+\method{[}{igraph.es}(x, i) <- value
+
+\method{$}{igraph.es}(x, name)
+
+\method{$}{igraph.es}(x, name) <- value
+
+E(x, path = NULL, P = NULL, directed = NULL) <- value
+}
+\arguments{
+\item{x}{An edge sequence. For \code{E<-} it is a graph.}
+
+\item{i}{Index.}
+
+\item{value}{New value of the attribute, for the edges in the edge
+sequence.}
+
+\item{name}{Name of the edge attribute to query or set.}
+
+\item{path}{Select edges along a path, given by a vertex sequence See
+\code{\link{E}}.}
+
+\item{P}{Select edges via pairs of vertices. See \code{\link{E}}.}
+
+\item{directed}{Whether to use edge directions for the \code{path} or
+\code{P} arguments.}
+}
+\value{
+A vector or list, containing the values of the attribute
+  \code{name} for the edges in the sequence. For numeric, character or
+  logical attributes, it is a vector of the appropriate type, otherwise
+  it is a list.
+}
+\description{
+The \code{$} operator is a syntactic sugar to query and set
+edge attributes, for edges in an edge sequence.
+}
+\details{
+The query form of \code{$} is a shortcut for \code{\link{edge_attr}},
+e.g. \code{E(g)[idx]$attr} is equivalent to \code{edge_attr(g, attr,
+E(g)[idx])}.
+
+The assignment form of \code{$} is a shortcut for
+\code{\link{set_edge_attr}}, e.g. \code{E(g)[idx]$attr <- value} is
+equivalent to \code{g <- set_edge_attr(g, attr, E(g)[idx], value)}.
+}
+\examples{
+# color edges of the largest component
+largest_comp <- function(graph) {
+  cl <- components(graph)
+  V(graph)[which.max(cl$csize) == cl$membership]
+}
+g <- sample_(gnp(100, 1/100),
+  with_vertex_(size = 3, label = ""),
+  with_graph_(layout = layout_with_fr)
+)
+giant_v <- largest_comp(g)
+E(g)$color <- "orange"
+E(g)[giant_v \%--\% giant_v]$color <- "blue"
+plot(g)
+}
+\seealso{
+Other vertex and edge sequences: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+
+Other vertex and edge sequences: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/igraph-es-indexing.Rd b/man/igraph-es-indexing.Rd
new file mode 100644
index 0000000..f3814ed
--- /dev/null
+++ b/man/igraph-es-indexing.Rd
@@ -0,0 +1,154 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{igraph-es-indexing}
+\alias{[.igraph.es}
+\alias{\%--\%}
+\alias{\%->\%}
+\alias{\%<-\%}
+\alias{igraph-es-indexing}
+\title{Indexing edge sequences}
+\usage{
+\method{[}{igraph.es}(x, ...)
+}
+\arguments{
+\item{x}{An edge sequence}
+
+\item{...}{Indices, see details below.}
+}
+\value{
+Another edge sequence, referring to the same graph.
+}
+\description{
+Edge sequences can be indexed very much like a plain numeric R vector,
+with some extras.
+}
+\section{Multiple indices}{
+
+When using multiple indices within the bracket, all of them
+are evaluated independently, and then the results are concatenated
+using the \code{c()} function. E.g. \code{E(g)[1, 2, inc(1)]}
+is equivalent to \code{c(E(g)[1], E(g)[2], E(g)[inc(1)])}.
+}
+
+\section{Index types}{
+
+Edge sequences can be indexed with positive numeric vectors,
+negative numeric vectors, logical vectors, character vectors:
+\itemize{
+  \item When indexed with positive numeric vectors, the edges at the
+    given positions in the sequence are selected. This is the same as
+    indexing a regular R atomic vector with positive numeric vectors.
+  \item When indexed with negative numeric vectors, the edges at the
+    given positions in the sequence are omitted. Again, this is the same
+    as indexing a regular R atomic vector.
+  \item When indexed with a logical vector, the lengths of the edge
+    sequence and the index must match, and the edges for which the
+    index is \code{TRUE} are selected.
+  \item Named graphs can be indexed with character vectors,
+    to select edges with the given names. Note that a graph may
+    have edge names and vertex names, and both can be used to select
+    edges. Edge names are simply used as names of the nuumeric
+    edge id vector. Vertex names effectively only work in graphs without
+    multiple edges, and must be separated with a \code{|} bar character
+    to select an edges that incident to the two given vertices. See
+    examples below.
+}
+}
+
+\section{Edge attributes}{
+
+When indexing edge sequences, edge attributes can be refered
+to simply by using their names. E.g. if a graph has a \code{weight} edge
+attribute, then \code{E(G)[weight > 1]} selects all edges with a larger
+than one weight. See more examples below.
+}
+
+\section{Special functions}{
+
+There are some special igraph functions that can be used
+only in expressions indexing edge sequences: \describe{
+  \item{\code{inc}}{takes a vertex sequence, and selects
+    all edges that have at least one incident vertex in the vertex
+    sequence.}
+  \item{\code{from}}{similar to \code{inc()}, but only
+    the tails of the edges are considered.}
+  \item{\code{to}}{is similar to \code{inc()}, but only
+    the heads of the edges are considered.}
+  \item{\code{\%--\%}}{a special operator that can be
+    used to select all edges between two sets of vertices. It ignores
+    the edge directions in directed graphs.}
+  \item{\code{\%->\%}}{similar to \code{\%--\%},
+    but edges \emph{from} the left hand side argument, pointing
+    \emph{to} the right hand side argument, are selected, in directed
+    graphs.}
+  \item{\code{\%<-\%}}{similar to \code{\%--\%},
+    but edges \emph{to} the left hand side argument, pointing
+    \emph{from} the right hand side argument, are selected, in directed
+    graphs.}
+}
+Note that multiple special functions can be used together, or with
+regular indices, and then their results are concatenated. See more
+examples below.
+}
+\examples{
+# special operators for indexing based on graph structure
+g <- sample_pa(100, power = 0.3)
+E(g) [ 1:3 \%--\% 2:6 ]
+E(g) [ 1:5 \%->\% 1:6 ]
+E(g) [ 1:3 \%<-\% 2:6 ]
+
+# the edges along the diameter
+g <- sample_pa(100, directed = FALSE)
+d <- get_diameter(g)
+E(g, path = d)
+
+# select edges based on attributes
+g <- sample_gnp(20, 3/20) \%>\%
+  set_edge_attr("weight", value = rnorm(gsize(.)))
+E(g)[[ weight < 0 ]]
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/igraph-es-indexing2.Rd b/man/igraph-es-indexing2.Rd
new file mode 100644
index 0000000..355ae45
--- /dev/null
+++ b/man/igraph-es-indexing2.Rd
@@ -0,0 +1,85 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{igraph-es-indexing2}
+\alias{[[.igraph.es}
+\alias{igraph-es-indexing2}
+\title{Select edges and show their metadata}
+\usage{
+\method{[[}{igraph.es}(x, ...)
+}
+\arguments{
+\item{x}{An edge sequence.}
+
+\item{...}{Additional arguments, passed to \code{[}.}
+}
+\value{
+Another edge sequence, with metadata printing turned on.
+See details below.
+}
+\description{
+The double bracket operator can be used on edge sequences, to print
+the meta-data (edge attributes) of the edges in the sequence.
+}
+\details{
+Technically, when used with edge sequences, the double bracket
+operator does exactly the same as the single bracket operator,
+but the resulting edge sequence is printed differently: all
+attributes of the edges in the sequence are printed as well.
+
+See \code{\link{[.igraph.es}} for more about indexing edge sequences.
+}
+\examples{
+g <- make_(ring(10),
+  with_vertex_(name = LETTERS[1:10]),
+  with_edge_(weight = 1:10, color = "green"))
+E(g)
+E(g)[[]]
+E(g)[[inc('A')]]
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/igraph-minus.Rd b/man/igraph-minus.Rd
new file mode 100644
index 0000000..fa25d0e
--- /dev/null
+++ b/man/igraph-minus.Rd
@@ -0,0 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{igraph-minus}
+\alias{-.igraph}
+\alias{igraph-minus}
+\title{Delete vertices or edges from a graph}
+\usage{
+\method{-}{igraph}(e1, e2)
+}
+\arguments{
+\item{e1}{Left argument, see details below.}
+
+\item{e2}{Right argument, see details below.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Delete vertices or edges from a graph
+}
+\details{
+The minus operator (\sQuote{\code{-}}) can be used to remove vertices
+or edges from the graph. The operation performed is selected based on
+the type of the right hand side argument:
+\itemize{
+\item If it is an igraph graph object, then the difference of the
+  two graphs is calculated, see \code{\link{difference}}.
+\item If it is a numeric or character vector, then it is interpreted
+  as a vector of vertex ids and the specified vertices will be
+  deleted from the graph. Example: \preformatted{  g <- make_ring(10)
+V(g)$name <- letters[1:10]
+g <- g - c("a", "b")}
+\item If \code{e2} is a vertex sequence (e.g. created by the
+  \code{\link{V}} function), then these vertices will be deleted from
+  the graph.
+\item If it is an edge sequence (e.g. created by the \code{\link{E}}
+  function), then these edges will be deleted from the graph.
+\item If it is an object created with the \code{\link{vertex}} (or the
+  \code{\link{vertices}}) function, then all arguments of \code{\link{vertices}} are
+  concatenated and the result is interpreted as a vector of vertex
+  ids. These vertices will be removed from the graph.
+\item If it is an object created with the \code{\link{edge}} (or the
+  \code{\link{edges}}) function, then all arguments of \code{\link{edges}} are
+  concatenated and then interpreted as edges to be removed from the
+  graph.
+  Example: \preformatted{  g <- make_ring(10)
+V(g)$name <- letters[1:10]
+E(g)$name <- LETTERS[1:10]
+g <- g - edge("e|f")
+g <- g - edge("H")}
+\item If it is an object created with the \code{\link{path}} function,
+  then all \code{\link{path}} arguments are concatenated and then interpreted
+  as a path along which edges will be removed from the graph.
+  Example: \preformatted{  g <- make_ring(10)
+V(g)$name <- letters[1:10]
+g <- g - path("a", "b", "c", "d")}
+}
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{path}};
+  \code{\link{vertex}}, \code{\link{vertices}}
+}
+
diff --git a/man/igraph-vs-attributes.Rd b/man/igraph-vs-attributes.Rd
new file mode 100644
index 0000000..9aa6127
--- /dev/null
+++ b/man/igraph-vs-attributes.Rd
@@ -0,0 +1,133 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{igraph-vs-attributes}
+\alias{$.igraph.vs}
+\alias{$<-.igraph.vs}
+\alias{V<-}
+\alias{[<-.igraph.vs}
+\alias{[[<-.igraph.vs}
+\alias{igraph-vs-attributes}
+\title{Query or set attributes of the vertices in a vertex sequence}
+\usage{
+\method{[[}{igraph.vs}(x, i) <- value
+
+\method{[}{igraph.vs}(x, i) <- value
+
+\method{$}{igraph.vs}(x, name)
+
+\method{$}{igraph.vs}(x, name) <- value
+
+V(x) <- value
+}
+\arguments{
+\item{x}{A vertex sequence. For \code{V<-} it is a graph.}
+
+\item{i}{Index.}
+
+\item{value}{New value of the attribute, for the vertices in the
+  vertex sequence.}
+
+\item{name}{Name of the vertex attribute to query or set.}
+}
+\value{
+A vector or list, containing the values of
+  attribute \code{name} for the vertices in the vertex sequence.
+  For numeric, character or logical attributes, it is a vector of the
+  appropriate type, otherwise it is a list.
+}
+\description{
+The \code{$} operator is a syntactic sugar to query and set the
+attributes of the vertices in a vertex sequence.
+}
+\details{
+The query form of \code{$} is a shortcut for
+\code{\link{vertex_attr}}, e.g. \code{V(g)[idx]$attr} is equivalent
+to \code{vertex_attr(g, attr, V(g)[idx])}.
+
+The assignment form of \code{$} is a shortcut for
+\code{\link{set_vertex_attr}}, e.g. \code{V(g)[idx]$attr <- value} is
+equivalent to \code{g <- set_vertex_attr(g, attr, V(g)[idx], value)}.
+}
+\examples{
+g <- make_(ring(10),
+  with_vertex_(
+    name = LETTERS[1:10],
+    color = sample(1:2, 10, replace=TRUE)
+  )
+)
+V(g)$name
+V(g)$color
+V(g)$frame.color <- V(g)$color
+
+# color vertices of the largest component
+largest_comp <- function(graph) {
+  cl <- components(graph)
+  V(graph)[which.max(cl$csize) == cl$membership]
+}
+g <- sample_(gnp(100, 2/100),
+  with_vertex_(size = 3, label = ""),
+  with_graph_(layout = layout_with_fr)
+)
+giant_v <- largest_comp(g)
+V(g)$color <- "blue"
+V(g)[giant_v]$color <- "orange"
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph}},
+  \code{\link{$<-.igraph}}, \code{\link{igraph-dollar}},
+  \code{\link{igraph-dollar}}; \code{\link{attributes}},
+  \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/igraph-vs-indexing.Rd b/man/igraph-vs-indexing.Rd
new file mode 100644
index 0000000..efd4854
--- /dev/null
+++ b/man/igraph-vs-indexing.Rd
@@ -0,0 +1,167 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{igraph-vs-indexing}
+\alias{[.igraph.vs}
+\alias{igraph-vs-indexing}
+\title{Indexing vertex sequences}
+\usage{
+\method{[}{igraph.vs}(x, ..., na_ok = FALSE)
+}
+\arguments{
+\item{x}{A vertex sequence.}
+
+\item{...}{Indices, see details below.}
+
+\item{na_ok}{Whether it is OK to have \code{NA}s in the vertex
+sequence.}
+}
+\value{
+Another vertex sequence, referring to the same graph.
+}
+\description{
+Vertex sequences can be indexed very much like a plain numeric R vector,
+with some extras.
+}
+\details{
+Vertex sequences can be indexed using both the single bracket and
+the double bracket operators, and they both work the same way.
+The only difference between them is that the double bracket operator
+marks the result for printing vertex attributes.
+}
+\section{Multiple indices}{
+
+When using multiple indices within the bracket, all of them
+are evaluated independently, and then the results are concatenated
+using the \code{c()} function (except for the \code{na_ok} argument,
+which is special an must be named. E.g. \code{V(g)[1, 2, nei(1)]}
+is equivalent to \code{c(V(g)[1], V(g)[2], V(g)[nei(1)])}.
+}
+
+\section{Index types}{
+
+Vertex sequences can be indexed with positive numeric vectors,
+negative numeric vectors, logical vectors, character vectors:
+\itemize{
+  \item When indexed with positive numeric vectors, the vertices at the
+    given positions in the sequence are selected. This is the same as
+    indexing a regular R atomic vector with positive numeric vectors.
+  \item When indexed with negative numeric vectors, the vertices at the
+    given positions in the sequence are omitted. Again, this is the same
+    as indexing a regular R atomic vector.
+  \item When indexed with a logical vector, the lengths of the vertex
+    sequence and the index must match, and the vertices for which the
+    index is \code{TRUE} are selected.
+  \item Named graphs can be indexed with character vectors,
+    to select vertices with the given names.
+}
+}
+
+\section{Vertex attributes}{
+
+When indexing vertex sequences, vertex attributes can be refered
+to simply by using their names. E.g. if a graph has a \code{name} vertex
+attribute, then \code{V(g)[name == "foo"]} is equivalent to
+\code{V(g)[V(g)$name == "foo"]}. See examples below.
+}
+
+\section{Special functions}{
+
+There are some special igraph functions that can be used only
+in expressions indexing vertex sequences: \describe{
+  \item{\code{nei}}{takes a vertex sequence as its argument
+    and selects neighbors of these vertices. An optional \code{mode}
+    argument can be used to select successors (\code{mode="out"}), or
+    precedessors (\code{mode="in"}) in directed graphs.}
+  \item{\code{inc}}{Takes an edge sequence as an argument, and
+    selects vertices that have at least one incident edge in this
+    edge sequence.}
+  \item{\code{from}}{Similar to \code{inc}, but only considers the
+    tails of the edges.}
+  \item{\code{to}}{Similar to \code{inc}, but only considers the
+    heads of the edges.}
+  \item{\code{innei}, \code{outnei}}{\code{innei(v)} is a shorthand for
+    \code{nei(v, mode = "in")}, and \code{outnei(v)} is a shorthand for
+    \code{nei(v, mode = "out")}.
+  }
+}
+Note that multiple special functions can be used together, or with
+regular indices, and then their results are concatenated. See more
+examples below.
+}
+\examples{
+# -----------------------------------------------------------------
+# Setting attributes for subsets of vertices
+largest_comp <- function(graph) {
+  cl <- components(graph)
+  V(graph)[which.max(cl$csize) == cl$membership]
+}
+g <- sample_(gnp(100, 2/100),
+  with_vertex_(size = 3, label = ""),
+  with_graph_(layout = layout_with_fr)
+)
+giant_v <- largest_comp(g)
+V(g)$color <- "green"
+V(g)[giant_v]$color <- "red"
+plot(g)
+
+# -----------------------------------------------------------------
+# nei() special function
+g <- graph( c(1,2, 2,3, 2,4, 4,2) )
+V(g)[ nei( c(2,4) ) ]
+V(g)[ nei( c(2,4), "in") ]
+V(g)[ nei( c(2,4), "out") ]
+
+# -----------------------------------------------------------------
+# The same with vertex names
+g <- graph(~ A -+ B, B -+ C:D, D -+ B)
+V(g)[ nei( c('B', 'D') ) ]
+V(g)[ nei( c('B', 'D'), "in" ) ]
+V(g)[ nei( c('B', 'D'), "out" ) ]
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/igraph-vs-indexing2.Rd b/man/igraph-vs-indexing2.Rd
new file mode 100644
index 0000000..76436d2
--- /dev/null
+++ b/man/igraph-vs-indexing2.Rd
@@ -0,0 +1,86 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{igraph-vs-indexing2}
+\alias{[[.igraph.vs}
+\alias{igraph-vs-indexing2}
+\title{Select vertices and show their metadata}
+\usage{
+\method{[[}{igraph.vs}(x, ...)
+}
+\arguments{
+\item{x}{A vertex sequence.}
+
+\item{...}{Additional arguments, passed to \code{[}.}
+}
+\value{
+The double bracket operator returns another vertex sequence,
+  with meta-data (attribute) printing turned on. See details below.
+}
+\description{
+The double bracket operator can be used on vertex sequences, to print
+the meta-data (vertex attributes) of the vertices in the sequence.
+}
+\details{
+Technically, when used with vertex sequences, the double bracket
+operator does exactly the same as the single bracket operator,
+but the resulting vertex sequence is printed differently: all
+attributes of the vertices in the sequence are printed as well.
+
+See \code{\link{[.igraph.vs}} for more about indexing vertex sequences.
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_vertex_attr("color", value = "red") \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10])
+V(g)
+V(g)[[]]
+V(g)[1:5]
+V(g)[[1:5]]
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{print.igraph.es}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/igraph.console.Rd b/man/igraph.console.Rd
deleted file mode 100644
index 318f8d6..0000000
--- a/man/igraph.console.Rd
+++ /dev/null
@@ -1,28 +0,0 @@
-\name{igraph console}
-\alias{igraph.console}
-\concept{The igraph console}
-\title{The igraph console}
-\description{The igraph console is a GUI windows that shows what the
-  currently running igraph function is doing.}
-\usage{
-igraph.console()
-}
-%\arguments{}
-\details{
-  The console can be started by calling the \code{igraph.console}
-  function. Then it stays open, until the user closes it.
-
-  Another way to start it to set the \code{verbose} igraph option to
-  \dQuote{tkconsole} via \code{igraph.options}. Then the console
-  (re)opens each time an igraph function supporting it starts; to close
-  it, set the \code{verbose} option to another value.
-
-  The console is written in Tcl/Tk and required the \code{tcltk}
-  package.
-}
-\value{\code{NULL}, invisibly.}
-% \references
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{igraph.options}} and the \code{verbose} option.}
-%\examples{}
-\keyword{graphs}
diff --git a/man/igraph.par.Rd b/man/igraph.par.Rd
deleted file mode 100644
index dd993d7..0000000
--- a/man/igraph.par.Rd
+++ /dev/null
@@ -1,108 +0,0 @@
-\name{igraph options}
-\alias{igraph.options}
-\alias{getIgraphOpt}
-\alias{igraph.par}
-\title{Parameters for the igraph package}
-\description{igraph has some parameters which (usually) affect the
-  behavior of many functions. These can be set for the whole session via
-  \code{igraph.options}.
-}
-\usage{
-igraph.options(\dots)
-getIgraphOpt(x, default = NULL)
-igraph.par(parid, parvalue = NULL)
-}
-\arguments{
-  \item{\dots}{A list may be given as the only argument, or any number
-    of arguments may be in the \code{name=value} form, or no argument at
-    all may be given. See the Value and Details sections for explanation.}
-  \item{x}{A character string holding an option name.}
-  \item{default}{If the specified option is not set in the options list,
-    this value is returned. This facilitates retrieving an option and
-    checking whether it is set and setting it separately if not.}
-  \item{parid}{The name of the parameter. See the currently used
-    parameters below.}
-  \item{parvalue}{The new value of the parameter. If \code{NULL} then
-    the current value of the parameter is listed.}
-}
-\details{
-  From igraph version 0.6, \code{igraph.par} is deprecated. Please use
-  the more flexible \code{igraph.options} and \code{getIgraphOpt}
-  functions instead.
-
-  The parameter values set via a call to the \code{igraph.options}
-  function will remain in effect for the rest of the session, affecting
-  the subsequent behaviour of the other functions of the \code{igraph}
-  package for which the given parameters are relevant.
-
-  This offers the possibility of customizing the functioning of the
-  \code{igraph} package, for instance by insertions of appropriate calls
-  to \code{igraph.options} in a load hook for package \pkg{igraph}.
-  
-  The currently used parameters in alphabetical order:
-  \describe{
-    \item{add.params}{Logical scalar, whether to add model
-      parameter to the graphs that are created by the various
-      graph constructors. By default it is \code{TRUE}.}
-    \item{add.vertex.names}{Logical scalar, whether to add
-      vertex names to node level indices, like degree, betweenness
-      scores, etc. By default it is \code{TRUE}.}
-    \item{annotate.plot}{Logical scalar, whether to annotate igraph
-      plots with the graph's name (\code{name} graph attribute, if
-      present) as \code{main}, and with the number of vertices and edges
-      as \code{xlab}. Defaults to \code{FALSE}.}
-    \item{dend.plot.type}{The plotting function to use when plotting
-      community structure dendrograms via
-      \code{\link{dendPlot}}}. Possible values are \sQuote{auto} (the
-      default), \sQuote{phylo}, \sQuote{hclust} and
-      \sQuote{dendrogram}. See \code{\link{dendPlot}} for details.
-    \item{edge.attr.comb}{Specifies what to do with the edge
-      attributes if the graph is modified. The default value is
-      \code{list(weight="sum", name="concat", "ignore")}. See
-      \code{\link{attribute.combination}} for details on this.}
-    \item{nexus.url}{The base URL of the default Nexus server. See
-      \code{\link{nexus}} for details.}
-    \item{print.edge.attributes}{Logical constant, whether to print edge
-      attributes when printing graphs. Defaults to \code{FALSE}.}
-    \item{print.full}{Logical scalar, whether \code{\link{print.igraph}}
-      should show the graph structure as well, or only a summary of the
-      graph.}
-    \item{print.graph.attributes}{Logical constant, whether to print
-      graph attributes when printing graphs. Defaults to \code{FALSE}.}
-    \item{print.vertex.attributes}{Logical constant, whether to print
-      vertex attributes when printing graphs. Defaults to \code{FALSE}.}
-    \item{sparsematrices}{Whether to use the \code{Matrix} package for
-      (sparse) matrices. It is recommended, if the user works with
-      larger graphs.}
-    \item{verbose}{Logical constant, whether igraph functions should
-      talk more than minimal. Eg. if \code{TRUE} thne some functions
-      will use progress bars while computing. Defaults to \code{FALSE}.}
-    \item{vertex.attr.comb}{Specifies what to do with the vertex
-      attributes if the graph is modified. The default value is
-      \code{list(name="concat", "ignore")} See
-      \code{\link{attribute.combination}} for details on this.}
-  }
-}
-\value{
-  \code{igraph.options} returns a list with  the updated values of the
-  parameters. If the argument list is not empty, the returned list is
-  invisible.
-
-  For \code{getIgraphOpt}, the current value set for option \code{x}, or
-  \code{NULL} if the option is unset.
-  
-  If \code{parvalue} is \code{NULL} then \code{igraph.par} returns the
-  current value of the parameter. Otherwise the new value of the
-  parameter is returned invisibly.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{igraph.options} is similar to \code{\link{options}} and
-  \code{getIgraphOpt} is similar to \code{\link{getOption}}.}
-\examples{
-oldval <- getIgraphOpt("verbose")
-igraph.options(verbose=TRUE)
-layout.kamada.kawai(graph.ring(10))
-igraph.options(verbose=oldval)
-}
-\keyword{graphs}
diff --git a/man/igraph.sample.Rd b/man/igraph.sample.Rd
deleted file mode 100644
index b8811e0..0000000
--- a/man/igraph.sample.Rd
+++ /dev/null
@@ -1,29 +0,0 @@
-\name{igraph.sample}
-\alias{igraph.sample}
-\title{Sampling a random integer sequence}
-\description{This function provides a very efficient way to pull an
-  integer random sample sequence from an integer interval.}
-\usage{
-igraph.sample(low, high, length)
-}
-\arguments{
-  \item{low}{The lower limit of the interval (inclusive).}
-  \item{high}{The higher limit of the interval (inclusive).}
-  \item{length}{The length of the sample.}
-}
-\details{The algorithm runs in \code{O(length)} expected time, even if
-  \code{high-low} is big. It is much faster (but of course less general)
-  than the builtin \code{sample} function of R.}
-\value{
-  An increasing numeric vector containing integers, the sample.
-}
-\references{Jeffrey Scott Vitter: An Efficient Algorithm for Sequential
-  Random Sampling, \emph{ACM Transactions on Mathematical Software}, 13/1,
-  58--67.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\examples{
-rs <- igraph.sample(1, 100000000, 10)
-rs
-}
-\keyword{datagen}
-    
\ No newline at end of file
diff --git a/man/igraph.version.Rd b/man/igraph.version.Rd
deleted file mode 100644
index 378db8c..0000000
--- a/man/igraph.version.Rd
+++ /dev/null
@@ -1,30 +0,0 @@
-\name{igraph.version}
-\alias{igraph.version}
-\title{Query igraph's version string}
-\description{Queries igraph's original version string. See details
-  below.}
-\usage{
-igraph.version()
-}
-\details{
-  The igraph version string is the same as the version of the R package
-  for all realeased igraph versions. For development versions and
-  nightly builds, they might differ however.
-
-  The reason for this is, that R package version numbers are not
-  flexible enough to cover in-between releases versions, e.g. alpha and
-  beta versions, release candidates, etc.
-}
-\value{
-  A character scalar, the igraph version string.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-% \seealso{}
-\examples{
-## Compare to the package version
-packageDescription("igraph")$Version
-igraph.version()
-
-}
-\keyword{graphs}
diff --git a/man/igraph.vertex.shapes.Rd b/man/igraph.vertex.shapes.Rd
deleted file mode 100644
index c892a4e..0000000
--- a/man/igraph.vertex.shapes.Rd
+++ /dev/null
@@ -1,257 +0,0 @@
-\name{Vertex shapes}
-\alias{igraph.vertex.shapes}
-\alias{vertex.shapes}
-\alias{add.vertex.shape}
-\alias{igraph.shape.noclip}
-\alias{igraph.shape.noplot}
-\concept{Vertex shapes}
-\concept{Visualization}
-\title{Various vertex shapes when plotting igraph graphs}
-\description{Starting from version 0.5.1 igraph supports different
-  vertex shapes when plotting graphs.}
-\usage{
-vertex.shapes (shape = NULL)
-add.vertex.shape (shape, clip = igraph.shape.noclip,
-       plot = igraph.shape.noplot, parameters = list())
-igraph.shape.noclip (coords, el, params, end = c("both", "from", "to"))
-igraph.shape.noplot (coords, v = NULL, params)
-}
-\arguments{
-  \item{shape}{Character scalar, name of a vertex shape. If it is
-    \code{NULL} for \code{vertex.shapes}, then the names of all defined
-    vertex shapes are returned.} 
-  \item{clip}{An R function object, the clipping function.}
-  \item{plot}{An R function object, the plotting function.}
-  \item{parameters}{Named list, additional plot/vertex/edge
-    parameters. The element named define the new parameters, and the
-    elements themselves define their default values.
-    Vertex parameters should have a prefix
-    \sQuote{\code{vertex.}}, edge parameters a prefix
-    \sQuote{\code{edge.}}. Other general plotting parameters should have
-    a prefix \sQuote{\code{plot.}}. See Details below.}
-  \item{coords,el,params,end,v}{See parameters of the clipping/plotting
-    functions below.} 
-}
-\details{
-  In igraph a vertex shape is defined by two functions: 1) provides
-  information about the size of the shape for clipping the edges and 2)
-  plots the shape if requested. These functions are called \dQuote{shape
-    functions} in the rest of this manual page. The first one is the
-  clipping function and the second is the plotting function.
-  
-  The clipping function has the following arguments:
-  \describe{
-    \item{coords}{A matrix with four columns, it contains the
-      coordinates of the vertices for the edge list supplied in the
-      \code{el} argument.}
-    \item{el}{A matrix with two columns, the edges of which some end
-      points will be clipped. It should have the same number of rows as
-      \code{coords}.}
-    \item{params}{This is a function object that can be called to query
-      vertex/edge/plot graphical parameters. The first argument of the
-      function is \dQuote{\code{vertex}}, \dQuote{\code{edge}} or
-      \dQuote{\code{plot}} to decide the type of the parameter, the
-      second is a character string giving the name of the
-      parameter. E.g.
-      \preformatted{
-	params("vertex", "size")
-      }
-    }
-    \item{end}{Character string, it gives which end points will be
-      used. Possible values are \dQuote{\code{both}},
-      \dQuote{\code{from}} and \dQuote{\code{to}}. If
-      \dQuote{\code{from}} the function is expected to clip the
-      first column in the \code{el} edge list, \dQuote{\code{to}}
-      selects the second column, \dQuote{\code{both}} selects both.}
-  }
-
-  The clipping function should return a matrix
-  with the same number of rows as the \code{el} arguments.
-  If \code{end} is \code{both} then the matrix must have four
-  columns, otherwise two. The matrix contains the modified coordinates,
-  with the clipping applied.
-
-  The plotting function has the following arguments:
-  \describe{
-    \item{coords}{The coordinates of the vertices, a matrix with two
-      columns.}
-    \item{v}{The ids of the vertices to plot. It should match the number
-      of rows in the \code{coords} argument.}
-    \item{params}{The same as for the clipping function, see above.}
-  }
-
-  The return value of the plotting function is not used.
-
-  \code{vertex.shapes} can be used to list the names of all installed
-  vertex shapes, by calling it without arguments, or setting the
-  \code{shape} argument to \code{NULL}. If a shape name is given, then
-  the clipping and plotting functions of that shape are returned in a
-  named list.
-
-  \code{add.vertex.shape} can be used to add new vertex shapes to
-  igraph. For this one must give the clipping and plotting functions of
-  the new shape. It is also possible to list the plot/vertex/edge
-  parameters, in the \code{parameters} argument, that the clipping
-  and/or plotting functions can make use of. An example would be a
-  generic regular polygon shape, which can have a parameter for the
-  number of sides.
-
-  \code{igraph.shape.noclip} is a very simple clipping function that the
-  user can use in their own shape definitions. It does no clipping, the
-  edges will be drawn exactly until the listed vertex position
-  coordinates.
-
-  \code{igraph.shape.noplot} is a very simple (and probably not very
-  useful) plotting function, that does not plot anything.
-}
-\value{
-  \code{vertex.shapes} returns a character vector if the \code{shape}
-  argument is \code{NULL}. It returns a named list with entries named
-  \sQuote{clip} and \sQuote{plot}, both of them R functions.
-
-  \code{add.vertex.shape} returns \code{TRUE}, invisibly.
-
-  \code{igraph.shape.noclip} returns the appropriate columns of its
-  \code{coords} argument.
-
-  \code{igraph.shape.noplot} returns \code{NULL}, invisibly.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{igraph.plotting}}, \code{\link{plot.igraph}} }
-\examples{
-#################################################################
-# all vertex shapes, minus "raster", that might not be available
-shapes <- setdiff(vertex.shapes(), "")
-g <- graph.ring(length(shapes))
-set.seed(42)
-plot(g, vertex.shape=shapes, vertex.label=shapes, vertex.label.dist=1,
-     vertex.size=15, vertex.size2=15,
-     vertex.pie=lapply(shapes, function(x) if (x=="pie") 2:6 else 0),
-     vertex.pie.color=list(heat.colors(5)))
-
-# add new vertex shape, plot nothing with no clipping
-add.vertex.shape("nil")
-plot(g, vertex.shape="nil")
-
-#################################################################
-# triangle vertex shape
-mytriangle <- function(coords, v=NULL, params) {
-  vertex.color <- params("vertex", "color")
-  if (length(vertex.color) != 1 && !is.null(v)) {
-    vertex.color <- vertex.color[v]
-  }
-  vertex.size <- 1/200 * params("vertex", "size")
-  if (length(vertex.size) != 1 && !is.null(v)) {
-    vertex.size <- vertex.size[v]
-  }
-
-  symbols(x=coords[,1], y=coords[,2], bg=vertex.color,
-          stars=cbind(vertex.size, vertex.size, vertex.size),
-          add=TRUE, inches=FALSE)
-}
-# clips as a circle
-add.vertex.shape("triangle", clip=vertex.shapes("circle")$clip,
-                 plot=mytriangle)
-plot(g, vertex.shape="triangle", vertex.color=rainbow(vcount(g)),
-     vertex.size=seq(10,20,length=vcount(g)))
-
-#################################################################
-# generic star vertex shape, with a parameter for number of rays
-mystar <- function(coords, v=NULL, params) {
-  vertex.color <- params("vertex", "color")
-  if (length(vertex.color) != 1 && !is.null(v)) {
-    vertex.color <- vertex.color[v]
-  }
-  vertex.size  <- 1/200 * params("vertex", "size")
-  if (length(vertex.size) != 1 && !is.null(v)) {
-    vertex.size <- vertex.size[v]
-  }
-  norays <- params("vertex", "norays")
-  if (length(norays) != 1 && !is.null(v)) {
-    norays <- norays[v]
-  }
-
-  mapply(coords[,1], coords[,2], vertex.color, vertex.size, norays,
-         FUN=function(x, y, bg, size, nor) {
-           symbols(x=x, y=y, bg=bg,
-                   stars=matrix(c(size,size/2), nrow=1, ncol=nor*2),
-                   add=TRUE, inches=FALSE)
-         })
-}
-# no clipping, edges will be below the vertices anyway
-add.vertex.shape("star", clip=igraph.shape.noclip,
-                 plot=mystar, parameters=list(vertex.norays=5))
-plot(g, vertex.shape="star", vertex.color=rainbow(vcount(g)),
-     vertex.size=seq(10,20,length=vcount(g)))
-plot(g, vertex.shape="star", vertex.color=rainbow(vcount(g)),
-     vertex.size=seq(10,20,length=vcount(g)),
-     vertex.norays=rep(4:8, length=vcount(g)))
-
-#################################################################
-# Pictures as vertices.
-# Similar musicians from last.fm, we start from an artist and
-# will query two levels. We will use the XML, png and jpeg packages
-# for this, so these must be available. Otherwise the example is
-# skipped
-
-loadIfYouCan <- function(pkg) suppressWarnings(do.call(require, list(pkg)))
-
-if (loadIfYouCan("XML") && loadIfYouCan("png") &&
-    loadIfYouCan("jpeg")) {
-  url <- paste(sep="",
-               'http://ws.audioscrobbler.com/',
-               '2.0/?method=artist.getinfo&artist=\%s',
-               '&api_key=1784468ada3f544faf9172ee8b99fca3')
-  getartist <- function(artist) {
-    cat("Downloading from last.fm. ... ")
-    txt <- readLines(sprintf(url, URLencode(artist)))
-    xml <- xmlTreeParse(txt, useInternal=TRUE)
-    img <- xpathSApply(xml, "/lfm/artist/image[@size='medium'][1]",
-                       xmlValue)
-    if (img != "") {
-      con <- url(img, open="rb")
-      bin <- readBin(con, what="raw", n=10^6)
-      close(con)
-      if (grepl("\\\\.png$", img)) {
-        rast <- readPNG(bin, native=TRUE)
-      } else if (grepl("\\\\.jpe?g$", img)) {
-        rast <- readJPEG(bin, native=TRUE)
-      } else {
-        rast <- as.raster(matrix())
-      }
-    } else {
-      rast <- as.raster(numeric())
-    }
-    sim <- xpathSApply(xml, "/lfm/artist/similar/artist/name", xmlValue)
-    cat("done.\\n")
-    list(name=artist, image=rast, similar=sim)
-  }
-
-  ego <- getartist("Placebo")
-  similar <- lapply(ego$similar, getartist)
-  
-  edges1 <- cbind(ego$name, ego$similar)
-  edges2 <- lapply(similar, function(x) cbind(x$name, x$similar))
-  edges3 <- rbind(edges1, do.call(rbind, edges2))
-  edges <- edges3[ edges3[,1] \%in\% c(ego$name, ego$similar) &
-                   edges3[,2] \%in\% c(ego$name, ego$similar), ]
-
-  musnet <- simplify(graph.data.frame(edges, dir=FALSE,
-                     vertices=data.frame(name=c(ego$name, ego$similar))))
-  str(musnet)
-  
-  V(musnet)$raster <- c(list(ego$image), lapply(similar, "[[", "image"))
-  plot(musnet, layout=layout.star, vertex.shape="raster",
-       vertex.label=V(musnet)$name, margin=.2,
-       vertex.size=50, vertex.size2=50,
-       vertex.label.dist=2, vertex.label.degree=0)
-} else {
-  message("You need the `XML', `png' and `jpeg' packages to run this")
-}
-
-}
-
-	      
-	      
-\keyword{graphs}
-
diff --git a/man/igraph_demo.Rd b/man/igraph_demo.Rd
new file mode 100644
index 0000000..ac941f9
--- /dev/null
+++ b/man/igraph_demo.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/demo.R
+\name{igraph_demo}
+\alias{igraph_demo}
+\alias{igraphdemo}
+\title{Run igraph demos, step by step}
+\usage{
+igraph_demo(which)
+}
+\arguments{
+\item{which}{If not given, then the names of the available demos are listed.
+Otherwise it should be either a filename or the name of an igraph demo.}
+}
+\value{
+Returns \code{NULL}, invisibly.
+}
+\description{
+Run one of the accompanying igraph demos, somewhat interactively, using a Tk
+window.
+}
+\details{
+This function provides a somewhat nicer interface to igraph demos that come
+with the package, than the standard \code{\link{demo}} function. Igraph
+demos are divided into chunks and \code{igraph_demo} runs them chunk by
+chunk, with the possibility of inspecting the workspace between two chunks.
+
+The \code{tcltk} package is needed for \code{igraph_demo}.
+}
+\examples{
+igraph_demo()
+if (interactive()) {
+  igraph_demo("centrality")
+}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{demo}}
+}
+\keyword{graphs}
+
diff --git a/man/igraph_options.Rd b/man/igraph_options.Rd
new file mode 100644
index 0000000..bc2154f
--- /dev/null
+++ b/man/igraph_options.Rd
@@ -0,0 +1,106 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/par.R
+\name{igraph_options}
+\alias{getIgraphOpt}
+\alias{igraph.options}
+\alias{igraph_opt}
+\alias{igraph_options}
+\title{Parameters for the igraph package}
+\usage{
+igraph_options(...)
+
+igraph_opt(x, default = NULL)
+}
+\arguments{
+\item{x}{A character string holding an option name.}
+
+\item{default}{If the specified option is not set in the options list, this
+value is returned. This facilitates retrieving an option and checking
+whether it is set and setting it separately if not.}
+
+\item{\dots}{A list may be given as the only argument, or any number of
+arguments may be in the \code{name=value} form, or no argument at all may be
+given. See the Value and Details sections for explanation.}
+}
+\value{
+\code{igraph_options} returns a list with the updated values of the
+parameters. If the argument list is not empty, the returned list is
+invisible.
+
+For \code{igraph_opt}, the current value set for option \code{x}, or
+\code{NULL} if the option is unset.
+}
+\description{
+igraph has some parameters which (usually) affect the behavior of many
+functions. These can be set for the whole session via \code{igraph_options}.
+}
+\details{
+The parameter values set via a call to the \code{igraph_options} function
+will remain in effect for the rest of the session, affecting the subsequent
+behaviour of the other functions of the \code{igraph} package for which the
+given parameters are relevant.
+
+This offers the possibility of customizing the functioning of the
+\code{igraph} package, for instance by insertions of appropriate calls to
+\code{igraph_options} in a load hook for package \pkg{igraph}.
+
+The currently used parameters in alphabetical order:
+\describe{
+  \item{add.params}{Logical scalar, whether to add model
+    parameter to the graphs that are created by the various
+    graph constructors. By default it is \code{TRUE}.}
+  \item{add.vertex.names}{Logical scalar, whether to add
+    vertex names to node level indices, like degree, betweenness
+    scores, etc. By default it is \code{TRUE}.}
+  \item{annotate.plot}{Logical scalar, whether to annotate igraph
+    plots with the graph's name (\code{name} graph attribute, if
+    present) as \code{main}, and with the number of vertices and edges
+    as \code{xlab}. Defaults to \code{FALSE}.}
+  \item{dend.plot.type}{The plotting function to use when plotting
+    community structure dendrograms via
+    \code{\link{plot_dendrogram}}}. Possible values are \sQuote{auto} (the
+    default), \sQuote{phylo}, \sQuote{hclust} and
+    \sQuote{dendrogram}. See \code{\link{plot_dendrogram}} for details.
+  \item{edge.attr.comb}{Specifies what to do with the edge
+    attributes if the graph is modified. The default value is
+    \code{list(weight="sum", name="concat", "ignore")}. See
+    \code{\link{attribute.combination}} for details on this.}
+  \item{nexus.url}{The base URL of the default Nexus server. See
+    \code{\link{nexus}} for details.}
+  \item{print.edge.attributes}{Logical constant, whether to print edge
+    attributes when printing graphs. Defaults to \code{FALSE}.}
+  \item{print.full}{Logical scalar, whether \code{\link{print.igraph}}
+    should show the graph structure as well, or only a summary of the
+    graph.}
+  \item{print.graph.attributes}{Logical constant, whether to print
+    graph attributes when printing graphs. Defaults to \code{FALSE}.}
+  \item{print.vertex.attributes}{Logical constant, whether to print
+    vertex attributes when printing graphs. Defaults to \code{FALSE}.}
+  \item{sparsematrices}{Whether to use the \code{Matrix} package for
+    (sparse) matrices. It is recommended, if the user works with
+    larger graphs.}
+  \item{verbose}{Logical constant, whether igraph functions should
+    talk more than minimal. Eg. if \code{TRUE} thne some functions
+    will use progress bars while computing. Defaults to \code{FALSE}.}
+  \item{vertex.attr.comb}{Specifies what to do with the vertex
+    attributes if the graph is modified. The default value is
+    \code{list(name="concat", "ignore")} See
+    \code{\link{attribute.combination}} for details on this.}
+}
+}
+\examples{
+oldval <- igraph_opt("verbose")
+igraph_options(verbose=TRUE)
+layout_with_kk(make_ring(10))
+igraph_options(verbose=oldval)
+#'
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{igraph_options} is similar to \code{\link{options}} and
+\code{igraph_opt} is similar to \code{\link{getOption}}.
+}
+\keyword{graphs}
+
diff --git a/man/igraph_test.Rd b/man/igraph_test.Rd
new file mode 100644
index 0000000..a622bb6
--- /dev/null
+++ b/man/igraph_test.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/test.R
+\name{igraph_test}
+\alias{igraph_test}
+\alias{igraphtest}
+\title{Run package tests}
+\usage{
+igraph_test()
+}
+\value{
+Whatever is returned by \code{test_dir} from the \code{testthat}
+package.
+}
+\description{
+Runs all package tests.
+}
+\details{
+The \code{testthat} package is needed to run all tests. The location tests
+themselves can be extracted from the package via \code{system.file("tests",
+package="igraph")}.
+
+This function simply calls the \code{test_dir} function from the
+\code{testthat} package on the test directory.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/igraph_version.Rd b/man/igraph_version.Rd
new file mode 100644
index 0000000..50b25b9
--- /dev/null
+++ b/man/igraph_version.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/test.R
+\name{igraph_version}
+\alias{igraph.version}
+\alias{igraph_version}
+\title{Query igraph's version string}
+\usage{
+igraph_version()
+}
+\value{
+A character scalar, the igraph version string.
+}
+\description{
+Queries igraph's original version string. See details below.
+}
+\details{
+The igraph version string is the same as the version of the R package for
+all realeased igraph versions. For development versions and nightly builds,
+they might differ however.
+
+The reason for this is, that R package version numbers are not flexible
+enough to cover in-between releases versions, e.g. alpha and beta versions,
+release candidates, etc.
+}
+\examples{
+## Compare to the package version
+packageDescription("igraph")$Version
+igraph_version()
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/igraphdemo.Rd b/man/igraphdemo.Rd
deleted file mode 100644
index 6e27124..0000000
--- a/man/igraphdemo.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-\name{igraphdemo}
-\alias{igraphdemo}
-\title{Run igraph demos, step by step}
-\description{Run one of the accompanying igraph demos, somewhat
-  interactively, using a Tk window. }
-\usage{
-igraphdemo(which)
-}
-\arguments{
-  \item{which}{If not given, then the names of the available demos are
-    listed. Otherwise it should be either a filename or the name of an
-    igraph demo.}
-}
-\details{
-  This function provides a somewhat nicer interface to igraph demos that
-  come with the package, than the standard \code{\link{demo}}
-  function. Igraph demos are divided into chunks and \code{igraphdemo}
-  runs them chunk by chunk, with the possibility of inspecting the
-  workspace between two chunks.
-
-  The \code{tcltk} package is needed for \code{igraphdemo}.
-}
-\value{Returns \code{NULL}, invisibly.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{demo}}}
-\examples{
-igraphdemo()
-if (interactive()) {
-  igraphdemo("centrality")
-}
-}
-\keyword{graphs}
diff --git a/man/igraphtest.Rd b/man/igraphtest.Rd
deleted file mode 100644
index 2cfb36f..0000000
--- a/man/igraphtest.Rd
+++ /dev/null
@@ -1,22 +0,0 @@
-\name{igraphtest}
-\alias{igraphtest}
-\title{Run package tests}
-\description{Runs all package tests.}
-\usage{
-igraphtest()
-}
-\details{
-	The \code{testthat} package is needed to run all tests. The location
-	tests themselves can be extracted from the package via
-	\code{system.file("tests", package="igraph")}.
-
-	This function simply calls the \code{test_dir} function from the
-	\code{testthat} package on the test directory.
-}
-\value{Whatever is returned by \code{test_dir} from the \code{testthat}
-	package.}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-% \seealso{}
-% \examples{}
-\keyword{graphs}
diff --git a/man/incident.Rd b/man/incident.Rd
new file mode 100644
index 0000000..d214833
--- /dev/null
+++ b/man/incident.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{incident}
+\alias{incident}
+\title{Incident edges of a vertex in a graph}
+\usage{
+incident(graph, v, mode = c("all", "out", "in", "total"))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{v}{The vertex of which the indicent edges are queried.}
+
+\item{mode}{Whether to query outgoing (\sQuote{out}), incoming
+(\sQuote{in}) edges, or both types (\sQuote{all}). This is
+ignored for undirected graphs.}
+}
+\value{
+An edge sequence containing the incident edges of
+  the input vertex.
+}
+\description{
+Incident edges of a vertex in a graph
+}
+\examples{
+g <- make_graph("Zachary")
+incident(g, 1)
+incident(g, 34)
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{is.directed}}, \code{\link{is_directed}};
+  \code{\link{neighbors}}; \code{\link{tail_of}}
+}
+
diff --git a/man/incident_edges.Rd b/man/incident_edges.Rd
new file mode 100644
index 0000000..9477340
--- /dev/null
+++ b/man/incident_edges.Rd
@@ -0,0 +1,41 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{incident_edges}
+\alias{incident_edges}
+\title{Incident edges of multiple vertices in a graph}
+\usage{
+incident_edges(graph, v, mode = c("out", "in", "all", "total"))
+}
+\arguments{
+\item{graph}{Input graph.}
+
+\item{v}{The vertices to query}
+
+\item{mode}{Whether to query outgoing (\sQuote{out}), incoming
+(\sQuote{in}) edges, or both types (\sQuote{all}). This is
+ignored for undirected graphs.}
+}
+\value{
+A list of edge sequences.
+}
+\description{
+This function is similar to \code{\link{incident}}, but it
+queries multiple vertices at once.
+}
+\examples{
+g <- make_graph("Zachary")
+incident_edges(g, c(1, 34))
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident}};
+  \code{\link{is.directed}}, \code{\link{is_directed}};
+  \code{\link{neighbors}}; \code{\link{tail_of}}
+}
+
diff --git a/man/independent.sets.Rd b/man/independent.sets.Rd
deleted file mode 100644
index 7c7fa85..0000000
--- a/man/independent.sets.Rd
+++ /dev/null
@@ -1,76 +0,0 @@
-\name{independent.vertex.sets}
-\alias{independent.vertex.sets}
-\alias{largest.independent.vertex.sets}
-\alias{maximal.independent.vertex.sets}
-\alias{independence.number}
-\concept{Independent vertex set}
-\title{Independent vertex sets}
-\description{A vertex set is called independent if there no edges
-  between any two vertices in it. These functions find independent
-  vertex sets in undirected graphs}
-\usage{
-independent.vertex.sets(graph, min=NULL, max=NULL)
-largest.independent.vertex.sets(graph)
-maximal.independent.vertex.sets(graph)
-independence.number(graph)
-}
-\arguments{
-  \item{graph}{The input graph, directed graphs are considered as
-    undirected, loop edges and multiple edges are ignored.}
-  \item{min}{Numeric constant, limit for the minimum size of the
-    independent vertex sets to find. \code{NULL} means no limit.}
-  \item{max}{Numeric constant, limit for the maximum size of
-    the independent vertex sets to find. \code{NULL} means no limit.
-  }
-}
-\details{
-  \code{independent.vertex.sets} finds all independent vertex sets in
-  the network, obeying the size limitations given in the \code{min} and
-  \code{max} arguments.
-
-  \code{largest.independent.vertex.sets} finds the largest independent
-  vertex sets in the graph. An independent vertex set is largest if
-  there is no independent vertex set with more vertices.
-
-  \code{maximal.independent.vertex.sets} finds the maximal independent
-  vertex sets in the graph. An independent vertex set is maximal if it
-  cannot be extended to a larger independent vertex set. The largest
-  independent vertex sets are maximal, but the opposite is not always
-  true.
-
-  \code{independece.number} calculate the size of the largest
-  independent vertex set(s).
-
-  These functions use the algorithm described by Tsukiyama et al., see
-  reference below.
-}
-\value{
-  \code{independent.vertex.sets}, \code{largest.independent.vertex.sets}
-  and \code{maximal.independent.vertex.sets} return a list containing
-  numeric vertex ids, each list element is an independent vertex set.
-
-  \code{independence.number} returns an integer constant.
-}
-\references{
-  S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new algorithm
-  for generating all the maximal independent sets. \emph{SIAM J Computing},
-  6:505--517, 1977.
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com} ported it from the Very
-  Nauty Graph Library by Keith Briggs (\url{http://keithbriggs.info/})
-  and Gabor Csardi \email{csardi.gabor at gmail.com} wrote the R interface
-  and this manual page. }
-\seealso{\code{\link{cliques}}}
-\examples{
-# A quite dense graph
-set.seed(42)
-g <- erdos.renyi.game(100, 0.9)
-independence.number(g)
-independent.vertex.sets(g, min=independence.number(g))
-largest.independent.vertex.sets(g)
-# Empty graph
-induced.subgraph(g, largest.independent.vertex.sets(g)[[1]])
-
-length(maximal.independent.vertex.sets(g))
-}
-\keyword{graphs}
diff --git a/man/infomap.Rd b/man/infomap.Rd
deleted file mode 100644
index 1447b4d..0000000
--- a/man/infomap.Rd
+++ /dev/null
@@ -1,64 +0,0 @@
-\name{infomap.community}
-\alias{infomap.community}
-\concept{Community structure}
-\title{Infomap community finding}
-\description{Find community structure that minimizes the expected
-  description length of a random walker trajectory}
-\usage{
-infomap.community (graph, e.weights = NULL, v.weights = NULL,
-                   nb.trials = 10, modularity = TRUE) 
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{e.weights}{If not \code{NULL}, then a numeric vector of edge
-    weights. The length must match the number of edges in the graph.
-    By default the \sQuote{\code{weight}} edge attribute is used as
-    weights. If it is not present, then all edges are considered to have
-    the same weight.}
-  \item{v.weights}{If not \code{NULL}, then a numeric vector of vertex
-    weights. The length must match the number of vertices in the graph.
-    By default the \sQuote{\code{weight}} vertex attribute is used as
-    weights. If it is not present, then all vertices are considered to have
-    the same weight.}
-  \item{nb.trials}{The number of attempts to partition the network
-    (can be any integer value equal or larger than 1).}
-  \item{modularity}{Logical scalar, whether to calculate the modularity
-    score of the detected community structure.}
-}
-\details{
-  Please see the details of this method in the references given below.
-}
-\value{
-  \code{infomap.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\references{
-  The original paper: M. Rosvall and C. T. Bergstrom, Maps of
-  information flow reveal community structure in complex networks,
-  \emph{PNAS} 105, 1118 (2008)
-  \url{http://dx.doi.org/10.1073/pnas.0706851105}, 
-  \url{http://arxiv.org/abs/0707.0609}
-
-  A more detailed paper: M. Rosvall, D. Axelsson, and C. T. Bergstrom,
-  The map equation, \emph{Eur. Phys. J. Special Topics} 178, 13 (2009).
-  \url{http://dx.doi.org/10.1140/epjst/e2010-01179-1},
-  \url{http://arxiv.org/abs/0906.1405}.
-}
-\author{
-  Martin Rosvall (\url{http://www.tp.umu.se/~rosvall/}) wrote
-  the original C++ code. This was ported to be more igraph-like by
-  Emmanuel Navarro (\url{http://www.irit.fr/~Emmanuel.Navarro/}).
-  The R interface and some cosmetics was done by Gabor Csardi
-  \email{csardi.gabor at gmail.com}.
-}
-\seealso{Other community finding methods and \code{\link{communities}}.}
-\examples{
-## Zachary's karate club
-g <- graph.famous("Zachary")
-
-imc <- infomap.community(g)
-membership(imc)
-communities(imc)
-}
-\keyword{graphs}
diff --git a/man/interconnected.islands.Rd b/man/interconnected.islands.Rd
deleted file mode 100644
index ab59243..0000000
--- a/man/interconnected.islands.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-\name{interconnected.islands}
-\alias{interconnected.islands.game}
-\concept{Random graph model}
-\title{A graph with subgraphs that are each a random graph.}
-\description{
-  Create a number of Erdos-Renyi random graphs with identical
-  parameters, and connect them with the specified number of edges.
-}
-\usage{
-interconnected.islands.game (islands.n, islands.size, islands.pin,
-                             n.inter)
-}
-\arguments{
-  \item{islands.n}{The number of islands in the graph.}
-  \item{islands.size}{The size of islands in the graph.}
-  \item{islands.pin}{The probability to create each possible edge into
-    each island.}
-  \item{n.inter}{The number of edges to create between two islands.}
-}
-% \details{}
-\value{
-  An igraph graph.
-}
-% \references{}
-\author{Samuel Thiriot (\url{http://samuelthiriot.res-ear.ch/})}
-\seealso{\code{\link{erdos.renyi.game}}}
-\examples{
-g <- interconnected.islands.game(3, 10, 5/10, 1)
-oc <- optimal.community(g)
-oc
-}
-\keyword{graphs}
-
diff --git a/man/intersection.Rd b/man/intersection.Rd
new file mode 100644
index 0000000..994979a
--- /dev/null
+++ b/man/intersection.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{intersection}
+\alias{intersection}
+\title{Intersection of two or more sets}
+\usage{
+intersection(...)
+}
+\arguments{
+\item{...}{Arguments, their number and interpretation depends on
+the function that implements \code{intersection}.}
+}
+\value{
+Depends on the function that implements this method.
+}
+\description{
+This is an S3 generic function. See \code{methods("intersection")}
+for the actual implementations for various S3 classes. Initially
+it is implemented for igraph graphs and igraph vertex and edge
+sequences. See
+\code{\link{intersection.igraph}}, and
+\code{\link{intersection.igraph.vs}}.
+}
+
diff --git a/man/intersection.igraph.Rd b/man/intersection.igraph.Rd
new file mode 100644
index 0000000..ee7b401
--- /dev/null
+++ b/man/intersection.igraph.Rd
@@ -0,0 +1,63 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{intersection.igraph}
+\alias{\%s\%}
+\alias{graph.intersection}
+\alias{intersection.igraph}
+\title{Intersection of graphs}
+\usage{
+\method{intersection}{igraph}(..., byname = "auto",
+  keep.all.vertices = TRUE)
+}
+\arguments{
+\item{byname}{A logical scalar, or the character scalar \code{auto}. Whether
+to perform the operation based on symbolic vertex names. If it is
+\code{auto}, that means \code{TRUE} if all graphs are named and \code{FALSE}
+otherwise. A warning is generated if \code{auto} and some (but not all)
+graphs are named.}
+
+\item{keep.all.vertices}{Logical scalar, whether to keep vertices that only
+appear in a subset of the input graphs.}
+
+\item{\dots}{Graph objects or lists of graph objects.}
+}
+\value{
+A new graph object.
+}
+\description{
+The intersection of two or more graphs are created.  The graphs may have
+identical or overlapping vertex sets.
+}
+\details{
+\code{intersection} creates the intersection of two or more graphs:
+only edges present in all graphs will be included.  The corresponding
+operator is \%s\%.
+
+If the \code{byname} argument is \code{TRUE} (or \code{auto} and all graphs
+are named), then the operation is performed on symbolic vertex names instead
+of the internal numeric vertex ids.
+
+\code{intersection} keeps the attributes of all graphs. All graph,
+vertex and edge attributes are copied to the result. If an attribute is
+present in multiple graphs and would result a name clash, then this
+attribute is renamed by adding suffixes: _1, _2, etc.
+
+The \code{name} vertex attribute is treated specially if the operation is
+performed based on symbolic vertex names. In this case \code{name} must be
+present in all graphs, and it is not renamed in the result graph.
+
+An error is generated if some input graphs are directed and others are
+undirected.
+}
+\examples{
+## Common part of two social networks
+net1 <- graph_from_literal(D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G,
+                  H-F:G, H-I-J)
+net2 <- graph_from_literal(D-A:F:Y, B-A-X-F-H-Z, F-Y)
+str(net1 \%s\% net2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/intersection.igraph.es.Rd b/man/intersection.igraph.es.Rd
new file mode 100644
index 0000000..70b8cf0
--- /dev/null
+++ b/man/intersection.igraph.es.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{intersection.igraph.es}
+\alias{intersection.igraph.es}
+\title{Intersection of edge sequences}
+\usage{
+\method{intersection}{igraph.es}(...)
+}
+\arguments{
+\item{...}{The edge sequences to take the intersection of.}
+}
+\value{
+An edge sequence that contains edges that appear in all
+given sequences, each edge exactly once.
+}
+\description{
+Intersection of edge sequences
+}
+\details{
+They must belong to the same graph. Note that this function has
+\sQuote{set} semantics and the multiplicity of edges is lost in the
+result.
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+intersection(E(g)[1:6], E(g)[5:9])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/intersection.igraph.vs.Rd b/man/intersection.igraph.vs.Rd
new file mode 100644
index 0000000..0d786d5
--- /dev/null
+++ b/man/intersection.igraph.vs.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{intersection.igraph.vs}
+\alias{intersection.igraph.vs}
+\title{Intersection of vertex sequences}
+\usage{
+\method{intersection}{igraph.vs}(...)
+}
+\arguments{
+\item{...}{The vertex sequences to take the intersection of.}
+}
+\value{
+A vertex sequence that contains vertices that appear in all
+given sequences, each vertex exactly once.
+}
+\description{
+Intersection of vertex sequences
+}
+\details{
+They must belong to the same graph. Note that this function has
+\sQuote{set} semantics and the multiplicity of vertices is lost in the
+result.
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+intersection(E(g)[1:6], E(g)[5:9])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/is.bipartite.Rd b/man/is.bipartite.Rd
deleted file mode 100644
index c775db0..0000000
--- a/man/is.bipartite.Rd
+++ /dev/null
@@ -1,56 +0,0 @@
-\name{bipartite.mapping}
-\alias{bipartite.mapping}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\title{Decide whether a graph is bipartite}
-\description{This function decides whether the vertices of a network can
-  be mapped to two vertex types in a way that no vertices of the same
-  type are connected.}
-\usage{
-bipartite.mapping(graph)
-}
-\arguments{
-  \item{graph}{The input graph.}
-}
-\details{
-  A bipartite graph in igraph has a \sQuote{\code{type}} vertex
-  attribute giving the two vertex types.
-
-  This function simply checks whether a graph \emph{could} be
-  bipartite. It tries to find a mapping that gives a possible division
-  of the vertices into two classes, such that no two vertices of the
-  same class are connected by an edge.
-
-  The existence of such a mapping is equivalent of having no circuits of
-  odd length in the graph. A graph with loop edges cannot bipartite.
-
-  Note that the mapping is not necessarily unique, e.g. if the graph has
-  at least two components, then the vertices in the separate components
-  can be mapped independently.
-}
-\value{
-  A named list with two elements:
-  \item{res}{A logical scalar, \code{TRUE} if the can be bipartite,
-    \code{FALSE} otherwise.}
-  \item{type}{A possibly vertex type mapping, a logical vector. If no
-    such mapping exists, then an empty vector.}
-}
-% e
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-% \seealso{}
-\examples{
-## A ring has just one loop, so it is fine
-g <- graph.ring(10)
-bipartite.mapping(g)
-
-## A star is fine, too
-g2 <- graph.star(10)
-bipartite.mapping(g2)
-
-## A graph containing a triangle is not fine
-g3 <- graph.ring(10)
-g3 <- add.edges(g3, c(1,3))
-bipartite.mapping(g3)
-}
-\keyword{graphs}
diff --git a/man/is.chordal.Rd b/man/is.chordal.Rd
deleted file mode 100644
index 4859586..0000000
--- a/man/is.chordal.Rd
+++ /dev/null
@@ -1,71 +0,0 @@
-\name{is.chordal}
-\alias{is.chordal}
-\concept{maximum cardinality search}
-\concept{graph decomposition}
-\concept{chordal graph}
-\title{Chordality of a graph}
-\description{
-  A graph is chordal (or triangulated) if each of its cycles of four or
-  more nodes has a chord, which is an edge joining two nodes that are
-  not adjacent in the cycle. An equivalent definition is that any
-  chordless cycles have at most three nodes.}
-\usage{
-is.chordal(graph, alpha = NULL, alpham1 = NULL, fillin = FALSE,
-           newgraph = FALSE)
-}
-\arguments{
-  \item{graph}{The input graph. It may be directed, but edge directions
-    are ignored, as the algorithm is defined for undirected graphs.}
-  \item{alpha}{Numeric vector, the maximal chardinality ordering of the
-    vertices. If it is \code{NULL}, then it is automatically calculated
-    by calling \code{\link{maximum.cardinality.search}}, or from
-    \code{alpham1} if that is given..}
-  \item{alpham1}{Numeric vector, the inverse of \code{alpha}. If it is
-    \code{NULL}, then it is automatically calculated by calling
-    \code{\link{maximum.cardinality.search}}, or from \code{alpha}.}
-  \item{fillin}{Logical scalar, whether to calculate the fill-in edges.}
-  \item{newgraph}{Logical scalar, whether to calculate the triangulated
-    graph.}
-}
-\details{
-  The chordality of the graph is decided by first performing maximum
-  cardinality search on it (if the \code{alpha} and \code{alpham1}
-  arguments are \code{NULL}), and then calculating the set of fill-in
-  edges.
-
-  The set of fill-in edges is empty if and only if the graph is
-  chordal.
-
-  It is also true that adding the fill-in edges to the graph makes it
-  chordal.
-}
-\value{
-  A list with three members:
-  \item{chordal}{Logical scalar, it is \code{TRUE} iff the input graph
-    is chordal.}
-  \item{fillin}{If requested, then a numeric vector giving the fill-in
-    edges. \code{NULL} otherwise.}
-  \item{newgraph}{If requested, then the triangulated graph, an
-    \code{igraph} object. \code{NULL} otherwise.}
-}
-\references{ Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
-  linear-time algorithms to test chordality of graphs, test acyclicity
-  of hypergraphs, and selectively reduce acyclic hypergraphs.
-  \emph{SIAM Journal of Computation} 13, 566--579.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{maximum.cardinality.search}} }
-\examples{
-## The examples from the Tarjan-Yannakakis paper
-g1 <- graph.formula(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
-                    E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
-                    I-A:H)
-maximum.cardinality.search(g1)
-is.chordal(g1, fillin=TRUE)
-
-g2 <- graph.formula(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
-                    E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
-                    I-G:H:J, J-H:I)
-maximum.cardinality.search(g2)
-is.chordal(g2, fillin=TRUE)
-}
-\keyword{graphs}
diff --git a/man/is.dag.Rd b/man/is.dag.Rd
deleted file mode 100644
index cc79672..0000000
--- a/man/is.dag.Rd
+++ /dev/null
@@ -1,28 +0,0 @@
-\name{is.dag}
-\alias{is.dag}
-\concept{DAG}
-\title{Directed acyclic graphs}
-\description{This function tests whether the given graph is a DAG, a
-  directed acyclic graph.}
-\usage{
-is.dag(graph)
-}
-\arguments{
-  \item{graph}{The input graph. It may be undirected, in which case
-    \code{FALSE} is reported.}
-}
-\details{
-  \code{is.dag} checks whether there is a directed cycle in the
-  graph. If not, the graph is a DAG.
-}
-\value{A logical vector of length one.}
-\author{Tamas Nepusz \email{ntamas at gmail.com} for the C code,
-  Gabor Csardi \email{csardi.gabor at gmail.com} for the R interface.
-}
-\examples{
-g <- graph.tree(10)
-is.dag(g)
-g2 <- g + edge(5,1)
-is.dag(g2)
-}
-\keyword{graphs}
diff --git a/man/is.degree.sequence.Rd b/man/is.degree.sequence.Rd
deleted file mode 100644
index f206a49..0000000
--- a/man/is.degree.sequence.Rd
+++ /dev/null
@@ -1,55 +0,0 @@
-\name{is.degree.sequence}
-\alias{is.degree.sequence}
-\alias{is.graphical.degree.sequence}
-\concept{Degree sequence}
-\title{Degree sequences of graphs}
-\description{
-  These functions decide whether a sequence (or two, if the graph is
-  directed) of integers can be realized as vertex degrees by a graph or
-  simple graph.
-}
-\usage{
-is.degree.sequence (out.deg, in.deg = NULL)
-is.graphical.degree.sequence (out.deg, in.deg = NULL)
-}
-\arguments{
-  \item{out.deg}{Integer vector, the degree sequence for undirected
-    graphs, or the out-degree sequence for directed graphs.}
-  \item{in.deg}{\code{NULL} or an integer vector. For undireted graphs,
-    it should be \code{NULL}. For directed graphs it specifies the
-    in-degrees.}
-}
-\details{
-  \code{is.degree.sequence} checks whether the given vertex degrees (in-
-  and out-degrees for directed graphs) can be realized by a graph. Note
-  that the graph does not have to be simple, it may contain loop and
-  multiple edges. For undirected graphs, it also checks whether the sum
-  of degrees is even. For directed graphs, the function checks whether
-  the lengths of the two degree vectors are equal and whether their sums
-  are also equal. These are known sufficient and necessary conditions
-  for a degree sequence to be valid.
-
-  \code{is.graphial.degree.sequence} determines whether the given vertex
-  degrees (in- and out-degrees for directed graphs) can be reliazed in a
-  simple graph, i.e. a graph without multiple or loop edges.
-}
-\value{
-  A logical scalar.
-}
-\references{
-  Hakimi SL: On the realizability of a set of integers as degrees of the
-  vertices of a simple graph. \emph{J SIAM Appl Math} 10:496-506, 1962.
- 
-  PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm
-  to realize graphical degree sequences of directed graphs.
-  \emph{The Electronic Journal of Combinatorics} 17(1):R66, 2010.
-}
-\author{
-  Tamas Nepusz \email{ntamas at gmail.com}
-}
-\examples{
-g <- erdos.renyi.game(100, 2/100)
-is.degree.sequence(degree(g))
-is.graphical.degree.sequence(degree(g))
-}
-\keyword{graphs}
diff --git a/man/is.graph.Rd b/man/is.graph.Rd
deleted file mode 100644
index df51aaf..0000000
--- a/man/is.graph.Rd
+++ /dev/null
@@ -1,24 +0,0 @@
-\name{is.igraph}
-\alias{is.igraph}
-\title{Is this object a graph?}
-\description{\code{is.graph} makes its decision based on the class
-  attribute of the object.}
-\usage{
-is.igraph(graph)
-}
-\arguments{
-  \item{graph}{An R object.}
-}
-% \details{}
-\value{
-  A logical constant, \code{TRUE} if argument \code{graph} is a graph
-  object.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g <- graph.ring(10)
-is.igraph(g)
-is.igraph(numeric(10))
-}
-\keyword{graphs}
diff --git a/man/is.multiple.Rd b/man/is.multiple.Rd
deleted file mode 100644
index 7411fc3..0000000
--- a/man/is.multiple.Rd
+++ /dev/null
@@ -1,76 +0,0 @@
-\name{is.multiple}
-\alias{has.multiple}
-\alias{is.loop}
-\alias{is.multiple}
-\alias{count.multiple}
-\concept{Simple graph}
-\title{Find the multiple or loop edges in a graph}
-\description{A loop edge is an edge from a vertex to itself. An edge is
-  a multiple edge if it has exactly the same head and tail vertices as
-  another edge. A graph without multiple and loop edges is called a
-  simple graph.}
-\usage{
-is.loop(graph, eids=E(graph))
-has.multiple(graph)
-is.multiple(graph, eids=E(graph))
-count.multiple(graph, eids=E(graph))
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{eids}{The edges to which the query is restricted. By default
-    this is all edges in the graph.}
-}
-\details{
-  \code{is.loop} decides whether the edges of the graph are loop edges.
-  
-  \code{has.multiple} decides whether the graph has any multiple edges.
-
-  \code{is.multiple} decides whether the edges of the graph are multiple
-  edges.
-
-  \code{count.multiple} counts the multiplicity of each edge of a
-  graph.
-  
-  Note that the semantics for \code{is.multiple} and
-  \code{count.multiple} is different. \code{is.multiple} gives \code{TRUE}
-  for all occurences of a multiple edge except for one. Ie. if there are
-  three \code{i-j} edges in the graph then \code{is.multiple} returns
-  \code{TRUE} for only two of them while \code{count.multiple} returns
-  \sQuote{3} for all three.
-
-  See the examples for getting rid of multiple edges while keeping their
-  original multiplicity as an edge attribute.
-}
-\value{
-  \code{has.multiple} returns a logical scalar.
-  \code{is.loop} and \code{is.multiple} return a logical
-  vector. \code{count.multiple} returns a numeric vector.
-}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{simplify}} to eliminate loop and multiple edges.}
-\examples{
-# Loops
-g <- graph( c(1,1,2,2,3,3,4,5) )
-is.loop(g)
-
-# Multiple edges
-g <- barabasi.game(10, m=3, algorithm="bag")
-has.multiple(g)
-is.multiple(g)
-count.multiple(g)
-is.multiple(simplify(g))
-all(count.multiple(simplify(g)) == 1)
-
-# Direction of the edge is important
-is.multiple(graph( c(1,2, 2,1) ))
-is.multiple(graph( c(1,2, 2,1), dir=FALSE ))
-
-# Remove multiple edges but keep multiplicity
-g <- barabasi.game(10, m=3, algorithm="bag")
-E(g)$weight <- count.multiple(g)
-g <- simplify(g)
-any(is.multiple(g))
-E(g)$weight
-}
-\keyword{graphs}
\ No newline at end of file
diff --git a/man/is.mutual.Rd b/man/is.mutual.Rd
deleted file mode 100644
index 36d1a61..0000000
--- a/man/is.mutual.Rd
+++ /dev/null
@@ -1,39 +0,0 @@
-\name{is.mutual}
-\alias{is.mutual}
-\concept{Mutual edges}
-\concept{Reciprocity}
-\title{Find mutual edges in a directed graph}
-\description{This function checks the reciproc pair of the supplied edges.}
-\usage{
-is.mutual(graph, es = E(graph))
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{es}{Edge sequence, the edges that will be probed. By default is
-    includes all edges in the order of their ids.}
-}
-\details{
-  In a directed graph an (A,B) edge is mutual if the graph also includes
-  a (B,A) directed edge.
-
-  Note that multi-graphs are not handled properly, i.e. if the graph
-  contains two copies of (A,B) and one copy of (B,A), then these three
-  edges are considered to be mutual.
-
-  Undirected graphs contain only mutual edges by definition.
-}
-\value{
-  A logical vector of the same length as the number of edges supplied.
-}
-%\references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{reciprocity}}, \code{\link{dyad.census}} if you
-  just want some statistics about mutual edges.}
-\examples{
-g <- erdos.renyi.game(10,50,type="gnm",directed=TRUE)
-reciprocity(g)
-dyad.census(g)
-is.mutual(g)
-sum(is.mutual(g))/2 == dyad.census(g)$mut
-}
-\keyword{graphs}
diff --git a/man/is.named.Rd b/man/is.named.Rd
deleted file mode 100644
index 2166dad..0000000
--- a/man/is.named.Rd
+++ /dev/null
@@ -1,35 +0,0 @@
-\name{is.named}
-\alias{is.named}
-\concept{Named graphs}
-\title{Named graphs}
-\description{An igraph graph is named, if there is a symbolic name
-  associated with its vertices.}
-\usage{
-is.named(graph)
-}
-\arguments{
-  \item{graph}{The input graph.}
-}
-\details{
-  In igraph vertices can always be identified and specified via their
-  numeric vertex ids. This is, however, not always convenient, and in
-  many cases there exist symbolic ids that correspond to the
-  vertices. To allow this more flexible identification of vertices, one
-  can assign a vertex attribute called \sQuote{name} to an igraph
-  graph. After doing this, the symbolic vertex names can be used in all
-  igraph functions, instead of the numeric ids.
-
-  Note that the uniqueness of vertex names are currently not enforced in
-  igraph, you have to check that for yourself, when assigning the vertex
-  names.
-}
-\value{A logical scalar.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\examples{
-g <- graph.ring(10)
-is.named(g)
-V(g)$name <- letters[1:10]
-is.named(g)
-neighbors(g, "a")
-}
-\keyword{graphs}
diff --git a/man/is.separator.Rd b/man/is.separator.Rd
deleted file mode 100644
index b50fe48..0000000
--- a/man/is.separator.Rd
+++ /dev/null
@@ -1,69 +0,0 @@
-\name{is.separator}
-\alias{is.separator}
-\alias{is.minimal.separator}
-\concept{Vertex separator}
-\title{Vertex separators}
-\description{These functions check whether a given set of vertices is a
-  vertex separator, or a minimal vertex separator.
-}
-\usage{
-is.separator(graph, candidate)
-is.minimal.separator(graph, candidate)
-}
-\arguments{
-  \item{graph}{The input graph. It may be directed, but edge directions
-    are ignored.}
-  \item{candidate}{A numeric vector giving the vertex ids of the
-    candidate separator.}
-}
-\details{
-  \code{is.separator} decides whether the supplied vertex set is a
-  vertex separator. A vertex set is a vertex separator if its removal
-  results a disconnected graph.
-
-  \code{is.minimal.separator} decides whether the supplied vertex set is
-  a minimal vertex separator. A minimal vertex separator is a vertex
-  separator, such that none of its subsets is a vertex separator.
-
-  In the special case of a fully connected graph with \eqn{n} vertices,
-  each set of \eqn{n-1} vertices is considered to be a vertex
-  separator.
-}
-\value{
-  A logical scalar, whether the supplied vertex set is a (minimal)
-  vertex separator or not.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  \code{\link{minimum.size.separators}} lists all vertex separator of
-  minimum size.
-}
-\examples{
-# The graph from the Moody-White paper
-mw <- graph.formula(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
-                    5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
-                    10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
-                    17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
-                    21-22:23, 22-23)
-
-# Cohesive subgraphs
-mw1 <- induced.subgraph(mw, as.character(c(1:7, 17:23)))
-mw2 <- induced.subgraph(mw, as.character(7:16))
-mw3 <- induced.subgraph(mw, as.character(17:23))
-mw4 <- induced.subgraph(mw, as.character(c(7,8,11,14)))
-mw5 <- induced.subgraph(mw, as.character(1:7))
-
-check.sep <- function(G) {
-  sep <- minimum.size.separators(G)
-  sapply(sep, is.minimal.separator, graph=G)
-}
-
-check.sep(mw)
-check.sep(mw1)
-check.sep(mw2)
-check.sep(mw3)
-check.sep(mw4)
-check.sep(mw5)
-}
-\keyword{graphs}
diff --git a/man/is.weighted.Rd b/man/is.weighted.Rd
deleted file mode 100644
index 8a9a762..0000000
--- a/man/is.weighted.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-\name{is.weighted}
-\alias{is.weighted}
-\concept{Weighted graphs}
-\title{Weighted graphs}
-\description{In weighted graphs, a real number is assigned to each
-  (directed or undirected) edge.}
-\usage{
-is.weighted(graph)
-}
-\arguments{
-  \item{graph}{The input graph.}
-}
-\details{
-  In igraph edge weights are represented via an edge attribute, called
-  \sQuote{weight}. The \code{is.weighted} function only checks that such
-  an attribute exists. (It does not even checks that it is a numeric edge
-  attribute.)
-
-  Edge weights are used for different purposes by the different
-  functions. E.g. shortest path functions use it as the cost of the
-  path; community finding methods use it as the strength of the
-  relationship between two vertices, etc. Check the manual pages of the
-  functions working with weighted graphs for details.
-}
-\value{A logical scalar.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\examples{
-g <- graph.ring(10)
-get.shortest.paths(g, 8, 2)
-E(g)$weight <- seq_len(ecount(g))
-get.shortest.paths(g, 8, 2)
-}
-\keyword{graphs}
diff --git a/man/is_chordal.Rd b/man/is_chordal.Rd
new file mode 100644
index 0000000..0506795
--- /dev/null
+++ b/man/is_chordal.Rd
@@ -0,0 +1,77 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/decomposition.R
+\name{is_chordal}
+\alias{is.chordal}
+\alias{is_chordal}
+\title{Chordality of a graph}
+\usage{
+is_chordal(graph, alpha = NULL, alpham1 = NULL, fillin = FALSE,
+  newgraph = FALSE)
+}
+\arguments{
+\item{graph}{The input graph. It may be directed, but edge directions are
+ignored, as the algorithm is defined for undirected graphs.}
+
+\item{alpha}{Numeric vector, the maximal chardinality ordering of the
+vertices. If it is \code{NULL}, then it is automatically calculated by
+calling \code{\link{max_cardinality}}, or from \code{alpham1} if
+that is given..}
+
+\item{alpham1}{Numeric vector, the inverse of \code{alpha}. If it is
+\code{NULL}, then it is automatically calculated by calling
+\code{\link{max_cardinality}}, or from \code{alpha}.}
+
+\item{fillin}{Logical scalar, whether to calculate the fill-in edges.}
+
+\item{newgraph}{Logical scalar, whether to calculate the triangulated graph.}
+}
+\value{
+A list with three members: \item{chordal}{Logical scalar, it is
+\code{TRUE} iff the input graph is chordal.} \item{fillin}{If requested,
+then a numeric vector giving the fill-in edges. \code{NULL} otherwise.}
+\item{newgraph}{If requested, then the triangulated graph, an \code{igraph}
+object. \code{NULL} otherwise.}
+}
+\description{
+A graph is chordal (or triangulated) if each of its cycles of four or more
+nodes has a chord, which is an edge joining two nodes that are not adjacent
+in the cycle. An equivalent definition is that any chordless cycles have at
+most three nodes.
+}
+\details{
+The chordality of the graph is decided by first performing maximum
+cardinality search on it (if the \code{alpha} and \code{alpham1} arguments
+are \code{NULL}), and then calculating the set of fill-in edges.
+
+The set of fill-in edges is empty if and only if the graph is chordal.
+
+It is also true that adding the fill-in edges to the graph makes it chordal.
+}
+\examples{
+## The examples from the Tarjan-Yannakakis paper
+g1 <- graph_from_literal(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
+                E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
+                I-A:H)
+max_cardinality(g1)
+is_chordal(g1, fillin=TRUE)
+
+g2 <- graph_from_literal(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
+                E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
+                I-G:H:J, J-H:I)
+max_cardinality(g2)
+is_chordal(g2, fillin=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
+linear-time algorithms to test chordality of graphs, test acyclicity of
+hypergraphs, and selectively reduce acyclic hypergraphs.  \emph{SIAM Journal
+of Computation} 13, 566--579.
+}
+\seealso{
+\code{\link{max_cardinality}}
+}
+\keyword{graphs}
+
diff --git a/man/is_dag.Rd b/man/is_dag.Rd
new file mode 100644
index 0000000..7b14215
--- /dev/null
+++ b/man/is_dag.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/paths.R
+\name{is_dag}
+\alias{is.dag}
+\alias{is_dag}
+\title{Directed acyclic graphs}
+\usage{
+is_dag(graph)
+}
+\arguments{
+\item{graph}{The input graph. It may be undirected, in which case
+\code{FALSE} is reported.}
+}
+\value{
+A logical vector of length one.
+}
+\description{
+This function tests whether the given graph is a DAG, a directed acyclic
+graph.
+}
+\details{
+\code{is_dag} checks whether there is a directed cycle in the graph. If not,
+the graph is a DAG.
+}
+\examples{
+g <- make_tree(10)
+is_dag(g)
+g2 <- g + edge(5,1)
+is_dag(g2)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} for the C code, Gabor Csardi
+\email{csardi.gabor at gmail.com} for the R interface.
+}
+\keyword{graphs}
+
diff --git a/man/is_degseq.Rd b/man/is_degseq.Rd
new file mode 100644
index 0000000..a23cf2a
--- /dev/null
+++ b/man/is_degseq.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/degseq.R
+\name{is_degseq}
+\alias{is.degree.sequence}
+\alias{is_degseq}
+\title{Check if a degree sequence is valid for a multi-graph}
+\usage{
+is_degseq(out.deg, in.deg = NULL)
+}
+\arguments{
+\item{out.deg}{Integer vector, the degree sequence for undirected graphs, or
+the out-degree sequence for directed graphs.}
+
+\item{in.deg}{\code{NULL} or an integer vector. For undireted graphs, it
+should be \code{NULL}. For directed graphs it specifies the in-degrees.}
+}
+\value{
+A logical scalar.
+}
+\description{
+\code{is_degseq} checks whether the given vertex degrees (in- and
+out-degrees for directed graphs) can be realized by a graph. Note that the
+graph does not have to be simple, it may contain loop and multiple edges.
+For undirected graphs, it also checks whether the sum of degrees is even.
+For directed graphs, the function checks whether the lengths of the two
+degree vectors are equal and whether their sums are also equal. These are
+known sufficient and necessary conditions for a degree sequence to be valid.
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Hakimi SL: On the realizability of a set of integers as degrees
+of the vertices of a simple graph. \emph{J SIAM Appl Math} 10:496-506, 1962.
+
+PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm to
+realize graphical degree sequences of directed graphs.  \emph{The Electronic
+Journal of Combinatorics} 17(1):R66, 2010.
+}
+\seealso{
+Other graphical degree sequences
+
+g <- sample_gnp(100, 2/100)
+is_degseq(degree(g))
+is_graphical(degree(g)): \code{\link{is.graphical.degree.sequence}},
+  \code{\link{is_graphical}}
+}
+\keyword{graphs}
+
diff --git a/man/is_directed.Rd b/man/is_directed.Rd
new file mode 100644
index 0000000..80512d9
--- /dev/null
+++ b/man/is_directed.Rd
@@ -0,0 +1,38 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{is_directed}
+\alias{is.directed}
+\alias{is_directed}
+\title{Check whether a graph is directed}
+\usage{
+is_directed(graph)
+}
+\arguments{
+\item{graph}{The input graph}
+}
+\value{
+Logical scalar, whether the graph is directed.
+}
+\description{
+Check whether a graph is directed
+}
+\examples{
+g <- make_ring(10)
+is_directed(g)
+
+g2 <- make_ring(10, directed = TRUE)
+is_directed(g2)
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{neighbors}};
+  \code{\link{tail_of}}
+}
+
diff --git a/man/is_graphical.Rd b/man/is_graphical.Rd
new file mode 100644
index 0000000..51963c2
--- /dev/null
+++ b/man/is_graphical.Rd
@@ -0,0 +1,45 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/degseq.R
+\name{is_graphical}
+\alias{is.graphical.degree.sequence}
+\alias{is_graphical}
+\title{Is a degree sequence graphical?}
+\usage{
+is_graphical(out.deg, in.deg = NULL)
+}
+\arguments{
+\item{out.deg}{Integer vector, the degree sequence for undirected graphs, or
+the out-degree sequence for directed graphs.}
+
+\item{in.deg}{\code{NULL} or an integer vector. For undireted graphs, it
+should be \code{NULL}. For directed graphs it specifies the in-degrees.}
+}
+\value{
+A logical scalar.
+}
+\description{
+Determine whether the given vertex degrees (in- and out-degrees for
+directed graphs) can be reliazed in a simple graph, i.e. a graph without
+multiple or loop edges.
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Hakimi SL: On the realizability of a set of integers as degrees
+of the vertices of a simple graph. \emph{J SIAM Appl Math} 10:496-506, 1962.
+
+PL Erdos, I Miklos and Z Toroczkai: A simple Havel-Hakimi type algorithm to
+realize graphical degree sequences of directed graphs.  \emph{The Electronic
+Journal of Combinatorics} 17(1):R66, 2010.
+}
+\seealso{
+Other graphical degree sequences
+
+g <- sample_gnp(100, 2/100)
+is_degseq(degree(g))
+is_graphical(degree(g)): \code{\link{is.degree.sequence}},
+  \code{\link{is_degseq}}
+}
+\keyword{graphs}
+
diff --git a/man/is_igraph.Rd b/man/is_igraph.Rd
new file mode 100644
index 0000000..079382f
--- /dev/null
+++ b/man/is_igraph.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/basic.R
+\name{is_igraph}
+\alias{is.igraph}
+\alias{is_igraph}
+\title{Is this object an igraph graph?}
+\usage{
+is_igraph(graph)
+}
+\arguments{
+\item{graph}{An R object.}
+}
+\value{
+A logical constant, \code{TRUE} if argument \code{graph} is a graph
+object.
+}
+\description{
+Is this object an igraph graph?
+}
+\examples{
+g <- make_ring(10)
+is_igraph(g)
+is_igraph(numeric(10))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/is_min_separator.Rd b/man/is_min_separator.Rd
new file mode 100644
index 0000000..2e68836
--- /dev/null
+++ b/man/is_min_separator.Rd
@@ -0,0 +1,63 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{is_min_separator}
+\alias{is.minimal.separator}
+\alias{is_min_separator}
+\title{Minumal vertex separators}
+\usage{
+is_min_separator(graph, candidate)
+}
+\arguments{
+\item{graph}{The input graph. It may be directed, but edge directions are
+ignored.}
+
+\item{candidate}{A numeric vector giving the vertex ids of the candidate
+separator.}
+}
+\value{
+A logical scalar, whether the supplied vertex set is a (minimal)
+vertex separator or not.
+}
+\description{
+Check whether a given set of vertices is a minimal vertex separator.
+}
+\details{
+\code{is_min_separator} decides whether the supplied vertex set is a minimal
+vertex separator. A minimal vertex separator is a vertex separator, such
+that none of its subsets is a vertex separator.
+
+In the special case of a fully connected graph with \eqn{n} vertices, each
+set of \eqn{n-1} vertices is considered to be a vertex separator.
+}
+\examples{
+# The graph from the Moody-White paper
+mw <- graph_from_literal(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
+                5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
+                10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
+                17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
+                21-22:23, 22-23)
+
+# Cohesive subgraphs
+mw1 <- induced_subgraph(mw, as.character(c(1:7, 17:23)))
+mw2 <- induced_subgraph(mw, as.character(7:16))
+mw3 <- induced_subgraph(mw, as.character(17:23))
+mw4 <- induced_subgraph(mw, as.character(c(7,8,11,14)))
+mw5 <- induced_subgraph(mw, as.character(1:7))
+
+check.sep <- function(G) {
+  sep <- min_separators(G)
+  sapply(sep, is_min_separator, graph=G)
+}
+
+check.sep(mw)
+check.sep(mw1)
+check.sep(mw2)
+check.sep(mw3)
+check.sep(mw4)
+check.sep(mw5)
+}
+\seealso{
+\code{\link{min_separators}} lists all vertex separator of minimum
+size.
+}
+
diff --git a/man/is_named.Rd b/man/is_named.Rd
new file mode 100644
index 0000000..3fec0d7
--- /dev/null
+++ b/man/is_named.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{is_named}
+\alias{is.named}
+\alias{is_named}
+\title{Named graphs}
+\usage{
+is_named(graph)
+}
+\arguments{
+\item{graph}{The input graph.}
+}
+\value{
+A logical scalar.
+}
+\description{
+An igraph graph is named, if there is a symbolic name associated with its
+vertices.
+}
+\details{
+In igraph vertices can always be identified and specified via their numeric
+vertex ids. This is, however, not always convenient, and in many cases there
+exist symbolic ids that correspond to the vertices. To allow this more
+flexible identification of vertices, one can assign a vertex attribute
+called \sQuote{name} to an igraph graph. After doing this, the symbolic
+vertex names can be used in all igraph functions, instead of the numeric
+ids.
+
+Note that the uniqueness of vertex names are currently not enforced in
+igraph, you have to check that for yourself, when assigning the vertex
+names.
+}
+\examples{
+g <- make_ring(10)
+is_named(g)
+V(g)$name <- letters[1:10]
+is_named(g)
+neighbors(g, "a")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/is_separator.Rd b/man/is_separator.Rd
new file mode 100644
index 0000000..5600bcc
--- /dev/null
+++ b/man/is_separator.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{is_separator}
+\alias{is.separator}
+\alias{is_separator}
+\title{Vertex separators}
+\usage{
+is_separator(graph, candidate)
+}
+\arguments{
+\item{graph}{The input graph. It may be directed, but edge directions are
+ignored.}
+
+\item{candidate}{A numeric vector giving the vertex ids of the candidate
+separator.}
+}
+\value{
+A logical scalar, whether the supplied vertex set is a (minimal)
+  vertex separator or not.
+}
+\description{
+Check whether a given set of vertices is a vertex separator.
+}
+\details{
+\code{is_separator} decides whether the supplied vertex set is a vertex
+separator. A vertex set is a vertex separator if its removal results a
+disconnected graph.
+
+In the special case of a fully connected graph with \eqn{n} vertices, each
+set of \eqn{n-1} vertices is considered to be a vertex separator.
+}
+\seealso{
+\code{\link{is_min_separator}}, \code{\link{min_separators}}
+  lists all vertex separator of minimum size.
+}
+
diff --git a/man/is_weighted.Rd b/man/is_weighted.Rd
new file mode 100644
index 0000000..3d8b31c
--- /dev/null
+++ b/man/is_weighted.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{is_weighted}
+\alias{is.weighted}
+\alias{is_weighted}
+\title{Weighted graphs}
+\usage{
+is_weighted(graph)
+}
+\arguments{
+\item{graph}{The input graph.}
+}
+\value{
+A logical scalar.
+}
+\description{
+In weighted graphs, a real number is assigned to each (directed or
+undirected) edge.
+}
+\details{
+In igraph edge weights are represented via an edge attribute, called
+\sQuote{weight}. The \code{is_weighted} function only checks that such an
+attribute exists. (It does not even checks that it is a numeric edge
+attribute.)
+
+Edge weights are used for different purposes by the different functions.
+E.g. shortest path functions use it as the cost of the path; community
+finding methods use it as the strength of the relationship between two
+vertices, etc. Check the manual pages of the functions working with weighted
+graphs for details.
+}
+\examples{
+g <- make_ring(10)
+shortest_paths(g, 8, 2)
+E(g)$weight <- seq_len(ecount(g))
+shortest_paths(g, 8, 2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/isomorphic.Rd b/man/isomorphic.Rd
new file mode 100644
index 0000000..d279686
--- /dev/null
+++ b/man/isomorphic.Rd
@@ -0,0 +1,150 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{isomorphic}
+\alias{graph.isomorphic}
+\alias{graph.isomorphic.34}
+\alias{graph.isomorphic.bliss}
+\alias{graph.isomorphic.vf2}
+\alias{is_isomorphic_to}
+\alias{isomorphic}
+\title{Decide if two graphs are isomorphic}
+\usage{
+isomorphic(graph1, graph2, method = c("auto", "direct", "vf2", "bliss"), ...)
+
+is_isomorphic_to(graph1, graph2, method = c("auto", "direct", "vf2", "bliss"),
+  ...)
+}
+\arguments{
+\item{graph1}{The first graph.}
+
+\item{graph2}{The second graph.}
+
+\item{method}{The method to use. Possible values: \sQuote{auto},
+\sQuote{direct}, \sQuote{vf2}, \sQuote{bliss}. See their details
+below.}
+
+\item{...}{Additional arguments, passed to the various methods.}
+}
+\value{
+Logical scalar, \code{TRUE} if the graphs are isomorphic.
+}
+\description{
+Decide if two graphs are isomorphic
+}
+\section{\sQuote{auto} method}{
+
+It tries to select the appropriate method based on the two graphs.
+This is the algorithm it uses:
+\enumerate{
+  \item If the two graphs do not agree on their order and size
+    (i.e. number of vertices and edges), then return \code{FALSE}.
+  \item If the graphs have three or four vertices, then the
+    \sQuote{direct} method is used.
+  \item If the graphs are directed, then the \sQuote{vf2} method is
+    used.
+  \item Otherwise the \sQuote{bliss} method is used.
+}
+}
+
+\section{\sQuote{direct} method}{
+
+This method only works on graphs with three or four vertices,
+and it is based on a pre-calculated and stored table. It does not
+have any extra arguments.
+}
+
+\section{\sQuote{vf2} method}{
+
+This method uses the VF2 algorithm by Cordella, Foggia et al., see
+references below. It supports vertex and edge colors and have the
+following extra arguments:
+\describe{
+  \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+    colors of the vertices for colored graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} vertex attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments. See also examples
+    below.}
+  \item{edge.color1, edge.color2}{Optional integer vectors giving the
+    colors of the edges for edge-colored (sub)graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} edge attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments.}
+}
+}
+
+\section{\sQuote{bliss} method}{
+
+Uses the BLISS algorithm by Junttila and Kaski, and it works for
+undirected graphs. For both graphs the
+\code{\link{canonical_permutation}} and then the \code{\link{permute}}
+function is called to transfer them into canonical form; finally the
+canonical forms are compared.
+Extra arguments:
+\describe{
+  \item{sh1}{Character constant, the heuristics to use in the BLISS
+    algorithm, for \code{graph1}. See the \code{sh} argument of
+    \code{\link{canonical_permutation}} for possible values.}
+  \item{sh2}{Character constant, the heuristics to use in the BLISS
+    algorithm, for \code{graph2}. See the \code{sh} argument of
+    \code{\link{canonical_permutation}} for possible values.}
+}
+\code{sh1} and \code{sh2} default to \sQuote{fm}.
+}
+\examples{
+# create some non-isomorphic graphs
+g1 <- graph_from_isomorphism_class(3, 10)
+g2 <- graph_from_isomorphism_class(3, 11)
+isomorphic(g1, g2)
+
+# create two isomorphic graphs, by permuting the vertices of the first
+g1 <- barabasi.game(30, m=2, directed=FALSE)
+g2 <- permute(g1, sample(vcount(g1)))
+# should be TRUE
+isomorphic(g1, g2)
+isomorphic(g1, g2, method = "bliss")
+isomorphic(g1, g2, method = "vf2")
+
+# colored graph isomorphism
+g1 <- make_ring(10)
+g2 <- make_ring(10)
+isomorphic(g1, g2)
+
+V(g1)$color <- rep(1:2, length = vcount(g1))
+V(g2)$color <- rep(2:1, length = vcount(g2))
+# consider colors by default
+count_isomorphisms(g1, g2)
+# ignore colors
+count_isomorphisms(g1, g2, vertex.color1 = NULL,
+    vertex.color2 = NULL)
+}
+\references{
+Tommi Junttila and Petteri Kaski: Engineering an Efficient Canonical
+ Labeling Tool for Large and Sparse Graphs, \emph{Proceedings of the
+ Ninth Workshop on Algorithm Engineering and Experiments and the Fourth
+ Workshop on Analytic Algorithms and Combinatorics.} 2007.
+
+ LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+ for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+ on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/isomorphism_class.Rd b/man/isomorphism_class.Rd
new file mode 100644
index 0000000..ac05cf8
--- /dev/null
+++ b/man/isomorphism_class.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{isomorphism_class}
+\alias{graph.isoclass}
+\alias{graph.isoclass.subgraph}
+\alias{isomorphism_class}
+\title{Isomorphism class of a graph}
+\usage{
+isomorphism_class(graph, v)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{v}{Optionally a vertex sequence. If not missing, then an induced
+subgraph of the input graph, consisting of this vertices, is used.}
+}
+\value{
+An integer number.
+}
+\description{
+The isomorphism class is a non-negative integer number.
+Graphs (with the same number of vertices) having the same isomorphism
+class are isomorphic and isomorphic graphs always have the same
+isomorphism class. Currently it can handle only graphs with 3 or 4
+vertices.
+}
+\examples{
+# create some non-isomorphic graphs
+g1 <- graph_from_isomorphism_class(3, 10)
+g2 <- graph_from_isomorphism_class(3, 11)
+isomorphism_class(g1)
+isomorphism_class(g2)
+isomorphic(g1, g2)
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/isomorphisms.Rd b/man/isomorphisms.Rd
new file mode 100644
index 0000000..41bad4b
--- /dev/null
+++ b/man/isomorphisms.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{isomorphisms}
+\alias{graph.get.isomorphisms.vf2}
+\alias{isomorphisms}
+\title{Calculate all isomorphic mappings between the vertices of two graphs}
+\usage{
+isomorphisms(graph1, graph2, method = "vf2", ...)
+}
+\arguments{
+\item{graph1}{The first graph.}
+
+\item{graph2}{The second graph.}
+
+\item{method}{Currently only \sQuote{vf2} is supported, see
+\code{\link{isomorphic}} for details about it and extra arguments.}
+
+\item{...}{Extra arguments, passed to the various methods.}
+}
+\value{
+A list of vertex sequences, corresponding to all
+  mappings from the first graph to the second.
+}
+\description{
+Calculate all isomorphic mappings between the vertices of two graphs
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/iterators.Rd b/man/iterators.Rd
deleted file mode 100644
index 02b7131..0000000
--- a/man/iterators.Rd
+++ /dev/null
@@ -1,234 +0,0 @@
-\name{iterators}
-\alias{iterators}
-\alias{V}
-\alias{E}
-\alias{V<-}
-\alias{E<-}
-\alias{\%--\%}
-\alias{\%->\%}
-\alias{\%<-\%}
-\alias{[<-.igraph.es}
-\alias{[.igraph.es}
-\alias{[[<-.igraph.es}
-\alias{[[.igraph.es}
-\alias{$<-.igraph.es}
-\alias{$.igraph.es}
-\alias{[<-.igraph.vs}
-\alias{[.igraph.vs}
-\alias{[[<-.igraph.vs}
-\alias{[[.igraph.vs}
-\alias{$<-.igraph.vs}
-\alias{$.igraph.vs}
-\alias{print.igraph.es}
-\alias{print.igraph.vs}
-\title{Vertex and edge sequences and iterators}
-\description{Vertex and edge sequences are central concepts of
-  igraph.}
-\usage{
-V(graph)
-E(graph, P=NULL, path=NULL, directed=TRUE)
-}
-\arguments{
-  \item{graph}{A graph object.}
-  \item{P}{Numeric vector for selecting edges by giving their end
-    points. See details below.}
-  \item{path}{Numeric vector, this is for selecting all edges along a
-    path. See also details below.}
-  \item{directed}{Logcal constant, can be supplied only if either
-    \code{P} or \code{path} is also present and gives whether the pairs
-    or the path are directed or not.} 
-}
-\details{
-  One often needs to perform an operation on a subset of vertices of
-  edges in a graph.
-
-  A vertex sequence is simply a vector containing vertex ids, but it has
-  a special class attribute which makes it possible to perform graph
-  specific operations on it, like selecting a subset of the vertices
-  based on some vertex attributes.
-
-  A vertex sequence is created by \code{V(g)} this selects are vertices
-  in increasing vertex id order. A vertex sequence can be indexed by a
-  numeric vector, and a subset of all vertices can be
-  selected.
-
-  Vertex sequences provide powerful operations for dealing with vertex
-  attributes. A vertex sequence can be indexed with the
-  \sQuote{\code{$}} operator to select (or modify) the attributes of a
-  subset of vertices. A vertex sequence can be indexed by a logical
-  expression, and this expression may contain the names of the vertex
-  attributes and ordinary variables as well. The return value of such a
-  construct (ie. a vertex sequence indexed by a logical expression) is
-  another vertex sequence containing only vertices from the original
-  sequence for which the expression evaluates to TRUE.
-
-  Let us see an example to make everything clear. We assign random
-  numbers between 1 and 100 to the vertices, and select those vertices
-  for which the number is less than 50. We set the color of these
-  vertices to red.
-  \preformatted{
-    g <- graph.ring(10)
-    V(g)$number <- sample(1:100, vcount(g), replace=TRUE)
-    V(g)$color <- "grey"
-    V(g)[ number < 50 ]$color <- "red"
-    plot(g, layout=layout.circle, vertex.color=V(g)$color,
-         vertex.label=V(g)$number)
-  }
-
-  There is a similar notation for edges. \code{E(g)} selects all edges
-  from the \sQuote{\code{g}} graph. Edge sequences can be also indexed
-  with logical expressions containing edge attributes:
-  \preformatted{
-    g <- graph.ring(10)
-    E(g)$weight <- runif(ecount(g))
-    E(g)$width <- 1
-    E(g)[ weight >= 0.5 ]$width <- 3
-    plot(g, layout=layout.circle, edge.width=E(g)$width, edge.color="black")
-  }
-
-  It is important to note that, whenever we use iterators to assign new
-  attribute values, the new values are recycled. So in the following
-  example half of the vertices will be black, the other half red, in an
-  alternated way.
-  \preformatted{
-    g <- graph.ring(10)
-    V(g)$color <- c("black", "red")
-    plot(g, layout=layout.circle)
-  }
-
-  For the recycling, the standard R rules apply and a warning is given
-  if the number of items to replace is not a multiple of the replacement
-  length. E.g. the following code gives a warning, because we set the
-  attribute for three vertices, but supply only two values:
-  \preformatted{
-    g <- graph.tree(10)
-    V(g)$color <- "grey"
-    V(g)[1:3]$color <- c("green", "blue")
-  }
-  
-  If a new vertex/edge attribute is created with an assignment, but only
-  a subset of of vertices are specified, then the rest is set to
-  \code{NA} if the new values are in a vector and to \code{NULL} if they
-  are a list. Try the following:
-  \preformatted{
-    V(g)[5]$foo <- "foo"
-    V(g)$foo
-    V(g)[5]$bar <- list(bar="bar")
-    V(g)$bar
-  }
-  
-  There are some special functions which are only defined in the
-  indexing expressions of vertex and edge sequences. For vertex
-  sequences these are: \code{nei}, \code{inc}, \code{from} and
-  \code{to}, \code{innei} and \code{outnei}. (The \code{adj} special
-  function is an alias for \code{inc}, for compatibility reasons.)
-
-  \code{nei} has a mandatory and an optional argument, the first is
-  another vertex sequence, the second is a mode argument similar to that
-  of the \code{\link{neighbors}} function. \code{nei} returns a logical
-  vector of the same length as the indexed vertex sequence and evaluates
-  to \code{TRUE} for those vertices only which have a neighbor vertex in
-  the vertex sequence supplied as a parameter. Thus for selecting all
-  neighbors of vertices 1 and 2 one can write:
-  \preformatted{
-    V(g) [ nei( 1:2 ) ]
-  }
-  The mode argument (just like for \code{\link{neighbors}}) gives the
-  type of the neighbors to be included, it is interpreted only in
-  directed graphs, and defaults to all types of neighbors. See the
-  example below. \code{innei(v)} is a shorthand for the \sQuote{incoming}
-  neighbors (\code{nei(v, mode="in")}), and \code{outnei(v)} is a
-  shorthand for the \sQuote{outgoing} neighbors
-  (\code{nei(v,mode="out")}).
-
-  \code{inc} takes an edge sequence as an argument and returns
-  \code{TRUE} for vertices which have at least one incident edge in it.
-
-  \code{from} and \code{to} are similar to \code{inc} but only edges
-  originated at (\code{from}) or pointing to (\code{to}) are taken into
-  account.
-
-  For edge sequences the special functions are: \code{inc}, \code{from},
-  \code{to}, \code{\%--\%}, \code{\%->\%} and \code{\%<-\%}.
-
-  \code{inc} takes a vertex sequence as an argument and returns
-  \code{TRUE} for edges which have an incident vertex in it.
-
-  \code{from} and \code{to} are similar to \code{inc}, but only vertices
-  at the source (\code{from}) or target (\code{to}) of the edge.
-
-  The \code{\%--\%} operator selects edges connecting two vertex
-  sequences, the direction of the edges is ignored. The \code{\%->\%} is
-  different only for directed graphs and only edges pointing from the
-  left hand side argument to the right hand side argument are selected.
-  \code{\%<-\%} is exactly the opposite, it selects edges pointing from
-  the right hand side to the left hand side.  
-
-  \code{E} has two optional arguments: \code{P} and \code{path}. If
-  given \code{P} can be used to select edges based on their end points,
-  eg. \code{E(g, P=c(1,2))} selects edge \code{1->2}.
-
-  \code{path} can be used to select all edges along a path. The path
-  should be given with the visited vertex ids in the appropriate order.
-  
-  See also the examples below.  
-}
-\note{
-  A note about the performance of the \code{V} and \code{E} functions,
-  and the selection of edges and vertices. Since all selectors
-  are evaluated as logical vectors on all vertices/edges, their
-  performance is bad on large graphs. (Time complexity is proportional
-  to the total number of vertices/edges.) We suggest using the
-  \code{\link{neighbors}}, \code{\link{incident}} functions and
-  simple R vector operations for manipulating vertex/edge sequences
-  in large graphs.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-# mean degree of vertices in the largest cluster in a random graph
-g <- erdos.renyi.game(100, 2/100)
-c <- clusters(g)
-vsl <- which(which.max(c$csize)==c$membership)
-mean(degree(g, vsl))
-
-# set the color of these vertices to red, others greens
-V(g)$color <- "green"
-V(g)[vsl]$color <- "red"
-\dontrun{plot(g, vertex.size=3, labels=NA, vertex.color="a:color",
-              layout=layout.fruchterman.reingold)}
-
-# the longest geodesic within the largest cluster
-long <- numeric()
-for (v in vsl) {
-  paths <- get.shortest.paths(g, from=v, to=vsl)
-  fl <- paths[[ which.max(sapply(paths, length)) ]]
-  if (length(fl) > length(long)) {
-    long <- fl
-  }
-}
-
-# the mode argument of the nei() function
-g <- graph( c(1,2, 2,3, 2,4, 4,2) )
-V(g)[ nei( c(2,4) ) ]
-V(g)[ nei( c(2,4), "in") ]
-V(g)[ nei( c(2,4), "out") ]
-
-# operators for edge sequences
-g <- barabasi.game(100, power=0.3)
-E(g) [ 1:3 \%--\% 2:6 ]
-E(g) [ 1:5 \%->\% 1:6 ]
-E(g) [ 1:3 \%<-\% 2:6 ]
-
-# the edges along the diameter
-g <- barabasi.game(100, directed=FALSE)
-d <- get.diameter(g)
-E(g, path=d)
-
-# performance for large graphs is bad
-largeg <- graph.lattice(c(1000, 100))
-system.time(E(largeg)[inc(1)])
-system.time(incident(largeg, 1))
-}
-\keyword{graphs}
diff --git a/man/ivs.Rd b/man/ivs.Rd
new file mode 100644
index 0000000..9ac22be
--- /dev/null
+++ b/man/ivs.Rd
@@ -0,0 +1,90 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/cliques.R
+\name{ivs}
+\alias{independence.number}
+\alias{independent.vertex.sets}
+\alias{ivs}
+\alias{ivs_size}
+\alias{largest.independent.vertex.sets}
+\alias{largest_ivs}
+\alias{maximal.independent.vertex.sets}
+\alias{maximal_ivs}
+\title{Independent vertex sets}
+\usage{
+ivs(graph, min = NULL, max = NULL)
+}
+\arguments{
+\item{graph}{The input graph, directed graphs are considered as undirected,
+loop edges and multiple edges are ignored.}
+
+\item{min}{Numeric constant, limit for the minimum size of the independent
+vertex sets to find. \code{NULL} means no limit.}
+
+\item{max}{Numeric constant, limit for the maximum size of the independent
+vertex sets to find. \code{NULL} means no limit.}
+}
+\value{
+\code{ivs},
+\code{largest_ivs} and
+\code{maximal_ivs} return a list containing numeric
+vertex ids, each list element is an independent vertex set.
+
+\code{ivs_size} returns an integer constant.
+}
+\description{
+A vertex set is called independent if there no edges between any two
+vertices in it. These functions find independent vertex sets in undirected
+graphs
+}
+\details{
+\code{ivs} finds all independent vertex sets in the
+network, obeying the size limitations given in the \code{min} and \code{max}
+arguments.
+
+\code{largest_ivs} finds the largest independent vertex
+sets in the graph. An independent vertex set is largest if there is no
+independent vertex set with more vertices.
+
+\code{maximal_ivs} finds the maximal independent vertex
+sets in the graph. An independent vertex set is maximal if it cannot be
+extended to a larger independent vertex set. The largest independent vertex
+sets are maximal, but the opposite is not always true.
+
+\code{independece.number} calculate the size of the largest independent
+vertex set(s).
+
+These functions use the algorithm described by Tsukiyama et al., see
+reference below.
+}
+\examples{
+# Do not run, takes a couple of seconds
+\dontrun{
+
+# A quite dense graph
+set.seed(42)
+g <- sample_gnp(100, 0.9)
+ivs_size(g)
+ivs(g, min=ivs_size(g))
+largest_ivs(g)
+# Empty graph
+induced_subgraph(g, largest_ivs(g)[[1]])
+
+length(maximal_ivs(g))
+}
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} ported it from the Very Nauty
+Graph Library by Keith Briggs (\url{http://keithbriggs.info/}) and Gabor
+Csardi \email{csardi.gabor at gmail.com} wrote the R interface and this manual
+page.
+}
+\references{
+S. Tsukiyama, M. Ide, H. Ariyoshi and I. Shirawaka. A new
+algorithm for generating all the maximal independent sets. \emph{SIAM J
+Computing}, 6:505--517, 1977.
+}
+\seealso{
+\code{\link{cliques}}
+}
+\keyword{graphs}
+
diff --git a/man/k.regular.game.Rd b/man/k.regular.game.Rd
deleted file mode 100644
index bbbc59b..0000000
--- a/man/k.regular.game.Rd
+++ /dev/null
@@ -1,51 +0,0 @@
-\name{k.regular.game}
-\alias{k.regular.game}
-\concept{Random graph model}
-\concept{Regular graph}
-\title{Create a random regular graph}
-\description{Generate a random graph where each vertex has the same
-  degree.}
-\usage{
-k.regular.game (no.of.nodes, k, directed = FALSE, multiple = FALSE) 
-}
-\arguments{
-  \item{no.of.nodes}{Integer scalar, the number of vertices in the
-    generated graph.}
-  \item{k}{Integer scalar, the degree of each vertex in the graph, or
-    the out-degree and in-degree in a directed graph.}
-  \item{directed}{Logical scalar, whether to create a directed graph.}
-  \item{multiple}{Logical scalar, whether multiple edges are allowed.}
-}
-\details{
-  This game generates a directed or undirected random graph where the
-  degrees of vertices are equal to a predefined constant k. For undirected
-  graphs, at least one of k and the number of vertices must be even.
-
-  The game simply uses \code{\link{degree.sequence.game}} with
-  appropriately constructed degree sequences.
-}
-\value{
-  An igraph graph.
-}
-% \references{}
-\author{
-  Tamas Nepusz \email{ntamas at gmail.com}
-}
-\seealso{
-  \code{\link{degree.sequence.game}} for a generator with prescribed
-  degree sequence.
-}
-\examples{
-## A simple ring
-ring <- k.regular.game(10, 2)
-plot(ring)
-
-## k-regular graphs on 10 vertices, with k=1:9
-k10 <- lapply(1:9, k.regular.game, no.of.nodes=10)
-
-layout(matrix(1:9, nrow=3, byrow=TRUE))
-sapply(k10, plot, vertex.label=NA)
-}
-\keyword{graphs}
-
-
diff --git a/man/keeping_degseq.Rd b/man/keeping_degseq.Rd
new file mode 100644
index 0000000..e15a21b
--- /dev/null
+++ b/man/keeping_degseq.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/rewire.R
+\name{keeping_degseq}
+\alias{keeping_degseq}
+\title{Graph rewiring while preserving the degree distribution}
+\usage{
+keeping_degseq(loops = FALSE, niter = 100)
+}
+\arguments{
+\item{loops}{Whether to allow destroying and creating loop edges.}
+
+\item{niter}{Number of rewiring trials to perform.}
+}
+\description{
+This function can be used together with \code{\link{rewire}} to
+randomly rewire the edges while preserving the original graph's degree
+distribution.
+}
+\details{
+The rewiring algorithm chooses two arbitrary edges in each step ((a,b)
+and (c,d)) and substitutes them with (a,d) and (c,b), if they not
+already exists in the graph. The algorithm does not create multiple
+edges.
+}
+\examples{
+g <- make_ring(10)
+g \%>\%
+  rewire(keeping_degseq(niter = 20)) \%>\%
+  degree()
+str(rewire(g, with = keeping_degseq(niter = vcount(g) * 10)))
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{sample_degseq}}
+
+Other rewiring functions: \code{\link{each_edge}};
+  \code{\link{rewire}}
+}
+\keyword{graphs}
+
diff --git a/man/kleinberg.Rd b/man/kleinberg.Rd
deleted file mode 100644
index 3038e77..0000000
--- a/man/kleinberg.Rd
+++ /dev/null
@@ -1,65 +0,0 @@
-\name{kleinberg}
-\alias{authority.score}
-\alias{hub.score}
-\concept{Hub and authority score}
-\title{Kleinberg's centrality scores.}
-\description{Kleinberg's hub and authority scores.}
-\usage{
-authority.score (graph, scale = TRUE, weights=NULL, options = igraph.arpack.default) 
-hub.score (graph, scale = TRUE, weights=NULL, options = igraph.arpack.default) 
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{scale}{Logical scalar, whether to scale the result to have a
-    maximum score of one. If no scaling is used then the result vector
-    has unit length in the Euclidean norm.}
-  \item{weights}{Optional positive weight vector for calculating
-    weighted scores. If the graph has a \code{weight} edge
-    attribute, then this is used by default.}
-  \item{options}{A named list, to override some ARPACK options. See
-    \code{\link{arpack}} for details.}
-}
-\details{
-  The authority scores of the vertices are defined as the principal
-  eigenvector of \eqn{A^T A}{t(A)*A}, where \eqn{A} is the adjacency
-  matrix of the graph.
-
-  The hub scores of the vertices are defined as the principal
-  eigenvector of \eqn{A A^T}{A*t(A)}, where \eqn{A} is the adjacency
-  matrix of the graph.
-
-  Obviously, for undirected matrices the adjacency matrix is symmetric
-  and the two scores are the same.
-}
-\value{
-  A named list with members:
-  \item{vector}{The authority/hub scores of the vertices.}
-  \item{value}{The corresponding eigenvalue of the calculated
-    principal eigenvector.}
-  \item{options}{Some information about the ARPACK computation, it has
-    the same members as the \code{options} member returned by
-    \code{\link{arpack}}, see that for documentation.}
-}
-\references{
-  J. Kleinberg. Authoritative sources in a hyperlinked
-  environment. \emph{Proc. 9th ACM-SIAM Symposium on Discrete Algorithms},
-  1998. Extended version in \emph{Journal of the ACM} 46(1999). Also
-  appears as IBM Research Report RJ 10076, May 1997.
-}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{\code{\link{evcent}} for eigenvector centrality,
-  \code{\link{page.rank}} for the Page Rank scores. \code{\link{arpack}}
-  for the underlining machinery of the computation.
-}
-\examples{
-## An in-star
-g <- graph.star(10)
-hub.score(g)$vector
-authority.score(g)$vector
-
-## A ring
-g2 <- graph.ring(10)
-hub.score(g2)$vector
-authority.score(g2)$vector
-}
-\keyword{graphs}
diff --git a/man/knn.Rd b/man/knn.Rd
new file mode 100644
index 0000000..aa41d62
--- /dev/null
+++ b/man/knn.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{knn}
+\alias{graph.knn}
+\alias{knn}
+\title{Average nearest neighbor degree}
+\usage{
+knn(graph, vids = V(graph), weights = NULL)
+}
+\arguments{
+\item{graph}{The input graph. It can be directed, but it will be treated as
+undirected, i.e. the direction of the edges is ignored.}
+
+\item{vids}{The vertices for which the calculation is performed. Normally it
+includes all vertices. Note, that if not all vertices are given here, then
+both \sQuote{\code{knn}} and \sQuote{\code{knnk}} will be calculated based
+on the given vertices only.}
+
+\item{weights}{Weight vector. If the graph has a \code{weight} edge
+attribute, then this is used by default. If this argument is given, then
+vertex strength (see \code{\link{strength}}) is used instead of vertex
+degree. But note that \code{knnk} is still given in the function of the
+normal vertex degree.}
+}
+\value{
+A list with two members: \item{knn}{A numeric vector giving the
+average nearest neighbor degree for all vertices in \code{vids}.}
+\item{knnk}{A numeric vector, its length is the maximum (total) vertex
+degree in the graph. The first element is the average nearest neighbor
+degree of vertices with degree one, etc.  }
+}
+\description{
+Calculate the average nearest neighbor degree of the given vertices and the
+same quantity in the function of vertex degree
+}
+\details{
+Note that for zero degree vertices the answer in \sQuote{\code{knn}} is
+\code{NaN} (zero divided by zero), the same is true for \sQuote{\code{knnk}}
+if a given degree never appears in the network.
+}
+\examples{
+# Some trivial ones
+g <- make_ring(10)
+knn(g)
+g2 <- make_star(10)
+knn(g2)
+
+# A scale-free one, try to plot 'knnk'
+g3 <- sample_pa(1000, m=5)
+knn(g3)
+
+# A random graph
+g4 <- sample_gnp(1000, p=5/1000)
+knn(g4)
+
+# A weighted graph
+g5 <- make_star(10)
+E(g5)$weight <- seq(ecount(g5))
+knn(g5)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras,
+Alessandro Vespignani: The architecture of complex weighted networks, Proc.
+Natl. Acad. Sci. USA 101, 3747 (2004)
+}
+\keyword{graphs}
+
diff --git a/man/label.propagation.community.Rd b/man/label.propagation.community.Rd
deleted file mode 100644
index 6dbf504..0000000
--- a/man/label.propagation.community.Rd
+++ /dev/null
@@ -1,70 +0,0 @@
-\name{label.propagation.community}
-\alias{label.propagation.community}
-\concept{Community structure}
-\title{Finding communities based on propagating labels}
-\description{
-  This is a fast, nearly linear time algorithm for detecting community
-  structure in networks. In works by labeling the vertices with unique
-  labels and then updating the labels by majority voting in the
-  neighborhood of the vertex.
-}
-\usage{
-label.propagation.community (graph, weights = NULL,
-            initial = NULL, fixed = NULL)
-}
-\arguments{
-  \item{graph}{The input graph, should be undirected to make sense.}
-  \item{weights}{An optional weight vector. It should contain a positive
-    weight for all the edges. The \sQuote{weight} edge attribute is used
-    if present. Supply \sQuote{\code{NA}} here if you want to ignore the
-    \sQuote{weight} edge attribute.}
-  \item{initial}{The initial state. If \code{NULL}, every vertex will have
-    a different label at the beginning. Otherwise it must be a vector
-    with an entry for each vertex. Non-negative values denote different
-    labels, negative entries denote vertices without labels.}
-  \item{fixed}{Logical vector denoting which labels are fixed. Of course
-    this makes sense only if you provided an initial state, otherwise
-    this element will be ignored. Also note that vertices without labels
-    cannot be fixed.}
-}
-\details{
-  This function implements the community detection method described in:
-  Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time algorithm
-  to detect community structures in large-scale networks. Phys Rev E
-  76, 036106. (2007). This version extends the original method by
-  the ability to take edge weights into consideration and also
-  by allowing some labels to be fixed.
-
-  From the abstract of the paper:
-  \dQuote{In our algorithm every node is initialized with a unique label
-    and at every step each node adopts the label that most of its
-    neighbors currently have. In this iterative process densely
-    connected groups of  nodes form a consensus on a unique label to form
-    communities.}
-}
-\value{
-  \code{label.propagation.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\references{
-  Raghavan, U.N. and Albert, R. and Kumara, S.: Near linear time algorithm
-  to detect community structures in large-scale networks. \emph{Phys Rev E}
-  76, 036106. (2007)
-}
-\author{
-  Tamas Nepusz \email{ntamas at gmail.com} for the C implementation,
-  Gabor Csardi \email{csardi.gabor at gmail.com} for this manual page.
-}
-\seealso{
-  \code{\link{communities}} for extracting the actual results.
-  
-  \code{\link{fastgreedy.community}},
-  \code{\link{walktrap.community}} and \code{\link{spinglass.community}}
-  for other community detection methods.}
-\examples{
-  g <- erdos.renyi.game(10, 5/10) \%du\% erdos.renyi.game(9, 5/9)
-  g <- add.edges(g, c(1, 12))
-  label.propagation.community(g)
-}
-\keyword{graphs}
diff --git a/man/laplacian_matrix.Rd b/man/laplacian_matrix.Rd
new file mode 100644
index 0000000..2d1cf45
--- /dev/null
+++ b/man/laplacian_matrix.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{laplacian_matrix}
+\alias{graph.laplacian}
+\alias{laplacian_matrix}
+\title{Graph Laplacian}
+\usage{
+laplacian_matrix(graph, normalized = FALSE, weights = NULL,
+  sparse = igraph_opt("sparsematrices"))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{normalized}{Whether to calculate the normalized Laplacian. See
+definitions below.}
+
+\item{weights}{An optional vector giving edge weights for weighted Laplacian
+matrix. If this is \code{NULL} and the graph has an edge attribute called
+\code{weight}, then it will be used automatically. Set this to \code{NA} if
+you want the unweighted Laplacian on a graph that has a \code{weight} edge
+attribute.}
+
+\item{sparse}{Logical scalar, whether to return the result as a sparse
+matrix. The \code{Matrix} package is required for sparse matrices.}
+}
+\value{
+A numeric matrix.
+}
+\description{
+The Laplacian of a graph.
+}
+\details{
+The Laplacian Matrix of a graph is a symmetric matrix having the same number
+of rows and columns as the number of vertices in the graph and element (i,j)
+is d[i], the degree of vertex i if if i==j, -1 if i!=j and there is an edge
+between vertices i and j and 0 otherwise.
+
+A normalized version of the Laplacian Matrix is similar: element (i,j) is 1
+if i==j, -1/sqrt(d[i] d[j]) if i!=j and there is an edge between vertices i
+and j and 0 otherwise.
+
+The weighted version of the Laplacian simply works with the weighted degree
+instead of the plain degree. I.e. (i,j) is d[i], the weighted degree of
+vertex i if if i==j, -w if i!=j and there is an edge between vertices i and
+j with weight w, and 0 otherwise. The weighted degree of a vertex is the sum
+of the weights of its adjacent edges.
+}
+\examples{
+g <- make_ring(10)
+laplacian_matrix(g)
+laplacian_matrix(g, norm=TRUE)
+laplacian_matrix(g, norm=TRUE, sparse=FALSE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/layout.Rd b/man/layout.Rd
deleted file mode 100644
index 0ae14f4..0000000
--- a/man/layout.Rd
+++ /dev/null
@@ -1,324 +0,0 @@
-\name{layout}
-\alias{layout}
-\alias{layout.auto}
-\alias{layout.random}
-\alias{layout.circle}
-\alias{layout.sphere}
-\alias{layout.fruchterman.reingold}
-\alias{layout.fruchterman.reingold.grid}
-\alias{layout.kamada.kawai}
-\alias{layout.spring}
-\alias{layout.reingold.tilford}
-\alias{layout.lgl}
-\alias{layout.svd}
-\alias{layout.graphopt}
-\alias{layout.norm}
-\concept{Graph layout}
-\title{Generate coordinates for plotting graphs}
-\description{Some simple and not so simple functions determining the
-  placement of the vertices for drawing a graph.}
-\usage{
-layout.auto(graph, dim=2, \dots)
-layout.random(graph, params, dim=2)
-layout.circle(graph, params)
-layout.sphere(graph, params)
-layout.fruchterman.reingold(graph, \dots, dim=2, params)
-layout.kamada.kawai(graph, \dots, dim=2, params)
-layout.spring(graph, \dots, params)
-layout.reingold.tilford(graph, \dots, params)
-layout.fruchterman.reingold.grid(graph, \dots, params)
-layout.lgl(graph, \dots, params)
-layout.graphopt(graph, ..., params=list())
-layout.svd(graph, d=shortest.paths(graph), ...)
-layout.norm(layout, xmin = NULL, xmax = NULL, ymin = NULL, ymax = NULL,
-      zmin = NULL, zmax = NULL)
-}
-\arguments{
-  \item{graph}{The graph to place.}
-  \item{params}{The list of function dependent parameters.}
-  \item{dim}{Numeric constant, either 2 or 3. Some functions are able
-    to generate 2d and 3d layouts as well, supply this argument to
-    change the default behavior.}
-  \item{\dots}{Function dependent parameters, this is an alternative
-    notation to the \code{params} argument. For \code{layout.auto} these
-    extra parameters are simply passed to the real layout function, if
-    one is called.}
-  \item{d}{The matrix used for singular value decomposition. By default it
-    is the distance matrix of the graph.}
-  \item{layout}{A matrix with two or three columns, the layout to
-    normalize.}
-  \item{xmin,xmax}{The limits for the first coordinate, if one of them
-    or both are \code{NULL} then no normalization is performed along
-    this direction.}
-  \item{ymin,ymax}{The limits for the second coordinate, if one of them
-    or both are \code{NULL} then no normalization is performed along
-    this direction.}
-  \item{zmin,zmax}{The limits for the third coordinate, if one of them
-    or both are \code{NULL} then no normalization is performed along
-    this direction.}  
-}
-\details{
-  These functions calculate the coordinates of the vertices for a graph
-  usually based on some optimality criterion.
-
-  \code{layout.auto} tries to choose an appropriate layout function for
-  the supplied graph, and uses that to generate the layout. The current
-  implementations works like this:
-  \enumerate{
-    \item If the graph has a graph attribute called \sQuote{layout},
-    then this is used. If this attribute is an R function, then it is
-    called, with the graph and any other extra arguments.
-    \item Otherwise, if the graph has vertex attributes called
-    \sQuote{x} and \sQuote{y}, then these are used as coordinates. If
-    the graph has an additional \sQuote{z} vertex attribute, that is
-    also used.
-    \item Otherwise, if the graph is connected and has less than 100
-    vertices, the Kamada-Kawai layout is used, by calling
-    \code{layout.kamada.kawai}.
-    \item Otherwise, if the graph has less than 1000 vertices, then the
-    Fruchterman-Reingold layout is used, by calling
-    \code{layout.fruchterman.reingold}.
-    \item Otherwise the DrL layout is used, \code{layout.drl} is called.
-  }
-  
-  \code{layout.random} simply places the vertices randomly on a
-  square. It has no parameters.
-
-  \code{layout.circle} places the vertices on a unit circle
-  equidistantly. It has no paramaters.
-
-  \code{layout.sphere} places the vertices (approximately) uniformly on
-  the surface of a sphere, this is thus a 3d layout. It is not clear
-  however what \dQuote{uniformly on a sphere} means.
-  
-  \code{layout.fruchterman.reingold} uses a force-based algorithm
-  proposed by Fruchterman and Reingold, see references. Parameters and
-  their default values:
-  \describe{
-    \item{niter}{Numeric, the number of iterations to perform (500).}
-    \item{coolexp}{Numeric, the cooling exponent for the simulated
-      annealing (3).}
-    \item{maxdelta}{Maximum change (\code{vcount(graph)}).}
-    \item{area}{Area parameter (\code{vcount(graph)^2}).}
-    \item{repulserad}{Cancellation radius (\code{area}*vcount(graph)).}
-    \item{weights}{A vector giving edge weights or \code{NULL}. If not
-      \code{NULL} then the attraction along the edges will be multiplied
-      by the given edge weights (\code{NULL}).}
-    \item{minx}{If not \code{NULL}, then it must be a numeric vector
-      that gives lower boundaries for the \sQuote{x} coordinates of the
-      vertices. The length of the vector must match the number of
-      vertices in the graph.}
-    \item{maxx}{Similar to \code{minx}, but gives the upper boundaries.}
-    \item{miny}{Similar to \code{minx}, but gives the lower boundaries
-      of the \sQuote{y} coordinates.}
-    \item{maxy}{Similar to \code{minx}, but gives the upper boundaries
-      of the \sQuote{y} coordinates.}    
-    \item{minz}{Similar to \code{minx}, but gives the lower boundaries
-      of the \sQuote{z} coordinates, if the \code{dim} argument is
-      3. Otherwise it is ignored.}
-    \item{maxz}{Similar to \code{minx}, but gives the upper boundaries
-      of the \sQuote{z} coordinates, if the \code{dim} argument is
-      3. Otherwise it is ignored.}
-    \item{start}{If given, then it should be a matrix with two columns
-      and one line for each vertex. This matrix will be used as starting
-      positions for the algorithm. If not given, then a random starting
-      matrix is used.}
-  }
-  This function was ported from the SNA package.
-
-  \code{layout.kamada.kawai} is another force based algorithm. 
-  Parameters and default values:
-  \describe{
-    \item{niter}{Number of iterations to perform (1000).}
-    \item{sigma}{Sets the base standard deviation of position change
-      proposals (vcount(graph)/4).}
-    \item{initemp}{The initial temperature (10).}
-    \item{coolexp}{The cooling exponent (0.99).}
-    \item{kkconst}{Sets the Kamada-Kawai vertex attraction
-      constant (vcount(graph)**2).}
-    \item{minx}{If not \code{NULL}, then it must be a numeric vector
-      that gives lower boundaries for the \sQuote{x} coordinates of the
-      vertices. The length of the vector must match the number of
-      vertices in the graph.}
-    \item{maxx}{Similar to \code{minx}, but gives the upper boundaries.}
-    \item{miny}{Similar to \code{minx}, but gives the lower boundaries
-      of the \sQuote{y} coordinates.}
-    \item{maxy}{Similar to \code{minx}, but gives the upper boundaries
-      of the \sQuote{y} coordinates.}    
-    \item{minz}{Similar to \code{minx}, but gives the lower boundaries
-      of the \sQuote{z} coordinates, if the \code{dim} argument is
-      3. Otherwise it is ignored.}
-    \item{maxz}{Similar to \code{minx}, but gives the upper boundaries
-      of the \sQuote{z} coordinates, if the \code{dim} argument is
-      3. Otherwise it is ignored.}
-    \item{start}{If given, then it should be a matrix with two columns
-      and one line for each vertex. This matrix will be used as starting
-      positions for the algorithm. If not given, then a random starting
-      matrix is used.}
-  }
-  This function performs very well for connected graphs, but it gives
-  poor results for unconnected ones.
-  This function was ported from the SNA package.
-
-  \code{layout.spring} is a spring embedder algorithm.
-  Parameters and default values:
-  \describe{
-    \item{mass}{The vertex mass (in \sQuote{quasi-kilograms}). (Defaults to 0.1.)}
-    \item{equil}{The equilibrium spring extension (in
-      \sQuote{quasi-meters}). (Defaults to 1.)}
-    \item{k}{The spring coefficient (in \sQuote{quasi-Newtons per
-      quasi-meter}). (Defaults to 0.001.)}
-    \item{repeqdis}{The point at which repulsion (if employed) balances
-      out the spring extension force (in \sQuote{quasi-meters}). (Defaults to
-      0.1.)}
-    \item{kfr}{The base coefficient of kinetic friction (in
-      \sQuote{quasi-Newton quasi-kilograms}). (Defaults to 0.01.)}
-    \item{repulse}{Should repulsion be used? (Defaults to FALSE.)}
-  }
-  This function was ported from the SNA package.
-
-  \code{layout.reingold.tilford} generates a tree-like layout, so it is
-  mainly for trees. Parameters and default values:
-  \describe{
-    \item{root}{The id of the root vertex, defaults to 1.}
-    \item{circular}{Logical scalar, whether to plot the tree in a
-      circular fashion, defaults to \code{FALSE}.}
-    \item{flip.y}{Logical scalar, whether to flip the \sQuote{y}
-      coordinates. The default is flipping because that puts the root
-      vertex on the top.}
-  }
-  
-  \code{layout.fruchterman.reingold.grid} is similar to
-  \code{layout.fruchterman.reingold} but repelling force is calculated
-  only between vertices that are closer to each other than a limit, so
-  it is faster. Patameters and default values:
-  \describe{
-    \item{niter}{Numeric, the number of iterations to perform (500).}
-    \item{maxdelta}{Maximum change for one vertex in one iteration. (The
-      number of vertices in the graph.)}
-    \item{area}{The area of the surface on which the vertices are placed.
-      (The square of the number of vertices.)}
-    \item{coolexp}{The cooling exponent of the simulated annealing
-      (1.5).}
-    \item{repulserad}{Cancellation radius for the repulsion (the
-      \code{area} times the number of vertices).}
-    \item{cellsize}{The size of the cells for the grid. When calculating
-      the repulsion forces between vertices only vertices in the same or
-      neighboring grid cells are taken into account (the fourth root of
-      the number of \code{area}.}
-    \item{start}{If given, then it should be a matrix with two columns
-      and one line for each vertex. This matrix will be used as starting
-      positions for the algorithm. If not given, then a random starting
-      matrix is used.}
-  }
-  
-  \code{layout.lgl} is for large connected graphs, it is similar to the
-  layout generator of the Large Graph Layout software
-  (\url{http://lgl.sourceforge.net/}). Parameters and
-  default values:
-  \describe{
-    \item{maxiter}{The maximum number of iterations to perform (150).}
-    \item{maxdelta}{The maximum change for a vertex during an iteration
-      (the number of vertices).}
-    \item{area}{The area of the surface on which the vertices are placed
-      (square of the number of vertices). }
-    \item{coolexp}{The cooling exponent of the simulated annealing (1.5).}
-    \item{repulserad}{Cancellation radius for the repulsion (the
-      \code{area} times the number of vertices).}
-    \item{cellsize}{The size of the cells for the grid. When calculating
-      the repulsion forces between vertices only vertices in the same or
-      neighboring grid cells are taken into account (the fourth root of
-      the number of \code{area}.}
-    \item{root}{The id of the vertex to place at the middle of the
-      layout. The default value is -1 which means that a random vertex
-      is selected.}
-  }
-
-  \code{layout.graphopt} is a port of the graphopt layout algorithm by
-  Michael Schmuhl. graphopt version 0.4.1 was rewritten in C and the
-  support for layers was removed (might be added later) and a code was a
-  bit reorganized to avoid some unneccessary steps is the node charge
-  (see below) is zero.
-
-  graphopt uses physical analogies for defining attracting and repelling 
-  forces among the vertices and then the physical system is simulated 
-  until it reaches an equilibrium. (There is no simulated annealing or 
-  anything like that, so a stable fixed point is not guaranteed.)
-  
-  See also \url{http://www.schmuhl.org/graphopt/} for the original
-  graphopt.
-
-  Parameters and default values:
-  \describe{
-    \item{niter}{Integer scalar, the number of iterations to perform.
-      Should be a couple of hundred in general. If you have a large graph 
-      then you might want to only do a few iterations and then check the 
-      result. If it is not good enough you can feed it in again in 
-      the \code{start} argument. The default value is 500.
-    }
-    \item{charge}{The charge of the vertices, used to calculate electric
-      repulsion. The default is 0.001.}
-    \item{mass}{The mass of the vertices, used for the spring
-      forces. The default is 30.}
-    \item{spring.length}{The length of the springs, an integer
-      number. The default value is zero.}
-    \item{spring.constant}{The spring constant, the default value is one.}
-    \item{max.sa.movement}{Real constant, it gives the maximum amount of
-      movement allowed in a single step along a single axis. The default
-      value is 5.}
-    \item{start}{If given, then it should be a matrix with two columns
-      and one line for each vertex. This matrix will be used as starting
-      positions for the algorithm. If not given, then a random starting
-      matrix is used.}
-  }
-  
-  \code{layout.svd} is a currently \emph{experimental} layout function based on
-  singular value decomposition. It does not have the usual \code{params}
-  argument, but take a single argument, the distance matrix of the
-  graph. This function generates the layout separately for each graph
-  component and then merges them via \code{\link{layout.merge}}.
-
-  \code{layout.norm} normalizes a layout, it linearly transforms each
-  coordinate separately to fit into the given limits.
-
-  \code{layout.drl} is another force-driven layout generator, it is
-  suitable for quite large graphs. See \code{\link{layout.drl}} for
-  details.
-}
-\value{All these functions return a numeric matrix with at least two
-  columns and the same number of lines as the number of vertices.}
-\references{
-  Fruchterman, T.M.J. and Reingold, E.M. (1991). Graph Drawing by
-  Force-directed Placement. \emph{Software - Practice and Experience},
-  21(11):1129-1164. 
-
-  Kamada, T. and Kawai, S. (1989). An Algorithm for Drawing General
-  Undirected Graphs. \emph{Information Processing Letters}, 31(1):7-15. 
-
-  Reingold, E and Tilford, J (1981). Tidier drawing of trees.
-  \emph{IEEE Trans. on Softw. Eng.}, SE-7(2):223--228.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{layout.drl}}, \code{\link{plot.igraph}}, \code{\link{tkplot}}}
-\examples{
-g <- graph.ring(10)
-layout.random(g)
-layout.kamada.kawai(g)
-
-# Fixing ego
-g <- ba.game(20, m=2)
-minC <- rep(-Inf, vcount(g))
-maxC <- rep(Inf, vcount(g))
-minC[1] <- maxC[1] <- 0
-co <- layout.fruchterman.reingold(g, minx=minC, maxx=maxC,
-                                  miny=minC, maxy=maxC)
-co[1,]
-\dontrun{plot(g, layout=co, vertex.size=30, edge.arrow.size=0.2,
-     vertex.label=c("ego", rep("", vcount(g)-1)), rescale=FALSE,
-     xlim=range(co[,1]), ylim=range(co[,2]), vertex.label.dist=1,
-     vertex.label.color="red")
-axis(1)
-axis(2)
-}
-}
-\keyword{graphs}
diff --git a/man/layout.bipartite.Rd b/man/layout.bipartite.Rd
deleted file mode 100644
index b365258..0000000
--- a/man/layout.bipartite.Rd
+++ /dev/null
@@ -1,48 +0,0 @@
-\name{layout.bipartite}
-\alias{layout.bipartite}
-\concept{Graph layout}
-\concept{Bipartite graph}
-\concept{Two-mode network}
-\title{Simple two-row layout for bipartite graphs}
-\description{Minimize edge-crossings in a simple two-row (or column)
-  layout for bipartite graphs.}
-\usage{
-layout.bipartite (graph, types = NULL, hgap = 1, vgap = 1, maxiter = 100) 
-}
-\arguments{
-  \item{graph}{The bipartite input graph. It should have a logical
-    \sQuote{\code{type}} vertex attribute, or the \code{types} argument
-    must be given.}
-  \item{types}{A logical vector, the vertex types. If this argument is
-    \code{NULL} (the default), then the \sQuote{\code{type}} vertex
-    attribute is used.}
-  \item{hgap}{Real scalar, the minimum horizontal gap between vertices
-    in the same layer.}
-  \item{vgap}{Real scalar, the distance between the two layers.}
-  \item{maxiter}{Integer scalar, the maximum number of iterations in the
-    crossing minimization stage. 100 is a reasonable default; if you
-    feel that you have too many edge crossings, increase this.}
-}
-\details{
-  The layout is created by first placing the vertices in two rows,
-  according to their types. Then the positions within the rows are
-  optimized to minimize edge crossings, using the Sugiyama algorithm
-  (see \code{\link{layout.sugiyama}}).
-}
-\value{A matrix with two columns and as many rows as the number of
-  vertices in the input graph.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{layout.sugiyama}}}
-\examples{
-# Random bipartite graph
-inc <- matrix(sample(0:1, 50, replace=TRUE, prob=c(2,1)), 10, 5)
-g <- graph.incidence(inc)
-plot(g, layout=layout.bipartite,
-     vertex.color=c("green","cyan")[V(g)$type+1])
-
-# Two columns
-lay <- layout.bipartite(g)
-plot(g, layout=lay[,2:1])
-}
-\keyword{graphs}
diff --git a/man/layout.deprecated.Rd b/man/layout.deprecated.Rd
new file mode 100644
index 0000000..86f4157
--- /dev/null
+++ b/man/layout.deprecated.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout.reingold.tilford}
+\alias{layout.circle}
+\alias{layout.fruchterman.reingold}
+\alias{layout.kamada.kawai}
+\alias{layout.lgl}
+\alias{layout.random}
+\alias{layout.reingold.tilford}
+\alias{layout.sphere}
+\title{Deprecated layout functions}
+\usage{
+layout.reingold.tilford(..., params = list())
+
+layout.circle(..., params = list())
+
+layout.sphere(..., params = list())
+
+layout.random(..., params = list())
+
+layout.fruchterman.reingold(..., params = list())
+
+layout.kamada.kawai(..., params = list())
+
+layout.lgl(..., params = list())
+}
+\arguments{
+\item{...}{Passed to the new layout functions.}
+
+\item{params}{Passed to the new layout functions as arguments.}
+}
+\description{
+Please use the new names, see \code{\link{layout_}}.
+}
+
diff --git a/man/layout.drl.Rd b/man/layout.drl.Rd
deleted file mode 100644
index 20d223b..0000000
--- a/man/layout.drl.Rd
+++ /dev/null
@@ -1,103 +0,0 @@
-\name{layout.drl}
-\alias{layout.drl}
-\alias{igraph.drl.default}
-\alias{igraph.drl.coarsen}
-\alias{igraph.drl.coarsest}
-\alias{igraph.drl.refine}
-\alias{igraph.drl.final}
-\concept{Graph layout}
-\title{The DrL graph layout generator}
-\description{
-  DrL is a force-directed graph layout toolbox focused on
-  real-world large-scale graphs, developed by Shawn Martin and
-  colleagues at Sandia National Laboratories.
-}
-\usage{
-layout.drl (graph, use.seed = FALSE, seed = matrix(runif(vcount(graph) * 
-    2), ncol = 2), options = igraph.drl.default, weights = E(graph)$weight, 
-    fixed = NULL, dim = 2) 
-}
-\arguments{
-  \item{graph}{The input graph, in can be directed or undirected.}
-  \item{use.seed}{Logical scalar, whether to use the coordinates given
-    in the \code{seed} argument as a starting point.}
-  \item{seed}{A matrix with two columns, the starting coordinates for
-    the vertices is \code{use.seed} is \code{TRUE}. It is ignored
-    otherwise.}
-  \item{options}{Options for the layout generator, a named list. See
-    details below.}
-  \item{weights}{Optional edge weights. Supply \code{NULL} here if you
-    want to weight edges equally. By default the \code{weight} edge
-    attribute is used if the graph has one.}
-  \item{fixed}{Logical vector, it can be used to fix some vertices. All
-    vertices for which it is \code{TRUE} are kept at the coordinates
-    supplied in the \code{seed} matrix. It is ignored it \code{NULL} or
-    if \code{use.seed} is \code{FALSE}. }
-  \item{dim}{Either \sQuote{2} or \sQuote{3}, it specifies whether we
-    want a two dimensional or a three dimensional layout. Note that
-    because of the nature of the DrL algorithm, the three dimensional
-    layout takes significantly longer to compute.}
-}
-\details{
-  This function implements the force-directed DrL layout generator.
-
-  The generator has the following parameters:
-  \describe{
-    \item{edge.cut}{Edge cutting is done in the late stages of the
-      algorithm in order to achieve less dense layouts.  Edges are cut
-      if there is a lot of stress on them (a large value in the
-      objective function sum). The edge cutting parameter is a value
-      between 0 and 1 with 0 representing no edge cutting and 1
-      representing maximal edge cutting. } 
-    \item{init.iterations}{Number of iterations in the first phase.}
-    \item{init.temperature}{Start temperature, first phase.}
-    \item{init.attraction}{Attraction, first phase.}
-    \item{init.damping.mult}{Damping, first phase.}
-    \item{liquid.iterations}{Number of iterations, liquid phase.}
-    \item{liquid.temperature}{Start temperature, liquid phase.}
-    \item{liquid.attraction}{Attraction, liquid phase.}
-    \item{liquid.damping.mult}{Damping, liquid phase.}
-    \item{expansion.iterations}{Number of iterations, expansion phase.}
-    \item{expansion.temperature}{Start temperature, expansion phase.}
-    \item{expansion.attraction}{Attraction, expansion phase.}
-    \item{expansion.damping.mult}{Damping, expansion phase.}
-    \item{cooldown.iterations}{Number of iterations, cooldown phase.}
-    \item{cooldown.temperature}{Start temperature, cooldown phase.}
-    \item{cooldown.attraction}{Attraction, cooldown phase.}
-    \item{cooldown.damping.mult}{Damping, cooldown phase.}
-    \item{crunch.iterations}{Number of iterations, crunch phase.}
-    \item{crunch.temperature}{Start temperature, crunch phase.}
-    \item{crunch.attraction}{Attraction, crunch phase.}
-    \item{crunch.damping.mult}{Damping, crunch phase.}
-    \item{simmer.iterations}{Number of iterations, simmer phase.}
-    \item{simmer.temperature}{Start temperature, simmer phase.}
-    \item{simmer.attraction}{Attraction, simmer phase.}
-    \item{simmer.damping.mult}{Damping, simmer phase.}
-
-    There are five pre-defined parameter settings as well, these are
-    called \code{igraph.drl.default}, \code{igraph.drl.coarsen},
-    \code{igraph.drl.coarsest}, \code{igraph.drl.refine} and
-    \code{igraph.drl.final}.
-  }
-}
-\value{
-  A numeric matrix with two columns.
-}
-\references{
-  See the following technical report:
-  Martin, S., Brown, W.M., Klavans, R., Boyack, K.W., DrL: Distributed
-  Recursive (Graph) Layout. SAND Reports, 2008. 2936: p. 1-10. 
-}
-\author{Shawn Martin
-  (\url{http://www.cs.otago.ac.nz/homepages/smartin/})
-  and Gabor Csardi \email{csardi.gabor at gmail.com} for the R/igraph
-  interface and the three dimensional version.}
-\seealso{\code{\link{layout}} for other layout generators.}
-\examples{
-g <- as.undirected(ba.game(100, m=1))
-l <- layout.drl(g, options=list(simmer.attraction=0))
-\dontrun{
-plot(g, layout=l, vertex.size=3, vertex.label=NA)
-}
-}
-\keyword{graphs}
diff --git a/man/layout.fruchterman.reingold.grid.Rd b/man/layout.fruchterman.reingold.grid.Rd
new file mode 100644
index 0000000..8e80d65
--- /dev/null
+++ b/man/layout.fruchterman.reingold.grid.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout.fruchterman.reingold.grid}
+\alias{layout.fruchterman.reingold.grid}
+\title{Grid Fruchterman-Reingold layout, this was removed from igraph}
+\usage{
+layout.fruchterman.reingold.grid(graph, ...)
+}
+\arguments{
+\item{graph}{Input graph.}
+
+\item{...}{Extra arguments are ignored.}
+}
+\value{
+Layout coordinates, a two column matrix.
+}
+\description{
+Now it calls the Fruchterman-Reingold layout, with a warning.
+}
+
diff --git a/man/layout.grid.Rd b/man/layout.grid.Rd
deleted file mode 100644
index 01df2a8..0000000
--- a/man/layout.grid.Rd
+++ /dev/null
@@ -1,47 +0,0 @@
-\name{layout.grid}
-\alias{layout.grid}
-\alias{layout.grid.3d}
-\concept{Graph layout}
-\title{Simple grid layout}
-\description{This layout places vertices on a rectangulat grid, in two
-  or three dimensions.}
-\usage{
-layout.grid (graph, width = 0)
-layout.grid.3d (graph, width = 0, height = 0)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{width}{The number of vertices in a single row of the grid. If
-    this is zero or negative for \code{layout.grid}, then the width of
-    the grid will be the square root of the number of vertices in the
-    graph, rounded up to the next integer. Similarly, it will be the
-    cube root for \code{layout.grid.3d}.}
-  \item{height}{The number of vertices in a single column of the
-    grid, for three dimensional layouts. If this is zero or negative,
-    then it is determinted automatically.}
-}
-\details{
-  These functions place the vertices on a simple rectangular grid, one
-  after the other. If you want to change the order of the vertices, then
-  see the \code{\link{permute.vertices}} function.
-}
-\value{
-  A two-column matrix for \code{layout.grid}, a three-column matrix for
-  \code{layout.grid.3d}.
-}
-% \references{}
-\author{ Tamas Nepusz \email{ntamas at gmail.com} }
-\seealso{ \code{\link{layout}} for other layout generators }
-\examples{
-g <- graph.lattice( c(3,3) )
-layout.grid(g)
-
-g2 <- graph.lattice( c(3,3,3) )
-layout.grid.3d(g2)
-
-\dontrun{
-plot(g, layout=layout.grid)
-rglplot(g, layout=layout.grid.3d)
-}
-}
-\keyword{graphs}
diff --git a/man/layout.mds.Rd b/man/layout.mds.Rd
deleted file mode 100644
index d8e3cbd..0000000
--- a/man/layout.mds.Rd
+++ /dev/null
@@ -1,52 +0,0 @@
-\name{layout.mds}
-\alias{layout.mds}
-\concept{Graph layout}
-\title{Graph layout by multidimensional scaling}
-\description{
-  Multidimensional scaling of some distance matrix defined on the
-  vertices of a graph.
-}
-\usage{
-layout.mds(graph, dist=NULL, dim=2, options=igraph.arpack.default)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{dist}{The distance matrix for the multidimensional scaling.
-    If \code{NULL} (the default), then the unweighted shortest path
-    matrix is used.}
-  \item{dim}{\code{layout.mds} supports dimensions up to the number of
-    nodes minus one, but only if the graph is connected; for unconnected
-    graphs, the only possible values is 2. This is because
-    \code{layout.merge} only works in 2D.}
-  \item{options}{This is currently ignored, as ARPACK is not used
-    any more for solving the eigenproblem}
-}
-\details{
-  \code{layout.mds} uses metric multidimensional scaling for generating
-  the coordinates. Multidimensional scaling aims to place points from a
-  higher dimensional space in a (typically) 2 dimensional plane, so that
-  the distance between the points are kept as much as this is possible.
-
-  By default igraph uses the shortest path matrix as the distances
-  between the nodes, but the user can override this via the \code{dist}
-  argument.
-
-  This function generates the layout separately for each graph component
-  and then merges them via \code{\link{layout.merge}}.
-}
-\value{
-  A numeric matrix with \code{dim} columns.
-}
-\references{
-  Cox, T. F. and Cox, M. A. A. (2001) \emph{Multidimensional Scaling}.
-  Second edition. Chapman and Hall.
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and
-  Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{layout}}, \code{\link{plot.igraph}}}
-\examples{
-g <- erdos.renyi.game(100, 2/100)
-l <- layout.mds(g)
-plot(g, layout=l, vertex.label=NA, vertex.size=3)
-}
-\keyword{graphs}
diff --git a/man/layout.merge.Rd b/man/layout.merge.Rd
deleted file mode 100644
index 3ab5107..0000000
--- a/man/layout.merge.Rd
+++ /dev/null
@@ -1,58 +0,0 @@
-\name{layout.merge}
-\alias{layout.merge}
-\alias{piecewise.layout}
-\title{Merging graph layouts}
-\description{Place several graphs on the same layout}
-\usage{
-layout.merge(graphs, layouts, method = "dla")
-piecewise.layout(graph, layout=layout.kamada.kawai, \dots)
-}
-\arguments{
-  \item{graphs}{A list of graph objects.}
-  \item{layouts}{A list of two-column matrices.}
-  \item{method}{Character constant giving the method to use. Right now
-    only \code{dla} is implemented.}
-  \item{graph}{The input graph.}
-  \item{layout}{A function object, the layout function to use.}
-  \item{\dots}{Additional arguments to pass to the \code{layout} layout
-    function.}
-}
-\details{
-  \code{layout.merge} takes a list of graphs and a list of coordinates and
-  places the graphs in a common layout. The method to use is chosen via
-  the \code{method} parameter, although right now only the \code{dla}
-  method is implemented.
-
-  The \code{dla} method covers the graph with circles.
-  Then it sorts the graphs based on the number of vertices
-  first and places the largest graph at the center of the layout. Then
-  the other graphs are placed in decreasing order via a DLA (diffision
-  limited aggregation) algorithm: the graph is placed randomly on a
-  circle far away from the center and a random walk is conducted until
-  the graph walks into the larger graphs already placed or walks too far
-  from the center of the layout.
-
-  The \code{piecewise.layout} function disassembles the graph first into
-  maximal connected components and calls the supplied \code{layout}
-  function for each component separately. Finally it merges the layouts
-  via calling \code{layout.merge}.
-}
-\value{
-  A matrix with two columns and as many lines as the total number of
-  vertices in the graphs.
-}
-% \references
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{plot.igraph}}, \code{\link{tkplot}},
-  \code{\link{layout}}, \code{\link{graph.disjoint.union}}
-}
-\examples{
-# create 20 scale-free graphs and place them in a common layout
-graphs <- lapply(sample(5:20, 20, replace=TRUE),
-          barabasi.game, directed=FALSE)
-layouts <- lapply(graphs, layout.kamada.kawai)
-lay <- layout.merge(graphs, layouts)
-g <- graph.disjoint.union(graphs)
-\dontrun{plot(g, layout=lay, vertex.size=3, labels=NA, edge.color="black")}
-}
-\keyword{graphs}
diff --git a/man/layout.spring.Rd b/man/layout.spring.Rd
new file mode 100644
index 0000000..9b6e25f
--- /dev/null
+++ b/man/layout.spring.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout.spring}
+\alias{layout.spring}
+\title{Spring layout, this was removed from igraph}
+\usage{
+layout.spring(graph, ...)
+}
+\arguments{
+\item{graph}{Input graph.}
+
+\item{...}{Extra arguments are ignored.}
+}
+\value{
+Layout coordinates, a two column matrix.
+}
+\description{
+Now it calls the Fruchterman-Reingold layout, with a warning.
+}
+
diff --git a/man/layout.star.Rd b/man/layout.star.Rd
deleted file mode 100644
index d97175e..0000000
--- a/man/layout.star.Rd
+++ /dev/null
@@ -1,36 +0,0 @@
-\name{layout.star}
-\alias{layout.star}
-\concept{Graph layout}
-\title{Generate coordinates to place the vertices of a graph in a
-  star-shape}
-\description{
-  A simple layout generator, that places one vertex in the center of a
-  circle and the rest of the vertices equidistantly on the perimeter.
-}
-\usage{
-layout.star(graph, center = V(graph)[1], order = NULL)
-}
-\arguments{
-  \item{graph}{The graph to layout.}
-  \item{center}{The id of the vertex to put in the center. By default it
-    is the first vertex.}
-  \item{order}{Numeric vector, the order of the vertices along the
-    perimeter. The default ordering is given by the vertex ids.}
-}
-\details{
-  It is possible to choose the vertex that will be in the center, and
-  the order of the vertices can be also given.
-}
-\value{A matrix with two columns and as many rows as the number of
-  vertices in the input graph.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{layout}} and \code{\link{layout.drl}} for other
-  layout algorithms, \code{\link{plot.igraph}} and \code{\link{tkplot}}
-  on how to plot graphs and \code{\link{graph.star}} on how to create
-  ring graphs.}
-\examples{
-g <- graph.star(10)
-layout.star(g)
-}
-\keyword{graphs}
diff --git a/man/layout.sugiyama.Rd b/man/layout.sugiyama.Rd
deleted file mode 100644
index def0757..0000000
--- a/man/layout.sugiyama.Rd
+++ /dev/null
@@ -1,195 +0,0 @@
-\name{layout.sugiyama}
-\alias{layout.sugiyama}
-\concept{Graph layout}
-\title{The Sugiyama graph layout generator}
-\description{
-  Sugiyama layout algorithm for layered directed acyclic graphs. The
-  algorithm minimized edge crossings.
-}
-\usage{
-layout.sugiyama (graph, layers = NULL, hgap = 1, vgap = 1, maxiter = 100, 
-    weights = NULL, attributes = c("default", "all", "none")) 
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{layers}{A numeric vector or \code{NULL}. If not \code{NULL},
-    then it should specify the layer index of the vertices. Layers are
-    numbered from one. If \code{NULL}, then igraph calculates the layers
-    automatically.}
-  \item{hgap}{Real scalar, the minimum horizontal gap between vertices
-    in the same layer.}
-  \item{vgap}{Real scalar, the distance between layers.}
-  \item{maxiter}{Integer scalar, the maximum number of iterations in the
-    crossing minimization stage. 100 is a reasonable default; if you
-    feel that you have too many edge crossings, increase this.}
-  \item{weights}{Optional edge weight vector. If \code{NULL}, then the
-    'weight' edge attribute is used, if there is one. Supply \code{NA}
-    here and igraph ignores the edge weights.}
-  \item{attributes}{Which graph/vertex/edge attributes to keep in the
-    extended graph. \sQuote{default} keeps the \sQuote{size},
-    \sQuote{size2}, \sQuote{shape}, \sQuote{label} and \sQuote{color}
-    vertex attributes and the \sQuote{arrow.mode} and
-    \sQuote{arrow.size} edge attributes. \sQuote{all} keep all graph,
-    vertex and edge attributes, \sQuote{none} keeps none of them.}
-}
-\details{
-  This layout algorithm is designed for directed acyclic graphs where each
-  vertex is assigned to a layer. Layers are indexed from zero, and vertices
-  of the same layer will be placed on the same horizontal line. The X
-  coordinates of vertices within each layer are decided by the heuristic
-  proposed by Sugiyama et al. to minimize edge crossings.
-
-  You can also try to lay out undirected graphs, graphs containing cycles, or
-  graphs without an a priori layered assignment with this algorithm. igraph
-  will try to eliminate cycles and assign vertices to layers, but there is no
-  guarantee on the quality of the layout in such cases.
-
-  The Sugiyama layout may introduce \dQuote{bends} on the edges in order
-  to obtain a visually more pleasing layout. This is achieved by adding
-  dummy nodes to edges spanning more than one layer. The resulting
-  layout assigns coordinates not only to the nodes of the original graph
-  but also to the dummy nodes. The layout algorithm will also return the
-  extended graph with the dummy nodes.
-
-  For more details, see the reference below.
-}
-\value{
-  A list with the components:
-  \item{layout}{The layout, a two-column matrix, for the original graph
-    vertices.}
-  \item{layout.dummy}{The layout for the dummy vertices, a two column
-    matrix.}
-  \item{extd_graph}{The original graph, extended with dummy vertices.
-    The \sQuote{dummy} vertex attribute is set on this graph, 
-    it is a logical attributes, and it tells you whether the vertex is a
-    dummy vertex. The \sQuote{layout} graph attribute is also set, and
-    it is the layout matrix for all (original and dummy) vertices.}
-}
-\references{
-  K. Sugiyama, S. Tagawa and M. Toda, "Methods for Visual Understanding
-  of Hierarchical Systems". IEEE Transactions on Systems, Man and
-  Cybernetics 11(2):109-125, 1981.
-}
-\author{
-  Tamas Nepusz \email{ntamas at gmail.com}
-}
-\examples{
-## Data taken from http://tehnick-8.narod.ru/dc_clients/
-DC <- graph.formula("DC++" -+
-                "LinuxDC++":"BCDC++":"EiskaltDC++":"StrongDC++":"DiCe!++",
-                "LinuxDC++" -+ "FreeDC++", "BCDC++" -+ "StrongDC++",
-                "FreeDC++" -+ "BMDC++":"EiskaltDC++",
-                "StrongDC++" -+ "AirDC++":"zK++":"ApexDC++":"TkDC++",
-                "StrongDC++" -+ "StrongDC++ SQLite":"RSX++",
-                "ApexDC++" -+ "FlylinkDC++ ver <= 4xx",
-                "ApexDC++" -+ "ApexDC++ Speed-Mod":"DiCe!++",
-                "StrongDC++ SQLite" -+ "FlylinkDC++ ver >= 5xx",
-                "ApexDC++ Speed-Mod" -+ "FlylinkDC++ ver <= 4xx",
-                "ApexDC++ Speed-Mod" -+ "GreylinkDC++",
-                "FlylinkDC++ ver <= 4xx" -+ "FlylinkDC++ ver >= 5xx",
-                "FlylinkDC++ ver <= 4xx" -+ AvaLink,
-                "GreylinkDC++" -+ AvaLink:"RayLinkDC++":"SparkDC++":PeLink)
-
-## Use edge types
-E(DC)$lty <- 1
-E(DC)["BCDC++" \%->\% "StrongDC++"]$lty <- 2
-E(DC)["FreeDC++" \%->\% "EiskaltDC++"]$lty <- 2
-E(DC)["ApexDC++" \%->\% "FlylinkDC++ ver <= 4xx"]$lty <- 2
-E(DC)["ApexDC++" \%->\% "DiCe!++"]$lty <- 2
-E(DC)["StrongDC++ SQLite" \%->\% "FlylinkDC++ ver >= 5xx"]$lty <- 2
-E(DC)["GreylinkDC++" \%->\% "AvaLink"]$lty <- 2
-
-## Layers, as on the plot
-layers <- list(c("DC++"),
-               c("LinuxDC++", "BCDC++"),
-               c("FreeDC++", "StrongDC++"),
-               c("BMDC++", "EiskaltDC++", "AirDC++", "zK++", "ApexDC++",
-                 "TkDC++", "RSX++"),
-               c("StrongDC++ SQLite", "ApexDC++ Speed-Mod", "DiCe!++"),
-               c("FlylinkDC++ ver <= 4xx", "GreylinkDC++"),
-               c("FlylinkDC++ ver >= 5xx", "AvaLink", "RayLinkDC++",
-                 "SparkDC++", "PeLink"))
-
-## Check that we have all nodes
-all(sort(unlist(layers)) == sort(V(DC)$name))
-
-## Add some graphical parameters
-V(DC)$color <- "white"
-V(DC)$shape <- "rectangle"
-V(DC)$size <- 20
-V(DC)$size2 <- 10
-V(DC)$label <- lapply(V(DC)$name, function(x)
-                      paste(strwrap(x, 12), collapse="\n"))
-E(DC)$arrow.size <- 0.5
-
-## Create a similar layout using the predefined layers
-lay1 <- layout.sugiyama(DC, layers=apply(sapply(layers,
-                        function(x) V(DC)$name \%in\% x), 1, which))
-
-## Simple plot, not very nice
-par(mar=rep(.1, 4))
-plot(DC, layout=lay1$layout, vertex.label.cex=0.5)
-
-## Sugiyama plot
-plot(lay1$extd_graph, vertex.label.cex=0.5)
-
-## The same with automatic layer calculation
-## Keep vertex/edge attributes in the extended graph
-lay2 <- layout.sugiyama(DC, attributes="all")
-plot(lay2$extd_graph, vertex.label.cex=0.5)
-
-## Another example, from the following paper:
-## Markus Eiglsperger, Martin Siebenhaller, Michael Kaufmann:
-## An Efficient Implementation of Sugiyama's Algorithm for
-## Layered Graph Drawing, Journal of Graph Algorithms and
-## Applications 9, 305--325 (2005).
-
-ex <- graph.formula( 0 -+ 29: 6: 5:20: 4,
-                     1 -+ 12,
-                     2 -+ 23: 8,
-                     3 -+  4,
-                     4,
-                     5 -+  2:10:14:26: 4: 3,
-                     6 -+  9:29:25:21:13,
-                     7,
-                     8 -+ 20:16,
-                     9 -+ 28: 4,
-                    10 -+ 27,
-                    11 -+  9:16,
-                    12 -+  9:19,
-                    13 -+ 20,
-                    14 -+ 10,
-                    15 -+ 16:27,
-                    16 -+ 27,
-                    17 -+  3,
-                    18 -+ 13,
-                    19 -+  9,
-                    20 -+  4,
-                    21 -+ 22,
-                    22 -+  8: 9,
-                    23 -+  9:24,
-                    24 -+ 12:15:28,
-                    25 -+ 11,
-                    26 -+ 18,
-                    27 -+ 13:19,
-                    28 -+  7,
-                    29 -+ 25                    )
-
-layers <- list( 0, c(5, 17), c(2, 14, 26, 3), c(23, 10, 18), c(1, 24),
-                12, 6, c(29,21), c(25,22), c(11,8,15), 16, 27, c(13,19),
-                c(9, 20), c(4, 28), 7 )
-
-layex <- layout.sugiyama(ex, layers=apply(sapply(layers,
-                        function(x) V(ex)$name \%in\% as.character(x)),
-                        1, which))
-
-origvert <- c(rep(TRUE, vcount(ex)), rep(FALSE, nrow(layex$layout.dummy)))
-realedge <- get.edgelist(layex$extd_graph)[,2] <= vcount(ex)
-plot(layex$extd_graph, vertex.label.cex=0.5,
-     edge.arrow.size=.5, 
-     vertex.size=ifelse(origvert, 5, 0),
-     vertex.shape=ifelse(origvert, "square", "none"),
-     vertex.label=ifelse(origvert, V(ex)$name, ""),
-     edge.arrow.mode=ifelse(realedge, 2, 0))
-}
-\keyword{graphs}
diff --git a/man/layout.svd.Rd b/man/layout.svd.Rd
new file mode 100644
index 0000000..3d0d03c
--- /dev/null
+++ b/man/layout.svd.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout.svd}
+\alias{layout.svd}
+\title{SVD layout, this was removed from igraph}
+\usage{
+layout.svd(graph, ...)
+}
+\arguments{
+\item{graph}{Input graph.}
+
+\item{...}{Extra arguments are ignored.}
+}
+\value{
+Layout coordinates, a two column matrix.
+}
+\description{
+Now it calls the Fruchterman-Reingold layout, with a warning.
+}
+
diff --git a/man/layout_.Rd b/man/layout_.Rd
new file mode 100644
index 0000000..a6d6965
--- /dev/null
+++ b/man/layout_.Rd
@@ -0,0 +1,107 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_}
+\alias{layout}
+\alias{layout_}
+\alias{print.igraph_layout_modifier}
+\alias{print.igraph_layout_spec}
+\title{Graph layouts}
+\usage{
+layout_(graph, layout, ...)
+
+\method{print}{igraph_layout_spec}(x, ...)
+
+\method{print}{igraph_layout_modifier}(x, ...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{layout}{The layout specification. It must be a call
+to a layout specification function.}
+
+\item{...}{Further modifiers, see a complete list below.
+For the \code{print} methods, it is ignored.}
+
+\item{x}{The layout specification}
+}
+\value{
+The return value of the layout function, usually a
+  two column matrix. For 3D layouts a three column matrix.
+}
+\description{
+This is a generic function to apply a layout function to
+a graph.
+}
+\details{
+There are two ways to calculate graph layouts in igraph.
+The first way is to call a layout function (they all have
+prefix \code{layout_} on a graph, to get the vertex coordinates.
+
+The second way (new in igraph 0.8.0), has two steps, and it
+is more flexible. First you call a layout specification
+function (the one without the \code{layout_} prefix, and
+then \code{layout_} (or \code{\link{add_layout_}}) to
+perform the layouting.
+
+The second way is preferred, as it is more flexible. It allows
+operations before and after the layouting. E.g. using the
+\code{component_wise} argument, the layout can be calculated
+separately for each component, and then merged to get the
+final results.
+}
+\section{Modifiers}{
+
+Modifiers modify how a layout calculation is performed.
+Currently implemented modifyers: \itemize{
+  \item \code{component_wise} calculates the layout separately
+    for each component of the graph, and then merges
+    them.
+  \item \code{normalize} scales the layout to a square.
+}
+}
+\examples{
+g <- make_ring(10) + make_full_graph(5)
+coords <- layout_(g, as_star())
+plot(g, layout = coords)
+}
+\seealso{
+\code{\link{add_layout_}} to add the layout to the
+  graph as an attribute.
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{normalize}}
+}
+
diff --git a/man/layout_as_bipartite.Rd b/man/layout_as_bipartite.Rd
new file mode 100644
index 0000000..bf9fb05
--- /dev/null
+++ b/man/layout_as_bipartite.Rd
@@ -0,0 +1,104 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_as_bipartite}
+\alias{as_bipartite}
+\alias{layout.bipartite}
+\alias{layout_as_bipartite}
+\title{Simple two-row layout for bipartite graphs}
+\usage{
+layout_as_bipartite(graph, types = NULL, hgap = 1, vgap = 1,
+  maxiter = 100)
+
+as_bipartite(...)
+}
+\arguments{
+\item{graph}{The bipartite input graph. It should have a logical
+\sQuote{\code{type}} vertex attribute, or the \code{types} argument must be
+given.}
+
+\item{types}{A logical vector, the vertex types. If this argument is
+\code{NULL} (the default), then the \sQuote{\code{type}} vertex attribute is
+used.}
+
+\item{hgap}{Real scalar, the minimum horizontal gap between vertices in the
+same layer.}
+
+\item{vgap}{Real scalar, the distance between the two layers.}
+
+\item{maxiter}{Integer scalar, the maximum number of iterations in the
+crossing minimization stage. 100 is a reasonable default; if you feel that
+you have too many edge crossings, increase this.}
+
+\item{...}{Arguments to pass to \code{layout_as_bipartite}.}
+}
+\value{
+A matrix with two columns and as many rows as the number of vertices
+in the input graph.
+}
+\description{
+Minimize edge-crossings in a simple two-row (or column) layout for bipartite
+graphs.
+}
+\details{
+The layout is created by first placing the vertices in two rows, according
+to their types. Then the positions within the rows are optimized to minimize
+edge crossings, using the Sugiyama algorithm (see
+\code{\link{layout_with_sugiyama}}).
+}
+\examples{
+# Random bipartite graph
+inc <- matrix(sample(0:1, 50, replace = TRUE, prob=c(2,1)), 10, 5)
+g <- graph_from_incidence_matrix(inc)
+plot(g, layout = layout_as_bipartite,
+     vertex.color=c("green","cyan")[V(g)$type+1])
+
+# Two columns
+g \%>\%
+  add_layout_(as_bipartite()) \%>\%
+  plot()
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{layout_with_sugiyama}}
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_star}}, \code{\link{layout.star}},
+  \code{\link{layout_as_star}}; \code{\link{as_tree}},
+  \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_as_star.Rd b/man/layout_as_star.Rd
new file mode 100644
index 0000000..95b0508
--- /dev/null
+++ b/man/layout_as_star.Rd
@@ -0,0 +1,90 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_as_star}
+\alias{as_star}
+\alias{layout.star}
+\alias{layout_as_star}
+\title{Generate coordinates to place the vertices of a graph in a star-shape}
+\usage{
+layout_as_star(graph, center = V(graph)[1], order = NULL)
+
+as_star(...)
+}
+\arguments{
+\item{graph}{The graph to layout.}
+
+\item{center}{The id of the vertex to put in the center. By default it is
+the first vertex.}
+
+\item{order}{Numeric vector, the order of the vertices along the perimeter.
+The default ordering is given by the vertex ids.}
+
+\item{...}{Arguments to pass to \code{layout_as_star}.}
+}
+\value{
+A matrix with two columns and as many rows as the number of vertices
+in the input graph.
+}
+\description{
+A simple layout generator, that places one vertex in the center of a circle
+and the rest of the vertices equidistantly on the perimeter.
+}
+\details{
+It is possible to choose the vertex that will be in the center, and the
+order of the vertices can be also given.
+}
+\examples{
+g <- make_star(10)
+layout_as_star(g)
+
+## Alternative form
+layout_(g, as_star())
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{layout}} and \code{\link{layout.drl}} for other layout
+algorithms, \code{\link{plot.igraph}} and \code{\link{tkplot}} on how to
+plot graphs and \code{\link{star}} on how to create ring graphs.
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_tree}},
+  \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_as_tree.Rd b/man/layout_as_tree.Rd
new file mode 100644
index 0000000..e36eaec
--- /dev/null
+++ b/man/layout_as_tree.Rd
@@ -0,0 +1,119 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_as_tree}
+\alias{as_tree}
+\alias{layout_as_tree}
+\title{The Reingold-Tilford graph layout algorithm}
+\usage{
+layout_as_tree(graph, root = numeric(), circular = FALSE,
+  rootlevel = numeric(), mode = "out", flip.y = TRUE)
+
+as_tree(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{root}{The index of the root vertex or root vertices.  If this is a
+non-empty vector then the supplied vertex ids are used as the roots of the
+trees (or a single tree if the graph is connected).  If it is an empty
+vector, then the root vertices are automatically calculated based on
+topological sorting, performed with the opposite mode than the \code{mode}
+argument. After the vertices have been sorted, one is selected from each
+component.}
+
+\item{circular}{Logical scalar, whether to plot the tree in a circular
+fashion. Defaults to \code{FALSE}, so the tree branches are going bottom-up
+(or top-down, see the \code{flip.y} argument.}
+
+\item{rootlevel}{This argument can be useful when drawing forests which are
+not trees (i.e. they are unconnected and have tree components). It specifies
+the level of the root vertices for every tree in the forest. It is only
+considered if the \code{roots} argument is not an empty vector.}
+
+\item{mode}{Specifies which edges to consider when building the tree.  If it
+is \sQuote{out}, then only the outgoing, if it is \sQuote{in}, then only the
+incoming edges of a parent are considered. If it is \sQuote{all} then all
+edges are used (this was the behavior in igraph 0.5 and before). This
+parameter also influences how the root vertices are calculated, if they are
+not given. See the \code{roots} parameter.}
+
+\item{flip.y}{Logical scalar, whether to flip the \sQuote{y} coordinates.
+The default is flipping because that puts the root vertex on the top.}
+
+\item{...}{Passed to \code{layout_as_tree}.}
+}
+\value{
+A numeric matrix with two columns, and one row for each vertex.
+}
+\description{
+A tree-like layout, it is perfect for trees, acceptable for graphs with not
+too many cycles.
+}
+\details{
+Arranges the nodes in a tree where the given node is used as the root.  The
+tree is directed downwards and the parents are centered above its children.
+For the exact algorithm, the refernce below.
+
+If the given graph is not a tree, a breadth-first search is executed first
+to obtain a possible spanning tree.
+}
+\examples{
+tree <- make_tree(20, 3)
+plot(tree, layout=layout_as_tree)
+plot(tree, layout=layout_as_tree(tree, flip.y=FALSE))
+plot(tree, layout=layout_as_tree(tree, circular=TRUE))
+
+tree2 <- make_tree(10, 3) + make_tree(10, 2)
+plot(tree2, layout=layout_as_tree)
+plot(tree2, layout=layout_as_tree(tree2, root=c(1,11),
+                                           rootlevel=c(2,1)))
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
+\references{
+Reingold, E and Tilford, J (1981). Tidier drawing of trees.
+\emph{IEEE Trans. on Softw. Eng.}, SE-7(2):223--228.
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_in_circle.Rd b/man/layout_in_circle.Rd
new file mode 100644
index 0000000..10614c6
--- /dev/null
+++ b/man/layout_in_circle.Rd
@@ -0,0 +1,88 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_in_circle}
+\alias{in_circle}
+\alias{layout_in_circle}
+\title{Graph layout with vertices on a circle.}
+\usage{
+layout_in_circle(graph, order = V(graph))
+
+in_circle(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{order}{The vertices to place on the circle, in the order of their
+desired placement. Vertices that are not included here will be placed at
+(0,0).}
+
+\item{...}{Passed to \code{layout_in_circle}.}
+}
+\value{
+A numeric matrix with two columns, and one row for each vertex.
+}
+\description{
+Place vertices on a circle, in the order of their vertex ids.
+}
+\details{
+If you want to order the vertices differently, then permute them using the
+\code{\link{permute}} function.
+}
+\examples{
+## Place vertices on a circle, order them according to their
+## community
+\dontrun{
+library(igraphdata)
+data(karate)
+karate_groups <- cluster_optimal(karate)
+coords <- layout_in_circle(karate, order =
+          order(membership(karate_groups)))
+V(karate)$label <- sub("Actor ", "", V(karate)$name)
+V(karate)$label.color <- membership(karate_groups)
+V(karate)$shape <- "none"
+plot(karate, layout = coords)
+}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{layout.auto}},
+  \code{\link{layout_nicely}}, \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_nicely.Rd b/man/layout_nicely.Rd
new file mode 100644
index 0000000..52d66c2
--- /dev/null
+++ b/man/layout_nicely.Rd
@@ -0,0 +1,86 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_nicely}
+\alias{layout.auto}
+\alias{layout_nicely}
+\alias{nicely}
+\title{Choose an appropriate graph layout algorithm automatically}
+\usage{
+layout_nicely(graph, dim = 2, ...)
+
+nicely(...)
+}
+\arguments{
+\item{graph}{The input graph}
+
+\item{dim}{Dimensions, should be 2 or 3.}
+
+\item{\dots}{For \code{layout_nicely} the extra arguments are passed to
+the real layout function. For \code{nicely} all argument are passed to
+\code{layout_nicely}.}
+}
+\value{
+A numeric matrix with two or three columns.
+}
+\description{
+This function tries to choose an appropriate graph layout algorithm for the
+graph, automatically, based on a simple algorithm. See details below.
+}
+\details{
+\code{layout_nicely} tries to choose an appropriate layout function for the
+supplied graph, and uses that to generate the layout. The current
+implementation works like this: \enumerate{ \item If the graph has a graph
+attribute called \sQuote{layout}, then this is used. If this attribute is an
+R function, then it is called, with the graph and any other extra arguments.
+\item Otherwise, if the graph has vertex attributes called \sQuote{x} and
+\sQuote{y}, then these are used as coordinates. If the graph has an
+additional \sQuote{z} vertex attribute, that is also used.  \item Otherwise,
+if the graph is connected and has less than 1000 vertices, the
+Fruchterman-Reingold layout is used, by calling \code{layout_with_fr}.
+\item Otherwise the DrL layout is used, \code{layout_with_drl} is called.  }
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{plot.igraph}}
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_on_grid.Rd b/man/layout_on_grid.Rd
new file mode 100644
index 0000000..f177a80
--- /dev/null
+++ b/man/layout_on_grid.Rd
@@ -0,0 +1,99 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_on_grid}
+\alias{layout.grid}
+\alias{layout.grid.3d}
+\alias{layout_on_grid}
+\alias{on_grid}
+\title{Simple grid layout}
+\usage{
+layout_on_grid(graph, width = 0, height = 0, dim = 2)
+
+on_grid(...)
+
+layout.grid.3d(graph, width = 0, height = 0)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{width}{The number of vertices in a single row of the grid. If this is
+zero or negative, then for 2d layouts the width of the grid will be the
+square root of the number of vertices in the graph, rounded up to the next
+integer. Similarly, it will be the cube root for 3d layouts.}
+
+\item{height}{The number of vertices in a single column of the grid, for
+three dimensional layouts. If this is zero or negative, then it is
+determinted automatically.}
+
+\item{dim}{Two or three. Whether to make 2d or a 3d layout.}
+
+\item{...}{Passed to \code{layout_on_grid}.}
+}
+\value{
+A two-column or three-column matrix.
+}
+\description{
+This layout places vertices on a rectangulat grid, in two or three
+dimensions.
+}
+\details{
+The function places the vertices on a simple rectangular grid, one after the
+other. If you want to change the order of the vertices, then see the
+\code{\link{permute}} function.
+}
+\examples{
+g <- make_lattice( c(3,3) )
+layout_on_grid(g)
+
+g2 <- make_lattice( c(3,3,3) )
+layout_on_grid(g2, dim = 3)
+
+\dontrun{
+plot(g, layout=layout_on_grid)
+rglplot(g, layout=layout_on_grid(g, dim = 3))
+}
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\seealso{
+\code{\link{layout}} for other layout generators
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.mds}},
+  \code{\link{layout_with_mds}}, \code{\link{with_mds}};
+  \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_on_sphere.Rd b/man/layout_on_sphere.Rd
new file mode 100644
index 0000000..3a54ec9
--- /dev/null
+++ b/man/layout_on_sphere.Rd
@@ -0,0 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_on_sphere}
+\alias{layout_on_sphere}
+\alias{on_sphere}
+\title{Graph layout with vertices on the surface of a sphere}
+\usage{
+layout_on_sphere(graph)
+
+on_sphere(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{...}{Passed to \code{layout_on_sphere}.}
+}
+\value{
+A numeric matrix with three columns, and one row for each vertex.
+}
+\description{
+Place vertices on a sphere, approximately uniformly, in the order of their
+vertex ids.
+}
+\details{
+\code{layout_on_sphere} places the vertices (approximately) uniformly on the
+surface of a sphere, this is thus a 3d layout. It is not clear however what
+\dQuote{uniformly on a sphere} means.
+
+If you want to order the vertices differently, then permute them using the
+\code{\link{permute}} function.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_randomly.Rd b/man/layout_randomly.Rd
new file mode 100644
index 0000000..a8d0610
--- /dev/null
+++ b/man/layout_randomly.Rd
@@ -0,0 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_randomly}
+\alias{layout_randomly}
+\alias{randomly}
+\title{Randomly place vertices on a plane or in 3d space}
+\usage{
+layout_randomly(graph, dim = 2)
+
+randomly(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{dim}{Integer scalar, the dimension of the space to use. It must be 2
+or 3.}
+
+\item{...}{Parameters to pass to \code{layout_randomly}.}
+}
+\value{
+A numeric matrix with two or three columns.
+}
+\description{
+This function uniformly randomly places the vertices of the graph in two or
+three dimensions.
+}
+\details{
+Randomly places vertices on a [-1,1] square (in 2d) or in a cube (in 3d). It
+is probably a useless layout, but it can use as a starting point for other
+layout generators.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_dh.Rd b/man/layout_with_dh.Rd
new file mode 100644
index 0000000..6379145
--- /dev/null
+++ b/man/layout_with_dh.Rd
@@ -0,0 +1,173 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_dh}
+\alias{layout.davidson.harel}
+\alias{layout_with_dh}
+\alias{with_dh}
+\title{The Davidson-Harel layout algorithm}
+\usage{
+layout_with_dh(graph, coords = NULL, maxiter = 10, fineiter = max(10,
+  log2(vcount(graph))), cool.fact = 0.75, weight.node.dist = 1,
+  weight.border = 0, weight.edge.lengths = edge_density(graph)/10,
+  weight.edge.crossings = 1 - sqrt(edge_density(graph)),
+  weight.node.edge.dist = 0.2 * (1 - edge_density(graph)))
+
+with_dh(...)
+}
+\arguments{
+\item{graph}{The graph to lay out. Edge directions are ignored.}
+
+\item{coords}{Optional starting positions for the vertices. If this argument
+is not \code{NULL} then it should be an appropriate matrix of starting
+coordinates.}
+
+\item{maxiter}{Number of iterations to perform in the first phase.}
+
+\item{fineiter}{Number of iterations in the fine tuning phase.}
+
+\item{cool.fact}{Cooling factor.}
+
+\item{weight.node.dist}{Weight for the node-node distances component of the
+energy function.}
+
+\item{weight.border}{Weight for the distance from the border component of
+the energy function. It can be set to zero, if vertices are allowed to sit
+on the border.}
+
+\item{weight.edge.lengths}{Weight for the edge length component of the
+energy function.}
+
+\item{weight.edge.crossings}{Weight for the edge crossing component of the
+energy function.}
+
+\item{weight.node.edge.dist}{Weight for the node-edge distance component of
+the energy function.}
+
+\item{...}{Passed to \code{layout_with_dh}.}
+}
+\value{
+A two- or three-column matrix, each row giving the coordinates of a
+vertex, according to the ids of the vertex ids.
+}
+\description{
+Place vertices of a graph on the plane, according to the simulated annealing
+algorithm by Davidson and Harel.
+}
+\details{
+This function implements the algorithm by Davidson and Harel, see Ron
+Davidson, David Harel: Drawing Graphs Nicely Using Simulated Annealing. ACM
+Transactions on Graphics 15(4), pp. 301-331, 1996.
+
+The algorithm uses simulated annealing and a sophisticated energy function,
+which is unfortunately hard to parameterize for different graphs. The
+original publication did not disclose any parameter values, and the ones
+below were determined by experimentation.
+
+The algorithm consists of two phases, an annealing phase, and a fine-tuning
+phase. There is no simulated annealing in the second phase.
+
+Our implementation tries to follow the original publication, as much as
+possible. The only major difference is that coordinates are explicitly kept
+within the bounds of the rectangle of the layout.
+}
+\examples{
+set.seed(42)
+## Figures from the paper
+g_1b <- make_star(19, mode="undirected") + path(c(2:19, 2)) +
+  path(c(seq(2, 18, by=2), 2))
+plot(g_1b, layout=layout_with_dh)
+
+g_2 <- make_lattice(c(8, 3)) + edges(1,8, 9,16, 17,24)
+plot(g_2, layout=layout_with_dh)
+
+g_3 <- make_empty_graph(n=70)
+plot(g_3, layout=layout_with_dh)
+
+g_4 <- make_empty_graph(n=70, directed=FALSE) + edges(1:70)
+plot(g_4, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_5a <- make_ring(24)
+plot(g_5a, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_5b <- make_ring(40)
+plot(g_5b, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_6 <- make_lattice(c(2,2,2))
+plot(g_6, layout=layout_with_dh)
+
+g_7 <- graph_from_literal(1:3:5 -- 2:4:6)
+plot(g_7, layout=layout_with_dh, vertex.label=V(g_7)$name)
+
+g_8 <- make_ring(5) + make_ring(10) + make_ring(5) +
+  edges(1,6, 2,8, 3, 10, 4,12, 5,14,
+        7,16, 9,17, 11,18, 13,19, 15,20)
+plot(g_8, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_9 <- make_lattice(c(3,2,2))
+plot(g_9, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_10 <- make_lattice(c(6,6))
+plot(g_10, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_11a <- make_tree(31, 2, mode="undirected")
+plot(g_11a, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_11b <- make_tree(21, 4, mode="undirected")
+plot(g_11b, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+
+g_12 <- make_empty_graph(n=37, directed=FALSE) +
+  path(1:5,10,22,31,37:33,27,16,6,1) + path(6,7,11,9,10) + path(16:22) +
+  path(27:31) + path(2,7,18,28,34) + path(3,8,11,19,29,32,35) +
+  path(4,9,20,30,36) + path(1,7,12,14,19,24,26,30,37) +
+  path(5,9,13,15,19,23,25,28,33) + path(3,12,16,25,35,26,22,13,3)
+plot(g_12,  layout=layout_with_dh, vertex.size=5, vertex.label=NA)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Ron Davidson, David Harel: Drawing Graphs Nicely Using Simulated
+Annealing. \emph{ACM Transactions on Graphics} 15(4), pp. 301-331, 1996.
+}
+\seealso{
+\code{\link{layout_with_fr}},
+\code{\link{layout_with_kk}} for other layout algorithms.
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}}; \code{\link{layout.gem}},
+  \code{\link{layout_with_gem}}, \code{\link{with_gem}};
+  \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+
diff --git a/man/layout_with_drl.Rd b/man/layout_with_drl.Rd
new file mode 100644
index 0000000..d1c8a1b
--- /dev/null
+++ b/man/layout_with_drl.Rd
@@ -0,0 +1,116 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout_drl.R
+\name{layout_with_drl}
+\alias{drl_defaults}
+\alias{igraph.drl.coarsen}
+\alias{igraph.drl.coarsest}
+\alias{igraph.drl.default}
+\alias{igraph.drl.final}
+\alias{igraph.drl.refine}
+\alias{layout.drl}
+\alias{layout_with_drl}
+\alias{with_drl}
+\title{The DrL graph layout generator}
+\usage{
+layout_with_drl(graph, use.seed = FALSE, seed = matrix(runif(vcount(graph) *
+  2), ncol = 2), options = drl_defaults$default, weights = E(graph)$weight,
+  fixed = NULL, dim = 2)
+
+with_drl(...)
+}
+\arguments{
+\item{graph}{The input graph, in can be directed or undirected.}
+
+\item{use.seed}{Logical scalar, whether to use the coordinates given in the
+\code{seed} argument as a starting point.}
+
+\item{seed}{A matrix with two columns, the starting coordinates for the
+vertices is \code{use.seed} is \code{TRUE}. It is ignored otherwise.}
+
+\item{options}{Options for the layout generator, a named list. See details
+below.}
+
+\item{weights}{Optional edge weights. Supply \code{NULL} here if you want to
+weight edges equally. By default the \code{weight} edge attribute is used if
+the graph has one.}
+
+\item{fixed}{Logical vector, it can be used to fix some vertices. All
+vertices for which it is \code{TRUE} are kept at the coordinates supplied in
+the \code{seed} matrix. It is ignored it \code{NULL} or if \code{use.seed}
+is \code{FALSE}.}
+
+\item{dim}{Either \sQuote{2} or \sQuote{3}, it specifies whether we want a
+two dimensional or a three dimensional layout. Note that because of the
+nature of the DrL algorithm, the three dimensional layout takes
+significantly longer to compute.}
+
+\item{...}{Passed to \code{layout_with_drl}.}
+}
+\value{
+A numeric matrix with two columns.
+}
+\description{
+DrL is a force-directed graph layout toolbox focused on real-world
+large-scale graphs, developed by Shawn Martin and colleagues at Sandia
+National Laboratories.
+}
+\details{
+This function implements the force-directed DrL layout generator.
+
+The generator has the following parameters: \describe{ \item{edge.cut}{Edge
+cutting is done in the late stages of the algorithm in order to achieve less
+dense layouts.  Edges are cut if there is a lot of stress on them (a large
+value in the objective function sum). The edge cutting parameter is a value
+between 0 and 1 with 0 representing no edge cutting and 1 representing
+maximal edge cutting. } \item{init.iterations}{Number of iterations in the
+first phase.} \item{init.temperature}{Start temperature, first phase.}
+\item{init.attraction}{Attraction, first phase.}
+\item{init.damping.mult}{Damping, first phase.}
+\item{liquid.iterations}{Number of iterations, liquid phase.}
+\item{liquid.temperature}{Start temperature, liquid phase.}
+\item{liquid.attraction}{Attraction, liquid phase.}
+\item{liquid.damping.mult}{Damping, liquid phase.}
+\item{expansion.iterations}{Number of iterations, expansion phase.}
+\item{expansion.temperature}{Start temperature, expansion phase.}
+\item{expansion.attraction}{Attraction, expansion phase.}
+\item{expansion.damping.mult}{Damping, expansion phase.}
+\item{cooldown.iterations}{Number of iterations, cooldown phase.}
+\item{cooldown.temperature}{Start temperature, cooldown phase.}
+\item{cooldown.attraction}{Attraction, cooldown phase.}
+\item{cooldown.damping.mult}{Damping, cooldown phase.}
+\item{crunch.iterations}{Number of iterations, crunch phase.}
+\item{crunch.temperature}{Start temperature, crunch phase.}
+\item{crunch.attraction}{Attraction, crunch phase.}
+\item{crunch.damping.mult}{Damping, crunch phase.}
+\item{simmer.iterations}{Number of iterations, simmer phase.}
+\item{simmer.temperature}{Start temperature, simmer phase.}
+\item{simmer.attraction}{Attraction, simmer phase.}
+\item{simmer.damping.mult}{Damping, simmer phase.}
+
+There are five pre-defined parameter settings as well, these are called
+\code{drl_defaults$default}, \code{drl_defaults$coarsen},
+\code{drl_defaults$coarsest}, \code{drl_defaults$refine} and
+\code{drl_defaults$final}.  }
+}
+\examples{
+g <- as.undirected(sample_pa(100, m=1))
+l <- layout_with_drl(g, options=list(simmer.attraction=0))
+\dontrun{
+plot(g, layout=l, vertex.size=3, vertex.label=NA)
+}
+}
+\author{
+Shawn Martin (\url{http://www.cs.otago.ac.nz/homepages/smartin/})
+and Gabor Csardi \email{csardi.gabor at gmail.com} for the R/igraph interface
+and the three dimensional version.
+}
+\references{
+See the following technical report: Martin, S., Brown, W.M.,
+Klavans, R., Boyack, K.W., DrL: Distributed Recursive (Graph) Layout. SAND
+Reports, 2008. 2936: p. 1-10.
+}
+\seealso{
+\code{\link{layout}} for other layout generators.
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_fr.Rd b/man/layout_with_fr.Rd
new file mode 100644
index 0000000..b018430
--- /dev/null
+++ b/man/layout_with_fr.Rd
@@ -0,0 +1,146 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_fr}
+\alias{layout_with_fr}
+\alias{with_fr}
+\title{The Fruchterman-Reingold layout algorithm}
+\usage{
+layout_with_fr(graph, coords = NULL, dim = 2, niter = 500,
+  start.temp = sqrt(vcount(graph)), grid = c("auto", "grid", "nogrid"),
+  weights = NULL, minx = NULL, maxx = NULL, miny = NULL, maxy = NULL,
+  minz = NULL, maxz = NULL, coolexp, maxdelta, area, repulserad, maxiter)
+
+with_fr(...)
+}
+\arguments{
+\item{graph}{The graph to lay out. Edge directions are ignored.}
+
+\item{coords}{Optional starting positions for the vertices. If this argument
+is not \code{NULL} then it should be an appropriate matrix of starting
+coordinates.}
+
+\item{dim}{Integer scalar, 2 or 3, the dimension of the layout.  Two
+dimensional layouts are places on a plane, three dimensional ones in the 3d
+space.}
+
+\item{niter}{Integer scalar, the number of iterations to perform.}
+
+\item{start.temp}{Real scalar, the start temperature. This is the maximum
+amount of movement alloved along one axis, within one step, for a vertex.
+Currently it is decreased linearly to zero during the iteration.}
+
+\item{grid}{Character scalar, whether to use the faster, but less accurate
+grid based implementation of the algorithm. By default (\dQuote{auto}), the
+grid-based implementation is used if the graph has more than one thousand
+vertices.}
+
+\item{weights}{A vector giving edge weights. The \code{weight} edge
+attribute is used by default, if present. If weights are given, then the
+attraction along the edges will be multiplied by the given edge weights.}
+
+\item{minx}{If not \code{NULL}, then it must be a numeric vector that gives
+lower boundaries for the \sQuote{x} coordinates of the vertices. The length
+of the vector must match the number of vertices in the graph.}
+
+\item{maxx}{Similar to \code{minx}, but gives the upper boundaries.}
+
+\item{miny}{Similar to \code{minx}, but gives the lower boundaries of the
+\sQuote{y} coordinates.}
+
+\item{maxy}{Similar to \code{minx}, but gives the upper boundaries of the
+\sQuote{y} coordinates.}
+
+\item{minz}{Similar to \code{minx}, but gives the lower boundaries of the
+\sQuote{z} coordinates.}
+
+\item{maxz}{Similar to \code{minx}, but gives the upper boundaries of the
+\sQuote{z} coordinates.}
+
+\item{coolexp,maxdelta,area,repulserad}{These arguments are not supported
+from igraph version 0.8.0 and are ignored (with a warning).}
+
+\item{maxiter}{A deprecated synonym of \code{niter}, for compatibility.}
+
+\item{...}{Passed to \code{layout_with_fr}.}
+}
+\value{
+A two- or three-column matrix, each row giving the coordinates of a
+vertex, according to the ids of the vertex ids.
+}
+\description{
+Place vertices on the plane using the force-directed layout algorithm by
+Fruchterman and Reingold.
+}
+\details{
+See the referenced paper below for the details of the algorithm.
+
+This function was rewritten from scratch in igraph version 0.8.0.
+}
+\examples{
+# Fixing ego
+g <- sample_pa(20, m=2)
+minC <- rep(-Inf, vcount(g))
+maxC <- rep(Inf, vcount(g))
+minC[1] <- maxC[1] <- 0
+co <- layout_with_fr(g, minx=minC, maxx=maxC,
+                                  miny=minC, maxy=maxC)
+co[1,]
+plot(g, layout=co, vertex.size=30, edge.arrow.size=0.2,
+     vertex.label=c("ego", rep("", vcount(g)-1)), rescale=FALSE,
+     xlim=range(co[,1]), ylim=range(co[,2]), vertex.label.dist=0,
+     vertex.label.color="red")
+axis(1)
+axis(2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Fruchterman, T.M.J. and Reingold, E.M. (1991). Graph Drawing by
+Force-directed Placement. \emph{Software - Practice and Experience},
+21(11):1129-1164.
+}
+\seealso{
+\code{\link{layout_with_drl}}, \code{\link{layout_with_kk}} for
+other layout algorithms.
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_gem.Rd b/man/layout_with_gem.Rd
new file mode 100644
index 0000000..95521d1
--- /dev/null
+++ b/man/layout_with_gem.Rd
@@ -0,0 +1,105 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_gem}
+\alias{layout.gem}
+\alias{layout_with_gem}
+\alias{with_gem}
+\title{The GEM layout algorithm}
+\usage{
+layout_with_gem(graph, coords = NULL, maxiter = 40 * vcount(graph)^2,
+  temp.max = vcount(graph), temp.min = 1/10,
+  temp.init = sqrt(vcount(graph)))
+
+with_gem(...)
+}
+\arguments{
+\item{graph}{The input graph. Edge directions are ignored.}
+
+\item{coords}{If not \code{NULL}, then the starting coordinates should be
+given here, in a two or three column matrix, depending on the \code{dim}
+argument.}
+
+\item{maxiter}{The maximum number of iterations to perform. Updating a
+single vertex counts as an iteration.  A reasonable default is 40 * n * n,
+where n is the number of vertices. The original paper suggests 4 * n * n,
+but this usually only works if the other parameters are set up carefully.}
+
+\item{temp.max}{The maximum allowed local temperature. A reasonable default
+is the number of vertices.}
+
+\item{temp.min}{The global temperature at which the algorithm terminates
+(even before reaching \code{maxiter} iterations). A reasonable default is
+1/10.}
+
+\item{temp.init}{Initial local temperature of all vertices. A reasonable
+default is the square root of the number of vertices.}
+
+\item{...}{Passed to \code{layout_with_gem}.}
+}
+\value{
+A numeric matrix with two columns, and as many rows as the number of
+vertices.
+}
+\description{
+Place vertices on the plane using the GEM force-directed layout algorithm.
+}
+\details{
+See the referenced paper below for the details of the algorithm.
+}
+\examples{
+set.seed(42)
+g <- make_ring(10)
+plot(g, layout=layout_with_gem)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Arne Frick, Andreas Ludwig, Heiko Mehldau: A Fast Adaptive
+Layout Algorithm for Undirected Graphs, \emph{Proc. Graph Drawing 1994},
+LNCS 894, pp. 388-403, 1995.
+}
+\seealso{
+\code{\link{layout_with_fr}},
+\code{\link{plot.igraph}}, \code{\link{tkplot}}
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_graphopt.Rd b/man/layout_with_graphopt.Rd
new file mode 100644
index 0000000..a3afaab
--- /dev/null
+++ b/man/layout_with_graphopt.Rd
@@ -0,0 +1,108 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_graphopt}
+\alias{layout.graphopt}
+\alias{layout_with_graphopt}
+\alias{with_graphopt}
+\title{The graphopt layout algorithm}
+\usage{
+layout_with_graphopt(graph, start = NULL, niter = 500, charge = 0.001,
+  mass = 30, spring.length = 0, spring.constant = 1,
+  max.sa.movement = 5)
+
+with_graphopt(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{start}{If given, then it should be a matrix with two columns and one
+line for each vertex. This matrix will be used as starting positions for the
+algorithm. If not given, then a random starting matrix is used.}
+
+\item{niter}{Integer scalar, the number of iterations to perform.  Should be
+a couple of hundred in general. If you have a large graph then you might
+want to only do a few iterations and then check the result. If it is not
+good enough you can feed it in again in the \code{start} argument. The
+default value is 500.}
+
+\item{charge}{The charge of the vertices, used to calculate electric
+repulsion. The default is 0.001.}
+
+\item{mass}{The mass of the vertices, used for the spring forces. The
+default is 30.}
+
+\item{spring.length}{The length of the springs, an integer number. The
+default value is zero.}
+
+\item{spring.constant}{The spring constant, the default value is one.}
+
+\item{max.sa.movement}{Real constant, it gives the maximum amount of
+movement allowed in a single step along a single axis. The default value is
+5.}
+
+\item{...}{Passed to \code{layout_with_graphopt}.}
+}
+\value{
+A numeric matrix with two columns, and a row for each vertex.
+}
+\description{
+A force-directed layout algorithm, that scales relatively well to large
+graphs.
+}
+\details{
+\code{layout_with_graphopt} is a port of the graphopt layout algorithm by Michael
+Schmuhl. graphopt version 0.4.1 was rewritten in C and the support for
+layers was removed (might be added later) and a code was a bit reorganized
+to avoid some unneccessary steps is the node charge (see below) is zero.
+
+graphopt uses physical analogies for defining attracting and repelling
+forces among the vertices and then the physical system is simulated until it
+reaches an equilibrium. (There is no simulated annealing or anything like
+that, so a stable fixed point is not guaranteed.)
+
+See also \url{http://www.schmuhl.org/graphopt/} for the original graphopt.
+}
+\author{
+Michael Schmuhl for the original graphopt code, rewritten and
+wrapped by Gabor Csardi \email{csardi.gabor at gmail.com}.
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_kk.Rd b/man/layout_with_kk.Rd
new file mode 100644
index 0000000..ec86681
--- /dev/null
+++ b/man/layout_with_kk.Rd
@@ -0,0 +1,134 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_kk}
+\alias{layout_with_kk}
+\alias{with_kk}
+\title{The Kamada-Kawai layout algorithm}
+\usage{
+layout_with_kk(graph, coords = NULL, dim = 2, maxiter = 50 *
+  vcount(graph), epsilon = 0, kkconst = vcount(graph), weights = NULL,
+  minx = NULL, maxx = NULL, miny = NULL, maxy = NULL, minz = NULL,
+  maxz = NULL, niter, sigma, initemp, coolexp, start)
+
+with_kk(...)
+}
+\arguments{
+\item{graph}{The input graph. Edge directions are ignored.}
+
+\item{coords}{If not \code{NULL}, then the starting coordinates should be
+given here, in a two or three column matrix, depending on the \code{dim}
+argument.}
+
+\item{dim}{Integer scalar, 2 or 3, the dimension of the layout.  Two
+dimensional layouts are places on a plane, three dimensional ones in the 3d
+space.}
+
+\item{maxiter}{The maximum number of iterations to perform. The algorithm
+might terminate earlier, see the \code{epsilon} argument.}
+
+\item{epsilon}{Numeric scalar, the algorithm terminates, if the maximal
+delta is less than this. (See the reference below for what delta means.) If
+you set this to zero, then the function always performs \code{maxiter}
+iterations.}
+
+\item{kkconst}{Numeric scalar, the Kamada-Kawai vertex attraction constant.
+Typical (and default) value is the number of vertices.}
+
+\item{weights}{Edge weights, larger values will result longer edges.}
+
+\item{minx}{If not \code{NULL}, then it must be a numeric vector that gives
+lower boundaries for the \sQuote{x} coordinates of the vertices. The length
+of the vector must match the number of vertices in the graph.}
+
+\item{maxx}{Similar to \code{minx}, but gives the upper boundaries.}
+
+\item{miny}{Similar to \code{minx}, but gives the lower boundaries of the
+\sQuote{y} coordinates.}
+
+\item{maxy}{Similar to \code{minx}, but gives the upper boundaries of the
+\sQuote{y} coordinates.}
+
+\item{minz}{Similar to \code{minx}, but gives the lower boundaries of the
+\sQuote{z} coordinates.}
+
+\item{maxz}{Similar to \code{minx}, but gives the upper boundaries of the
+\sQuote{z} coordinates.}
+
+\item{niter,sigma,initemp,coolexp}{These arguments are not supported from
+igraph version 0.8.0 and are ignored (with a warning).}
+
+\item{start}{Deprecated synonym for \code{coords}, for compatibility.}
+
+\item{...}{Passed to \code{layout_with_kk}.}
+}
+\value{
+A numeric matrix with two (dim=2) or three (dim=3) columns, and as
+many rows as the number of vertices, the x, y and potentially z coordinates
+of the vertices.
+}
+\description{
+Place the vertices on the plane, or in the 3d space, based on a phyisical
+model of springs.
+}
+\details{
+See the referenced paper below for the details of the algorithm.
+
+This function was rewritten from scratch in igraph version 0.8.0 and it
+follows truthfully the original publication by Kamada and Kawai now.
+}
+\examples{
+g <- make_ring(10)
+E(g)$weight <- rep(1:2, length.out=ecount(g))
+plot(g, layout=layout_with_kk, edge.label=E(g)$weight)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Kamada, T. and Kawai, S.: An Algorithm for Drawing General
+Undirected Graphs. \emph{Information Processing Letters}, 31/1, 7--15, 1989.
+}
+\seealso{
+\code{\link{layout_with_drl}}, \code{\link{plot.igraph}},
+\code{\link{tkplot}}
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_lgl.Rd b/man/layout_with_lgl.Rd
new file mode 100644
index 0000000..a4059a2
--- /dev/null
+++ b/man/layout_with_lgl.Rd
@@ -0,0 +1,94 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_lgl}
+\alias{layout_with_lgl}
+\alias{with_lgl}
+\title{Large Graph Layout}
+\usage{
+layout_with_lgl(graph, maxiter = 150, maxdelta = vcount(graph),
+  area = vcount(graph)^2, coolexp = 1.5, repulserad = area *
+  vcount(graph), cellsize = sqrt(sqrt(area)), root = NULL)
+
+with_lgl(...)
+}
+\arguments{
+\item{graph}{The input graph}
+
+\item{maxiter}{The maximum number of iterations to perform (150).}
+
+\item{maxdelta}{The maximum change for a vertex during an iteration (the
+number of vertices).}
+
+\item{area}{The area of the surface on which the vertices are placed (square
+of the number of vertices).}
+
+\item{coolexp}{The cooling exponent of the simulated annealing (1.5).}
+
+\item{repulserad}{Cancellation radius for the repulsion (the \code{area}
+times the number of vertices).}
+
+\item{cellsize}{The size of the cells for the grid. When calculating the
+repulsion forces between vertices only vertices in the same or neighboring
+grid cells are taken into account (the fourth root of the number of
+\code{area}.}
+
+\item{root}{The id of the vertex to place at the middle of the layout. The
+default value is -1 which means that a random vertex is selected.}
+
+\item{...}{Passed to \code{layout_with_lgl}.}
+}
+\value{
+A numeric matrix with two columns and as many rows as vertices.
+}
+\description{
+A layout generator for larger graphs.
+}
+\details{
+\code{layout_with_lgl} is for large connected graphs, it is similar to the layout
+generator of the Large Graph Layout software
+(\url{http://lgl.sourceforge.net/}).
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_mds.Rd b/man/layout_with_mds.Rd
new file mode 100644
index 0000000..5fd1057
--- /dev/null
+++ b/man/layout_with_mds.Rd
@@ -0,0 +1,103 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_mds}
+\alias{layout.mds}
+\alias{layout_with_mds}
+\alias{with_mds}
+\title{Graph layout by multidimensional scaling}
+\usage{
+layout_with_mds(graph, dist = NULL, dim = 2, options = arpack_defaults)
+
+with_mds(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{dist}{The distance matrix for the multidimensional scaling.  If
+\code{NULL} (the default), then the unweighted shortest path matrix is used.}
+
+\item{dim}{\code{layout_with_mds} supports dimensions up to the number of nodes
+minus one, but only if the graph is connected; for unconnected graphs, the
+only possible values is 2. This is because \code{merge_coords} only works in
+2D.}
+
+\item{options}{This is currently ignored, as ARPACK is not used any more for
+solving the eigenproblem}
+
+\item{...}{Passed to \code{layout_with_mds}.}
+}
+\value{
+A numeric matrix with \code{dim} columns.
+}
+\description{
+Multidimensional scaling of some distance matrix defined on the vertices of
+a graph.
+}
+\details{
+\code{layout_with_mds} uses metric multidimensional scaling for generating the
+coordinates. Multidimensional scaling aims to place points from a higher
+dimensional space in a (typically) 2 dimensional plane, so that the distance
+between the points are kept as much as this is possible.
+
+By default igraph uses the shortest path matrix as the distances between the
+nodes, but the user can override this via the \code{dist} argument.
+
+This function generates the layout separately for each graph component and
+then merges them via \code{\link{merge_coords}}.
+}
+\examples{
+g <- sample_gnp(100, 2/100)
+l <- layout_with_mds(g)
+plot(g, layout=l, vertex.label=NA, vertex.size=3)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
+\references{
+Cox, T. F. and Cox, M. A. A. (2001) \emph{Multidimensional
+Scaling}.  Second edition. Chapman and Hall.
+}
+\seealso{
+\code{\link{layout}}, \code{\link{plot.igraph}}
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/layout_with_sugiyama.Rd b/man/layout_with_sugiyama.Rd
new file mode 100644
index 0000000..a54b0e6
--- /dev/null
+++ b/man/layout_with_sugiyama.Rd
@@ -0,0 +1,242 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{layout_with_sugiyama}
+\alias{layout.sugiyama}
+\alias{layout_with_sugiyama}
+\alias{with_sugiyama}
+\title{The Sugiyama graph layout generator}
+\usage{
+layout_with_sugiyama(graph, layers = NULL, hgap = 1, vgap = 1,
+  maxiter = 100, weights = NULL, attributes = c("default", "all", "none"))
+
+with_sugiyama(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{layers}{A numeric vector or \code{NULL}. If not \code{NULL}, then it
+should specify the layer index of the vertices. Layers are numbered from
+one. If \code{NULL}, then igraph calculates the layers automatically.}
+
+\item{hgap}{Real scalar, the minimum horizontal gap between vertices in the
+same layer.}
+
+\item{vgap}{Real scalar, the distance between layers.}
+
+\item{maxiter}{Integer scalar, the maximum number of iterations in the
+crossing minimization stage. 100 is a reasonable default; if you feel that
+you have too many edge crossings, increase this.}
+
+\item{weights}{Optional edge weight vector. If \code{NULL}, then the
+'weight' edge attribute is used, if there is one. Supply \code{NA} here and
+igraph ignores the edge weights.}
+
+\item{attributes}{Which graph/vertex/edge attributes to keep in the extended
+graph. \sQuote{default} keeps the \sQuote{size}, \sQuote{size2},
+\sQuote{shape}, \sQuote{label} and \sQuote{color} vertex attributes and the
+\sQuote{arrow.mode} and \sQuote{arrow.size} edge attributes. \sQuote{all}
+keep all graph, vertex and edge attributes, \sQuote{none} keeps none of
+them.}
+
+\item{...}{Passed to \code{layout_with_sugiyama}.}
+}
+\value{
+A list with the components: \item{layout}{The layout, a two-column
+matrix, for the original graph vertices.} \item{layout.dummy}{The layout for
+the dummy vertices, a two column matrix.} \item{extd_graph}{The original
+graph, extended with dummy vertices.  The \sQuote{dummy} vertex attribute is
+set on this graph, it is a logical attributes, and it tells you whether the
+vertex is a dummy vertex. The \sQuote{layout} graph attribute is also set,
+and it is the layout matrix for all (original and dummy) vertices.}
+}
+\description{
+Sugiyama layout algorithm for layered directed acyclic graphs. The algorithm
+minimized edge crossings.
+}
+\details{
+This layout algorithm is designed for directed acyclic graphs where each
+vertex is assigned to a layer. Layers are indexed from zero, and vertices of
+the same layer will be placed on the same horizontal line. The X coordinates
+of vertices within each layer are decided by the heuristic proposed by
+Sugiyama et al. to minimize edge crossings.
+
+You can also try to lay out undirected graphs, graphs containing cycles, or
+graphs without an a priori layered assignment with this algorithm. igraph
+will try to eliminate cycles and assign vertices to layers, but there is no
+guarantee on the quality of the layout in such cases.
+
+The Sugiyama layout may introduce \dQuote{bends} on the edges in order to
+obtain a visually more pleasing layout. This is achieved by adding dummy
+nodes to edges spanning more than one layer. The resulting layout assigns
+coordinates not only to the nodes of the original graph but also to the
+dummy nodes. The layout algorithm will also return the extended graph with
+the dummy nodes.
+
+For more details, see the reference below.
+}
+\examples{
+## Data taken from http://tehnick-8.narod.ru/dc_clients/
+DC <- graph_from_literal("DC++" -+
+                "LinuxDC++":"BCDC++":"EiskaltDC++":"StrongDC++":"DiCe!++",
+                "LinuxDC++" -+ "FreeDC++", "BCDC++" -+ "StrongDC++",
+                "FreeDC++" -+ "BMDC++":"EiskaltDC++",
+                "StrongDC++" -+ "AirDC++":"zK++":"ApexDC++":"TkDC++",
+                "StrongDC++" -+ "StrongDC++ SQLite":"RSX++",
+                "ApexDC++" -+ "FlylinkDC++ ver <= 4xx",
+                "ApexDC++" -+ "ApexDC++ Speed-Mod":"DiCe!++",
+                "StrongDC++ SQLite" -+ "FlylinkDC++ ver >= 5xx",
+                "ApexDC++ Speed-Mod" -+ "FlylinkDC++ ver <= 4xx",
+                "ApexDC++ Speed-Mod" -+ "GreylinkDC++",
+                "FlylinkDC++ ver <= 4xx" -+ "FlylinkDC++ ver >= 5xx",
+                "FlylinkDC++ ver <= 4xx" -+ AvaLink,
+                "GreylinkDC++" -+ AvaLink:"RayLinkDC++":"SparkDC++":PeLink)
+
+## Use edge types
+E(DC)$lty <- 1
+E(DC)["BCDC++" \%->\% "StrongDC++"]$lty <- 2
+E(DC)["FreeDC++" \%->\% "EiskaltDC++"]$lty <- 2
+E(DC)["ApexDC++" \%->\% "FlylinkDC++ ver <= 4xx"]$lty <- 2
+E(DC)["ApexDC++" \%->\% "DiCe!++"]$lty <- 2
+E(DC)["StrongDC++ SQLite" \%->\% "FlylinkDC++ ver >= 5xx"]$lty <- 2
+E(DC)["GreylinkDC++" \%->\% "AvaLink"]$lty <- 2
+
+## Layers, as on the plot
+layers <- list(c("DC++"),
+               c("LinuxDC++", "BCDC++"),
+               c("FreeDC++", "StrongDC++"),
+               c("BMDC++", "EiskaltDC++", "AirDC++", "zK++", "ApexDC++",
+                 "TkDC++", "RSX++"),
+               c("StrongDC++ SQLite", "ApexDC++ Speed-Mod", "DiCe!++"),
+               c("FlylinkDC++ ver <= 4xx", "GreylinkDC++"),
+               c("FlylinkDC++ ver >= 5xx", "AvaLink", "RayLinkDC++",
+                 "SparkDC++", "PeLink"))
+
+## Check that we have all nodes
+all(sort(unlist(layers)) == sort(V(DC)$name))
+
+## Add some graphical parameters
+V(DC)$color <- "white"
+V(DC)$shape <- "rectangle"
+V(DC)$size <- 20
+V(DC)$size2 <- 10
+V(DC)$label <- lapply(V(DC)$name, function(x)
+                      paste(strwrap(x, 12), collapse="\\n"))
+E(DC)$arrow.size <- 0.5
+
+## Create a similar layout using the predefined layers
+lay1 <-  layout_with_sugiyama(DC, layers=apply(sapply(layers,
+                        function(x) V(DC)$name \%in\% x), 1, which))
+
+## Simple plot, not very nice
+par(mar=rep(.1, 4))
+plot(DC, layout=lay1$layout, vertex.label.cex=0.5)
+
+## Sugiyama plot
+plot(lay1$extd_graph, vertex.label.cex=0.5)
+
+## The same with automatic layer calculation
+## Keep vertex/edge attributes in the extended graph
+lay2 <-  layout_with_sugiyama(DC, attributes="all")
+plot(lay2$extd_graph, vertex.label.cex=0.5)
+
+## Another example, from the following paper:
+## Markus Eiglsperger, Martin Siebenhaller, Michael Kaufmann:
+## An Efficient Implementation of Sugiyama's Algorithm for
+## Layered Graph Drawing, Journal of Graph Algorithms and
+## Applications 9, 305--325 (2005).
+
+ex <- graph_from_literal( 0 -+ 29: 6: 5:20: 4,
+                 1 -+ 12,
+                 2 -+ 23: 8,
+                 3 -+  4,
+                 4,
+                 5 -+  2:10:14:26: 4: 3,
+                 6 -+  9:29:25:21:13,
+                 7,
+                 8 -+ 20:16,
+                 9 -+ 28: 4,
+                10 -+ 27,
+                11 -+  9:16,
+                12 -+  9:19,
+                13 -+ 20,
+                14 -+ 10,
+                15 -+ 16:27,
+                16 -+ 27,
+                17 -+  3,
+                18 -+ 13,
+                19 -+  9,
+                20 -+  4,
+                21 -+ 22,
+                22 -+  8: 9,
+                23 -+  9:24,
+                24 -+ 12:15:28,
+                25 -+ 11,
+                26 -+ 18,
+                27 -+ 13:19,
+                28 -+  7,
+                29 -+ 25                    )
+
+layers <- list( 0, c(5, 17), c(2, 14, 26, 3), c(23, 10, 18), c(1, 24),
+                12, 6, c(29,21), c(25,22), c(11,8,15), 16, 27, c(13,19),
+                c(9, 20), c(4, 28), 7 )
+
+layex <-  layout_with_sugiyama(ex, layers=apply(sapply(layers,
+                        function(x) V(ex)$name \%in\% as.character(x)),
+                        1, which))
+
+origvert <- c(rep(TRUE, vcount(ex)), rep(FALSE, nrow(layex$layout.dummy)))
+realedge <- as_edgelist(layex$extd_graph)[,2] <= vcount(ex)
+plot(layex$extd_graph, vertex.label.cex=0.5,
+     edge.arrow.size=.5,
+     vertex.size=ifelse(origvert, 5, 0),
+     vertex.shape=ifelse(origvert, "square", "none"),
+     vertex.label=ifelse(origvert, V(ex)$name, ""),
+     edge.arrow.mode=ifelse(realedge, 2, 0))
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+K. Sugiyama, S. Tagawa and M. Toda, "Methods for Visual
+Understanding of Hierarchical Systems". IEEE Transactions on Systems, Man
+and Cybernetics 11(2):109-125, 1981.
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/leading.eigenvector.Rd b/man/leading.eigenvector.Rd
deleted file mode 100644
index 80cb83c..0000000
--- a/man/leading.eigenvector.Rd
+++ /dev/null
@@ -1,133 +0,0 @@
-\name{leading.eigenvector.community}
-\alias{leading.eigenvector.community}
-\alias{community.le.to.membership}
-\concept{Community structure}
-\title{Community structure detecting based on the leading eigenvector
-  of the community matrix}
-\description{This function tries to find densely connected subgraphs in
-  a graph by calculating the leading non-negative eigenvector of the
-  modularity matrix of the graph.}
-\usage{
-leading.eigenvector.community(graph, steps = -1, weights = NULL,
-       start = NULL, options = igraph.arpack.default,
-       callback = NULL, extra = NULL, env = parent.frame())
-community.le.to.membership(merges, steps, membership) 
-}
-\arguments{
-  \item{graph}{The input graph. Should be undirected as the method needs
-    a symmetric matrix.}
-  \item{steps}{The number of steps to take, this is actually the number
-    of tries to make a step. It is not a particularly useful parameter.
-
-    For \code{community.le.to.membership} the number of merges to
-    produce from the supplied \code{membership} vector.
-  }
-  \item{weights}{An optional weight vector. The \sQuote{weight} edge
-    attribute is used if present. Supply \sQuote{\code{NA}} here if you
-    want to ignore the \sQuote{weight} edge attribute.}
-  \item{start}{\code{NULL}, or a numeric membership vector, giving the
-    start configuration of the algorithm.}
-  \item{membership}{The starting community
-    structure on which \code{steps} merges are performed.
-  }
-  \item{options}{A named list to override some ARPACK options.}
-  \item{callback}{If not \code{NULL}, then it must be callback
-    function. This is called after each iteration, after calculating the
-    leading eigenvector of the modularity matrix. See details below.}
-  \item{extra}{Additional argument to supply to the callback function.}
-  \item{env}{The environment in which the callback function is
-    evaluated.}
-  \item{merges}{The merge matrix, possible from the result of
-    \code{leading.eigenvector.community}.}
-}
-\details{
-  The function documented in these section implements the 
-  \sQuote{leading eigenvector} method developed by Mark Newman, see the
-  reference below.
-  
-  The heart of the method is the definition of the modularity matrix,
-  \code{B}, which is \code{B=A-P}, \code{A} being the adjacency matrix of
-  the (undirected) 
-  network, and \code{P} contains the probability that certain edges are
-  present according to the \sQuote{configuration model}. In
-  other words, a \code{P[i,j]} element of \code{P} is the probability that
-  there is an edge between vertices \code{i} and \code{j} in a random
-  network in which the degrees of all vertices are the same as in the
-  input graph.
-  
-  The leading eigenvector method works by calculating the eigenvector
-  of the modularity matrix for the largest positive eigenvalue and
-  then separating vertices into two community based on the sign of
-  the corresponding element in the eigenvector. If all elements in
-  the eigenvector are of the same sign that means that the network
-  has no underlying comuunity structure.
-  Check Newman's paper to understand why this is a good method for
-  detecting community structure.
-
-  \code{community.le.to.memberhip} creates a membership vector from the
-  result of \code{leading.eigenvector.community}. It takes
-  \code{membership} and permformes \code{steps} merges, according to the
-  supplied \code{merges} matrix.
-}
-\section{Callback functions}{
-  The \code{callback} argument can be used to supply a function that is
-  called after each eigenvector calculation. The following arguments are
-  supplied to this function:
-  \describe{
-    \item{membership}{The actual membership vector, with zero-based
-      indexing.}
-    \item{community}{The community that the algorithm just tried to
-      split, community numbering starts with zero here.}
-    \item{value}{The eigenvalue belonging to the leading eigenvector
-      the algorithm just found.}
-    \item{vector}{The leading eigenvector the algorithm just found.}
-    \item{multiplier}{An R function that can be used to multiple the
-      actual modularity matrix with an arbitrary vector. Supply the
-      vector as an argument to perform this multiplication. This
-      function can be used with ARPACK.}
-    \item{extra}{The \code{extra} argument that was passed to
-      \code{leading.eigenvector.community}. }
-  }
-}
-\value{
-  \code{leading.eigenvector.community} returns a named list with
-  the following members:
-  \item{membership}{The membership vector at the end of the algorithm,
-    when no more splits are possible.}
-  \item{merges}{The merges matrix starting from the state described by
-    the \code{membership} member. This is a two-column matrix and each
-    line describes a merge of two communities, the first line is the
-    first merge and it creates community \sQuote{\code{N}}, \code{N}
-    is the number of initial communities in the graph, the second line
-    creates community \code{N+1}, etc.
-  }
-  \item{options}{Information about the underlying ARPACK computation,
-    see \code{\link{arpack}} for details.
-  }
-
-  \code{community.le.to.membership} returns a named list with two
-  components:
-  \item{membership}{A membership vector, a numerical vector
-    indication which vertex belongs to which community. The
-    communities are always numbered from one.}
-  \item{csize}{A numeric vector giving the sizes of the communities.}
-}
-\references{
-  MEJ Newman: Finding community structure using the eigenvectors of
-  matrices, Physical Review E 74 036104, 2006.
-} 
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{modularity}}, \code{\link{walktrap.community}},
-  \code{\link{edge.betweenness.community}},
-  \code{\link{fastgreedy.community}},
-  \code{\link[stats]{as.dendrogram}}
-}
-\examples{
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
-lec <- leading.eigenvector.community(g)
-lec
-
-leading.eigenvector.community(g, start=membership(lec))
-}
-\keyword{graphs}
diff --git a/man/line.graph.Rd b/man/line.graph.Rd
deleted file mode 100644
index 4ae5b9c..0000000
--- a/man/line.graph.Rd
+++ /dev/null
@@ -1,38 +0,0 @@
-\name{line.graph}
-\alias{line.graph}
-\concept{Line graph}
-\title{Line graph of a graph}
-\description{This function calculates the line graph of another graph.}
-\usage{
-line.graph(graph)
-}
-\arguments{
-  \item{graph}{The input graph, it can be directed or undirected.}
-}
-\details{
- The line graph \code{L(G)} of a \code{G} undirected graph is defined as
- follows. \code{L(G)} has one vertex for each edge in \code{G} and two
- vertices in \code{L(G)} are connected  by an edge if their
- corresponding edges share an end point.
-
- The line graph \code{L(G)} of a \code{G} directed graph is slightly
- different, \code{L(G)} has one vertex for each edge in \code{G} and two
- vertices in \code{L(G)} are connected by a directed edge if the target
- of the first vertex's corresponding edge is the same as the source of
- the second vertex's corresponding edge.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}, the first version of the C
-  code was written by Vincent Matossian.}
-% \seealso{}
-\examples{
-# generate the first De-Bruijn graphs
-g <- graph.full(2, directed=TRUE, loops=TRUE)
-line.graph(g)
-line.graph(line.graph(g))
-line.graph(line.graph(line.graph(g)))
-}
-\keyword{graphs}
diff --git a/man/local_scan.Rd b/man/local_scan.Rd
new file mode 100644
index 0000000..41c3931
--- /dev/null
+++ b/man/local_scan.Rd
@@ -0,0 +1,99 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scan.R
+\name{local_scan}
+\alias{local_scan}
+\title{Compute local scan statistics on graphs}
+\usage{
+local_scan(graph.us, graph.them = NULL, k = 1, FUN = NULL,
+  weighted = FALSE, mode = c("out", "in", "all"), neighborhoods = NULL,
+  ...)
+}
+\arguments{
+\item{graph.us,graph}{An igraph object, the graph for which the scan
+statistics will be computed}
+
+\item{graph.them}{An igraph object or \code{NULL}, if not \code{NULL},
+then the \sQuote{them} statistics is computed, i.e. the neighborhoods
+calculated from \code{graph.us} are evaluated on \code{graph.them}.}
+
+\item{k}{An integer scalar, the size of the local neighborhood for each
+vertex. Should be non-negative.}
+
+\item{FUN}{Character, a function name, or a function object itself, for
+computing the local statistic in each neighborhood. If \code{NULL}(the
+default value), \code{ecount} is used for unweighted graphs (if
+\code{weighted=FALSE}) and a function that computes the sum of edge
+weights is used for weighted graphs (if \code{weighted=TRUE}). This
+argument is ignored if \code{k} is zero.}
+
+\item{weighted}{Logical scalar, TRUE if the edge weights should be used
+for computation of the scan statistic. If TRUE, the graph should be
+weighted.  Note that this argument is ignored if \code{FUN} is not
+\code{NULL}, \code{"ecount"} and \code{"sumweights"}.}
+
+\item{mode}{Character scalar, the kind of neighborhoods to use for the
+calculation. One of \sQuote{\code{out}}, \sQuote{\code{in}},
+\sQuote{\code{all}} or \sQuote{\code{total}}. This argument is ignored
+for undirected graphs.}
+
+\item{neighborhoods}{A list of neighborhoods, one for each vertex, or
+  \code{NULL}. If it is not \code{NULL}, then the function is evaluated on
+  the induced subgraphs specified by these neighborhoods.
+
+  In theory this could be useful if the same \code{graph.us} graph is used
+  for multiple \code{graph.them} arguments. Then the neighborhoods can be
+  calculated on \code{graph.us} and used with multiple graphs. In
+  practice, this is currently slower than simply using \code{graph.them}
+  multiple times.}
+
+\item{\dots}{Arguments passed to \code{FUN}, the function that computes
+the local statistics.}
+}
+\value{
+For \code{local_scan} typically a numeric vector containing the
+  computed local statistics for each vertex. In general a list or vector
+  of objects, as returned by \code{FUN}.
+}
+\description{
+The scan statistic is a summary of the locality statistics that is
+computed from the local neighborhood of each vertex. The
+\code{local_scan} function computes the local statistics for each vertex
+for a given neighborhood size and the statistic function.
+}
+\details{
+See the given reference below for the details on the local scan
+statistics.
+
+\code{local_scan} calculates exact local scan statistics.
+
+If \code{graph.them} is \code{NULL}, then \code{local_scan} computes the
+\sQuote{us} variant of the scan statistics.  Otherwise,
+\code{graph.them} should be an igraph object and the \sQuote{them}
+variant is computed using \code{graph.us} to extract the neighborhood
+information, and applying \code{FUN} on these neighborhoods in
+\code{graph.them}.
+}
+\examples{
+pair <- sample_correlated_gnp_pair(n = 10^3, corr = 0.8, p = 0.1)
+local_0_us <- local_scan(graph.us = pair$graph1, k = 0)
+local_1_us <- local_scan(graph.us = pair$graph1, k = 1)
+
+local_0_them <- local_scan(graph.us = pair$graph1,
+                           graph.them = pair$graph2, k = 0)
+local_1_them <- local_scan(graph.us = pair$graph1,
+                           graph.them = pair$graph2, k = 1)
+
+Neigh_1 <- neighborhood(pair$graph1, order = 1)
+local_1_them_nhood <- local_scan(graph.us = pair$graph1,
+                                 graph.them = pair$graph2,
+                                 neighborhoods = Neigh_1)
+}
+\references{
+Priebe, C. E., Conroy, J. M., Marchette, D. J., Park,
+  Y. (2005).  Scan Statistics on Enron Graphs. \emph{Computational and
+  Mathematical Organization Theory}.
+}
+\seealso{
+Other scan statistics: \code{\link{scan_stat}}
+}
+
diff --git a/man/make_.Rd b/man/make_.Rd
new file mode 100644
index 0000000..c6bc40f
--- /dev/null
+++ b/man/make_.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_}
+\alias{make_}
+\title{Make a new graph}
+\usage{
+make_(...)
+}
+\arguments{
+\item{...}{Parameters, see details below.}
+}
+\description{
+This is is generic function for creating graphs.
+}
+\details{
+\code{make_} is a generic function for creating graphs.
+For every graph constructor in igraph that has a \code{make_} prefix,
+there is a corresponding function without the prefix: e.g.
+for \code{\link{make_ring}} there is also \code{\link{ring}}, etc.
+
+The same is true for the random graph samplers, i.e. for each
+constructor with a \code{sample_} prefix, there is a corresponding
+function without that prefix.
+
+These shorter forms can be used together with \code{make_}.
+The advantage of this form is that the user can specify constructor
+modifiers which work with all constructors. E.g. the
+\code{link{with_vertex_}} modifier adds vertex attributes
+to the newly created graphs.
+
+See the examples and the various constructor modifiers below.
+}
+\examples{
+r <- make_(ring(10))
+l <- make_(lattice(c(3, 3, 3)))
+
+r2 <- make_(ring(10), with_vertex_(color = "red", name = LETTERS[1:10]))
+l2 <- make_(lattice(c(3, 3, 3)), with_edge_(weight = 2))
+
+ran <- sample_(degseq(c(3,3,3,3,3,3), method = "simple"), simplified())
+degree(ran)
+is_simple(ran)
+}
+\seealso{
+simplified with_edge_ with_graph_ with_vertex_
+  without_loops without_multiples
+}
+
diff --git a/man/make_bipartite_graph.Rd b/man/make_bipartite_graph.Rd
new file mode 100644
index 0000000..5625670
--- /dev/null
+++ b/man/make_bipartite_graph.Rd
@@ -0,0 +1,68 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R, R/make.R
+\name{is_bipartite}
+\alias{bipartite_graph}
+\alias{graph.bipartite}
+\alias{is.bipartite}
+\alias{is_bipartite}
+\alias{make_bipartite_graph}
+\title{Create a bipartite graph}
+\usage{
+is_bipartite(graph)
+
+make_bipartite_graph(types, edges, directed = FALSE)
+
+bipartite_graph(...)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{types}{A vector giving the vertex types. It will be coerced into
+boolean. The length of the vector gives the number of vertices in the graph.}
+
+\item{edges}{A vector giving the edges of the graph, the same way as for the
+regular \code{\link{graph}} function. It is checked that the edges indeed
+connect vertices of different kind, accoding to the supplied \code{types}
+vector.}
+
+\item{directed}{Whether to create a directed graph, boolean constant. Note
+that by default undirected graphs are created, as this is more common for
+bipartite graphs.}
+
+\item{...}{Passed to \code{make_bipartite_graph}.}
+}
+\value{
+\code{make_bipartite_graph} returns a bipartite igraph graph. In other
+words, an igraph graph that has a vertex attribute named \code{type}.
+
+\code{is_bipartite} returns a logical scalar.
+}
+\description{
+A bipartite graph has two kinds of vertices and connections are only allowed
+between different kinds.
+}
+\details{
+Bipartite graphs have a \code{type} vertex attribute in igraph, this is
+boolean and \code{FALSE} for the vertices of the first kind and \code{TRUE}
+for vertices of the second kind.
+
+\code{make_bipartite_graph} basically does three things. First it checks tha
+\code{edges} vector against the vertex \code{types}. Then it creates a graph
+using the \code{edges} vector and finally it adds the \code{types} vector as
+a vertex attribute called \code{type}.
+
+\code{is_bipartite} checks whether the graph is bipartite or not. It just
+checks whether the graph has a vertex attribute called \code{type}.
+}
+\examples{
+g <- make_bipartite_graph( rep(0:1,length=10), c(1:10))
+print(g, v=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{graph}} to create one-mode networks
+}
+\keyword{graphs}
+
diff --git a/man/make_chordal_ring.Rd b/man/make_chordal_ring.Rd
new file mode 100644
index 0000000..a1dbd1e
--- /dev/null
+++ b/man/make_chordal_ring.Rd
@@ -0,0 +1,70 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_chordal_ring}
+\alias{chordal_ring}
+\alias{graph.extended.chordal.ring}
+\alias{make_chordal_ring}
+\title{Create an extended chordal ring graph}
+\usage{
+make_chordal_ring(n, w)
+
+chordal_ring(...)
+}
+\arguments{
+\item{n}{The number of vertices.}
+
+\item{w}{A matrix which specifies the extended chordal ring. See
+details below.}
+
+\item{...}{Passed to \code{make_chordal_ring}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{make_chordal_ring} creates an extended chordal ring.
+An extended chordal ring is regular graph, each node has the same
+degree. It can be obtained from a simple ring by adding some extra
+edges specified by a matrix. Let p denote the number of columns in
+the \sQuote{\code{W}} matrix. The extra edges of vertex \code{i}
+are added according to column \code{i mod p} in
+\sQuote{\code{W}}. The number of extra edges is the number
+of rows in \sQuote{\code{W}}: for each row \code{j} an edge
+\code{i->i+w[ij]} is added if \code{i+w[ij]} is less than the number
+of total nodes. See also Kotsis, G: Interconnection Topologies for
+Parallel Processing Systems, PARS Mitteilungen 11, 1-6, 1993.
+}
+\examples{
+chord <- make_chordal_ring(15,
+    matrix(c(3, 12, 4, 7, 8, 11), nr = 2))
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+
diff --git a/man/make_clusters.Rd b/man/make_clusters.Rd
new file mode 100644
index 0000000..9ec90a0
--- /dev/null
+++ b/man/make_clusters.Rd
@@ -0,0 +1,35 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{make_clusters}
+\alias{create.communities}
+\alias{make_clusters}
+\title{Creates a communities object.}
+\usage{
+make_clusters(graph, membership = NULL, algorithm = NULL, merges = NULL,
+  modularity = TRUE)
+}
+\arguments{
+\item{graph}{The graph of the community structure.}
+
+\item{membership}{The membership vector of the community structure, a
+numeric vector denoting the id of the community for each vertex. It
+might be \code{NULL} for hierarchical community structures.}
+
+\item{algorithm}{Character string, the algorithm that generated
+the community structure, it can be arbitrary.}
+
+\item{merges}{A merge matrix, for hierarchical community structures (or
+\code{NULL} otherwise.}
+
+\item{modularity}{Modularity value of the community structure. If this
+is \code{TRUE} and the membership vector is available, then it the
+modularity values is calculated automatically.}
+}
+\value{
+A \code{communities} object.
+}
+\description{
+This is useful to integrate the results of community finding algorithms
+that are not included in igraph.
+}
+
diff --git a/man/make_de_bruijn_graph.Rd b/man/make_de_bruijn_graph.Rd
new file mode 100644
index 0000000..9f7cec5
--- /dev/null
+++ b/man/make_de_bruijn_graph.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_de_bruijn_graph}
+\alias{de_bruijn_graph}
+\alias{graph.de.bruijn}
+\alias{make_de_bruijn_graph}
+\title{De Bruijn graphs}
+\usage{
+make_de_bruijn_graph(m, n)
+
+de_bruijn_graph(...)
+}
+\arguments{
+\item{m}{Integer scalar, the size of the alphabet. See details below.}
+
+\item{n}{Integer scalar, the length of the labels. See details below.}
+
+\item{...}{Passed to \code{make_de_bruijn_graph}.}
+}
+\value{
+A graph object.
+}
+\description{
+De Bruijn graphs are labeled graphs representing the overlap of strings.
+}
+\details{
+A de Bruijn graph represents relationships between strings. An alphabet of
+\code{m} letters are used and strings of length \code{n} are considered.  A
+vertex corresponds to every possible string and there is a directed edge
+from vertex \code{v} to vertex \code{w} if the string of \code{v} can be
+transformed into the string of \code{w} by removing its first letter and
+appending a letter to it.
+
+Please note that the graph will have \code{m} to the power \code{n} vertices
+and even more edges, so probably you don't want to supply too big numbers
+for \code{m} and \code{n}.
+
+De Bruijn graphs have some interesting properties, please see another
+source, eg. Wikipedia for details.
+}
+\examples{
+# de Bruijn graphs can be created recursively by line graphs as well
+g <- make_de_bruijn_graph(2,1)
+make_de_bruijn_graph(2,2)
+make_line_graph(g)
+}
+\author{
+Gabor Csardi <csardi.gabor at gmail.com>
+}
+\seealso{
+\code{\link{make_kautz_graph}}, \code{\link{make_line_graph}}
+}
+\keyword{graphs}
+
diff --git a/man/make_empty_graph.Rd b/man/make_empty_graph.Rd
new file mode 100644
index 0000000..b893b81
--- /dev/null
+++ b/man/make_empty_graph.Rd
@@ -0,0 +1,63 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_empty_graph}
+\alias{empty_graph}
+\alias{graph.empty}
+\alias{make_empty_graph}
+\title{A graph with no edges}
+\usage{
+make_empty_graph(n = 0, directed = TRUE)
+
+empty_graph(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{directed}{Whether to create a directed graph.}
+
+\item{...}{Passed to \code{make_graph_empty}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+A graph with no edges
+}
+\examples{
+make_empty_graph(n = 10)
+make_empty_graph(n = 5, directed = FALSE)
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+\concept{
+Empty graph.
+}
+
diff --git a/man/make_full_bipartite_graph.Rd b/man/make_full_bipartite_graph.Rd
new file mode 100644
index 0000000..903625d
--- /dev/null
+++ b/man/make_full_bipartite_graph.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_full_bipartite_graph}
+\alias{full_bipartite_graph}
+\alias{graph.full.bipartite}
+\alias{make_full_bipartite_graph}
+\title{Create a full bipartite graph}
+\usage{
+make_full_bipartite_graph(n1, n2, directed = FALSE, mode = c("all", "out",
+  "in"))
+
+full_bipartite_graph(...)
+}
+\arguments{
+\item{n1}{The number of vertices of the first kind.}
+
+\item{n2}{The number of vertices of the second kind.}
+
+\item{directed}{Logical scalar, whether the graphs is directed.}
+
+\item{mode}{Scalar giving the kind of edges to create for directed graphs.
+If this is \sQuote{\code{out}} then all vertices of the first kind are
+connected to the others; \sQuote{\code{in}} specifies the opposite
+direction; \sQuote{\code{all}} creates mutual edges. This argument is
+ignored for undirected graphs.x}
+
+\item{...}{Passed to \code{make_full_bipartite_graph}.}
+}
+\value{
+An igraph graph, with the \sQuote{\code{type}} vertex attribute set.
+}
+\description{
+Bipartite graphs are also called two-mode by some. This function creates a
+bipartite graph in which every possible edge is present.
+}
+\details{
+Bipartite graphs have a \sQuote{\code{type}} vertex attribute in igraph,
+this is boolean and \code{FALSE} for the vertices of the first kind and
+\code{TRUE} for vertices of the second kind.
+}
+\examples{
+g <- make_full_bipartite_graph(2, 3)
+g2 <- make_full_bipartite_graph(2, 3, dir=TRUE)
+g3 <- make_full_bipartite_graph(2, 3, dir=TRUE, mode="in")
+g4 <- make_full_bipartite_graph(2, 3, dir=TRUE, mode="all")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{make_full_graph}} for creating one-mode full graphs
+}
+\keyword{graphs}
+
diff --git a/man/make_full_citation_graph.Rd b/man/make_full_citation_graph.Rd
new file mode 100644
index 0000000..3871aab
--- /dev/null
+++ b/man/make_full_citation_graph.Rd
@@ -0,0 +1,60 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_full_citation_graph}
+\alias{full_citation_graph}
+\alias{graph.full.citation}
+\alias{make_full_citation_graph}
+\title{Create a complete (full) citation graph}
+\usage{
+make_full_citation_graph(n, directed = TRUE)
+
+full_citation_graph(...)
+}
+\arguments{
+\item{n}{The number of vertices.}
+
+\item{directed}{Whether to create a directed graph.}
+
+\item{...}{Passed to \code{make_full_citation_graph}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{make_full_citation_graph} creates a full citation graph. This is a
+directed graph, where every \code{i->j} edge is present if and only if
+\eqn{j<i}. If \code{directed=FALSE} then the graph is just a full graph.
+}
+\examples{
+str(make_full_citation_graph(10))
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+
diff --git a/man/make_full_graph.Rd b/man/make_full_graph.Rd
new file mode 100644
index 0000000..e9c6a1c
--- /dev/null
+++ b/man/make_full_graph.Rd
@@ -0,0 +1,65 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_full_graph}
+\alias{full_graph}
+\alias{graph.full}
+\alias{make_full_graph}
+\title{Create a full graph}
+\usage{
+make_full_graph(n, directed = FALSE, loops = FALSE)
+
+full_graph(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{directed}{Whether to create a directed graph.}
+
+\item{loops}{Whether to add self-loops to the graph.}
+
+\item{...}{Passed to \code{make_full_graph}.}
+}
+\value{
+An igraph graph
+}
+\description{
+Create a full graph
+}
+\examples{
+make_full_graph(5)
+str(make_full_graph(4, directed = TRUE))
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+\concept{
+Full graph
+}
+
diff --git a/man/make_graph.Rd b/man/make_graph.Rd
new file mode 100644
index 0000000..bfffdc7
--- /dev/null
+++ b/man/make_graph.Rd
@@ -0,0 +1,211 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\encoding{UTF-8}
+\name{make_graph}
+\alias{directed_graph}
+\alias{graph}
+\alias{graph.famous}
+\alias{make_directed_graph}
+\alias{make_graph}
+\alias{make_undirected_graph}
+\alias{undirected_graph}
+\title{Create an igraph graph from a list of edges, or a notable graph}
+\usage{
+make_graph(edges, ..., n = max(edges), isolates = NULL, directed = TRUE,
+  dir = directed, simplify = TRUE)
+
+make_directed_graph(edges, n = max(edges))
+
+make_undirected_graph(edges, n = max(edges))
+
+directed_graph(...)
+
+undirected_graph(...)
+}
+\arguments{
+\item{edges}{A vector defining the edges, the first edge points
+  from the first element to the second, the second edge from the third
+  to the fourth, etc. For a numeric vector, these are interpreted
+  as internal vertex ids. For character vectors, they are interpreted
+  as vertex names.
+
+  Alternatively, this can be a character scalar, the name of a
+  notable graph. See Notable graphs below. The name is case
+  insensitive.
+
+  Starting from igraph 0.8.0, you can also include literals here,
+  via igraph's formula notation (see \code{\link{graph_from_literal}}).
+  In this case, the first term of the formula has to start with
+  a \sQuote{\code{~}} character, just like regular formulae in R.
+  See examples below.}
+
+\item{...}{For \code{make_graph}: extra arguments for the case when the
+graph is given via a literal, see \code{\link{graph_from_literal}}.
+For \code{directed_graph} and \code{undirected_graph}:
+Passed to \code{make_directed_graph} or \code{make_undirected_graph}.}
+
+\item{n}{The number of vertices in the graph. This argument is
+ignored (with a warning) if \code{edges} are symbolic vertex names. It
+is also ignored if there is a bigger vertex id in \code{edges}. This
+means that for this function it is safe to supply zero here if the
+vertex with the largest id is not an isolate.}
+
+\item{isolates}{Character vector, names of isolate vertices,
+for symbolic edge lists. It is ignored for numeric edge lists.}
+
+\item{directed}{Whether to create a directed graph.}
+
+\item{dir}{It is the same as \code{directed}, for compatibility.
+Do not give both of them.}
+
+\item{simplify}{For graph literals, whether to simplify the graph.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Create an igraph graph from a list of edges, or a notable graph
+}
+\section{Notable graphs}{
+
+
+\code{make_graph} can create some notable graphs. The name of the
+graph (case insensitive), a character scalar must be suppliced as
+the \code{edges} argument, and other arguments are ignored. (A warning
+is given is they are specified.)
+
+\code{make_graph} knows the following graphs: \describe{
+  \item{Bull}{The bull graph, 5 vertices, 5 edges, resembles to the head
+    of a bull if drawn properly.}
+  \item{Chvatal}{This is the smallest triangle-free graph that is
+    both 4-chromatic and 4-regular. According to the Grunbaum conjecture there
+    exists an m-regular, m-chromatic graph with n vertices for every m>1 and
+    n>2. The Chvatal graph is an example for m=4 and n=12. It has 24 edges.}
+  \item{Coxeter}{A non-Hamiltonian cubic symmetric graph with 28 vertices and
+    42 edges.}
+  \item{Cubical}{The Platonic graph of the cube. A convex regular
+    polyhedron with 8 vertices and 12 edges.}
+  \item{Diamond}{A graph with 4 vertices and 5 edges, resembles to a
+    schematic diamond if drawn properly.}
+  \item{Dodecahedral, Dodecahedron}{Another Platonic solid with 20 vertices
+    and 30 edges.}
+  \item{Folkman}{The semisymmetric graph with minimum number of
+    vertices, 20 and 40 edges. A semisymmetric graph is regular, edge transitive
+    and not vertex transitive.}
+  \item{Franklin}{This is a graph whose embedding
+    to the Klein bottle can be colored with six colors, it is a counterexample
+    to the neccessity of the Heawood conjecture on a Klein bottle. It has 12
+    vertices and 18 edges.}
+  \item{Frucht}{The Frucht Graph is the smallest
+    cubical graph whose automorphism group consists only of the identity
+    element. It has 12 vertices and 18 edges.}
+  \item{Grotzsch}{The Groetzsch
+    graph is a triangle-free graph with 11 vertices, 20 edges, and chromatic
+    number 4. It is named after German mathematician Herbert Groetzsch, and its
+    existence demonstrates that the assumption of planarity is necessary in
+    Groetzsch's theorem that every triangle-free planar graph is 3-colorable.}
+  \item{Heawood}{The Heawood graph is an undirected graph with 14 vertices and
+    21 edges. The graph is cubic, and all cycles in the graph have six or more
+    edges. Every smaller cubic graph has shorter cycles, so this graph is the
+    6-cage, the smallest cubic graph of girth 6.}
+  \item{Herschel}{The Herschel
+    graph is the smallest nonhamiltonian polyhedral graph. It is the unique such
+    graph on 11 nodes, and has 18 edges.}
+  \item{House}{The house graph is a
+    5-vertex, 6-edge graph, the schematic draw of a house if drawn properly,
+    basicly a triangle of the top of a square.}
+  \item{HouseX}{The same as the
+    house graph with an X in the square. 5 vertices and 8 edges.}
+  \item{Icosahedral, Icosahedron}{A Platonic solid with 12 vertices and 30
+    edges.}
+  \item{Krackhardt kite}{A social network with 10 vertices and 18
+    edges.  Krackhardt, D. Assessing the Political Landscape: Structure,
+    Cognition, and Power in Organizations.  Admin. Sci. Quart. 35, 342-369,
+    1990.}
+  \item{Levi}{The graph is a 4-arc transitive cubic graph, it has 30
+    vertices and 45 edges.}
+  \item{McGee}{The McGee graph is the unique 3-regular
+    7-cage graph, it has 24 vertices and 36 edges.}
+  \item{Meredith}{The Meredith
+    graph is a quartic graph on 70 nodes and 140 edges that is a counterexample
+    to the conjecture that every 4-regular 4-connected graph is Hamiltonian.}
+  \item{Noperfectmatching}{A connected graph with 16 vertices and 27 edges
+    containing no perfect matching. A matching in a graph is a set of pairwise
+    non-adjacent edges; that is, no two edges share a common vertex. A perfect
+    matching is a matching which covers all vertices of the graph.}
+  \item{Nonline}{A graph whose connected components are the 9 graphs whose
+    presence as a vertex-induced subgraph in a graph makes a nonline graph. It
+    has 50 vertices and 72 edges.}
+  \item{Octahedral, Octahedron}{Platonic solid
+    with 6 vertices and 12 edges.}
+  \item{Petersen}{A 3-regular graph with 10
+    vertices and 15 edges. It is the smallest hypohamiltonian graph, ie. it is
+    non-hamiltonian but removing any single vertex from it makes it
+    Hamiltonian.}
+  \item{Robertson}{The unique (4,5)-cage graph, ie. a 4-regular
+   graph of girth 5. It has 19 vertices and 38 edges.}
+  \item{Smallestcyclicgroup}{A smallest nontrivial graph whose automorphism
+    group is cyclic. It has 9 vertices and 15 edges.}
+  \item{Tetrahedral,
+    Tetrahedron}{Platonic solid with 4 vertices and 6 edges.}
+  \item{Thomassen}{The smallest hypotraceable graph, on 34 vertices and 52
+    edges. A hypotracable graph does not contain a Hamiltonian path but after
+    removing any single vertex from it the remainder always contains a
+    Hamiltonian path. A graph containing a Hamiltonian path is called tracable.}
+  \item{Tutte}{Tait's Hamiltonian graph conjecture states that every
+    3-connected 3-regular planar graph is Hamiltonian.  This graph is a
+    counterexample. It has 46 vertices and 69 edges.}
+  \item{Uniquely3colorable}{Returns a 12-vertex, triangle-free graph with
+    chromatic number 3 that is uniquely 3-colorable.}
+  \item{Walther}{An identity
+    graph with 25 vertices and 31 edges. An identity graph has a single graph
+    automorphism, the trivial one.}
+  \item{Zachary}{Social network of friendships
+    between 34 members of a karate club at a US university in the 1970s. See W.
+    W. Zachary, An information flow model for conflict and fission in small
+    groups, Journal of Anthropological Research 33, 452-473 (1977).  } }
+}
+\examples{
+make_graph(c(1, 2, 2, 3, 3, 4, 5, 6), directed = FALSE)
+make_graph(c("A", "B", "B", "C", "C", "D"), directed = FALSE)
+
+solids <- list(make_graph("Tetrahedron"),
+               make_graph("Cubical"),
+               make_graph("Octahedron"),
+               make_graph("Dodecahedron"),
+               make_graph("Icosahedron"))
+
+graph <- make_graph( ~ A-B-C-D-A, E-A:B:C:D,
+                      F-G-H-I-F, J-F:G:H:I,
+                      K-L-M-N-K, O-K:L:M:N,
+                      P-Q-R-S-P, T-P:Q:R:S,
+                      B-F, E-J, C-I, L-T, O-T, M-S,
+                      C-P, C-L, I-L, I-P)
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+
diff --git a/man/make_kautz_graph.Rd b/man/make_kautz_graph.Rd
new file mode 100644
index 0000000..e844609
--- /dev/null
+++ b/man/make_kautz_graph.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_kautz_graph}
+\alias{graph.kautz}
+\alias{kautz_graph}
+\alias{make_kautz_graph}
+\title{Kautz graphs}
+\usage{
+make_kautz_graph(m, n)
+
+kautz_graph(...)
+}
+\arguments{
+\item{m}{Integer scalar, the size of the alphabet. See details below.}
+
+\item{n}{Integer scalar, the length of the labels. See details below.}
+
+\item{...}{Passed to \code{make_kautz_graph}.}
+}
+\value{
+A graph object.
+}
+\description{
+Kautz graphs are labeled graphs representing the overlap of strings.
+}
+\details{
+A Kautz graph is a labeled graph, vertices are labeled by strings of length
+\code{n+1} above an alphabet with \code{m+1} letters, with the restriction
+that every two consecutive letters in the string must be different. There is
+a directed edge from a vertex \code{v} to another vertex \code{w} if it is
+possible to transform the string of \code{v} into the string of \code{w} by
+removing the first letter and appending a letter to it.
+
+Kautz graphs have some interesting properties, see eg. Wikipedia for
+details.
+}
+\examples{
+make_line_graph(make_kautz_graph(2,1))
+make_kautz_graph(2,2)
+}
+\author{
+Gabor Csardi <csardi.gabor at gmail.com>, the first version in R was
+written by Vincent Matossian.
+}
+\seealso{
+\code{\link{make_de_bruijn_graph}}, \code{\link{make_line_graph}}
+}
+\keyword{graphs}
+
diff --git a/man/make_lattice.Rd b/man/make_lattice.Rd
new file mode 100644
index 0000000..69652e6
--- /dev/null
+++ b/man/make_lattice.Rd
@@ -0,0 +1,83 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_lattice}
+\alias{graph.lattice}
+\alias{lattice}
+\alias{make_lattice}
+\title{Create a lattice graph}
+\usage{
+make_lattice(dimvector = NULL, length = NULL, dim = NULL, nei = 1,
+  directed = FALSE, mutual = FALSE, circular = FALSE)
+
+lattice(...)
+}
+\arguments{
+\item{dimvector}{A vector giving the size of the lattice in each
+dimension.}
+
+\item{length}{Integer constant, for regular lattices, the size of the
+lattice in each dimension.}
+
+\item{dim}{Integer constant, the dimension of the lattice.}
+
+\item{nei}{The distance within which (inclusive) the neighbors on the
+lattice will be connected. This parameter is not used right now.}
+
+\item{directed}{Whether to create a directed lattice.}
+
+\item{mutual}{Logical, if \code{TRUE} directed lattices will be
+mutually connected.}
+
+\item{circular}{Logical, if \code{TRUE} the lattice or ring will be
+circular.}
+
+\item{...}{Passed to \code{make_lattice}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{make_lattice} is a flexible function, it can create lattices of
+arbitrary dimensions, periodic or unperiodic ones. It has two
+forms. In the first form you only supply \code{dimvector}, but not
+\code{length} and \code{dim}. In the second form you omit
+\code{dimvector} and supply \code{length} and \code{dim}.
+}
+\examples{
+make_lattice(c(5, 5, 5))
+make_lattice(length = 5, dim = 3)
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}; \code{\link{graph.tree}},
+  \code{\link{make_tree}}, \code{\link{tree}}
+}
+\concept{
+Lattice
+}
+
diff --git a/man/make_line_graph.Rd b/man/make_line_graph.Rd
new file mode 100644
index 0000000..ccbe667
--- /dev/null
+++ b/man/make_line_graph.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_line_graph}
+\alias{line.graph}
+\alias{line_graph}
+\alias{make_line_graph}
+\title{Line graph of a graph}
+\usage{
+make_line_graph(graph)
+
+line_graph(...)
+}
+\arguments{
+\item{graph}{The input graph, it can be directed or undirected.}
+
+\item{...}{Passed to \code{make_line_graph}.}
+}
+\value{
+A new graph object.
+}
+\description{
+This function calculates the line graph of another graph.
+}
+\details{
+The line graph \code{L(G)} of a \code{G} undirected graph is defined as
+follows. \code{L(G)} has one vertex for each edge in \code{G} and two
+vertices in \code{L(G)} are connected by an edge if their corresponding
+edges share an end point.
+
+The line graph \code{L(G)} of a \code{G} directed graph is slightly
+different, \code{L(G)} has one vertex for each edge in \code{G} and two
+vertices in \code{L(G)} are connected by a directed edge if the target of
+the first vertex's corresponding edge is the same as the source of the
+second vertex's corresponding edge.
+}
+\examples{
+# generate the first De-Bruijn graphs
+g <- make_full_graph(2, directed=TRUE, loops=TRUE)
+make_line_graph(g)
+make_line_graph(make_line_graph(g))
+make_line_graph(make_line_graph(make_line_graph(g)))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}, the first version of
+the C code was written by Vincent Matossian.
+}
+\keyword{graphs}
+
diff --git a/man/make_ring.Rd b/man/make_ring.Rd
new file mode 100644
index 0000000..32dc495
--- /dev/null
+++ b/man/make_ring.Rd
@@ -0,0 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_ring}
+\alias{graph.ring}
+\alias{make_ring}
+\alias{ring}
+\title{Create a ring graph}
+\usage{
+make_ring(n, directed = FALSE, mutual = FALSE, circular = TRUE)
+
+ring(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{directed}{Whether the graph is directed.}
+
+\item{mutual}{Whether directed edges are mutual. It is ignored in
+undirected graphs.}
+
+\item{circular}{Whether to create a circular ring. A non-circular
+ring is essentially a \dQuote{line}: a tree where every non-leaf
+vertex has one child.}
+
+\item{...}{Passed to \code{make_ring}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+A ring is a one-dimensional lattice and this function is a special case
+of \code{\link{make_lattice}}.
+}
+\examples{
+str(make_ring(10))
+str(make_ring(10, directed = TRUE, mutual = TRUE))
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.star}},
+  \code{\link{make_star}}, \code{\link{star}};
+  \code{\link{graph.tree}}, \code{\link{make_tree}},
+  \code{\link{tree}}
+}
+
diff --git a/man/make_star.Rd b/man/make_star.Rd
new file mode 100644
index 0000000..8583732
--- /dev/null
+++ b/man/make_star.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_star}
+\alias{graph.star}
+\alias{make_star}
+\alias{star}
+\title{Create a star graph, a tree with n vertices and n - 1 leaves}
+\usage{
+make_star(n, mode = c("in", "out", "mutual", "undirected"), center = 1)
+
+star(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{mode}{It defines the direction of the
+edges, \code{in}: the edges point \emph{to} the center, \code{out}:
+the edges point \emph{from} the center, \code{mutual}: a directed
+star is created with mutual edges, \code{undirected}: the edges
+are undirected.}
+
+\item{center}{ID of the center vertex.}
+
+\item{...}{Passed to \code{make_star}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{star} creates a star graph, in this every single vertex is
+connected to the center vertex and nobody else.
+}
+\examples{
+make_star(10, mode = "out")
+make_star(5, mode = "undirected")
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.tree}}, \code{\link{make_tree}},
+  \code{\link{tree}}
+}
+\concept{
+Star graph
+}
+
diff --git a/man/make_tree.Rd b/man/make_tree.Rd
new file mode 100644
index 0000000..6a153de
--- /dev/null
+++ b/man/make_tree.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{make_tree}
+\alias{graph.tree}
+\alias{make_tree}
+\alias{tree}
+\title{Create tree graphs}
+\usage{
+make_tree(n, children = 2, mode = c("out", "in", "undirected"))
+
+tree(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{children}{Integer scalar, the number of children of a vertex
+(except for leafs)}
+
+\item{mode}{Defines the direction of the
+edges. \code{out} indicates that the edges point from the parent to
+the children, \code{in} indicates that they point from the children
+to their parents, while \code{undirected} creates an undirected
+graph.}
+
+\item{...}{Passed to \code{make_tree}.}
+}
+\value{
+An igraph graph
+}
+\description{
+Create a regular tree graph.
+}
+\examples{
+make_tree(10, 2)
+make_tree(10, 3, mode = "undirected")
+}
+\seealso{
+Other determimistic constructors: \code{\link{atlas}},
+  \code{\link{graph.atlas}},
+  \code{\link{graph_from_atlas}};
+  \code{\link{chordal_ring}},
+  \code{\link{graph.extended.chordal.ring}},
+  \code{\link{make_chordal_ring}};
+  \code{\link{directed_graph}}, \code{\link{graph}},
+  \code{\link{graph.famous}},
+  \code{\link{make_directed_graph}},
+  \code{\link{make_graph}},
+  \code{\link{make_undirected_graph}},
+  \code{\link{undirected_graph}};
+  \code{\link{empty_graph}}, \code{\link{graph.empty}},
+  \code{\link{make_empty_graph}};
+  \code{\link{from_edgelist}},
+  \code{\link{graph.edgelist}},
+  \code{\link{graph_from_edgelist}};
+  \code{\link{from_literal}}, \code{\link{graph.formula}},
+  \code{\link{graph_from_literal}};
+  \code{\link{full_citation_graph}},
+  \code{\link{graph.full.citation}},
+  \code{\link{make_full_citation_graph}};
+  \code{\link{full_graph}}, \code{\link{graph.full}},
+  \code{\link{make_full_graph}};
+  \code{\link{graph.lattice}}, \code{\link{lattice}},
+  \code{\link{make_lattice}}; \code{\link{graph.ring}},
+  \code{\link{make_ring}}, \code{\link{ring}};
+  \code{\link{graph.star}}, \code{\link{make_star}},
+  \code{\link{star}}
+}
+\concept{
+Trees.
+}
+
diff --git a/man/match_vertices.Rd b/man/match_vertices.Rd
new file mode 100644
index 0000000..32efc64
--- /dev/null
+++ b/man/match_vertices.Rd
@@ -0,0 +1,80 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/sgm.R
+\name{match_vertices}
+\alias{match_vertices}
+\alias{seeded.graph.match}
+\title{Match Graphs given a seeding of vertex correspondences}
+\usage{
+match_vertices(A, B, m, start, iteration)
+}
+\arguments{
+\item{A}{a numeric matrix, the adjacency matrix of the first graph}
+
+\item{B}{a numeric matrix, the adjacency matrix of the second graph}
+
+\item{m}{The number of seeds. The first \code{m} vertices of both graphs are
+matched.}
+
+\item{start}{a numeric matrix, the permutation matrix estimate is
+initialized with \code{start}}
+
+\item{iteration}{The number of iterations for the Frank-Wolfe algorithm}
+}
+\value{
+A numeric matrix which is the permutation matrix that determines the
+bijection between the graphs of \code{A} and \code{B}
+}
+\description{
+Given two adjacency matrices \code{A} and \code{B} of the same size, match
+the two graphs with the help of \code{m} seed vertex pairs which correspond
+to the first \code{m} rows (and columns) of the adjacency matrices.
+}
+\details{
+The approximate graph matching problem is to find a bijection between the
+vertices of two graphs , such that the number of edge disagreements between
+the corresponding vertex pairs is minimized. For seeded graph matching, part
+of the bijection that consist of known correspondences (the seeds) is known
+and the problem task is to complete the bijection by estimating the
+permutation matrix that permutes the rows and columns of the adjacency
+matrix of the second graph.
+
+It is assumed that for the two supplied adjacency matrices \code{A} and
+\code{B}, both of size \eqn{n\times n}{n*n}, the first \eqn{m} rows(and
+columns) of \code{A} and \code{B} correspond to the same vertices in both
+graphs. That is, the \eqn{n \times n}{n*n} permutation matrix that defines
+the bijection is \eqn{I_{m} \bigoplus P} for a \eqn{(n-m)\times
+(n-m)}{(n-m)*(n-m)} permutation matrix \eqn{P} and \eqn{m} times \eqn{m}
+identity matrix \eqn{I_{m}}. The function \code{match_vertices} estimates
+the permutation matrix \eqn{P} via an optimization algorithm based on the
+Frank-Wolfe algorithm.
+
+See references for further details.
+}
+\examples{
+#require(Matrix)
+ g1 <- erdos.renyi.game(10, .1)
+ randperm <- c(1:3, 3+sample(7))
+ g2 <- sample_correlated_gnp(g1, corr=1, p=g1$p, perm=randperm)
+ A  <- as.matrix(get.adjacency(g1))
+ B  <- as.matrix(get.adjacency(g2))
+ P  <-match_vertices (A, B, m=3, start=diag(rep(1, nrow(A)-3)), 20)
+ P
+ #'
+}
+\author{
+Vince Lyzinski \url{http://www.ams.jhu.edu/~lyzinski/}
+}
+\references{
+Vogelstein, J. T., Conroy, J. M., Podrazik, L. J., Kratzer, S.
+G., Harley, E. T., Fishkind, D. E.,Vogelstein, R. J., Priebe, C. E. (2011).
+Fast Approximate Quadratic Programming for Large (Brain) Graph Matching.
+Online: \url{http://arxiv.org/abs/1112.5507}
+
+Fishkind, D. E., Adali, S., Priebe, C. E. (2012). Seeded Graph Matching
+Online: \url{http://arxiv.org/abs/1209.0367}
+}
+\seealso{
+\code{\link{sample_correlated_gnp}},\code{\link{sample_correlated_gnp_pair}}
+}
+\keyword{graphs}
+
diff --git a/man/matching.Rd b/man/matching.Rd
index 87080f4..fbb4cf1 100644
--- a/man/matching.Rd
+++ b/man/matching.Rd
@@ -1,76 +1,51 @@
-\name{graph.matching}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{is_matching}
 \alias{is.matching}
 \alias{is.maximal.matching}
+\alias{is_matching}
+\alias{is_max_matching}
+\alias{max_bipartite_match}
 \alias{maximum.bipartite.matching}
-\concept{Matching}
-\concept{Maximal matching}
-\concept{Maximum bipartite matching}
 \title{Graph matching}
-\description{A matching in a graph means the selection of a set of edges
-  that are pairwise non-adjacenct, i.e. they have no common incident
-  vertices. A matching is maximal if it is not a proper subset of any
-  other matching.}
 \usage{
-is.matching(graph, matching, types = NULL)
-is.maximal.matching(graph, matching, types = NULL)
-maximum.bipartite.matching(graph, types = NULL, weights = NULL,
-       eps = .Machine$double.eps)
+is_matching(graph, matching, types = NULL)
+
+is_max_matching(graph, matching, types = NULL)
+
+max_bipartite_match(graph, types = NULL, weights = NULL,
+  eps = .Machine$double.eps)
 }
 \arguments{
-  \item{graph}{The input graph. It might be directed, but edge directions
-    will be ignored.}
-  \item{types}{Vertex types, if the graph is bipartite. By default they
-    are taken from the \sQuote{\code{type}} vertex attribute, if
-    present.}
-  \item{matching}{A potential matching. An integer vector that gives the
-    pair in the matching for each vertex. For vertices without a pair,
-    supply \code{NA} here.}
-  \item{weights}{Potential edge weights. If the graph has an edge
-    attribute called \sQuote{\code{weight}}, and this argument is
-    \code{NULL}, then the edge attribute is used automatically.}
-  \item{eps}{A small real number used in equality tests in the weighted
-    bipartite matching algorithm. Two real numbers are considered
-    equal in the algorithm if their difference is smaller than
-    \code{eps}. This is required to avoid the accumulation of numerical
-    errors. By default it is set to the smallest \eqn{x}, such that
-    \eqn{1+x \ne 1}{1+x != 1} holds. If you are running the algorithm
-    with no  weights, this argument is ignored.}
-}
-\details{
-  \code{is.matching} checks a matching vector and verifies whether its
-  length matches the number of vertices in the given graph, its values
-  are between zero (inclusive) and the number of vertices (inclusive),
-  and whether there exists a corresponding edge in the graph for every
-  matched vertex pair. For bipartite graphs, it also verifies whether
-  the matched vertices are in different parts of the graph.
+\item{graph}{The input graph. It might be directed, but edge directions will
+be ignored.}
 
-  \code{is.maximal.matching} checks whether a matching is maximal.
-  A matching is maximal if and only if there exists no unmatched vertex
-  in a graph such that one of its neighbors is also unmatched.
+\item{matching}{A potential matching. An integer vector that gives the
+pair in the matching for each vertex. For vertices without a pair,
+supply \code{NA} here.}
 
-  \code{maximum.bipartite.matching} calculates a maximum matching in a
-  bipartite graph. A matching in a bipartite graph is a partial
-  assignment of vertices of the first kind to vertices of the second
-  kind such that each vertex of the first kind is matched to at most one
-  vertex of the second kind and vice versa, and matched vertices must be
-  connected by an edge in the graph. The size (or cardinality) of a
-  matching is the number of edges. A matching is a maximum matching if
-  there exists no other matching with larger cardinality. For weighted
-  graphs, a maximum matching is a matching whose edges have the largest
-  possible total weight among all possible matchings.
- 
-  Maximum matchings in bipartite graphs are found by the push-relabel
-  algorithm with greedy initialization and a global relabeling after
-  every \eqn{n/2} steps where \eqn{n} is the number of vertices in the
-  graph.
+\item{types}{Vertex types, if the graph is bipartite. By default they
+are taken from the \sQuote{\code{type}} vertex attribute, if present.}
+
+\item{weights}{Potential edge weights. If the graph has an edge
+attribute called \sQuote{\code{weight}}, and this argument is
+\code{NULL}, then the edge attribute is used automatically.}
+
+\item{eps}{A small real number used in equality tests in the weighted
+bipartite matching algorithm. Two real numbers are considered equal in
+the algorithm if their difference is smaller than \code{eps}. This is
+required to avoid the accumulation of numerical errors. By default it is
+set to the smallest \eqn{x}, such that \eqn{1+x \ne 1}{1+x != 1}
+holds. If you are running the algorithm with no weights, this argument
+is ignored.}
 }
 \value{
-  \code{is.matching} and \code{is.maximal.matching} return a logical
-  scalar.
+\code{is_matching} and \code{is_max_matching} return a logical
+scalar.
 
-  \code{maximum.bipartite.matching} returns a list with components:
-  \item{matching_size}{The size of the matching, i.e. the number of
-    edges connecting the matched vertices.}
+\code{max_bipartite_match} returns a list with components:
+  \item{matching_size}{The size of the matching, i.e. the number of edges
+    connecting the matched vertices.}
   \item{matching_weight}{The weights of the matching, if the graph was
     weighted. For unweighted graphs this is the same as the size of the
     matching.}
@@ -78,27 +53,62 @@ maximum.bipartite.matching(graph, types = NULL, weights = NULL,
     names if the graph was named. Non-matched vertices are denoted by
     \code{NA}.}
 }
-% \references{}
-\author{Tamas Nepusz \email{ntamas at gmail.com}}
+\description{
+A matching in a graph means the selection of a set of edges that are
+pairwise non-adjacenct, i.e. they have no common incident vertices. A
+matching is maximal if it is not a proper subset of any other matching.
+}
+\details{
+\code{is_matching} checks a matching vector and verifies whether its
+length matches the number of vertices in the given graph, its values are
+between zero (inclusive) and the number of vertices (inclusive), and
+whether there exists a corresponding edge in the graph for every matched
+vertex pair. For bipartite graphs, it also verifies whether the matched
+vertices are in different parts of the graph.
+
+\code{is_max_matching} checks whether a matching is maximal.  A matching
+is maximal if and only if there exists no unmatched vertex in a graph
+such that one of its neighbors is also unmatched.
+
+\code{max_bipartite_match} calculates a maximum matching in a bipartite
+graph. A matching in a bipartite graph is a partial assignment of
+vertices of the first kind to vertices of the second kind such that each
+vertex of the first kind is matched to at most one vertex of the second
+kind and vice versa, and matched vertices must be connected by an edge
+in the graph. The size (or cardinality) of a matching is the number of
+edges. A matching is a maximum matching if there exists no other
+matching with larger cardinality.  For weighted graphs, a maximum
+matching is a matching whose edges have the largest possible total
+weight among all possible matchings.
+
+Maximum matchings in bipartite graphs are found by the push-relabel
+algorithm with greedy initialization and a global relabeling after every
+\eqn{n/2} steps where \eqn{n} is the number of vertices in the graph.
+}
 \examples{
-g <- graph.formula( a-b-c-d-e-f )
+g <- graph_from_literal( a-b-c-d-e-f )
 m1 <- c("b", "a", "d", "c", "f", "e")   # maximal matching
 m2 <- c("b", "a", "d", "c", NA, NA)     # non-maximal matching
 m3 <- c("b", "c", "d", "c", NA, NA)     # not a matching
-is.matching(g, m1)
-is.matching(g, m2)
-is.matching(g, m3)
-is.maximal.matching(g, m1)
-is.maximal.matching(g, m2)
-is.maximal.matching(g, m3)
+is_matching(g, m1)
+is_matching(g, m2)
+is_matching(g, m3)
+is_max_matching(g, m1)
+is_max_matching(g, m2)
+is_max_matching(g, m3)
 
 V(g)$type <- c(FALSE,TRUE)
 str(g, v=TRUE)
-maximum.bipartite.matching(g)
+max_bipartite_match(g)
 
-g2 <- graph.formula( a-b-c-d-e-f-g )
+g2 <- graph_from_literal( a-b-c-d-e-f-g )
 V(g2)$type <- rep(c(FALSE,TRUE), length=vcount(g2))
 str(g2, v=TRUE)
-maximum.bipartite.matching(g2)
+max_bipartite_match(g2)
+#'
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
 }
 \keyword{graphs}
+
diff --git a/man/max_cardinality.Rd b/man/max_cardinality.Rd
new file mode 100644
index 0000000..16e55e0
--- /dev/null
+++ b/man/max_cardinality.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/paths.R
+\name{max_cardinality}
+\alias{max_cardinality}
+\alias{maximum.cardinality.search}
+\title{Maximum cardinality search}
+\usage{
+max_cardinality(graph)
+}
+\arguments{
+\item{graph}{The input graph. It may be directed, but edge directions are
+ignored, as the algorithm is defined for undirected graphs.}
+}
+\value{
+A list with two components: \item{alpha}{Numeric vector. The
+vertices ordered according to the maximum cardinality search.}
+\item{alpham1}{Numeric vector. The inverse of \code{alpha}.}
+}
+\description{
+Maximum cardinality search is a simple ordering a vertices that is useful in
+determining the chordality of a graph.
+}
+\details{
+Maximum cardinality search visits the vertices in such an order that every
+time the vertex with the most already visited neighbors is visited. Ties are
+broken randomly.
+
+The algorithm provides a simple basis for deciding whether a graph is
+chordal, see References below, and also \code{\link{is_chordal}}.
+}
+\examples{
+## The examples from the Tarjan-Yannakakis paper
+g1 <- graph_from_literal(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
+                E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
+                I-A:H)
+max_cardinality(g1)
+is_chordal(g1, fillin=TRUE)
+
+g2 <- graph_from_literal(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
+                E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
+                I-G:H:J, J-H:I)
+max_cardinality(g2)
+is_chordal(g2, fillin=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
+linear-time algorithms to test chordality of graphs, test acyclicity of
+hypergraphs, and selectively reduce acyclic hypergraphs.  \emph{SIAM Journal
+of Computation} 13, 566--579.
+}
+\seealso{
+\code{\link{is_chordal}}
+}
+\keyword{graphs}
+
diff --git a/man/max_flow.Rd b/man/max_flow.Rd
new file mode 100644
index 0000000..5e7a73a
--- /dev/null
+++ b/man/max_flow.Rd
@@ -0,0 +1,77 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{max_flow}
+\alias{graph.maxflow}
+\alias{max_flow}
+\title{Maximum flow in a graph}
+\usage{
+max_flow(graph, source, target, capacity = NULL)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{source}{The id of the source vertex.}
+
+\item{target}{The id of the target vertex (sometimes also called sink).}
+
+\item{capacity}{Vector giving the capacity of the edges. If this is
+\code{NULL} (the default) then the \code{capacity} edge attribute is used.}
+}
+\value{
+A named list with components:
+  \item{value}{A numeric scalar, the value of the maximum flow.}
+  \item{flow}{A numeric vector, the flow itself, one entry for each
+    edge. For undirected graphs this entry is bit trickier, since for
+    these the flow direction is not predetermined by the edge
+    direction. For these graphs the elements of the this vector can be
+    negative, this means that the flow goes from the bigger vertex id to
+    the smaller one. Positive values mean that the flow goes from
+    the smaller vertex id to the bigger one.}
+  \item{cut}{A numeric vector of edge ids, the minimum cut corresponding
+    to the maximum flow.}
+  \item{partition1}{A numeric vector of vertex ids, the vertices in the
+    first partition of the minimum cut corresponding to the maximum
+    flow.}
+  \item{partition2}{A numeric vector of vertex ids, the vertices in the
+    second partition of the minimum cut corresponding to the maximum
+    flow.}
+  \item{stats}{A list with some statistics from the push-relabel
+    algorithm. Five integer values currently: \code{nopush} is the
+    number of push operations, \code{norelabel} the number of
+    relabelings, \code{nogap} is the number of times the gap heuristics
+    was used, \code{nogapnodes} is the total number of gap nodes omitted
+    because of the gap heuristics and \code{nobfs} is the number of
+    times a global breadth-first-search update was performed to assign
+    better height (=distance) values to the vertices.}
+}
+\description{
+In a graph where each edge has a given flow capacity the maximal flow
+between two vertices is calculated.
+}
+\details{
+\code{max_flow} calculates the maximum flow between two vertices in a
+weighted (ie. valued) graph. A flow from \code{source} to \code{target} is
+an assignment of non-negative real numbers to the edges of the graph,
+satisfying two properties: (1) for each edge the flow (ie. the assigned
+number) is not more than the capacity of the edge (the \code{capacity}
+parameter or edge attribute), (2) for every vertex, except the source and
+the target the incoming flow is the same as the outgoing flow. The value of
+the flow is the incoming flow of the \code{target} vertex. The maximum flow
+is the flow of maximum value.
+}
+\examples{
+E <- rbind( c(1,3,3), c(3,4,1), c(4,2,2), c(1,5,1), c(5,6,2), c(6,2,10))
+colnames(E) <- c("from", "to", "capacity")
+g1 <- graph_from_data_frame(as.data.frame(E))
+max_flow(g1, source=V(g1)["1"], target=V(g1)["2"])
+}
+\references{
+A. V. Goldberg and R. E. Tarjan: A New Approach to the Maximum
+Flow Problem \emph{Journal of the ACM} 35:921-940, 1988.
+}
+\seealso{
+\code{\link{min_cut}} for minimum cut calculations,
+  \code{\link{distances}}, \code{\link{edge_connectivity}},
+  \code{\link{vertex_connectivity}}
+}
+
diff --git a/man/maximum.cardinality.search.Rd b/man/maximum.cardinality.search.Rd
deleted file mode 100644
index 8490e8e..0000000
--- a/man/maximum.cardinality.search.Rd
+++ /dev/null
@@ -1,49 +0,0 @@
-\name{maximum.cardinality.search}
-\alias{maximum.cardinality.search}
-\concept{maximum cardinality search}
-\concept{graph decomposition}
-\concept{chordal graph}
-\title{Maximum cardinality search}
-\description{Maximum cardinality search is a simple ordering a vertices
-  that is useful in determining the chordality of a graph.}
-\usage{
-maximum.cardinality.search(graph)
-}
-\arguments{
-  \item{graph}{The input graph. It may be directed, but edge directions
-    are ignored, as the algorithm is defined for undirected graphs.}
-}
-\details{
-  Maximum cardinality search visits the vertices in such an order that
-  every time the vertex with the most already visited neighbors is
-  visited. Ties are broken randomly.
-
-  The algorithm provides a simple basis for deciding whether a graph is
-  chordal, see References below, and also \code{\link{is.chordal}}.
-}
-\value{A list with two components:
-  \item{alpha}{Numeric vector. The vertices ordered according to the maximum cardinality
-    search.}
-  \item{alpham1}{Numeric vector. The inverse of \code{alpha}.}
-}
-\references{ Robert E Tarjan and Mihalis Yannakakis. (1984). Simple
-  linear-time algorithms to test chordality of graphs, test acyclicity
-  of hypergraphs, and selectively reduce acyclic hypergraphs.
-  \emph{SIAM Journal of Computation} 13, 566--579.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{is.chordal}} }
-\examples{
-## The examples from the Tarjan-Yannakakis paper
-g1 <- graph.formula(A-B:C:I, B-A:C:D, C-A:B:E:H, D-B:E:F,
-                    E-C:D:F:H, F-D:E:G, G-F:H, H-C:E:G:I,
-                    I-A:H)
-maximum.cardinality.search(g1)
-is.chordal(g1, fillin=TRUE)
-
-g2 <- graph.formula(A-B:E, B-A:E:F:D, C-E:D:G, D-B:F:E:C:G,
-                    E-A:B:C:D:F, F-B:D:E, G-C:D:H:I, H-G:I:J,
-                    I-G:H:J, J-H:I)
-maximum.cardinality.search(g2)
-is.chordal(g2, fillin=TRUE)
-}
-\keyword{graphs}
diff --git a/man/merge_coords.Rd b/man/merge_coords.Rd
new file mode 100644
index 0000000..4b09824
--- /dev/null
+++ b/man/merge_coords.Rd
@@ -0,0 +1,106 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{merge_coords}
+\alias{layout.merge}
+\alias{layout_components}
+\alias{merge_coords}
+\alias{piecewise.layout}
+\title{Merging graph layouts}
+\usage{
+merge_coords(graphs, layouts, method = "dla")
+
+layout_components(graph, layout = layout_with_kk, ...)
+}
+\arguments{
+\item{graphs}{A list of graph objects.}
+
+\item{layouts}{A list of two-column matrices.}
+
+\item{method}{Character constant giving the method to use. Right now only
+\code{dla} is implemented.}
+
+\item{graph}{The input graph.}
+
+\item{layout}{A function object, the layout function to use.}
+
+\item{\dots}{Additional arguments to pass to the \code{layout} layout
+function.}
+}
+\value{
+A matrix with two columns and as many lines as the total number of
+vertices in the graphs.
+}
+\description{
+Place several graphs on the same layout
+}
+\details{
+\code{merge_coords} takes a list of graphs and a list of coordinates and
+places the graphs in a common layout. The method to use is chosen via the
+\code{method} parameter, although right now only the \code{dla} method is
+implemented.
+
+The \code{dla} method covers the graph with circles.  Then it sorts the
+graphs based on the number of vertices first and places the largest graph at
+the center of the layout. Then the other graphs are placed in decreasing
+order via a DLA (diffision limited aggregation) algorithm: the graph is
+placed randomly on a circle far away from the center and a random walk is
+conducted until the graph walks into the larger graphs already placed or
+walks too far from the center of the layout.
+
+The \code{layout_components} function disassembles the graph first into
+maximal connected components and calls the supplied \code{layout} function
+for each component separately. Finally it merges the layouts via calling
+\code{merge_coords}.
+}
+\examples{
+# create 20 scale-free graphs and place them in a common layout
+graphs <- lapply(sample(5:20, 20, replace=TRUE),
+          barabasi.game, directed=FALSE)
+layouts <- lapply(graphs, layout_with_kk)
+lay <- merge_coords(graphs, layouts)
+g <- disjoint_union(graphs)
+\dontrun{plot(g, layout=lay, vertex.size=3, labels=NA, edge.color="black")}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{plot.igraph}}, \code{\link{tkplot}},
+\code{\link{layout}}, \code{\link{disjoint_union}}
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.norm}},
+  \code{\link{norm_coords}}; \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/min_cut.Rd b/man/min_cut.Rd
new file mode 100644
index 0000000..7bd83ab
--- /dev/null
+++ b/man/min_cut.Rd
@@ -0,0 +1,81 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{min_cut}
+\alias{graph.mincut}
+\alias{min_cut}
+\title{Minimum cut in a graph}
+\usage{
+min_cut(graph, source = NULL, target = NULL, capacity = NULL,
+  value.only = TRUE)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{source}{The id of the source vertex.}
+
+\item{target}{The id of the target vertex (sometimes also called sink).}
+
+\item{capacity}{Vector giving the capacity of the edges. If this is
+\code{NULL} (the default) then the \code{capacity} edge attribute is used.}
+
+\item{value.only}{Logical scalar, if \code{TRUE} only the minumum cut value
+is returned, if \code{FALSE} the edges in the cut and a the two (or more)
+partitions are also returned.}
+}
+\value{
+For \code{min_cut} a numeric constant, the value of the minimum
+cut, except if \code{value.only = FALSE}. In this case a named list with
+components:
+  \item{value}{Numeric scalar, the cut value.}
+  \item{cut}{Numeric vector, the edges in the cut.}
+  \item{partition1}{The vertices in the first partition after the cut
+    edges are removed. Note that these vertices might be actually in
+    different components (after the cut edges are removed), as the graph
+    may fall apart into more than two components.}
+  \item{partition2}{The vertices in the second partition
+    after the cut edges are removed. Note that these vertices might be
+    actually in different components (after the cut edges are removed), as
+    the graph may fall apart into more than two components.}
+}
+\description{
+\code{min_cut} calculates the minimum st-cut between two vertices in a graph
+(if the \code{source} and \code{target} arguments are given) or the minimum
+cut of the graph (if both \code{source} and \code{target} are \code{NULL}).
+}
+\details{
+The minimum st-cut between \code{source} and \code{target} is the minimum
+total weight of edges needed to remove to eliminate all paths from
+\code{source} to \code{target}.
+
+The minimum cut of a graph is the minimum total weight of the edges needed
+to remove to separate the graph into (at least) two components. (Which is to
+make the graph \emph{not} strongly connected in the directed case.)
+
+The maximum flow between two vertices in a graph is the same as the minimum
+st-cut, so \code{max_flow} and \code{min_cut} essentially calculate the same
+quantity, the only difference is that \code{min_cut} can be invoked without
+giving the \code{source} and \code{target} arguments and then minimum of all
+possible minimum cuts is calculated.
+
+For undirected graphs the Stoer-Wagner algorithm (see reference below) is
+used to calculate the minimum cut.
+}
+\examples{
+g <- make_ring(100)
+min_cut(g, capacity=rep(1,vcount(g)))
+min_cut(g, value.only=FALSE, capacity=rep(1,vcount(g)))
+
+g2 <- graph( c(1,2,2,3,3,4, 1,6,6,5,5,4, 4,1) )
+E(g2)$capacity <- c(3,1,2, 10,1,3, 2)
+min_cut(g2, value.only=FALSE)
+}
+\references{
+M. Stoer and F. Wagner: A simple min-cut algorithm,
+\emph{Journal of the ACM}, 44 585-591, 1997.
+}
+\seealso{
+\code{\link{max_flow}} for the related maximum flow
+  problem, \code{\link{distances}}, \code{\link{edge_connectivity}},
+  \code{\link{vertex_connectivity}}
+}
+
diff --git a/man/min_separators.Rd b/man/min_separators.Rd
new file mode 100644
index 0000000..c97166f
--- /dev/null
+++ b/man/min_separators.Rd
@@ -0,0 +1,81 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{min_separators}
+\alias{min_separators}
+\alias{minimum.size.separators}
+\title{Minimum size vertex separators}
+\usage{
+min_separators(graph)
+}
+\arguments{
+\item{graph}{The input graph. It may be directed, but edge directions are
+ignored.}
+}
+\value{
+A list of numeric vectors. Each numeric vector is a vertex
+separator.
+}
+\description{
+Find all vertex sets of minimal size whose removal separates the graph into
+more components
+}
+\details{
+This function implements the Kanevsky algorithm for finding all minimal-size
+vertex separators in an undirected graph. See the reference below for the
+details.
+
+In the special case of a fully connected input graph with \eqn{n} vertices,
+all subsets of size \eqn{n-1} are listed as the result.
+}
+\examples{
+# The graph from the Moody-White paper
+mw <- graph.formula(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
+                    5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
+                    10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
+                    17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
+                    21-22:23, 22-23)
+
+# Cohesive subgraphs
+mw1 <- induced.subgraph(mw, as.character(c(1:7, 17:23)))
+mw2 <- induced.subgraph(mw, as.character(7:16))
+mw3 <- induced.subgraph(mw, as.character(17:23))
+mw4 <- induced.subgraph(mw, as.character(c(7,8,11,14)))
+mw5 <- induced.subgraph(mw, as.character(1:7))
+
+min_separators(mw)
+min_separators(mw1)
+min_separators(mw2)
+min_separators(mw3)
+min_separators(mw4)
+min_separators(mw5)
+
+# Another example, the science camp network
+camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
+                      Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
+                      Holly   - Carol:Pat:Pam:Jennie:Bill,
+                      Bill    - Pauline:Michael:Lee:Holly,
+                      Pauline - Bill:Jennie:Ann,
+                      Jennie  - Holly:Michael:Lee:Ann:Pauline,
+                      Michael - Bill:Jennie:Ann:Lee:John,
+                      Ann     - Michael:Jennie:Pauline,
+                      Lee     - Michael:Bill:Jennie,
+                      Gery    - Pat:Steve:Russ:John,
+                      Russ    - Steve:Bert:Gery:John,
+                      John    - Gery:Russ:Michael)
+min_separators(camp)
+}
+\references{
+Arkady Kanevsky: Finding all minimum-size separating vertex sets
+in a graph. \emph{Networks} 23 533--541, 1993.
+
+JS Provan and DR Shier: A Paradigm for listing (s,t)-cuts in graphs,
+\emph{Algorithmica} 15, 351--372, 1996.
+
+J. Moody and D. R. White. Structural cohesion and embeddedness: A
+hierarchical concept of social groups. \emph{American Sociological Review},
+68 103--127, Feb 2003.
+}
+\seealso{
+\code{\link{is.separator}}
+}
+
diff --git a/man/min_st_separators.Rd b/man/min_st_separators.Rd
new file mode 100644
index 0000000..5afc8c4
--- /dev/null
+++ b/man/min_st_separators.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{min_st_separators}
+\alias{min_st_separators}
+\alias{minimal.st.separators}
+\title{Minimum size vertex separators}
+\usage{
+min_st_separators(graph)
+}
+\arguments{
+\item{graph}{The input graph. It may be directed, but edge directions are
+ignored.}
+}
+\value{
+A list of numeric vectors. Each vector contains a vertex set
+(defined by vertex ids), each vector is an (s,t) separator of the input
+graph, for some \eqn{s} and \eqn{t}.
+}
+\description{
+List all vertex sets that are minimal (s,t) separators for some s and t, in
+an undirected graph.
+}
+\details{
+A \eqn{(s,t)} vertex separator is a set of vertices, such that after their
+removal from the graph, there is no path between \eqn{s} and \eqn{t} in the
+graph.
+
+A \eqn{(s,t)} vertex separator is minimal if none of its subsets is an
+\eqn{(s,t)} vertex separator.
+}
+\examples{
+ring <- make_ring(4)
+min_st_separators(ring)
+
+chvatal <- make_graph("chvatal")
+min_st_separators(chvatal)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Anne Berry, Jean-Paul Bordat and Olivier Cogis: Generating All
+the Minimal Separators of a Graph, In: Peter Widmayer, Gabriele Neyer and
+Stephan Eidenbenz (editors): \emph{Graph-theoretic concepts in computer
+science}, 1665, 167--172, 1999. Springer.
+}
+\keyword{graphs}
+
diff --git a/man/minimal.st.separators.Rd b/man/minimal.st.separators.Rd
deleted file mode 100644
index ca7de2e..0000000
--- a/man/minimal.st.separators.Rd
+++ /dev/null
@@ -1,43 +0,0 @@
-\name{minimal.st.separators}
-\alias{minimal.st.separators}
-\concept{Minimal (s,t) separators}
-\concept{Vertex separator}
-\title{Minimum size vertex separators}
-\description{List all vertex sets that are minimal (s,t) separators for
-  some s and t, in an undirected graph.}
-\usage{
-minimal.st.separators(graph)
-}
-\arguments{
-  \item{graph}{The input graph. It may be directed, but edge directions
-    are ignored.}
-}
-\details{
-  A \eqn{(s,t)} vertex separator is a set of vertices, such that after
-  their removal from the graph, there is no path between \eqn{s} and
-  \eqn{t} in the graph.
-
-  A \eqn{(s,t)} vertex separator is minimal if none of its subsets is an
-  \eqn{(s,t)} vertex separator.
-}
-\value{
-  A list of numeric vectors. Each vector contains a vertex set (defined
-  by vertex ids), each vector is an (s,t) separator of the input graph,
-  for some \eqn{s} and \eqn{t}.
-}
-\references{
-  Anne Berry, Jean-Paul Bordat and Olivier Cogis: Generating All the
-  Minimal Separators of a Graph, In: Peter Widmayer, Gabriele Neyer
-  and Stephan Eidenbenz (editors): \emph{Graph-theoretic concepts in
-    computer science}, 1665, 167--172, 1999. Springer. 
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-%\seealso{}
-\examples{
-ring <- graph.ring(4)
-minimal.st.separators(ring)
-
-chvatal <- graph.famous("chvatal")
-minimal.st.separators(chvatal)
-}
-\keyword{graphs}
diff --git a/man/minimum.size.separators.Rd b/man/minimum.size.separators.Rd
deleted file mode 100644
index 1896e8a..0000000
--- a/man/minimum.size.separators.Rd
+++ /dev/null
@@ -1,78 +0,0 @@
-\name{minimum.size.separators}
-\alias{minimum.size.separators}
-\concept{Minimum size vertex separator}
-\concept{Vertex separator}
-\title{Minimum size vertex separators}
-\description{Find all vertex sets of minimal size whose removal
-  separates the graph into more components}
-\usage{
-minimum.size.separators (graph)
-}
-\arguments{
-  \item{graph}{The input graph. It may be directed, but edge directions
-    are ignored.}
-}
-\details{
-  This function implements the Kanevsky algorithm for finding all
-  minimal-size vertex separators in an undirected graph. See the
-  reference below for the details.
-
-  In the special case of a fully connected input graph with \eqn{n}
-  vertices, all subsets of size \eqn{n-1} are listed as the result.
-}
-\value{
-  A list of numeric vectors. Each numeric vector is a vertex separator.
-}
-\references{
-  Arkady Kanevsky: Finding all minimum-size separating vertex sets in a
-  graph. \emph{Networks} 23 533--541, 1993.
-
-  JS Provan and DR Shier: A Paradigm for listing
-  (s,t)-cuts in graphs, \emph{Algorithmica} 15, 351--372, 1996.
-
-  J. Moody and D. R. White. Structural cohesion and embeddedness: A
-  hierarchical concept of social groups. \emph{American Sociological
-    Review}, 68 103--127, Feb 2003.  
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  \code{\link{is.separator}}
-}
-\examples{
-# The graph from the Moody-White paper
-mw <- graph.formula(1-2:3:4:5:6, 2-3:4:5:7, 3-4:6:7, 4-5:6:7,
-                    5-6:7:21, 6-7, 7-8:11:14:19, 8-9:11:14, 9-10,
-                    10-12:13, 11-12:14, 12-16, 13-16, 14-15, 15-16,
-                    17-18:19:20, 18-20:21, 19-20:22:23, 20-21,
-                    21-22:23, 22-23)
-
-# Cohesive subgraphs
-mw1 <- induced.subgraph(mw, as.character(c(1:7, 17:23)))
-mw2 <- induced.subgraph(mw, as.character(7:16))
-mw3 <- induced.subgraph(mw, as.character(17:23))
-mw4 <- induced.subgraph(mw, as.character(c(7,8,11,14)))
-mw5 <- induced.subgraph(mw, as.character(1:7))
-
-minimum.size.separators(mw)
-minimum.size.separators(mw1)
-minimum.size.separators(mw2)
-minimum.size.separators(mw3)
-minimum.size.separators(mw4)
-minimum.size.separators(mw5)
-
-# Another example, the science camp network
-camp <- graph.formula(Harry:Steve:Don:Bert - Harry:Steve:Don:Bert,
-                      Pam:Brazey:Carol:Pat - Pam:Brazey:Carol:Pat,
-                      Holly   - Carol:Pat:Pam:Jennie:Bill,
-                      Bill    - Pauline:Michael:Lee:Holly,
-                      Pauline - Bill:Jennie:Ann,
-                      Jennie  - Holly:Michael:Lee:Ann:Pauline,
-                      Michael - Bill:Jennie:Ann:Lee:John,
-                      Ann     - Michael:Jennie:Pauline,
-                      Lee     - Michael:Bill:Jennie,
-                      Gery    - Pat:Steve:Russ:John,
-                      Russ    - Steve:Bert:Gery:John,
-                      John    - Gery:Russ:Michael)
-lapply(minimum.size.separators(camp), function(x) V(camp)[x])
-}
-\keyword{graphs}
diff --git a/man/minimum.spanning.tree.Rd b/man/minimum.spanning.tree.Rd
deleted file mode 100644
index 72b149a..0000000
--- a/man/minimum.spanning.tree.Rd
+++ /dev/null
@@ -1,47 +0,0 @@
-\name{minimum.spanning.tree}
-\alias{minimum.spanning.tree}
-\concept{Minimum spanning tree}
-\title{Minimum spanning tree}
-\description{A subgraph of a connected graph is a \emph{minimum spanning tree}
-  if it is tree, and the sum of its edge weights are the minimal among
-  all tree subgraphs of the graph. A minimum spanning forest of a graph
-  is the graph consisting of the minimum spanning trees of its
-  components.}
-\usage{
-minimum.spanning.tree(graph, weights=NULL, algorithm=NULL, \dots)
-}
-\arguments{
-  \item{graph}{The graph object to analyze.}
-  \item{weights}{Numeric algorithm giving the weights of the edges in
-    the graph. The order is determined by the edge ids. This is ignored
-    if the \code{unweighted} algorithm is chosen
-  }
-  \item{algorithm}{The algorithm to use for
-    calculation. \code{unweighted} can be used for unwieghted graphs,
-    and \code{prim} runs Prim's algorithm for weighted graphs.
-    If this is \code{NULL} then igraph tries to select the algorithm
-    automatically: if the graph has an edge attribute called
-    \code{weight} of the \code{weights} argument is not \code{NULL} then
-    Prim's algorithm is chosen, otherwise the unwweighted algorithm is
-    performed.
-  }
-  \item{\dots}{Additional arguments, unused.}
-}
-\details{
-  If the graph is unconnected a minimum spanning forest is returned.
-}
-\value{
-  A graph object with the minimum spanning forest. (To check that it is
-  a tree check that the number of its edges is \code{vcount(graph)-1}.)
-  The edge and vertex attributes of the original graph are preserved in
-  the result.
-}
-\references{ Prim, R.C. 1957. Shortest connection networks and some
-  generalizations \emph{Bell System Technical Journal}, 37 1389--1401.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{clusters}}}
-\examples{
-g <- erdos.renyi.game(100, 3/100)
-mst <- minimum.spanning.tree(g)
-}
-\keyword{graphs}
diff --git a/man/modularity.Rd b/man/modularity.Rd
deleted file mode 100644
index d749634..0000000
--- a/man/modularity.Rd
+++ /dev/null
@@ -1,79 +0,0 @@
-\name{modularity}
-\alias{modularity}
-\alias{mod.matrix}
-\alias{modularity.igraph}
-\concept{Modularity}
-\title{Modularity of a community structure of a graph}
-\description{This function calculates how modular is a given division of a
-  graph into subgraphs.
-}
-\usage{
-\method{modularity}{igraph}(x, membership, weights = NULL, \dots)
-mod.matrix (graph, membership, weights = NULL) 
-}
-\arguments{
-  \item{x,graph}{The input graph.}
-  \item{membership}{Numeric vector, for each vertex it gives its
-    community. The communities are numbered from one.
-  }
-  \item{weights}{If not \code{NULL} then a numeric vector giving edge
-    weights.}
-  \item{\dots}{Additional arguments, none currently.}
-}
-\details{
-  \code{modularity} calculates the modularity of a graph with respect to
-  the given \code{membership} vector.
-  
-  The modularity of a graph with respect to some division (or vertex
-  types) measures how good the division is, or how separated are the 
-  different vertex types from each other. It defined as 
-  \deqn{Q=\frac{1}{2m} \sum_{i,j} (A_{ij}-\frac{k_ik_j}{2m})\delta(c_i,c_j),}{Q=1/(2m) * sum( (Aij-ki*kj/(2m) ) delta(ci,cj),i,j),}
-  here \eqn{m} is the number of edges, \eqn{A_{ij}}{Aij} is the element
-  of the \eqn{A} adjacency matrix 
-  in row \eqn{i} and column \eqn{j}, \eqn{k_i}{ki} is the degree of \eqn{i},
-  \eqn{k_j}{kj} is the degree of \eqn{j}, \eqn{c_i}{ci} is the type (or
-  component) of \eqn{i}, \eqn{c_j}{cj} that of \eqn{j}, the sum goes
-  over all \eqn{i} and \eqn{j} pairs of vertices, and
-  \eqn{\delta(x,y)}{delta(x,y)} is 1 if \eqn{x=y} and 0 otherwise.
-
-  If edge weights are given, then these are considered as the element of
-  the \eqn{A} adjacency matrix, and \eqn{k_i}{ki} is the sum of weights
-  of adjacent edges for vertex \eqn{i}.
-
-  \code{mod.matrix} calculates the modularity matrix. This is a dense
-  matrix, and it is defined as the difference of the adjacency matrix
-  and the configuration model null model matrix. In other words element
-  \eqn{M_{ij}}{M[i,j]} is given as
-  \eqn{A_{ij}-d_i d_j/(2m)}{A[i,j]-d[i]d[j]/(2m)}, where
-  \eqn{A_{ij}}{A[i,j]} is the (possibly weighted) adjacency matrix,
-  \eqn{d_i}{d[i]} is the degree of vertex \eqn{i}, and \eqn{m} is the
-  number of edges (or the total weights in the graph, if it is
-  weighed).
-}
-\value{
-  For \code{modularity} a numeric scalar, the modularity score of the
-  given configuration.
-
-  For \code{mod.matrix} a numeic square matrix, its order is the number
-  of vertices in the graph.
-}
-\references{
-  Clauset, A.; Newman, M. E. J. & Moore, C. Finding community structure
-  in very large networks, \emph{Phyisical Review E} 2004, 70, 066111
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{
-  \code{\link{walktrap.community}},
-  \code{\link{edge.betweenness.community}},
-  \code{\link{fastgreedy.community}},
-  \code{\link{spinglass.community}} for various community detection
-  methods.
-}
-\examples{
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
-wtc <- walktrap.community(g)
-modularity(wtc)
-modularity(g, membership(wtc))
-}
-\keyword{graphs}
diff --git a/man/modularity.igraph.Rd b/man/modularity.igraph.Rd
new file mode 100644
index 0000000..c3d58ba
--- /dev/null
+++ b/man/modularity.igraph.Rd
@@ -0,0 +1,85 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{modularity.igraph}
+\alias{mod.matrix}
+\alias{modularity}
+\alias{modularity.igraph}
+\alias{modularity_matrix}
+\title{Modularity of a community structure of a graph}
+\usage{
+\method{modularity}{igraph}(x, membership, weights = NULL, ...)
+
+modularity_matrix(graph, membership, weights = NULL)
+}
+\arguments{
+\item{x,graph}{The input graph.}
+
+\item{membership}{Numeric vector, for each vertex it gives its community.
+The communities are numbered from one.}
+
+\item{weights}{If not \code{NULL} then a numeric vector giving edge weights.}
+
+\item{\dots}{Additional arguments, none currently.}
+}
+\value{
+For \code{modularity} a numeric scalar, the modularity score of the
+given configuration.
+
+For \code{modularity_matrix} a numeic square matrix, its order is the number of
+vertices in the graph.
+}
+\description{
+This function calculates how modular is a given division of a graph into
+subgraphs.
+}
+\details{
+\code{modularity} calculates the modularity of a graph with respect to the
+given \code{membership} vector.
+
+The modularity of a graph with respect to some division (or vertex types)
+measures how good the division is, or how separated are the different vertex
+types from each other. It defined as \deqn{Q=\frac{1}{2m} \sum_{i,j}
+(A_{ij}-\frac{k_ik_j}{2m})\delta(c_i,c_j),}{Q=1/(2m) * sum( (Aij-ki*kj/(2m)
+) delta(ci,cj),i,j),} here \eqn{m} is the number of edges, \eqn{A_{ij}}{Aij}
+is the element of the \eqn{A} adjacency matrix in row \eqn{i} and column
+\eqn{j}, \eqn{k_i}{ki} is the degree of \eqn{i}, \eqn{k_j}{kj} is the degree
+of \eqn{j}, \eqn{c_i}{ci} is the type (or component) of \eqn{i},
+\eqn{c_j}{cj} that of \eqn{j}, the sum goes over all \eqn{i} and \eqn{j}
+pairs of vertices, and \eqn{\delta(x,y)}{delta(x,y)} is 1 if \eqn{x=y} and 0
+otherwise.
+
+If edge weights are given, then these are considered as the element of the
+\eqn{A} adjacency matrix, and \eqn{k_i}{ki} is the sum of weights of
+adjacent edges for vertex \eqn{i}.
+
+\code{modularity_matrix} calculates the modularity matrix. This is a dense matrix,
+and it is defined as the difference of the adjacency matrix and the
+configuration model null model matrix. In other words element
+\eqn{M_{ij}}{M[i,j]} is given as \eqn{A_{ij}-d_i
+d_j/(2m)}{A[i,j]-d[i]d[j]/(2m)}, where \eqn{A_{ij}}{A[i,j]} is the (possibly
+weighted) adjacency matrix, \eqn{d_i}{d[i]} is the degree of vertex \eqn{i},
+and \eqn{m} is the number of edges (or the total weights in the graph, if it
+is weighed).
+}
+\examples{
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6, 11))
+wtc <- cluster_walktrap(g)
+modularity(wtc)
+modularity(g, membership(wtc))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Clauset, A.; Newman, M. E. J. & Moore, C. Finding community
+structure in very large networks, \emph{Phyisical Review E} 2004, 70, 066111
+}
+\seealso{
+\code{\link{cluster_walktrap}},
+\code{\link{cluster_edge_betweenness}},
+\code{\link{cluster_fast_greedy}}, \code{\link{cluster_spinglass}} for
+various community detection methods.
+}
+\keyword{graphs}
+
diff --git a/man/motifs.Rd b/man/motifs.Rd
new file mode 100644
index 0000000..e70706d
--- /dev/null
+++ b/man/motifs.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/motifs.R
+\name{motifs}
+\alias{graph.motifs}
+\alias{motifs}
+\title{Graph motifs}
+\usage{
+motifs(graph, size = 3, cut.prob = rep(0, size))
+}
+\arguments{
+\item{graph}{Graph object, the input graph.}
+
+\item{size}{The size of the motif, currently 3 and 4 are supported only.}
+
+\item{cut.prob}{Numeric vector giving the probabilities that the search
+graph is cut at a certain level. Its length should be the same as the size
+of the motif (the \code{size} argument). By default no cuts are made.}
+}
+\value{
+\code{motifs} returns a numeric vector, the number of occurences of
+each motif in the graph. The motifs are ordered by their isomorphism
+classes. Note that for unconnected subgraphs, which are not considered to be
+motifs, the result will be \code{NA}.
+}
+\description{
+Graph motifs are small connected subgraphs with a well-defined
+structure.  These functions search a graph for various motifs.
+}
+\details{
+\code{motifs} searches a graph for motifs of a given size and returns a
+numeric vector containing the number of different motifs. The order of
+the motifs is defined by their isomorphism class, see
+\code{\link{isomorphism_class}}.
+}
+\examples{
+g <- barabasi.game(100)
+motifs(g, 3)
+count_motifs(g, 3)
+sample_motifs(g, 3)
+}
+\seealso{
+\code{\link{isomorphism_class}}
+
+Other graph motifs: \code{\link{count_motifs}},
+  \code{\link{graph.motifs.no}};
+  \code{\link{graph.motifs.est}},
+  \code{\link{sample_motifs}}
+}
+
diff --git a/man/mst.Rd b/man/mst.Rd
new file mode 100644
index 0000000..4790021
--- /dev/null
+++ b/man/mst.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/minimum.spanning.tree.R
+\name{mst}
+\alias{minimum.spanning.tree}
+\alias{mst}
+\title{Minimum spanning tree}
+\usage{
+mst(graph, weights = NULL, algorithm = NULL, ...)
+}
+\arguments{
+\item{graph}{The graph object to analyze.}
+
+\item{weights}{Numeric algorithm giving the weights of the edges in the
+graph. The order is determined by the edge ids. This is ignored if the
+\code{unweighted} algorithm is chosen}
+
+\item{algorithm}{The algorithm to use for calculation. \code{unweighted} can
+be used for unwieghted graphs, and \code{prim} runs Prim's algorithm for
+weighted graphs.  If this is \code{NULL} then igraph tries to select the
+algorithm automatically: if the graph has an edge attribute called
+\code{weight} of the \code{weights} argument is not \code{NULL} then Prim's
+algorithm is chosen, otherwise the unwweighted algorithm is performed.}
+
+\item{\dots}{Additional arguments, unused.}
+}
+\value{
+A graph object with the minimum spanning forest. (To check that it
+is a tree check that the number of its edges is \code{vcount(graph)-1}.)
+The edge and vertex attributes of the original graph are preserved in the
+result.
+}
+\description{
+A subgraph of a connected graph is a \emph{minimum spanning tree} if it is
+tree, and the sum of its edge weights are the minimal among all tree
+subgraphs of the graph. A minimum spanning forest of a graph is the graph
+consisting of the minimum spanning trees of its components.
+}
+\details{
+If the graph is unconnected a minimum spanning forest is returned.
+}
+\examples{
+g <- sample_gnp(100, 3/100)
+g_mst <- mst(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Prim, R.C. 1957. Shortest connection networks and some
+generalizations \emph{Bell System Technical Journal}, 37 1389--1401.
+}
+\seealso{
+\code{\link{components}}
+}
+\keyword{graphs}
+
diff --git a/man/multilevel.community.Rd b/man/multilevel.community.Rd
deleted file mode 100644
index 4be333b..0000000
--- a/man/multilevel.community.Rd
+++ /dev/null
@@ -1,70 +0,0 @@
-\name{multilevel.community}
-\alias{multilevel.community}
-\concept{Community structure}
-\concept{Multilevel community detection}
-\title{Finding community structure by multi-level optimization of
-  modularity}
-\description{This function implements the multi-level modularity optimization
-  algorithm for finding community structure, see references below. It
-  is based on the modularity measure and a hierarchial approach.
-}
-\usage{
-multilevel.community (graph, weights = NULL) 
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{weights}{Optional positive weight vector.
-    If the graph has a \code{weight} edge attribute, then this is used
-    by default. Supply \code{NA} here if the graph has a \code{weight}
-    edge attribute, but you want to ignore it.}
-}
-\details{
-  This function implements the multi-level modularity optimization
-  algorithm for finding community structure, see 
-  VD Blondel, J-L Guillaume, R Lambiotte and E Lefebvre: Fast unfolding of
-  community hierarchies in large networks,
-  \url{http://arxiv.org/abs/arXiv:0803.0476}
-  for the details.
-
-  It is based on the modularity measure and a hierarchial approach. 
-  Initially, each vertex is assigned to a community on its own. In every
-  step, vertices are re-assigned to communities in a local, greedy way:
-  each vertex is moved to the community with which it achieves the
-  highest contribution to modularity. When no vertices can be
-  reassigned, each community is considered a vertex on its own, and the
-  process starts again with the merged communities. The process stops
-  when there is only a single vertex left or when the modularity
-  cannot be increased any more in a step.
-  
-  This function was contributed by Tom Gregorovic.
-}
-\value{
-  \code{multilevel.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\references{
-  Vincent D. Blondel, Jean-Loup Guillaume, Renaud Lambiotte, Etienne
-  Lefebvre: Fast unfolding of communities in large
-  networks. J. Stat. Mech. (2008) P10008   
-}
-\author{Tom Gregorovic, Tamas Nepusz \email{ntamas at gmail.com}}
-\seealso{
-  See \code{\link{communities}} for extracting the membership,
-  modularity scores, etc. from the results.
-  
-  Other community detection algorithms:
-  \code{\link{walktrap.community}},
-  \code{\link{spinglass.community}},
-  \code{\link{leading.eigenvector.community}},
-  \code{\link{edge.betweenness.community}},
-  \code{\link{fastgreedy.community}},
-  \code{\link{label.propagation.community}}
-}
-\examples{
-# This is so simple that we will have only one level
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
-multilevel.community(g)
-}
-\keyword{graphs}
\ No newline at end of file
diff --git a/man/neighborhood.Rd b/man/neighborhood.Rd
deleted file mode 100644
index 59487d2..0000000
--- a/man/neighborhood.Rd
+++ /dev/null
@@ -1,77 +0,0 @@
-\name{neighborhood}
-\alias{neighborhood}
-\alias{neighborhood.size}
-\alias{graph.neighborhood}
-\alias{connect.neighborhood}
-\title{Neighborhood of graph vertices}
-\description{These functions find the vertices not farther than a given
-  limit from another fixed vertex, these are called the neighborhood of
-  the vertex.}
-\usage{
-neighborhood.size(graph, order, nodes=V(graph), mode=c("all", "out", "in"))
-neighborhood(graph, order, nodes=V(graph), mode=c("all", "out", "in"))
-graph.neighborhood(graph, order, nodes=V(graph), mode=c("all", "out", "in"))
-connect.neighborhood(graph, order, mode=c("all", "out", "in", "total"))
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{order}{Integer giving the order of the neighborhood.}
-  \item{nodes}{The vertices for which the calculation is performed.}
-  \item{mode}{Character constatnt, it specifies how to use the direction
-    of the edges if a directed graph is analyzed. For \sQuote{out} only
-    the outgoing edges are followed, so all vertices reachable from the
-    source vertex in at most \code{order} steps are counted. For
-    \sQuote{"in"} all vertices from which the source vertex is reachable
-    in at most \code{order} steps are counted. \sQuote{"all"} ignores
-    the direction of the edges. This argument is ignored for undirected
-    graphs.} 
-}
-\details{
-  The neighborhood of a given order \code{o} of a vertex \code{v}
-  includes all vertices which are closer to \code{v} than the
-  order. Ie. order 0 is always \code{v} itself, order 1 is \code{v}
-  plus its immediate neighbors, order 2 is order 1 plus the immediate
-  neighbors of the vertices in order 1, etc.
-
-  \code{neighborhood.size} calculates the size of the neighborhoods for
-  the given vertices with the given order.
-
-  \code{neighborhood} calculates the neighborhoods of the given vertices
-  with the given order parameter.
-
-  \code{graph.neighborhood} is creates (sub)graphs from all neighborhoods of
-  the given vertices with the given order parameter. This function
-  preserves the vertex, edge and graph attributes.
-
-  \code{connect.neighborhood} creates a new graph by connecting each
-  vertex to all other vertices in its neighborhood.
-}
-\value{
-  \code{neighborhood.size} returns with an integer vector.
-
-  \code{neighborhood} returns with a list of integer vectors.
-
-  \code{graph.neighborhood} returns with a list of graphs.
-
-  \code{connect.neighborhood} returns with a new graph object.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}, the first version was
-  done by Vincent Matossian}
-\examples{
-g <- graph.ring(10)
-neighborhood.size(g, 0, 1:3)
-neighborhood.size(g, 1, 1:3)
-neighborhood.size(g, 2, 1:3)
-neighborhood(g, 0, 1:3)
-neighborhood(g, 1, 1:3)
-neighborhood(g, 2, 1:3)
-
-# attributes are preserved
-V(g)$name <- c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")
-graph.neighborhood(g, 2, 1:3)
-
-# connecting to the neighborhood
-g <- graph.ring(10)
-g <- connect.neighborhood(g, 2)
-}
-\keyword{graphs}
diff --git a/man/neighbors.Rd b/man/neighbors.Rd
new file mode 100644
index 0000000..d6db6b1
--- /dev/null
+++ b/man/neighbors.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/interface.R
+\name{neighbors}
+\alias{neighbors}
+\title{Neighboring (adjacent) vertices in a graph}
+\usage{
+neighbors(graph, v, mode = c("out", "in", "all", "total"))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{v}{The vertex of which the adjacent vertices are queried.}
+
+\item{mode}{Whether to query outgoing (\sQuote{out}), incoming
+(\sQuote{in}) edges, or both types (\sQuote{all}). This is
+ignored for undirected graphs.}
+}
+\value{
+A vertex sequence containing the neighbors of the input vertex.
+}
+\description{
+A vertex is a neighbor of another one (in other words, the two
+vertices are adjacent), if they are incident to the same edge.
+}
+\examples{
+g <- make_graph("Zachary")
+n1 <- neighbors(g, 1)
+n34 <- neighbors(g, 34)
+intersection(n1, n34)
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{tail_of}}
+}
+
diff --git a/man/nexus.Rd b/man/nexus.Rd
index 224e494..e5f2005 100644
--- a/man/nexus.Rd
+++ b/man/nexus.Rd
@@ -1,203 +1,214 @@
-\name{nexus}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/nexus.R
+\name{print.nexusDatasetInfo}
+\alias{[.nexusDatasetInfoList}
 \alias{nexus}
-\alias{nexus.list}
-\alias{nexus.info}
 \alias{nexus.get}
+\alias{nexus.info}
+\alias{nexus.list}
 \alias{nexus.search}
 \alias{nexusDatasetInfo}
+\alias{nexus_get}
+\alias{nexus_info}
+\alias{nexus_list}
+\alias{nexus_search}
 \alias{print.nexusDatasetInfo}
 \alias{print.nexusDatasetInfoList}
 \alias{summary.nexusDatasetInfoList}
-\concept{The Nexus network repository}
 \title{Query and download from the Nexus network repository}
-\description{The Nexus network repository is an online collection of
-  network data sets. These functions can be used to query it and
-  download data from it, directly as an igraph graph.}
 \usage{
-nexus.list(tags=NULL, offset=0, limit=10,
-           operator=c("or", "and"),
-           order=c("date", "name", "popularity"),
-           nexus.url=getIgraphOpt("nexus.url"))
-nexus.info(id, nexus.url=getIgraphOpt("nexus.url"))
-nexus.get(id, offset=0, order=c("date", "name", "popularity"),
-          nexus.url=getIgraphOpt("nexus.url"))
-nexus.search(q, offset=0, limit=10,
-             order=c("date", "name", "popularity"),
-             nexus.url=getIgraphOpt("nexus.url"))
-
-\method{print}{nexusDatasetInfo}(x, \dots)
-\method{summary}{nexusDatasetInfoList}(object, \dots)
-\method{print}{nexusDatasetInfoList}(x, \dots)
+\method{print}{nexusDatasetInfo}(x, ...)
+
+\method{summary}{nexusDatasetInfoList}(object, ...)
+
+\method{print}{nexusDatasetInfoList}(x, ...)
+
+nexus_list(tags = NULL, offset = 0, limit = 10, operator = c("or",
+  "and"), order = c("date", "name", "popularity"),
+  nexus.url = igraph_opt("nexus.url"))
+
+nexus_info(id, nexus.url = igraph_opt("nexus.url"))
+
+nexus_get(id, offset = 0, order = c("date", "name", "popularity"),
+  nexus.url = igraph_opt("nexus.url"))
+
+nexus_search(q, offset = 0, limit = 10, order = c("date", "name",
+  "popularity"), nexus.url = igraph_opt("nexus.url"))
+
+\method{[}{nexusDatasetInfoList}(x, i)
 }
 \arguments{
-  \item{tags}{A character vector, the tags that are searched. If not
-    given (or \code{NULL}), then all datasets are listed.}
-  \item{offset}{An offset to select part of the results. Results are
-    listed from \code{offset}+1.}
-  \item{limit}{The maximum number of results to return.}
-  \item{operator}{A character scalar. If \sQuote{or} (the default),
-    then all datasets that have at least one of the given tags, are
-    returned. If it if \sQuote{and}, then only datasets that have all
-    the given tags, are returned.}
-  \item{order}{The ordering of the results, possible values are:
-    \sQuote{date}, \sQuote{name}, \sQuote{popularity}.}
-  \item{id}{The numeric or character id of the data set to query or
-    download. Instead of the data set ids, it is possible to supply a
-    \code{nexusDatasetInfo} or \code{nexusDatasetInfoList} object
-    here directly and then the query is done on the corresponding data
-    set(s).}
-  \item{q}{Nexus search string. See examples below. For the complete
-    documentation please see the Nexus homepage at
-    \url{http://nexus.igraph.org}.}
-  \item{nexus.url}{The URL of the Nexus server. Don't change this from
-    the default, unless you set up your own Nexus server.}
-  \item{x,object}{The \code{nexusDatasetInfo} object to print.}
-  \item{\dots}{Currently ignored.}
+\item{x,object}{The \code{nexusDatasetInfo} object to print.}
+
+\item{tags}{A character vector, the tags that are searched. If not given (or
+\code{NULL}), then all datasets are listed.}
+
+\item{offset}{An offset to select part of the results. Results are listed
+from \code{offset}+1.}
+
+\item{limit}{The maximum number of results to return.}
+
+\item{operator}{A character scalar. If \sQuote{or} (the default), then all
+datasets that have at least one of the given tags, are returned. If it if
+\sQuote{and}, then only datasets that have all the given tags, are returned.}
+
+\item{order}{The ordering of the results, possible values are:
+\sQuote{date}, \sQuote{name}, \sQuote{popularity}.}
+
+\item{nexus.url}{The URL of the Nexus server. Don't change this from the
+default, unless you set up your own Nexus server.}
+
+\item{id}{The numeric or character id of the data set to query or download.
+Instead of the data set ids, it is possible to supply a
+\code{nexusDatasetInfo} or \code{nexusDatasetInfoList} object here directly
+and then the query is done on the corresponding data set(s).}
+
+\item{q}{Nexus search string. See examples below. For the complete
+documentation please see the Nexus homepage at
+\url{http://nexus.igraph.org}.}
+
+\item{i}{Index.}
+
+\item{\dots}{Currently ignored.}
+}
+\value{
+\code{nexus_list} and \code{nexus_search} return a list of
+\code{nexusDatasetInfo} objects. The list also has these attributes:
+\describe{ \item{size}{The number of data sets returned by the query.}
+\item{totalsize}{The total number of data sets found for the query.}
+\item{offset}{The offset parameter of the query.} \item{limit}{The limit
+parameter of the query.} }
+
+\code{nexus_info} returns a single \code{nexusDatasetInfo} object.
+
+\code{nexus_get} returns an igraph graph object, or a list of graph objects,
+if the data set consists of multiple networks.
+}
+\description{
+The Nexus network repository is an online collection of network data sets.
+These functions can be used to query it and download data from it, directly
+as an igraph graph.
 }
 \details{
-  Nexus is an online repository of networks, with an API that allow
-  programatic queries against it, and programatic data download as
-  well.
-
-  The \code{nexus.list} and \code{nexus.info} functions query the
-  online database. They both return \code{nexusDatasetInfo} objects.
-  \code{nexus.info} returns more information than \code{nexus.list}.
-
-  \code{nexus.search} searches Nexus, and returns a list of data sets,
-  as \code{nexusDatasetInfo} objects. See below for some search
-  examples.
-
-  \code{nexus.get} downloads a data set from Nexus, based on its numeric
-  id, or based on a Nexus search string. For search strings, only the
-  first search hit is downloaded, but see also the \code{offset}
-  argument. (If there are not data sets found, then the function returns
-  an error.)
-  
-  The \code{nexusDatasetInfo} objects returned by \code{nexus.list} have
-  the following fields:
-  \describe{
-    \item{id}{The numeric id of the dataset.}
-    \item{sid}{The character id of the dataset.}
-    \item{name}{Character scalar, the name of the dataset.}
-    \item{vertices/edges}{Character, the number of vertices and edges in
-      the graph(s). Vertices and edges are separated by a slash, and
-      if the data set consists of multiple networks, then they are
-      separated by spaces.}
-    \item{tags}{Character vector, the tags of the dataset. Directed
-      graph have the tags \sQuote{directed}. Undirected graphs are
-      tagged as \sQuote{undirected}. Other common tags are:
-      \sQuote{weighted}, \sQuote{bipartite}, \sQuote{social network},
-      etc.}
-    \item{networks}{The ids and names of the networks in the data
-      set. The numeric and character id are separated by a slash, and
-      multiple networks are separated by spaces.}
-  }
+Nexus is an online repository of networks, with an API that allow
+programatic queries against it, and programatic data download as well.
+
+The \code{nexus_list} and \code{nexus_info} functions query the online
+database. They both return \code{nexusDatasetInfo} objects.
+\code{nexus_info} returns more information than \code{nexus_list}.
+
+\code{nexus_search} searches Nexus, and returns a list of data sets, as
+\code{nexusDatasetInfo} objects. See below for some search examples.
+
+\code{nexus_get} downloads a data set from Nexus, based on its numeric id,
+or based on a Nexus search string. For search strings, only the first search
+hit is downloaded, but see also the \code{offset} argument. (If there are
+not data sets found, then the function returns an error.)
 
-  \code{nexusDatasetInfo} objects returned by \code{nexus.info} have the
-  following additional fields:
-  \describe{
-    \item{date}{Character scalar, e.g. \sQuote{2011-01-09}, the date
-      when the dataset was added to the database.}
-    \item{formats}{Character vector, the data formats in which the data
-      set is available. The various formats are separated by semicolons.}
-    \item{licence}{Character scalar, the licence of the dataset.}
-    \item{licence url}{Character scalar, the URL of the licence of the
-      dataset. Pleaase make sure you consult this before using a
-      dataset.}
-    \item{summary}{Character scalar, the short description of
-      the dataset, this is usually a single sentence.}
-    \item{description}{Character scalar, the full description of the
-      dataset.}
-    \item{citation}{Character scalar, the paper(s) describing the
-      dataset. Please cite these papers if you are using the dataset in
-      your research, the licence of most datasets requires this.}
-    \item{attributes}{A list of lists, each list entry is a graph,
-      vertex or edge attribute and has the following entries:
-      \describe{
-	\item{type}{Type of the attribute, either \sQuote{graph},
-	  \sQuote{vertex} or \sQuote{edge}.}
-	\item{datatype}{Data type of the attribute, currently it can be
-	  \sQuote{numeric} and \sQuote{string}.}
-	\item{name}{Character scalar, the name of the attribute.}
-	\item{description}{Character scalar, the description of the
-	  attribute.}
-      }
+The \code{nexusDatasetInfo} objects returned by \code{nexus_list} have the
+following fields: \describe{
+  \item{id}{The numeric id of the dataset.}
+  \item{sid}{The character id of the dataset.}
+  \item{name}{Character scalar, the name of the dataset.}
+  \item{vertices/edges}{Character, the number of vertices and edges in
+    the graph(s). Vertices and edges are separated by a  slash, and if
+    the data set consists of multiple networks, then they are separated
+    by spaces.}
+  \item{tags}{Character vector, the tags of the dataset. Directed graph
+    have the tags \sQuote{directed}. Undirected graphs are tagged
+    as \sQuote{undirected}. Other common tags are: \sQuote{weighted},
+    \sQuote{bipartite}, \sQuote{social network}, etc.}
+  \item{networks}{The ids and names of the networks in the data set. The
+    numeric and character id are separated by a slash, and multiple networks
+    are separated by spaces.}
+}
+
+\code{nexusDatasetInfo} objects returned by \code{nexus_info} have the
+following additional fields: \describe{
+  \item{date}{Character scalar, e.g. \sQuote{2011-01-09}, the date when
+    the dataset was added to the database.}
+  \item{formats}{Character vector, the data formats in which the data set is
+    available. The various formats are separated by semicolons.}
+  \item{licence}{Character scalar, the licence of the dataset.}
+  \item{licence url}{Character scalar, the URL of the licence of the
+    dataset. Pleaase make sure you consult this before using a dataset.}
+  \item{summary}{Character scalar, the short description of the dataset,
+    this is usually a single sentence.}
+  \item{description}{Character scalar, the full description of the
+    dataset.}
+  \item{citation}{Character scalar, the paper(s) describing the
+    dataset. Please cite these papers if you are using the dataset in your
+    research, the licence of most datasets requires this.}
+  \item{attributes}{A list of lists, each list entry is a graph, vertex
+    or edge attribute and has the following entries: \describe{
+      \item{type}{Type of the attribute, either \sQuote{graph},
+        \sQuote{vertex} or \sQuote{edge}.}
+      \item{datatype}{Data type of the attribute, currently it can be
+        \sQuote{numeric} and \sQuote{string}.}
+      \item{name}{Character scalar, the name of the attribute.}
+      \item{description}{Character scalar, the description of the
+        attribute.}
     }
   }
+}
 
-  The results of the Nexus queries are printed to the screen in a
-  consise format, similar to the format of igraph graphs. A data set
-  list (typically the result of \code{nexus.list} and
-  \code{nexus.search}) looks like this: \preformatted{NEXUS 1-5/18 -- data set list
+The results of the Nexus queries are printed to the screen in a consise
+format, similar to the format of igraph graphs. A data set list (typically
+the result of \code{nexus_list} and \code{nexus_search}) looks like this:
+\preformatted{NEXUS 1-5/18 -- data set list
 [1] kaptail.4         39/109-223   #18 Kapferer tailor shop
 [2] condmatcollab2003 31163/120029 #17 Condensed matter collaborations+
 [3] condmatcollab     16726/47594  #16 Condensed matter collaborations+
 [4] powergrid         4941/6594    #15 Western US power grid
 [5] celegansneural    297/2359     #14 C. Elegans neural network }
-  Each line here represents a data set, and the following information is
-  given about them: the character id of the data set
-  (e.g. \code{kaptail} or \code{powergrid}), the number of vertices and
-  number of edges in the graph of the data sets. For data sets with
-  multiple graphs, intervals are given here. Then the numeric id of the
-  data set and the reamining space is filled with the name of the data
-  set.
-
-  Summary information about an individual Nexus data set is printed
-  as \preformatted{NEXUS B--- 39 109-223 #18 kaptail -- Kapferer tailor shop
+Each line here represents a data set, and the following information is
+given about them: the character id of the data set (e.g. \code{kaptail}
+or \code{powergrid}), the number of vertices and number of edges in the
+graph of the data sets.  For data sets with multiple graphs, intervals
+are given here. Then the numeric id of the data set and the reamining
+space is filled with the name of the data set.
+
+Summary information about an individual Nexus data set is printed as
+\preformatted{NEXUS B--- 39 109-223 #18 kaptail -- Kapferer tailor shop
 + tags: directed; social network; undirected
 + nets: 1/KAPFTI2; 2/KAPFTS2; 3/KAPFTI1; 4/KAPFTS1}
-  This is very similar to the header that is used for printing igraph
-  graphs, but there are some differences as well. The four characters
-  after the \code{NEXUS} word give the most important properties of the
-  graph(s): the first is \sQuote{\code{U}} for undirected and
-  \sQuote{\code{D}} for directed graphs, and \sQuote{\code{B}} if the
-  data set contains both directed and undirected graphs. The second is
-  \sQuote{\code{N}} named graphs. The third character is
-  \sQuote{\code{W}} for weighted graphs, the fourth is \sQuote{\code{B}}
-  if the data set contains bipartite graphs. Then the number of vertices
-  and number of edges are printed, for data sets with multiple graphs,
-  the smallest and the largest values are given. Then comes the numeric
-  id, and the string id of the data set. The end of the first
-  line contains the name of the data set. The second row
-  lists the data set tags, and the third row the networks that are
-  included in the data set.
-
-  Detailed data set information is printed similarly, but it contains
-  more fields.
-}
-\value{
-  \code{nexus.list} and \code{nexus.search} return a list of
-  \code{nexusDatasetInfo} objects. The list also has these attributes:
-  \describe{
-    \item{size}{The number of data sets returned by the query.}
-    \item{totalsize}{The total number of data sets found for the query.}
-    \item{offset}{The offset parameter of the query.}
-    \item{limit}{The limit parameter of the query.}
-  }
-  
-  \code{nexus.info} returns a single \code{nexusDatasetInfo} object.
+This is very similar to the header that is used for printing igraph
+graphs, but there are some differences as well. The four characters
+after the \code{NEXUS} word give the most important properties of the
+graph(s): the first is \sQuote{\code{U}} for undirected and
+\sQuote{\code{D}} for directed graphs, and \sQuote{\code{B}} if the data
+set contains both directed and undirected graphs. The second is
+\sQuote{\code{N}} named graphs. The third character is \sQuote{\code{W}}
+for weighted graphs, the fourth is \sQuote{\code{B}} if the data set
+contains bipartite graphs. Then the number of vertices and number of
+edges are printed, for data sets with multiple graphs, the smallest and
+the largest values are given. Then comes the numeric id, and the string
+id of the data set. The end of the first line contains the name of the
+data set. The second row lists the data set tags, and the third row the
+networks that are included in the data set.
 
-  \code{nexus.get} returns an igraph graph object, or a list of graph
-  objects, if the data set consists of multiple networks.
+Detailed data set information is printed similarly, but it contains more
+fields.
 }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \url{http://nexus.igraph.org} }
 \examples{
-\dontrun{nexus.list(tag="weighted")
-nexus.list(limit=3, order="name")
-nexus.list(limit=3, order="name")[[1]]
-nexus.info(2)
-g <- nexus.get(2)
+\dontrun{nexus_list(tag="weighted")
+nexus_list(limit=3, order="name")
+nexus_list(limit=3, order="name")[[1]]
+nexus_info(2)
+g <- nexus_get(2)
 summary(g)
 
 ## Data sets related to 'US':
-nexus.search("US")
+nexus_search("US")
 
 ## Search for data sets that have 'network' in their name:
-nexus.search("name:network")
+nexus_search("name:network")
 
 ## Any word can match
-nexus.search("blog or US or karate")
+nexus_search("blog or US or karate")
 }
 }
-\keyword{graphs}
+\seealso{
+\url{http://nexus.igraph.org}
+}
+
diff --git a/man/norm_coords.Rd b/man/norm_coords.Rd
new file mode 100644
index 0000000..a5f0e47
--- /dev/null
+++ b/man/norm_coords.Rd
@@ -0,0 +1,77 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{norm_coords}
+\alias{layout.norm}
+\alias{norm_coords}
+\title{Normalize coordinates for plotting graphs}
+\usage{
+norm_coords(layout, xmin = -1, xmax = 1, ymin = -1, ymax = 1,
+  zmin = -1, zmax = 1)
+}
+\arguments{
+\item{layout}{A matrix with two or three columns, the layout to normalize.}
+
+\item{xmin,xmax}{The limits for the first coordinate, if one of them or both
+are \code{NULL} then no normalization is performed along this direction.}
+
+\item{ymin,ymax}{The limits for the second coordinate, if one of them or
+both are \code{NULL} then no normalization is performed along this
+direction.}
+
+\item{zmin,zmax}{The limits for the third coordinate, if one of them or both
+are \code{NULL} then no normalization is performed along this direction.}
+}
+\value{
+A numeric matrix with at the same dimension as \code{layout}.
+}
+\description{
+Rescale coordinates linearly to be within given bounds.
+}
+\details{
+\code{norm_coords} normalizes a layout, it linearly transforms each
+coordinate separately to fit into the given limits.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}};
+  \code{\link{normalize}}
+}
+\keyword{graphs}
+
diff --git a/man/normalize.Rd b/man/normalize.Rd
new file mode 100644
index 0000000..c8fd5e5
--- /dev/null
+++ b/man/normalize.Rd
@@ -0,0 +1,66 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/layout.R
+\name{normalize}
+\alias{normalize}
+\title{Normalize layout}
+\usage{
+normalize(xmin = -1, xmax = 1, ymin = xmin, ymax = xmax, zmin = xmin,
+  zmax = xmax)
+}
+\arguments{
+\item{xmin,xmax}{Minimum and maximum for x coordinates.}
+
+\item{ymin,ymax}{Minimum and maximum for y coordinates.}
+
+\item{zmin,zmax}{Minimum and maximum for z coordinates.}
+}
+\description{
+Scale coordinates of a layout.
+}
+\examples{
+layout_(make_ring(10), with_fr(), normalize())
+}
+\seealso{
+\code{\link{merge_coords}}, \code{\link{layout_}}.
+
+Other graph layouts: \code{\link{add_layout_}};
+  \code{\link{as_bipartite}},
+  \code{\link{layout.bipartite}},
+  \code{\link{layout_as_bipartite}}; \code{\link{as_star}},
+  \code{\link{layout.star}}, \code{\link{layout_as_star}};
+  \code{\link{as_tree}}, \code{\link{layout_as_tree}};
+  \code{\link{component_wise}}; \code{\link{in_circle}},
+  \code{\link{layout_in_circle}};
+  \code{\link{layout.auto}}, \code{\link{layout_nicely}},
+  \code{\link{nicely}};
+  \code{\link{layout.davidson.harel}},
+  \code{\link{layout_with_dh}}, \code{\link{with_dh}};
+  \code{\link{layout.gem}}, \code{\link{layout_with_gem}},
+  \code{\link{with_gem}}; \code{\link{layout.graphopt}},
+  \code{\link{layout_with_graphopt}},
+  \code{\link{with_graphopt}}; \code{\link{layout.grid}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout.grid.3d}},
+  \code{\link{layout_on_grid}}, \code{\link{on_grid}};
+  \code{\link{layout.mds}}, \code{\link{layout_with_mds}},
+  \code{\link{with_mds}}; \code{\link{layout.merge}},
+  \code{\link{layout_components}},
+  \code{\link{merge_coords}},
+  \code{\link{piecewise.layout}},
+  \code{\link{piecewise.layout}};
+  \code{\link{layout.norm}}, \code{\link{norm_coords}};
+  \code{\link{layout.sugiyama}},
+  \code{\link{layout_with_sugiyama}},
+  \code{\link{with_sugiyama}};
+  \code{\link{layout_on_sphere}}, \code{\link{on_sphere}};
+  \code{\link{layout_randomly}}, \code{\link{randomly}};
+  \code{\link{layout_with_fr}}, \code{\link{with_fr}};
+  \code{\link{layout_with_kk}}, \code{\link{with_kk}};
+  \code{\link{layout_with_lgl}}, \code{\link{with_lgl}};
+  \code{\link{layout}}, \code{\link{layout_}},
+  \code{\link{print.igraph_layout_modifier}},
+  \code{\link{print.igraph_layout_spec}}
+
+Other layout modifiers: \code{\link{component_wise}}
+}
+
diff --git a/man/optimal.community.Rd b/man/optimal.community.Rd
deleted file mode 100644
index 1fc6c4e..0000000
--- a/man/optimal.community.Rd
+++ /dev/null
@@ -1,70 +0,0 @@
-\name{optimal.community}
-\alias{optimal.community}
-\concept{Community structure}
-\concept{Modularity}
-\title{Optimal community structure}
-\description{
-  This function calculates the optimal community structure of a graph,
-  by maximizing the modularity measure over all possible partitions.}
-\usage{
-optimal.community(graph, weights = NULL)
-}
-\arguments{
-  \item{graph}{The input graph. Edge directions are ignored for directed
-    graphs.}
-  \item{weights}{Optional positive weight vector for optimizing
-    weighted modularity. If the graph has a \code{weight} edge
-    attribute, then this is used by default. Supply \code{NA} to ignore
-    the weights of a weighted graph.}
-}
-\details{
-  This function calculates the optimal community structure for a
-  graph, in terms of maximal modularity score. 
-  
-  The calculation is done by transforming the modularity maximization
-  into an integer programming problem, and then calling the GLPK
-  library to solve that. Please the reference below for details. 
-
-  Note that modularity optimization is an NP-complete problem, and
-  all known algorithms for it have exponential time complexity. This
-  means that you probably don't want to run this function on larger
-  graphs. Graphs with up to fifty vertices should be fine, graphs
-  with a couple of hundred vertices might be possible.
-}
-\value{
-  \code{optimal.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\references{
-  Ulrik Brandes, Daniel Delling, Marco Gaertler, Robert Gorke, Martin
-  Hoefer, Zoran Nikoloski, Dorothea Wagner: On Modularity Clustering,
-  \emph{IEEE Transactions on Knowledge and Data Engineering}
-  20(2):172-188, 2008.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{communities}} for the documentation of the result,
-  \code{\link{modularity}}. See also \code{\link{fastgreedy.community}} 
-  for a fast greedy optimizer.
-}
-\examples{
-## Zachary's karate club
-g <- graph.famous("Zachary")
-
-## We put everything into a big 'try' block, in case 
-## igraph was compiled without GLPK support
-
-try({
-  ## The calculation only takes a couple of seconds
-  oc <- optimal.community(g)
-
-  ## Double check the result
-  print(modularity(oc))
-  print(modularity(g, membership(oc)))
-
-  ## Compare to the greedy optimizer
-  fc <- fastgreedy.community(g)
-  print(modularity(fc))
-}, silent=TRUE)
-}
-\keyword{graphs}
diff --git a/man/page.rank.Rd b/man/page.rank.Rd
deleted file mode 100644
index d35afa5..0000000
--- a/man/page.rank.Rd
+++ /dev/null
@@ -1,130 +0,0 @@
-\name{page.rank}
-\alias{page.rank}
-\alias{page.rank.old}
-\concept{Page rank}
-\title{The Page Rank algorithm}
-\description{ Calculates the Google PageRank for the specified
-  vertices.}
-\usage{
-page.rank (graph, algo = c("prpack", "arpack", "power"),
-    vids = V(graph), directed = TRUE, damping = 0.85,
-    personalized = NULL, weights = NULL, options = NULL) 
-page.rank.old (graph, vids = V(graph), directed = TRUE, niter = 1000, 
-    eps = 0.001, damping = 0.85, old = FALSE) 
-}
-\arguments{
-  \item{graph}{The graph object. }
-  \item{algo}{Character scalar, which implementation to use to carry out
-    the calculation. The default is \code{"prpack"}, which uses the
-    PRPACK library (https://github.com/dgleich/prpack). This is a
-    new implementation in igraph version 0.7, and the suggested one, as
-    it is the most stable and the fastest for all but small graphs.
-    \code{"arpack"} uses the ARPACK library, the default implementation
-    from igraph version 0.5 until version 0.7. \code{power} uses a
-    simple implementation of the power method, this was the default in
-    igraph before version 0.5 and is the same as calling
-    \code{page.rank.old}.}
-  \item{vids}{The vertices of interest.}
-  \item{directed}{Logical, if true directed paths will be considered for
-    directed graphs. It is ignored for undirected graphs.}
-  \item{damping}{The damping factor (\sQuote{d} in the original paper).}
-  \item{personalized}{Optional vector giving a probability distribution
-    to calculate personalized PageRank. For personalized PageRank, the
-    probability of jumping to a node when abandoning the random walk is
-    not uniform, but it is given by this vector. The vector should
-    contains an entry for each vertex and it will be rescaled to sum up
-    to one.}
-  \item{weights}{A numerical vector or \code{NULL}. This argument can be
-    used to give edge weights for calculating the weighted PageRank of
-    vertices. If this is \code{NULL} and the graph has a \code{weight}
-    edge attribute then that is used. If \code{weights} is a numerical
-    vector then it used, even if the graph has a \code{weights} edge
-    attribute. If this is \code{NA}, then no edge weights are used (even
-    if the graph has a \code{weight} edge attribute.}
-  \item{options}{Either a named list, to override some ARPACK options. See
-    \code{\link{arpack}} for details; or a named list to override the
-    default options for the power method (if \code{algo="power"}).
-    The default options for the power method are \code{niter=1000} and
-    \code{eps=0.001}. This argument is ignored if the PRPACK
-    implementation is used.}
-  \item{niter}{The maximum number of iterations to perform.} 
-  \item{eps}{The algorithm will consider the calculation as complete if
-    the difference of PageRank values between iterations change less
-    than this value for every node.}
-  \item{old}{A logical scalar, whether the old style (pre igraph 0.5)
-    normalization to use. See details below.}
-}
-\details{
-  For the explanation of the PageRank algorithm, see the following
-  webpage: \url{http://infolab.stanford.edu/~backrub/google.html}, or the
-  following reference: 
-
-  Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual
-  Web Search Engine. Proceedings of the 7th World-Wide Web Conference,
-  Brisbane, Australia, April 1998.  
-
-  igraph 0.5 (and later) contains two PageRank calculation
-  implementations. The \code{page.rank} function uses ARPACK to perform
-  the calculation, see also \code{\link{arpack}}.
-
-  The \code{page.rank.old} function performs a simple power method, this
-  is the implementation that was available under the name
-  \code{page.rank} in pre 0.5 igraph versions. Note that
-  \code{page.rank.old} has an argument called \code{old}. If this
-  argument is \code{FALSE} (the default), then the proper PageRank
-  algorithm is used, i.e. \eqn{(1-d)/n} is added to the weighted
-  PageRank of vertices to calculate the next iteration. If this
-  argument is \code{TRUE} then \eqn{(1-d)} is added, just like in the
-  PageRank paper; \eqn{d} is the damping factor, and \eqn{n} is the
-  total number of vertices.
-  A further difference is that the old implementation does not
-  renormalize the page rank vector after each iteration.
-  Note that the \code{old=FALSE} method is not stable,
-  is does not necessarily converge to a fixed point. It should be
-  avoided for new code, it is only included for compatibility with old
-  igraph versions.
-  
-  Please note that the PageRank of a given vertex depends on the PageRank
-  of all other vertices, so even if you want to calculate the PageRank for
-  only some of the vertices, all of them must be calculated. Requesting
-  the PageRank for only some of the vertices does not result in any
-  performance increase at all. 
-
-  Since the calculation is an iterative process, the algorithm is
-  stopped after a given count of iterations or if the PageRank value
-  differences between iterations are less than a predefined value. 
-}
-\value{
-  For \code{page.rank} a named list with entries:
-  \item{vector}{A numeric vector with the PageRank scores.}
-  \item{value}{The eigenvalue corresponding to the eigenvector with
-    the page rank scores. It should be always exactly one.}
-  \item{options}{Some information about the underlying ARPACK
-    calculation. See \code{\link{arpack}} for details. This entry is
-    \code{NULL} if not the ARPACK implementation was used.}
-  
-  For \code{page.rank.old} a numeric vector of Page Rank scores.
-}
-\references{
-  Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual
-  Web Search Engine. Proceedings of the 7th World-Wide Web Conference,
-  Brisbane, Australia, April 1998.  
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and
-  Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{Other centrality scores: \code{\link{closeness}},
-  \code{\link{betweenness}}, \code{\link{degree}}}
-\examples{
-g <- random.graph.game(20, 5/20, directed=TRUE)
-page.rank(g)$vector
-
-g2 <- graph.star(10)
-page.rank(g2)$vector
-
-# Personalized PageRank
-g3 <- graph.ring(10)
-page.rank(g3)$vector
-reset <- seq(vcount(g3))
-page.rank(g3, personalized=reset)$vector
-}
-\keyword{graphs}
diff --git a/man/page_rank.Rd b/man/page_rank.Rd
new file mode 100644
index 0000000..5d478cf
--- /dev/null
+++ b/man/page_rank.Rd
@@ -0,0 +1,142 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{page_rank}
+\alias{page.rank}
+\alias{page.rank.old}
+\alias{page_rank}
+\alias{page_rank_old}
+\title{The Page Rank algorithm}
+\usage{
+page_rank(graph, algo = c("prpack", "arpack", "power"), vids = V(graph),
+  directed = TRUE, damping = 0.85, personalized = NULL, weights = NULL,
+  options = NULL)
+
+page_rank_old(graph, vids = V(graph), directed = TRUE, niter = 1000,
+  eps = 0.001, damping = 0.85, old = FALSE)
+}
+\arguments{
+\item{graph}{The graph object.}
+
+\item{algo}{Character scalar, which implementation to use to carry out the
+calculation. The default is \code{"prpack"}, which uses the PRPACK library
+(https://github.com/dgleich/prpack). This is a new implementation in igraph
+version 0.7, and the suggested one, as it is the most stable and the fastest
+for all but small graphs.  \code{"arpack"} uses the ARPACK library, the
+default implementation from igraph version 0.5 until version 0.7.
+\code{power} uses a simple implementation of the power method, this was the
+default in igraph before version 0.5 and is the same as calling
+\code{page_rank_old}.}
+
+\item{vids}{The vertices of interest.}
+
+\item{directed}{Logical, if true directed paths will be considered for
+directed graphs. It is ignored for undirected graphs.}
+
+\item{damping}{The damping factor (\sQuote{d} in the original paper).}
+
+\item{personalized}{Optional vector giving a probability distribution to
+calculate personalized PageRank. For personalized PageRank, the probability
+of jumping to a node when abandoning the random walk is not uniform, but it
+is given by this vector. The vector should contains an entry for each vertex
+and it will be rescaled to sum up to one.}
+
+\item{weights}{A numerical vector or \code{NULL}. This argument can be used
+to give edge weights for calculating the weighted PageRank of vertices. If
+this is \code{NULL} and the graph has a \code{weight} edge attribute then
+that is used. If \code{weights} is a numerical vector then it used, even if
+the graph has a \code{weights} edge attribute. If this is \code{NA}, then no
+edge weights are used (even if the graph has a \code{weight} edge attribute.}
+
+\item{options}{Either a named list, to override some ARPACK options. See
+\code{\link{arpack}} for details; or a named list to override the default
+options for the power method (if \code{algo="power"}).  The default options
+for the power method are \code{niter=1000} and \code{eps=0.001}. This
+argument is ignored if the PRPACK implementation is used.}
+
+\item{niter}{The maximum number of iterations to perform.}
+
+\item{eps}{The algorithm will consider the calculation as complete if the
+difference of PageRank values between iterations change less than this value
+for every node.}
+
+\item{old}{A logical scalar, whether the old style (pre igraph 0.5)
+normalization to use. See details below.}
+}
+\value{
+For \code{page_rank} a named list with entries: \item{vector}{A
+numeric vector with the PageRank scores.} \item{value}{The eigenvalue
+corresponding to the eigenvector with the page rank scores. It should be
+always exactly one.} \item{options}{Some information about the underlying
+ARPACK calculation. See \code{\link{arpack}} for details. This entry is
+\code{NULL} if not the ARPACK implementation was used.}
+
+For \code{page_rank_old} a numeric vector of Page Rank scores.
+}
+\description{
+Calculates the Google PageRank for the specified vertices.
+}
+\details{
+For the explanation of the PageRank algorithm, see the following webpage:
+\url{http://infolab.stanford.edu/~backrub/google.html}, or the following
+reference:
+
+Sergey Brin and Larry Page: The Anatomy of a Large-Scale Hypertextual Web
+Search Engine. Proceedings of the 7th World-Wide Web Conference, Brisbane,
+Australia, April 1998.
+
+igraph 0.5 (and later) contains two PageRank calculation implementations.
+The \code{page_rank} function uses ARPACK to perform the calculation, see
+also \code{\link{arpack}}.
+
+The \code{page_rank_old} function performs a simple power method, this is
+the implementation that was available under the name \code{page_rank} in pre
+0.5 igraph versions. Note that \code{page_rank_old} has an argument called
+\code{old}. If this argument is \code{FALSE} (the default), then the proper
+PageRank algorithm is used, i.e. \eqn{(1-d)/n} is added to the weighted
+PageRank of vertices to calculate the next iteration. If this argument is
+\code{TRUE} then \eqn{(1-d)} is added, just like in the PageRank paper;
+\eqn{d} is the damping factor, and \eqn{n} is the total number of vertices.
+A further difference is that the old implementation does not renormalize the
+page rank vector after each iteration.  Note that the \code{old=FALSE}
+method is not stable, is does not necessarily converge to a fixed point. It
+should be avoided for new code, it is only included for compatibility with
+old igraph versions.
+
+Please note that the PageRank of a given vertex depends on the PageRank of
+all other vertices, so even if you want to calculate the PageRank for only
+some of the vertices, all of them must be calculated. Requesting the
+PageRank for only some of the vertices does not result in any performance
+increase at all.
+
+Since the calculation is an iterative process, the algorithm is stopped
+after a given count of iterations or if the PageRank value differences
+between iterations are less than a predefined value.
+}
+\examples{
+g <- sample_gnp(20, 5/20, directed=TRUE)
+page_rank(g)$vector
+
+g2 <- make_star(10)
+page_rank(g2)$vector
+
+# Personalized PageRank
+g3 <- make_ring(10)
+page_rank(g3)$vector
+reset <- seq(vcount(g3))
+page_rank(g3, personalized=reset)$vector
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
+\references{
+Sergey Brin and Larry Page: The Anatomy of a Large-Scale
+Hypertextual Web Search Engine. Proceedings of the 7th World-Wide Web
+Conference, Brisbane, Australia, April 1998.
+}
+\seealso{
+Other centrality scores: \code{\link{closeness}},
+\code{\link{betweenness}}, \code{\link{degree}}
+}
+\keyword{graphs}
+
diff --git a/man/path.Rd b/man/path.Rd
new file mode 100644
index 0000000..91e485d
--- /dev/null
+++ b/man/path.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{path}
+\alias{path}
+\title{Helper function to add or delete edges along a path}
+\usage{
+path(...)
+}
+\arguments{
+\item{...}{See details below.}
+}
+\value{
+A special object that can be used together with igraph
+  graphs and the plus and minus operators.
+}
+\description{
+This function can be used to add or delete edges that form a path.
+}
+\details{
+When adding edges via \code{+}, all unnamed arguments are
+concatenated, and each element of a final vector is interpreted
+as a vertex in the graph. For a vector of length \eqn{n+1}, \eqn{n}
+edges are then added, from vertex 1 to vertex 2, from vertex 2 to vertex
+3, etc. Named arguments will be used as edge attributes for the new
+edges.
+
+When deleting edges, all attributes are concatenated and then passed
+to \code{\link{delete_edges}}.
+}
+\examples{
+# Create a (directed) wheel
+g <- make_star(11, center = 1) + path(2:11, 2)
+plot(g)
+
+g <- make_empty_graph(directed = FALSE, n = 10) \%>\%
+  set_vertex_attr("name", value = letters[1:10])
+
+g2 <- g + path("a", "b", "c", "d")
+plot(g2)
+
+g3 <- g2 + path("e", "f", "g", weight=1:2, color="red")
+E(g3)[[]]
+
+g4 <- g3 + path(c("f", "c", "j", "d"), width=1:3, color="green")
+E(g4)[[]]
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{vertex}},
+  \code{\link{vertices}}
+}
+
diff --git a/man/permute.Rd b/man/permute.Rd
new file mode 100644
index 0000000..a612f13
--- /dev/null
+++ b/man/permute.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{permute}
+\alias{permute}
+\alias{permute.vertices}
+\title{Permute the vertices of a graph}
+\usage{
+permute(graph, permutation)
+}
+\arguments{
+\item{graph}{The input graph, it can directed or undirected.}
+
+\item{permutation}{A numeric vector giving the permutation to apply. The
+first element is the new id of vertex 1, etc. Every number between one and
+\code{vcount(graph)} must appear exactly once.}
+}
+\value{
+A new graph object.
+}
+\description{
+Create a new graph, by permuting vertex ids.
+}
+\details{
+This function creates a new graph from the input graph by permuting its
+vertices according to the specified mapping. Call this function with the
+output of \code{\link{canonical_permutation}} to create the canonical form
+of a graph.
+
+\code{permute} keeps all graph, vertex and edge attributes of the graph.
+}
+\examples{
+# Random permutation of a random graph
+g <- sample_gnm(20, 50)
+g2 <- permute(g, sample(vcount(g)))
+graph.isomorphic(g, g2)
+
+# Permutation keeps all attributes
+g$name <- "Random graph, Gnm, 20, 50"
+V(g)$name <- letters[1:vcount(g)]
+E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
+g2 <- permute(g, sample(vcount(g)))
+graph.isomorphic(g, g2)
+g2$name
+V(g2)$name
+E(g2)$weight
+all(sort(E(g2)$weight) == sort(E(g)$weight))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{canonical_permutation}}
+}
+\keyword{graphs}
+
diff --git a/man/permute.vertices.Rd b/man/permute.vertices.Rd
deleted file mode 100644
index 3fe8edc..0000000
--- a/man/permute.vertices.Rd
+++ /dev/null
@@ -1,46 +0,0 @@
-\name{permute.vertices}
-\alias{permute.vertices}
-\concept{Permutation}
-\title{Permute the vertices of a graph}
-\description{Create a new graph, by permuting vertex ids.}
-\usage{
-permute.vertices(graph, permutation)
-}
-\arguments{
-  \item{graph}{The input graph, it can directed or undirected.}
-  \item{permutation}{A numeric vector giving the permutation to
-    apply. The first element is the new id of vertex 1, etc. Every
-    number between one and \code{vcount(graph)} must appear exactly
-    once.}
-}
-\details{
-  This function creates a new graph from the input graph by permuting
-  its vertices according to the specified mapping. Call this function
-  with the output of \code{\link{canonical.permutation}} to create
-  the canonical form of a graph.
-
-  \code{permute.vertices} keeps all graph, vertex and edge attributes of
-  the graph.
-}
-\value{A new graph object.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{canonical.permutation}}}
-\examples{
-# Random permutation of a random graph
-g <- random.graph.game(20, 50, type="gnm")
-g2 <- permute.vertices(g, sample(vcount(g)))
-graph.isomorphic(g, g2)
-
-# Permutation keeps all attributes
-g$name <- "Random graph, Gnm, 20, 50"
-V(g)$name <- letters[1:vcount(g)]
-E(g)$weight <- sample(1:5, ecount(g), replace=TRUE)
-g2 <- permute.vertices(g, sample(vcount(g)))
-graph.isomorphic(g, g2)
-g2$name
-V(g2)$name
-E(g2)$weight
-all(sort(E(g2)$weight) == sort(E(g)$weight))
-}
-\keyword{graphs}
diff --git a/man/pipe.Rd b/man/pipe.Rd
new file mode 100644
index 0000000..ba29b0c
--- /dev/null
+++ b/man/pipe.Rd
@@ -0,0 +1,28 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/igraph-package.R
+\name{\%>\%}
+\alias{\%>\%}
+\title{Magrittr's pipes}
+\usage{
+lhs \%>\% rhs
+}
+\arguments{
+\item{lhs}{Left hand side of the pipe.}
+
+\item{rhs}{Right hand side of the pipe.}
+}
+\value{
+Result of applying the right hand side to the
+  result of the left hand side.
+}
+\description{
+igraph re-exports the \code{\%>\%} operator of magrittr, because
+we find it very useful. Please see the documentation in the
+\code{magrittr} package.
+}
+\examples{
+make_ring(10) \%>\%
+  add_edges(c(1,6)) \%>\%
+  plot()
+}
+
diff --git a/man/plot.common.Rd b/man/plot.common.Rd
index eb7128e..e0b2317 100644
--- a/man/plot.common.Rd
+++ b/man/plot.common.Rd
@@ -55,12 +55,12 @@
   edge attributes are handy if you want to assign a given \sQuote{look}
   to a graph, attributes are saved with the graph is you save it with
   \code{\link[base]{save}} or in GraphML format with
-  \code{\link{write.graph}}, so the graph will have the same look after
+  \code{\link{write_graph}}, so the graph will have the same look after
   loading it again.
 
   If a parameter is not given in the command line, and the corresponding
   vertex/edge/graph attribute is also missing then the general igraph
-  parameters handled by \code{\link{igraph.options}} are also
+  parameters handled by \code{\link{igraph_options}} are also
   checked. Vertex parameters have prefix \sQuote{\code{vertex.}}, edge
   parameters are prefixed with \sQuote{\code{edge.}}, general parameters
   like \code{layout} are prefixed with \sQuote{\code{plot}}.
@@ -86,7 +86,7 @@
 \section{The list of parameters}{
   Vertex parameters first, note that the \sQuote{\code{vertex.}} prefix
   needs to be added if they are used as an argument or when setting via
-  \code{\link{igraph.options}}. The value of the parameter may be scalar
+  \code{\link{igraph_options}}. The value of the parameter may be scalar
   valid for every vertex or a vector with a separate value for each
   vertex. (Shorter vectors are recycled.)
   \describe{
@@ -109,11 +109,16 @@
     \item{color}{The fill color of the vertex. If it is numeric then
       the current palette is used, see
       \code{\link[grDevices]{palette}}. If it is a character vector then
-      it may either contain named colors or RGB specified colors with
-      three or four bytes. All strings starting with \sQuote{\code{#}}
-      are assumed to be RGB color specifications. It is possible to mix
-      named color and RGB colors. Note that \code{\link{tkplot}} ignores
-      the fourth byte (alpha channel) in the RGB color specification.
+      it may either contain integer values, named colors or RGB
+      specified colors with three or four bytes. All strings starting
+      with \sQuote{\code{#}} are assumed to be RGB color
+      specifications. It is possible to mix named color and RGB
+      colors. Note that \code{\link{tkplot}} ignores the fourth byte
+      (alpha channel) in the RGB color specification.
+
+      For \code{plot.igraph} and integer values, the default igraph
+      palette is used (see the \sQuote{palette} parameter below. Note
+      that this is different from the R palette.
 
       If you don't want (some) vertices to have any color, supply
       \code{NA} as the color name.
@@ -137,7 +142,7 @@
       and only by the \code{\link{plot.igraph}}
       command. \dQuote{\code{none}} does not draw the vertices at all,
       although vertex label are plotted (if given). See
-      \code{\link{igraph.vertex.shapes}} for details about vertex
+      \code{\link{shapes}} for details about vertex
       shapes and \code{\link{vertex.shape.pie}} for using pie charts as
       vertices.
 
@@ -239,7 +244,7 @@
   }
 
   Edge parameters require to add the \sQuote{\code{edge.}} prefix when
-  used as arguments or set by \code{\link{igraph.options}}. The edge
+  used as arguments or set by \code{\link{igraph_options}}. The edge
   parameters:
   \describe{
     \item{color}{The color of the edges, see the \code{color} vertex
@@ -316,7 +321,7 @@
       means curvature 0.5, \code{FALSE} means curvature zero.
 
       By default the vector specifying the curvatire is calculated via a
-      call to the \code{\link{autocurve.edges}} function. This function makes
+      call to the \code{\link{curve_multiple}} function. This function makes
       sure that multiple edges are curved and are all visible. This
       parameter is ignored for loop edges. 
       
@@ -382,8 +387,8 @@
       actual coordinates. The function should return a matrix with two
       or three columns. For the 2D plots the third column is ignored.
 
-      The default value is \code{layout.random}, ie. a function
-      returning with 2D random placement.}
+      The default value is \code{layout_nicely}, a smart function that
+      chooses a layouter based on the graph.}
     \item{margin}{The amount of empty space below, over, at the left and
       right of the plot, it is a numeric vector of length four. Usually
       values between 0 and 0.5 are meaningful, but negative values are
@@ -395,6 +400,12 @@
       
       Its default value is 0.
     }
+    \item{palette}{The color palette to use for vertex color.
+      The default is \code{\link{categorical_pal}}, which is a
+      color-blind friendly categorical palette. See its manual page
+      for details and other palettes. This parameters is only supported
+      by \code{plot}, and not by \code{tkplot} and \code{rglplot}.
+    }
     \item{rescale}{Logical constant, whether to rescale the coordinates
       to the [-1,1]x[-1,1](x[-1,1]) interval. This parameter is not
       implemented for \code{tkplot}.
@@ -429,42 +440,42 @@
 }
 \author{Gabor Csardi \email{csardi.gabor at gmail.com}}
 \seealso{ \code{\link{plot.igraph}}, \code{\link{tkplot}},
-  \code{\link{rglplot}}, \code{\link{igraph.options}}}
+  \code{\link{rglplot}}, \code{\link{igraph_options}}}
 \examples{
 \dontrun{
 
 # plotting a simple ring graph, all default parameters, except the layout
-g <- graph.ring(10)
-g$layout <- layout.circle
+g <- make_ring(10)
+g$layout <- layout_in_circle
 plot(g)
 tkplot(g)
 rglplot(g)
 
 # plotting a random graph, set the parameters in the command arguments
 g <- barabasi.game(100)
-plot(g, layout=layout.fruchterman.reingold, vertex.size=4,
+plot(g, layout=layout_with_fr, vertex.size=4,
      vertex.label.dist=0.5, vertex.color="red", edge.arrow.size=0.5)
 
 # plot a random graph, different color for each component
-g <- erdos.renyi.game(100, 1/100)
-comps <- clusters(g)$membership
+g <- sample_gnp(100, 1/100)
+comps <- components(g)$membership
 colbar <- rainbow(max(comps)+1)
 V(g)$color <- colbar[comps+1]
-plot(g, layout=layout.fruchterman.reingold, vertex.size=5, vertex.label=NA)
+plot(g, layout=layout_with_fr, vertex.size=5, vertex.label=NA)
 
 # plot communities in a graph
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6,11))
-com <- spinglass.community(g, spins=5)
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6,11))
+com <- cluster_spinglass(g, spins=5)
 V(g)$color <- com$membership+1
-g <- set.graph.attribute(g, "layout", layout.kamada.kawai(g))
+g <- set_graph_attr(g, "layout", layout_with_kk(g))
 plot(g, vertex.label.dist=1.5)
 
 # draw a bunch of trees, fix layout
-igraph.options(plot.layout=layout.reingold.tilford)
-plot(graph.tree(20, 2))
-plot(graph.tree(50, 3), vertex.size=3, vertex.label=NA)
-tkplot(graph.tree(50, 2, mode="undirected"), vertex.size=10,
+igraph_options(plot.layout=layout_as_tree)
+plot(make_tree(20, 2))
+plot(make_tree(50, 3), vertex.size=3, vertex.label=NA)
+tkplot(make_tree(50, 2, mode="undirected"), vertex.size=10,
 vertex.color="green")
 }
 }
diff --git a/man/plot.graph.Rd b/man/plot.graph.Rd
deleted file mode 100644
index 8012924..0000000
--- a/man/plot.graph.Rd
+++ /dev/null
@@ -1,64 +0,0 @@
-\name{plot.igraph}
-\alias{plot.igraph}
-\concept{Visualization}
-\title{Plotting of graphs}
-\description{\code{plot.graph} is able to plot graphs to any R
-  device. It is the non-interactive companion of the \code{tkplot}
-  function.}
-\usage{
-\S3method{plot}{igraph}(x, axes=FALSE, add=FALSE,
-      xlim=c(-1,1), ylim=c(-1,1),
-      mark.groups=list(), mark.shape=1/2, 
-      mark.col=rainbow(length(mark.groups), alpha=0.3),
-      mark.border=rainbow(length(mark.groups), alpha=1),
-      mark.expand=15, \dots)
-}
-\arguments{
-  \item{x}{The graph to plot.}
-  \item{axes}{Logical, whether to plot axes, defaults to FALSE.}
-  \item{add}{Logical scalar, whether to add the plot to the current
-    device, or delete the device's current contents first.}
-  \item{xlim}{The limits for the horizontal axis, it is unlikely that
-    you want to modify this.}
-  \item{ylim}{The limits for the vertical axis, it is unlikely that you
-    want to modify this.}
-  \item{mark.groups}{A list of vertex id vectors. It is interpreted as a
-    set of vertex groups. Each vertex group is highlighted, by plotting
-    a colored smoothed polygon around and \dQuote{under} it. See the
-    arguments below to control the look of the polygons.}
-  \item{mark.shape}{A numeric scalar or vector. Controls the smoothness
-    of the vertex group marking polygons. This is basically the \sQuote{shape}
-    parameter of the \code{\link[graphics]{xspline}} function, its
-    possible values are between -1 and 1. If it is a vector, then a
-    different value is used for the different vertex groups.}
-  \item{mark.col}{A scalar or vector giving the colors of marking the
-    polygons, in any format accepted by
-    \code{\link[graphics]{xspline}}; e.g. numeric color ids, symbolic
-    color names, or colors in RGB.}
-  \item{mark.border}{A scalar or vector giving the colors of the borders
-    of the vertex group marking polygons. If it is \code{NA}, then no
-    border is drawn.}
-  \item{mark.expand}{A numeric scalar or vector, the size of the border
-    around the marked vertex groups. It is in the same units as the vertex
-    sizes. If a vector is given, then different values are used for the
-    different vertex groups.} 
-  \item{\dots}{Additional plotting parameters. See
-    \link{igraph.plotting} for the complete list.}
-}
-\details{
-  One convenient way to plot graphs is to plot with \code{\link{tkplot}}
-  first, handtune the placement of the vertices, query the coordinates
-  by the \code{\link{tkplot.getcoords}} function and use them with
-  \code{plot} to plot the graph to any R device.}
-\value{Returns \code{NULL}, invisibly.}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{layout}} for different layouts,
-  \code{\link{igraph.plotting}} for the detailed description of the
-  plotting parameters and \code{\link{tkplot}} and \code{\link{rglplot}}
-  for other graph plotting functions. }
-\examples{
-g <- graph.ring(10)
-\dontrun{plot(g, layout=layout.kamada.kawai, vertex.color="green")}
-}
-\keyword{graphs}
diff --git a/man/plot.igraph.Rd b/man/plot.igraph.Rd
new file mode 100644
index 0000000..793fab4
--- /dev/null
+++ b/man/plot.igraph.Rd
@@ -0,0 +1,82 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/plot.R
+\name{plot.igraph}
+\alias{plot.graph}
+\alias{plot.igraph}
+\title{Plotting of graphs}
+\usage{
+\method{plot}{igraph}(x, axes = FALSE, add = FALSE, xlim = c(-1, 1),
+  ylim = c(-1, 1), mark.groups = list(), mark.shape = 1/2,
+  mark.col = rainbow(length(mark.groups), alpha = 0.3),
+  mark.border = rainbow(length(mark.groups), alpha = 1), mark.expand = 15,
+  ...)
+}
+\arguments{
+\item{x}{The graph to plot.}
+
+\item{axes}{Logical, whether to plot axes, defaults to FALSE.}
+
+\item{add}{Logical scalar, whether to add the plot to the current device, or
+delete the device's current contents first.}
+
+\item{xlim}{The limits for the horizontal axis, it is unlikely that you want
+to modify this.}
+
+\item{ylim}{The limits for the vertical axis, it is unlikely that you want
+to modify this.}
+
+\item{mark.groups}{A list of vertex id vectors. It is interpreted as a set
+of vertex groups. Each vertex group is highlighted, by plotting a colored
+smoothed polygon around and \dQuote{under} it. See the arguments below to
+control the look of the polygons.}
+
+\item{mark.shape}{A numeric scalar or vector. Controls the smoothness of the
+vertex group marking polygons. This is basically the \sQuote{shape}
+parameter of the \code{\link[graphics]{xspline}} function, its possible
+values are between -1 and 1. If it is a vector, then a different value is
+used for the different vertex groups.}
+
+\item{mark.col}{A scalar or vector giving the colors of marking the
+polygons, in any format accepted by \code{\link[graphics]{xspline}}; e.g.
+numeric color ids, symbolic color names, or colors in RGB.}
+
+\item{mark.border}{A scalar or vector giving the colors of the borders of
+the vertex group marking polygons. If it is \code{NA}, then no border is
+drawn.}
+
+\item{mark.expand}{A numeric scalar or vector, the size of the border around
+the marked vertex groups. It is in the same units as the vertex sizes. If a
+vector is given, then different values are used for the different vertex
+groups.}
+
+\item{\dots}{Additional plotting parameters. See \link{igraph.plotting} for
+the complete list.}
+}
+\value{
+Returns \code{NULL}, invisibly.
+}
+\description{
+\code{plot.igraph} is able to plot graphs to any R device. It is the
+non-interactive companion of the \code{tkplot} function.
+}
+\details{
+One convenient way to plot graphs is to plot with \code{\link{tkplot}}
+first, handtune the placement of the vertices, query the coordinates by the
+\code{\link{tk_coords}} function and use them with \code{plot} to
+plot the graph to any R device.
+}
+\examples{
+g <- ring(10)
+\dontrun{plot(g, layout=layout_with_kk, vertex.color="green")}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{layout}} for different layouts,
+\code{\link{igraph.plotting}} for the detailed description of the plotting
+parameters and \code{\link{tkplot}} and \code{\link{rglplot}} for other
+graph plotting functions.
+}
+\keyword{graphs}
+
diff --git a/man/plot.sir.Rd b/man/plot.sir.Rd
index b65eeb4..293955b 100644
--- a/man/plot.sir.Rd
+++ b/man/plot.sir.Rd
@@ -1,61 +1,79 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/epi.R
 \name{plot.sir}
 \alias{plot.sir}
-\concept{SIR model}
 \title{Plotting the results on multiple SIR model runs}
-\description{
-  This function can conveniently plot the results of multiple SIR model
-  simulations.
-}
 \usage{
-\S3method{plot}{sir}(x, comp = c("NI", "NS", "NR"), median = TRUE,
-    quantiles = c(0.1, 0.9), color = NULL, median_color = NULL,
-    quantile_color = NULL, lwd.median = 2, lwd.quantile = 2,
-    lty.quantile = 3, xlim = NULL, ylim = NULL,
-    xlab = "Time", ylab = NULL, \dots)
+\method{plot}{sir}(x, comp = c("NI", "NS", "NR"), median = TRUE,
+  quantiles = c(0.1, 0.9), color = NULL, median_color = NULL,
+  quantile_color = NULL, lwd.median = 2, lwd.quantile = 2,
+  lty.quantile = 3, xlim = NULL, ylim = NULL, xlab = "Time",
+  ylab = NULL, ...)
 }
 \arguments{
-  \item{x}{The output of the SIR simulation, coming from the
-    \code{\link{sir}} function.}
-  \item{comp}{Character scalar, which component to plot. Either
-    \sQuote{NI} (infected, default), \sQuote{NS} (susceptible) or
-    \sQuote{NR} (recovered). }
-  \item{median}{Logical scalar, whether to plot the (binned) median.}
-  \item{quantiles}{A vector of (binned) quantiles to plot.}
-  \item{color}{Color of the individual simulation curves.}
-  \item{median_color}{Color of the median curve.}
-  \item{quantile_color}{Color(s) of the quantile curves. (It is recycled
-    if needed and non-needed entries are ignored if too long.)}
-  \item{lwd.median}{Line width of the median.}
-  \item{lwd.quantile}{Line width of the quantile curves.}
-  \item{lty.quantile}{Line type of the quantile curves.}
-  \item{xlim}{The x limits, a two-element numeric vector. If
-    \code{NULL}, then it is calculated from the data.}
-  \item{ylim}{The y limits, a two-element numeric vector. If
-    \code{NULL}, then it is calculated from the data.}
-  \item{xlab}{The x label.}
-  \item{ylab}{The y label. If \code{NULL} then it is automatically added
-    based on the \code{comp} argument.}
-  \item{\dots}{Additional arguments are passed to \code{plot}, that is
-    run before any of the curves are added, to create the figure.}
+\item{x}{The output of the SIR simulation, coming from the \code{\link{sir}}
+function.}
+
+\item{comp}{Character scalar, which component to plot. Either \sQuote{NI}
+(infected, default), \sQuote{NS} (susceptible) or \sQuote{NR} (recovered).}
+
+\item{median}{Logical scalar, whether to plot the (binned) median.}
+
+\item{quantiles}{A vector of (binned) quantiles to plot.}
+
+\item{color}{Color of the individual simulation curves.}
+
+\item{median_color}{Color of the median curve.}
+
+\item{quantile_color}{Color(s) of the quantile curves. (It is recycled if
+needed and non-needed entries are ignored if too long.)}
+
+\item{lwd.median}{Line width of the median.}
+
+\item{lwd.quantile}{Line width of the quantile curves.}
+
+\item{lty.quantile}{Line type of the quantile curves.}
+
+\item{xlim}{The x limits, a two-element numeric vector. If \code{NULL}, then
+it is calculated from the data.}
+
+\item{ylim}{The y limits, a two-element numeric vector. If \code{NULL}, then
+it is calculated from the data.}
+
+\item{xlab}{The x label.}
+
+\item{ylab}{The y label. If \code{NULL} then it is automatically added based
+on the \code{comp} argument.}
+
+\item{\dots}{Additional arguments are passed to \code{plot}, that is run
+before any of the curves are added, to create the figure.}
 }
-\details{
-  The number of susceptible/infected/recovered individuals is
-  plotted over time, for multiple simulations.
+\value{
+Nothing.
 }
-\value{Nothing.}
-\references{
-  Bailey, Norman T. J. (1975). The mathematical theory of infectious
-  diseases and its applications (2nd ed.). London: Griffin.
+\description{
+This function can conveniently plot the results of multiple SIR model
+simulations.
 }
-\author{
-  Eric Kolaczyk (\url{http://math.bu.edu/people/kolaczyk/}) and
-  Gabor Csardi \email{csardi.gabor at gmail.com}.
+\details{
+The number of susceptible/infected/recovered individuals is plotted over
+time, for multiple simulations.
 }
-\seealso{\code{\link{sir}} for running the actual simulation.}
 \examples{
-g <- erdos.renyi.game(100, 100, type="gnm")
+g <- sample_gnm(100, 100)
 sm <- sir(g, beta=5, gamma=1)
 plot(sm)
 }
+\author{
+Eric Kolaczyk (\url{http://math.bu.edu/people/kolaczyk/}) and Gabor
+Csardi \email{csardi.gabor at gmail.com}.
+}
+\references{
+Bailey, Norman T. J. (1975). The mathematical theory of
+infectious diseases and its applications (2nd ed.). London: Griffin.
+}
+\seealso{
+\code{\link{sir}} for running the actual simulation.
+}
 \keyword{graphs}
-  
\ No newline at end of file
+
diff --git a/man/plot_dendrogram.communities.Rd b/man/plot_dendrogram.communities.Rd
new file mode 100644
index 0000000..cd5b851
--- /dev/null
+++ b/man/plot_dendrogram.communities.Rd
@@ -0,0 +1,100 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{plot_dendrogram}
+\alias{dendPlot}
+\alias{plot_dendrogram}
+\alias{plot_dendrogram.communities}
+\title{Community structure dendrogram plots}
+\usage{
+plot_dendrogram(x, mode = igraph_opt("dend.plot.type"), ...)
+
+\method{plot_dendrogram}{communities}(x, mode = igraph_opt("dend.plot.type"),
+  ..., use.modularity = FALSE, palette = categorical_pal(8))
+}
+\arguments{
+\item{x}{An object containing the community structure of a graph. See
+\code{\link{communities}} for details.}
+
+\item{mode}{Which dendrogram plotting function to use. See details below.}
+
+\item{use.modularity}{Logical scalar, whether to use the modularity values
+to define the height of the branches.}
+
+\item{palette}{The color palette to use for colored plots.}
+
+\item{\dots}{Additional arguments to supply to the dendrogram plotting
+function.}
+}
+\value{
+Returns whatever the return value was from the plotting function,
+\code{plot.phylo}, \code{plot.dendrogram} or \code{plot.hclust}.
+}
+\description{
+Plot a hierarchical community structure as a dendrogram.
+}
+\details{
+\code{plot_dendrogram} supports three different plotting functions, selected via
+the \code{mode} argument. By default the plotting function is taken from the
+\code{dend.plot.type} igraph option, and it has for possible values:
+\itemize{ \item \code{auto} Choose automatically between the plotting
+functions. As \code{plot.phylo} is the most sophisticated, that is choosen,
+whenever the \code{ape} package is available. Otherwise \code{plot.hclust}
+is used.  \item \code{phylo} Use \code{plot.phylo} from the \code{ape}
+package.  \item \code{hclust} Use \code{plot.hclust} from the \code{stats}
+package.  \item \code{dendrogram} Use \code{plot.dendrogram} from the
+\code{stats} package.  }
+
+The different plotting functions take different sets of arguments. When
+using \code{plot.phylo} (\code{mode="phylo"}), we have the following syntax:
+\preformatted{
+    plot_dendrogram(x, mode="phylo", colbar = palette(),
+            edge.color = NULL, use.edge.length = FALSE, \dots)
+} The extra arguments not documented above: \itemize{
+  \item \code{colbar} Color bar for the edges.
+  \item \code{edge.color} Edge colors. If \code{NULL}, then the
+    \code{colbar} argument is used.
+  \item \code{use.edge.length} Passed to \code{plot.phylo}.
+  \item \code{dots} Attitional arguments to pass to \code{plot.phylo}.
+}
+
+The syntax for \code{plot.hclust} (\code{mode="hclust"}): \preformatted{
+    plot_dendrogram(x, mode="hclust", rect = 0, colbar = palette(),
+            hang = 0.01, ann = FALSE, main = "", sub = "", xlab = "",
+            ylab = "", \dots)
+} The extra arguments not documented above: \itemize{
+  \item \code{rect} A numeric scalar, the number of groups to mark on
+    the dendrogram. The dendrogram is cut into exactly \code{rect}
+    groups and they are marked via the \code{rect.hclust} command. Set
+    this to zero if you don't want to mark any groups.
+  \item \code{colbar} The colors of the rectanges that mark the
+    vertex groups via the \code{rect} argument.
+  \item \code{hang} Where to put the leaf nodes, this corresponds to the
+    \code{hang} argument of \code{plot.hclust}.
+  \item \code{ann}  Whether to annotate the plot, the \code{ann}
+    argument of \code{plot.hclust}.
+  \item \code{main} The main title of the plot, the \code{main} argument
+    of \code{plot.hclust}.
+  \item \code{sub} The sub-title of the plot, the \code{sub} argument of
+    \code{plot.hclust}.
+  \item \code{xlab} The label on the horizontal axis, passed to
+    \code{plot.hclust}.
+  \item \code{ylab} The label on the vertical axis, passed to
+    \code{plot.hclust}.
+  \item \code{dots} Attitional arguments to pass to \code{plot.hclust}.
+}
+
+The syntax for \code{plot.dendrogram} (\code{mode="dendrogram"}):
+\preformatted{
+    plot_dendrogram(x, \dots)
+} The extra arguments are simply passed to \code{as.dendrogram}.
+}
+\examples{
+karate <- make_graph("Zachary")
+fc <- cluster_fast_greedy(karate)
+plot_dendrogram(fc)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/plot_dendrogram.igraphHRG.Rd b/man/plot_dendrogram.igraphHRG.Rd
new file mode 100644
index 0000000..4fbe545
--- /dev/null
+++ b/man/plot_dendrogram.igraphHRG.Rd
@@ -0,0 +1,92 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{plot_dendrogram.igraphHRG}
+\alias{hrg.dendrogram}
+\alias{plot_dendrogram.igraphHRG}
+\title{HRG dendrogram plot}
+\usage{
+\method{plot_dendrogram}{igraphHRG}(x, mode = igraph_opt("dend.plot.type"),
+  ...)
+}
+\arguments{
+\item{x}{An \code{igraphHRG}, a hierarchical random graph, as returned by
+the \code{\link{fit_hrg}} function.}
+
+\item{mode}{Which dendrogram plotting function to use. See details below.}
+
+\item{\dots}{Additional arguments to supply to the dendrogram plotting
+function.}
+}
+\value{
+Returns whatever the return value was from the plotting function,
+\code{plot.phylo}, \code{plot.dendrogram} or \code{plot.hclust}.
+}
+\description{
+Plot a hierarchical random graph as a dendrogram.
+}
+\details{
+\code{plot_dendrogram} supports three different plotting functions, selected via
+the \code{mode} argument. By default the plotting function is taken from the
+\code{dend.plot.type} igraph option, and it has for possible values:
+\itemize{ \item \code{auto} Choose automatically between the plotting
+functions. As \code{plot.phylo} is the most sophisticated, that is choosen,
+whenever the \code{ape} package is available. Otherwise \code{plot.hclust}
+is used.  \item \code{phylo} Use \code{plot.phylo} from the \code{ape}
+package.  \item \code{hclust} Use \code{plot.hclust} from the \code{stats}
+package.  \item \code{dendrogram} Use \code{plot.dendrogram} from the
+\code{stats} package.  }
+
+The different plotting functions take different sets of arguments. When
+using \code{plot.phylo} (\code{mode="phylo"}), we have the following syntax:
+\preformatted{
+    plot_dendrogram(x, mode="phylo", colbar = rainbow(11, start=0.7,
+            end=0.1), edge.color = NULL, use.edge.length = FALSE, \dots)
+} The extra arguments not documented above: \itemize{
+  \item \code{colbar} Color bar for the edges.
+  \item \code{edge.color} Edge colors. If \code{NULL}, then the
+    \code{colbar} argument is used.
+  \item \code{use.edge.length} Passed to \code{plot.phylo}.
+  \item \code{dots} Attitional arguments to pass to \code{plot.phylo}.
+}
+
+The syntax for \code{plot.hclust} (\code{mode="hclust"}): \preformatted{
+    plot_dendrogram(x, mode="hclust", rect = 0, colbar = rainbow(rect),
+            hang = 0.01, ann = FALSE, main = "", sub = "", xlab = "",
+            ylab = "", \dots)
+} The extra arguments not documented above: \itemize{
+  \item \code{rect} A numeric scalar, the number of groups to mark on
+    the dendrogram. The dendrogram is cut into exactly \code{rect}
+    groups and they are marked via the \code{rect.hclust} command. Set
+    this to zero if you don't want to mark any groups.
+  \item \code{colbar} The colors of the rectanges that mark the
+    vertex groups via the \code{rect} argument.
+  \item \code{hang} Where to put the leaf nodes, this corresponds to the
+    \code{hang} argument of \code{plot.hclust}.
+  \item \code{ann} Whether to annotate the plot, the \code{ann} argument
+    of \code{plot.hclust}.
+  \item \code{main} The main title of the plot, the \code{main} argument
+    of \code{plot.hclust}.
+  \item \code{sub} The sub-title of the plot, the \code{sub} argument of
+    \code{plot.hclust}.
+  \item \code{xlab} The label on the horizontal axis, passed to
+    \code{plot.hclust}.
+  \item \code{ylab} The label on the vertical axis, passed to
+    \code{plot.hclust}.
+  \item \code{dots} Attitional arguments to pass to \code{plot.hclust}.
+}
+
+The syntax for \code{plot.dendrogram} (\code{mode="dendrogram"}):
+\preformatted{
+    plot_dendrogram(x, \dots)
+} The extra arguments are simply passed to \code{as.dendrogram}.
+}
+\examples{
+g <- make_full_graph(5) + make_full_graph(5)
+hrg <- fit_hrg(g)
+plot_dendrogram(hrg)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/plus-.igraph.Rd b/man/plus-.igraph.Rd
new file mode 100644
index 0000000..c6c92fd
--- /dev/null
+++ b/man/plus-.igraph.Rd
@@ -0,0 +1,117 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{+.igraph}
+\alias{+.igraph}
+\title{Add vertices, edges or another graph to a graph}
+\usage{
+\method{+}{igraph}(e1, e2)
+}
+\arguments{
+\item{e1}{First argument, probably an igraph graph, but see details
+below.}
+
+\item{e2}{Second argument, see details below.}
+}
+\description{
+Add vertices, edges or another graph to a graph
+}
+\details{
+The plus operator can be used to add vertices or edges to graph.
+  The actual operation that is performed depends on the type of the
+  right hand side argument.
+  \itemize{
+  \item If is is another igraph graph object and they are both
+    named graphs, then the union of the two graphs are calculated,
+    see \code{\link{union}}.
+  \item If it is another igraph graph object, but either of the two
+    are not named, then the disjoint union of
+    the two graphs is calculated, see \code{\link{disjoint_union}}.
+  \item If it is a numeric scalar, then the specified number of vertices
+    are added to the graph.
+  \item If it is a character scalar or vector, then it is interpreted as
+    the names of the vertices to add to the graph.
+  \item If it is an object created with the \code{\link{vertex}} or
+    \code{\link{vertices}} function, then new vertices are added to the
+    graph. This form is appropriate when one wants to add some vertex
+    attributes as well. The operands of the \code{vertices} function
+    specifies the number of vertices to add and their attributes as
+    well.
+
+    The unnamed arguments of \code{vertices} are concatenated and
+    used as the \sQuote{\code{name}} vertex attribute (i.e. vertex
+    names), the named arguments will be added as additional vertex
+    attributes. Examples: \preformatted{  g <- g +
+        vertex(shape="circle", color= "red")
+  g <- g + vertex("foo", color="blue")
+  g <- g + vertex("bar", "foobar")
+  g <- g + vertices("bar2", "foobar2", color=1:2, shape="rectangle")}
+
+    \code{vertex} is just an alias to \code{vertices}, and it is
+    provided for readability. The user should use it if a single vertex
+    is added to the graph.
+
+  \item If it is an object created with the \code{\link{edge}} or
+    \code{\link{edges}} function, then new edges will be added to the
+    graph. The new edges and possibly their attributes can be specified as
+    the arguments of the \code{edges} function.
+
+    The unnamed arguments of \code{edges} are concatenated and used
+    as vertex ids of the end points of the new edges. The named
+    arguments will be added as edge attributes.
+
+    Examples: \preformatted{  g <- make_empty_graph() +
+         vertices(letters[1:10]) +
+         vertices("foo", "bar", "bar2", "foobar2")
+  g <- g + edge("a", "b")
+  g <- g + edges("foo", "bar", "bar2", "foobar2")
+  g <- g + edges(c("bar", "foo", "foobar2", "bar2"), color="red", weight=1:2)}
+    See more examples below.
+
+    \code{edge} is just an alias to \code{edges} and it is provided
+    for readability. The user should use it if a single edge is added to
+    the graph.
+
+  \item If it is an object created with the \code{\link{path}} function, then
+    new edges that form a path are added. The edges and possibly their
+    attributes are specified as the arguments to the \code{path}
+    function. The non-named arguments are concatenated and interpreted
+    as the vertex ids along the path. The remaining arguments are added
+    as edge attributes.
+
+    Examples: \preformatted{  g <- make_empty_graph() + vertices(letters[1:10])
+  g <- g + path("a", "b", "c", "d")
+  g <- g + path("e", "f", "g", weight=1:2, color="red")
+  g <- g + path(c("f", "c", "j", "d"), width=1:3, color="green")}
+  }
+
+  It is important to note that, although the plus operator is
+  commutative, i.e. is possible to write \preformatted{  graph <- "foo" + make_empty_graph()}
+  it is not associative, e.g. \preformatted{  graph <- "foo" + "bar" + make_empty_graph()}
+  results a syntax error, unless parentheses are used: \preformatted{  graph <- "foo" + ( "bar" + make_empty_graph() )}
+  For clarity, we suggest to always put the graph object on the left
+  hand side of the operator: \preformatted{  graph <- make_empty_graph() + "foo" + "bar"}
+}
+\examples{
+# 10 vertices named a,b,c,... and no edges
+g <- make_empty_graph() + vertices(letters[1:10])
+
+# Add edges to make it a ring
+g <- g + path(letters[1:10], letters[1], color = "grey")
+
+# Add some extra random edges
+g <- g + edges(sample(V(g), 10, replace = TRUE), color = "red")
+g$layout <- layout_in_circle
+plot(g)
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{-.igraph}},
+  \code{\link{igraph-minus}}; \code{\link{add.edges}},
+  \code{\link{add_edges}}; \code{\link{add.vertices}},
+  \code{\link{add_vertices}}; \code{\link{delete.edges}},
+  \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{path}};
+  \code{\link{vertex}}, \code{\link{vertices}}
+}
+
diff --git a/man/power.law.fit.Rd b/man/power.law.fit.Rd
deleted file mode 100644
index 41c1bf1..0000000
--- a/man/power.law.fit.Rd
+++ /dev/null
@@ -1,116 +0,0 @@
-\name{power.law.fit}
-\alias{power.law.fit}
-\concept{Power-law}
-\title{Fitting a power-law distribution function to discrete data}
-\description{\code{power.law.fit} fits a power-law distribution to a
-  data set.}
-\usage{
-power.law.fit(x, xmin=NULL, start=2, force.continuous=FALSE,
-              implementation=c("plfit", "R.mle"), \dots)
-}
-\arguments{
-  \item{x}{The data to fit, a numeric vector. For implementation
-    \sQuote{\code{R.mle}} the data must be integer values. For the
-    \sQuote{\code{plfit}} implementation non-integer values might be
-    present and then a continuous power-law distribution is fitted.}
-  \item{xmin}{Numeric scalar, or \code{NULL}. The lower bound for
-    fitting the power-law. If \code{NULL}, the smallest value in
-    \code{x} will be used for the \sQuote{\code{R.mle}} implementation,
-    and its value will be automatically determined for the
-    \sQuote{\code{plfit}} implementation. This argument makes it
-    possible to fit only the tail of the distribution. }
-  \item{start}{Numeric scalar. The initial value of the exponent for the
-    minimizing function, for the \sQuote{\code{R.mle}}
-    implementation. Ususally it is safe to leave this untouched.}
-  \item{force.continuous}{Logical scalar. Whether to force a continuous
-    distribution for the \sQuote{\code{plfit}} implementation, even if
-    the sample vector contains integer values only (by chance). If this
-    argument is false, igraph will assume a continuous distribution if
-    at least one sample is non-integer and assume a discrete
-    distribution otherwise.} 
-  \item{implementation}{Character scalar. Which implementation to
-    use. See details below.}
-  \item{\dots}{Additional arguments, passed to the maximum likelihood
-    optimizing function, \code{\link[stats4]{mle}}, if the
-    \sQuote{\code{R.mle}} implementation is chosen. It is ignored by the
-    \sQuote{\code{plfit}} implementation.}
-}
-\details{
-  This function fits a power-law distribution to a vector containing
-  samples from a distribution (that is assumed to follow a power-law of
-  course). In a power-law distribution, it is generally assumed that
-  \eqn{P(X=x)} is proportional to \eqn{x^{-alpha}}{x^-alpha}, where
-  \eqn{x} is a positive number and \eqn{\alpha}{alpha} is greater than
-  1. In many real-world cases, the power-law behaviour kicks in only
-  above a threshold value \eqn{x_{min}}{xmin}. The goal of this function
-  is to determine \eqn{\alpha}{alpha} if \eqn{x_{min}}{xmin} is given,
-  or to determine \eqn{x_{min}}{xmin} and the corresponding value of
-  \eqn{\alpha}{alpha}.
-
-  \code{power.law.fit} provides two maximum likelihood implementations.
-  If the \code{implementation} argument is \sQuote{\code{R.mle}}, then
-  the BFGS optimization (see \link[stats4]{mle}) algorithm is applied.
-  The additional arguments are passed to the mle function, so it is
-  possible to change the optimization method and/or its parameters.
-  This implementation can \emph{not} to fit the \eqn{x_{min}}{xmin}
-  argument, so use the \sQuote{\code{plfit}} implementation if you want
-  to do that.
-
-  The \sQuote{\code{plfit}} implementation also uses the maximum
-  likelihood principle to determine \eqn{\alpha}{alpha} for a given
-  \eqn{x_{min}}{xmin}; When \eqn{x_{min}}{xmin} is not given in advance,
-  the algorithm will attempt to find itsoptimal value for which the
-  \eqn{p}-value of a Kolmogorov-Smirnov test between the fitted
-  distribution and the original sample is the largest. The function uses
-  the method of Clauset, Shalizi and Newman to calculate the parameters
-  of the fitted distribution. See references below for the details.   
-}
-\value{
-  Depends on the \code{implementation} argument. If it is
-  \sQuote{\code{R.mle}}, then an object with class
-  \sQuote{\code{mle}}. It can be used to 
-  calculate confidence intervals and log-likelihood. See
-  \code{\link[stats4]{mle-class}} for details.
-
-  If \code{implementation} is \sQuote{\code{plfit}}, then the result is
-  a named list with entries:
-  \item{continuous}{Logical scalar, whether the fitted power-law
-  distribution was continuous or discrete.}
-  \item{alpha}{Numeric scalar, the exponent of the fitted power-law
-  distribution.}
-  \item{xmin}{Numeric scalar, the minimum value from which the power-law
-    distribution was fitted. In other words, only the values larger than
-    \code{xmin} were used from the input vector.}
-  \item{logLik}{Numeric scalar, the log-likelihood of the fitted
-    parameters.}
-  \item{KS.stat}{Numeric scalar, the test statistic of a
-    Kolmogorov-Smirnov test that compares the fitted distribution with
-    the input vector. Smaller scores denote better fit.}
-  \item{KS.p}{Numeric scalar, the p-value of the Kolmogorov-Smirnov
-    test. Small p-values (less than 0.05) indicate that the test
-    rejected the hypothesis that the original data could have been drawn
-    from the fitted power-law distribution.}
-}
-\references{
-  Power laws, Pareto distributions and Zipf's law,
-  M. E. J. Newman, \emph{Contemporary Physics}, 46, 323-351, 2005.
-
-  Aaron Clauset, Cosma R .Shalizi and Mark E.J. Newman: Power-law
-  distributions in empirical data. SIAM Review 51(4):661-703, 2009.
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and
-  Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link[stats4]{mle}}}
-\examples{
-# This should approximately yield the correct exponent 3
-g <- barabasi.game(1000) # increase this number to have a better estimate
-d <- degree(g, mode="in")
-fit1 <- power.law.fit(d+1, 10)
-fit2 <- power.law.fit(d+1, 10, implementation="R.mle")
-
-fit1$alpha
-coef(fit2)
-fit1$logLik
-logLik(fit2)
-}
-\keyword{graphs}
diff --git a/man/power_centrality.Rd b/man/power_centrality.Rd
new file mode 100644
index 0000000..994495b
--- /dev/null
+++ b/man/power_centrality.Rd
@@ -0,0 +1,131 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{power_centrality}
+\alias{bonpow}
+\alias{power_centrality}
+\title{Find Bonacich Power Centrality Scores of Network Positions}
+\usage{
+power_centrality(graph, nodes = V(graph), loops = FALSE, exponent = 1,
+  rescale = FALSE, tol = 1e-07, sparse = TRUE)
+}
+\arguments{
+\item{graph}{the input graph.}
+
+\item{nodes}{vertex sequence indicating which vertices are to be included in
+the calculation.  By default, all vertices are included.}
+
+\item{loops}{boolean indicating whether or not the diagonal should be
+treated as valid data.  Set this true if and only if the data can contain
+loops.  \code{loops} is \code{FALSE} by default.}
+
+\item{exponent}{exponent (decay rate) for the Bonacich power centrality
+score; can be negative}
+
+\item{rescale}{if true, centrality scores are rescaled such that they sum to
+1.}
+
+\item{tol}{tolerance for near-singularities during matrix inversion (see
+\code{\link{solve}})}
+
+\item{sparse}{Logical scalar, whether to use sparse matrices for the
+calculation. The \sQuote{Matrix} package is required for sparse matrix
+support}
+}
+\value{
+A vector, containing the centrality scores.
+}
+\description{
+\code{power_centrality} takes a graph (\code{dat}) and returns the Boncich power
+centralities of positions (selected by \code{nodes}).  The decay rate for
+power contributions is specified by \code{exponent} (1 by default).
+}
+\details{
+Bonacich's power centrality measure is defined by
+\eqn{C_{BP}\left(\alpha,\beta\right)=\alpha\left(\mathbf{I}-\beta\mathbf{A}\right)^{-1}\mathbf{A}\mathbf{1}}{C_BP(alpha,beta)=alpha
+(I-beta A)^-1 A 1}, where \eqn{\beta}{beta} is an attenuation parameter (set
+here by \code{exponent}) and \eqn{\mathbf{A}}{A} is the graph adjacency
+matrix.  (The coefficient \eqn{\alpha}{alpha} acts as a scaling parameter,
+and is set here (following Bonacich (1987)) such that the sum of squared
+scores is equal to the number of vertices.  This allows 1 to be used as a
+reference value for the ``middle'' of the centrality range.)  When
+\eqn{\beta \rightarrow }{beta->1/lambda_A1}\eqn{
+1/\lambda_{\mathbf{A}1}}{beta->1/lambda_A1} (the reciprocal of the largest
+eigenvalue of \eqn{\mathbf{A}}{A}), this is to within a constant multiple of
+the familiar eigenvector centrality score; for other values of \eqn{\beta},
+the behavior of the measure is quite different.  In particular, \eqn{\beta}
+gives positive and negative weight to even and odd walks, respectively, as
+can be seen from the series expansion
+\eqn{C_{BP}\left(\alpha,\beta\right)=\alpha \sum_{k=0}^\infty \beta^k
+}{C_BP(alpha,beta) = alpha sum( beta^k A^(k+1) 1, k in 0..infinity )}\eqn{
+\mathbf{A}^{k+1} \mathbf{1}}{C_BP(alpha,beta) = alpha sum( beta^k A^(k+1) 1,
+k in 0..infinity )} which converges so long as \eqn{|\beta|
+}{|beta|<1/lambda_A1}\eqn{ < 1/\lambda_{\mathbf{A}1}}{|beta|<1/lambda_A1}.
+The magnitude of \eqn{\beta}{beta} controls the influence of distant actors
+on ego's centrality score, with larger magnitudes indicating slower rates of
+decay.  (High rates, hence, imply a greater sensitivity to edge effects.)
+
+Interpretively, the Bonacich power measure corresponds to the notion that
+the power of a vertex is recursively defined by the sum of the power of its
+alters.  The nature of the recursion involved is then controlled by the
+power exponent: positive values imply that vertices become more powerful as
+their alters become more powerful (as occurs in cooperative relations),
+while negative values imply that vertices become more powerful only as their
+alters become \emph{weaker} (as occurs in competitive or antagonistic
+relations).  The magnitude of the exponent indicates the tendency of the
+effect to decay across long walks; higher magnitudes imply slower decay.
+One interesting feature of this measure is its relative instability to
+changes in exponent magnitude (particularly in the negative case).  If your
+theory motivates use of this measure, you should be very careful to choose a
+decay parameter on a non-ad hoc basis.
+}
+\note{
+This function was ported (ie. copied) from the SNA package.
+}
+\section{Warning }{
+ Singular adjacency matrices cause no end of headaches for
+this algorithm; thus, the routine may fail in certain cases.  This will be
+fixed when I get a better algorithm.  \code{power_centrality} will not symmetrize your
+data before extracting eigenvectors; don't send this routine asymmetric
+matrices unless you really mean to do so.
+}
+\examples{
+# Generate some test data from Bonacich, 1987:
+g.c <- graph( c(1,2,1,3,2,4,3,5), dir=FALSE)
+g.d <- graph( c(1,2,1,3,1,4,2,5,3,6,4,7), dir=FALSE)
+g.e <- graph( c(1,2,1,3,1,4,2,5,2,6,3,7,3,8,4,9,4,10), dir=FALSE)
+g.f <- graph( c(1,2,1,3,1,4,2,5,2,6,2,7,3,8,3,9,3,10,4,11,4,12,4,13), dir=FALSE)
+# Compute power centrality scores
+for (e in seq(-0.5,.5, by=0.1)) {
+  print(round(power_centrality(g.c, exp=e)[c(1,2,4)], 2))
+}
+
+for (e in seq(-0.4,.4, by=0.1)) {
+  print(round(power_centrality(g.d, exp=e)[c(1,2,5)], 2))
+}
+
+for (e in seq(-0.4,.4, by=0.1)) {
+  print(round(power_centrality(g.e, exp=e)[c(1,2,5)], 2))
+}
+
+for (e in seq(-0.4,.4, by=0.1)) {
+  print(round(power_centrality(g.f, exp=e)[c(1,2,5)], 2))
+}
+}
+\author{
+Carter T. Butts
+(\url{http://www.faculty.uci.edu/profile.cfm?faculty_id=5057}), ported to
+igraph by Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Bonacich, P.  (1972).  ``Factoring and Weighting Approaches to
+Status Scores and Clique Identification.'' \emph{Journal of Mathematical
+Sociology}, 2, 113-120.
+
+Bonacich, P.  (1987).  ``Power and Centrality: A Family of Measures.''
+\emph{American Journal of Sociology}, 92, 1170-1182.
+}
+\seealso{
+\code{\link{eigen_centrality}} and \code{\link{alpha_centrality}}
+}
+\keyword{graphs}
+
diff --git a/man/predict_edges.Rd b/man/predict_edges.Rd
new file mode 100644
index 0000000..b3ed071
--- /dev/null
+++ b/man/predict_edges.Rd
@@ -0,0 +1,85 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{predict_edges}
+\alias{hrg.predict}
+\alias{predict_edges}
+\title{Predict edges based on a hierarchical random graph model}
+\usage{
+predict_edges(graph, hrg = NULL, start = FALSE, num.samples = 10000,
+  num.bins = 25)
+}
+\arguments{
+\item{graph}{The graph to fit the model to. Edge directions are ignored in
+directed graphs.}
+
+\item{hrg}{A hierarchical random graph model, in the form of an
+\code{igraphHRG} object. \code{predict_edges}s allow this to be
+\code{NULL} as well, then a HRG is fitted to the graph first, from a
+random starting point.}
+
+\item{start}{Logical, whether to start the fitting/sampling from the
+supplied \code{igraphHRG} object, or from a random starting point.}
+
+\item{num.samples}{Number of samples to use for consensus generation or
+missing edge prediction.}
+
+\item{num.bins}{Number of bins for the edge probabilities. Give a higher
+number for a more accurate prediction.}
+}
+\value{
+A list with entries:
+  \item{edges}{The predicted edges, in a two-column matrix of vertex
+    ids.}
+  \item{prob}{Probabilities of these edges, according to the fitted
+    model.}
+  \item{hrg}{The (supplied or fitted) hierarchical random graph model.}
+}
+\description{
+\code{predict_edges} uses a hierarchical random graph model to predict
+missing edges from a network. This is done by sampling hierarchical models
+around the optimum model, proportionally to their likelihood. The MCMC
+sampling is stated from \code{hrg}, if it is given and the \code{start}
+argument is set to \code{TRUE}. Otherwise a HRG is fitted to the graph
+first.
+}
+\examples{
+## We are not running these examples any more, because they
+## take a long time (~15 seconds) to run and this is against the CRAN
+## repository policy. Copy and paste them by hand to your R prompt if
+## you want to run them.
+
+\dontrun{
+## A graph with two dense groups
+g <- sample_gnp(10, p=1/2) + sample_gnp(10, p=1/2)
+hrg <- fit_hrg(g)
+hrg
+
+## The consensus tree for it
+consensus_tree(g, hrg=hrg, start=TRUE)
+
+## Prediction of missing edges
+g2 <- make_full_graph(4) + (make_full_graph(4) - path(1,2))
+predict_edges(g2)
+}
+}
+\references{
+A. Clauset, C. Moore, and M.E.J. Newman. Hierarchical structure
+and the prediction of missing links in networks. \emph{Nature} 453, 98--101
+(2008);
+
+A. Clauset, C. Moore, and M.E.J. Newman. Structural Inference of Hierarchies
+in Networks. In E. M. Airoldi et al. (Eds.): ICML 2006 Ws, \emph{Lecture
+Notes in Computer Science} 4503, 1--13. Springer-Verlag, Berlin Heidelberg
+(2007).
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg_tree}}; \code{\link{hrg}},
+  \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/preference.game.Rd b/man/preference.game.Rd
deleted file mode 100644
index 7d55239..0000000
--- a/man/preference.game.Rd
+++ /dev/null
@@ -1,62 +0,0 @@
-\name{preference.game}
-\alias{preference.game}
-\alias{asymmetric.preference.game}
-\title{Trait-based random generation}
-\description{Generation of random graphs based on different vertex types.}
-\usage{
-preference.game(nodes, types, type.dist=rep(1, types), fixed.sizes=FALSE,
-    pref.matrix=matrix(1, types, types), directed=FALSE, loops=FALSE)
-asymmetric.preference.game(nodes, types,
-    type.dist.matrix=matrix(1,types,types),
-    pref.matrix = matrix(1, types, types), loops=FALSE)
-}
-\arguments{
-  \item{nodes}{The number of vertices in the graphs.}
-  \item{types}{The number of different vertex types.}
-  \item{type.dist}{The distribution of the vertex types, a numeric
-    vector of length \sQuote{types} containing non-negative numbers. The
-    vector will be normed to obtain probabilities.}
-  \item{fixed.sizes}{Fix the number of vertices with a given
-    vertex type label. The \code{type.dist} argument gives the group
-    sizes (i.e. number of vertices with the different labels) in this
-    case.}
-  \item{type.dist.matrix}{The joint distribution of the in- and
-    out-vertex types.}
-  \item{pref.matrix}{A square matrix giving the preferences of the
-    vertex types. The matrix has \sQuote{types} rows and columns.}
-  \item{directed}{Logical constant, whether to create a directed graph.}
-  \item{loops}{Logical constant, whether self-loops are allowed in the
-    graph.}
-}
-\details{
-  Both models generate random graphs with given vertex types. For
-  \code{preference.game} the probability that two vertices will be
-  connected depends on their type and is given by the
-  \sQuote{pref.matrix} argument. This matrix should be symmetric to make
-  sense but this is not checked. The distribution of the different
-  vertes types is given by the \sQuote{type.dist} vector.
-
-  For \code{asymmetric.preference.game} each vertex has an in-type and
-  an out-type and a directed graph is created. The probability that a
-  directed edge is realized from a vertex with a given out-type to a
-  vertex with a given in-type is given in the \sQuote{pref.matrix}
-  argument, which can be asymmetric. The joint distribution for the in-
-  and out-types is given in the \sQuote{type.dist.matrix} argument.
-}
-\value{An igraph graph.}
-%\references{}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
-  \email{csardi.gabor at gmail.com} for the R interface} 
-\examples{
-pf <- matrix( c(1, 0, 0, 1), nr=2)
-g <- preference.game(20, 2, pref.matrix=pf)
-\dontrun{tkplot(g, layout=layout.fruchterman.reingold)}
-
-pf <- matrix( c(0, 1, 0, 0), nr=2)
-g <- asymmetric.preference.game(20, 2, pref.matrix=pf)
-\dontrun{tkplot(g, layout=layout.circle)}
-}
-\seealso{\code{\link{establishment.game}}.
-  \code{\link{callaway.traits.game}}
-}
-\keyword{graphs}
diff --git a/man/print.graph.Rd b/man/print.graph.Rd
deleted file mode 100644
index d9babbb..0000000
--- a/man/print.graph.Rd
+++ /dev/null
@@ -1,82 +0,0 @@
-\name{print.igraph}
-\alias{print.igraph}
-\alias{str.igraph}
-\alias{summary.igraph}
-\title{Print graphs to the terminal}
-\description{These functions attempt to print a graph to the terminal in
-  a human readable form.}
-\usage{
-\method{print}{igraph}(x, full=getIgraphOpt("print.full"),
-  graph.attributes=getIgraphOpt("print.graph.attributes"),
-  vertex.attributes=getIgraphOpt("print.vertex.attributes"),
-  edge.attributes=getIgraphOpt("print.edge.attributes"),
-  names=TRUE, \dots)
-\method{summary}{igraph}(object, \dots)
-\method{str}{igraph}(object, \dots)
-}
-\arguments{
-  \item{x}{The graph to print.}
-  \item{full}{Logical scalar, whether to print the graph structure
-    itself as well.}
-  \item{graph.attributes}{Logical constant, whether to print graph attributes.}
-  \item{vertex.attributes}{Logical constant, whether to print vertex attributes.}
-  \item{edge.attributes}{Logical constant, whether to print edge
-    attributes.}
-  \item{names}{Logical constant, whether to print symbolic vertex names
-    (ie. the \code{name} vertex attribute) or vertex ids.}
-  \item{object}{The graph of which the summary will be printed.}
-  \item{\dots}{Additional agruments.}
-}
-\details{
-  \code{summary.igraph} prints the number of vertices, edges and whether the
-  graph is directed.
-
-  \code{str.igraph} prints the same information, and also lists
-  the edges, and optionally graph, vertex and/or edge attributes.
-
-  \code{print.igraph} behaves either as \code{summary.igraph} or
-  \code{str.igraph} depending on the \code{full} argument. See also the
-  \sQuote{print.full} igraph option and \code{\link{getIgraphOpt}}.
-
-  The graph summary printed by \code{summary.igraph} (and
-  \code{print.igraph} and \code{str.igraph}) consists one or more
-  lines. The first line contains the basic properties of the graph, and
-  the rest contains its attributes. Here is an example, a small star
-  graph with weighed directed edges and named vertices: \preformatted{    IGRAPH DNW- 10 9 -- In-star
-    + attr: name (g/c), mode (g/c), center (g/n), name (v/c),
-      weight (e/n) }
-  The first line always starts with \code{IGRAPH}, showing you that the
-  object is an igraph graph. Then a four letter long code string is
-  printed. The first letter distinguishes between directed
-  (\sQuote{\code{D}}) and undirected (\sQuote{\code{U}}) graphs. The
-  second letter is \sQuote{\code{N}} for named graphs, i.e. graphs with
-  the \code{name} vertex attribute set. The third letter is
-  \sQuote{\code{W}} for weighted graphs, i.e. graphs with the
-  \code{weight} edge attribute set. The fourth letter is
-  \sQuote{\code{B}} for bipartite graphs, i.e. for graphs with the
-  \code{type} vertex attribute set.
-
-  Then, after two dashes, the name of the graph is printed, if it has
-  one, i.e. if the \code{name} graph attribute is set.
-
-  From the second line, the attributes of the graph are listed,
-  separated by a comma. After the attribute names, the kind of the
-  attribute -- graph (\sQuote{\code{g}}), vertex (\sQuote{\code{v}}) or
-  edge (\sQuote{\code{e}}) -- is denoted, and the type of the 
-  attribute as well, character (\sQuote{\code{c}}), numeric
-  (\sQuote{\code{n}}), logical (\sQuote{\code{l}}), or
-  other (\sQuote{\code{x}}).  
-  
-  As of igraph 0.4 \code{str.igraph} and \code{print.igraph} use the
-  \code{max.print} option, see \code{\link[base]{options}} for details.
-}
-\value{All these functions return the graph invisibly.}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-%\seealso{}
-\examples{
-g <- graph.ring(10)
-g
-summary(g)
-}
-\keyword{graphs}
diff --git a/man/print.igraph.Rd b/man/print.igraph.Rd
new file mode 100644
index 0000000..ad6253d
--- /dev/null
+++ b/man/print.igraph.Rd
@@ -0,0 +1,97 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/print.R
+\name{print.igraph}
+\alias{print.igraph}
+\alias{str.igraph}
+\alias{summary.igraph}
+\title{Print graphs to the terminal}
+\usage{
+\method{print}{igraph}(x, full = igraph_opt("print.full"),
+  graph.attributes = igraph_opt("print.graph.attributes"),
+  vertex.attributes = igraph_opt("print.vertex.attributes"),
+  edge.attributes = igraph_opt("print.edge.attributes"), names = TRUE,
+  max.lines = igraph_opt("auto.print.lines"), ...)
+
+\method{summary}{igraph}(object, ...)
+}
+\arguments{
+\item{x}{The graph to print.}
+
+\item{full}{Logical scalar, whether to print the graph structure itself as
+well.}
+
+\item{graph.attributes}{Logical constant, whether to print graph attributes.}
+
+\item{vertex.attributes}{Logical constant, whether to print vertex
+attributes.}
+
+\item{edge.attributes}{Logical constant, whether to print edge attributes.}
+
+\item{names}{Logical constant, whether to print symbolic vertex names (ie.
+the \code{name} vertex attribute) or vertex ids.}
+
+\item{max.lines}{The maximum number of lines to use. The rest of the
+output will be truncated.}
+
+\item{object}{The graph of which the summary will be printed.}
+
+\item{\dots}{Additional agruments.}
+}
+\value{
+All these functions return the graph invisibly.
+}
+\description{
+These functions attempt to print a graph to the terminal in a human readable
+form.
+}
+\details{
+\code{summary.igraph} prints the number of vertices, edges and whether the
+graph is directed.
+
+\code{str.igraph} prints the same information, and also lists the edges, and
+optionally graph, vertex and/or edge attributes.
+
+\code{print.igraph} behaves either as \code{summary.igraph} or
+\code{str.igraph} depending on the \code{full} argument. See also the
+\sQuote{print.full} igraph option and \code{\link{igraph_opt}}.
+
+The graph summary printed by \code{summary.igraph} (and \code{print.igraph}
+and \code{str.igraph}) consists one or more lines. The first line contains
+the basic properties of the graph, and the rest contains its attributes.
+Here is an example, a small star graph with weighed directed edges and named
+vertices: \preformatted{    IGRAPH DNW- 10 9 -- In-star
+    + attr: name (g/c), mode (g/c), center (g/n), name (v/c),
+      weight (e/n) }
+The first line always
+starts with \code{IGRAPH}, showing you that the object is an igraph graph.
+Then a four letter long code string is printed. The first letter
+distinguishes between directed (\sQuote{\code{D}}) and undirected
+(\sQuote{\code{U}}) graphs. The second letter is \sQuote{\code{N}} for named
+graphs, i.e. graphs with the \code{name} vertex attribute set. The third
+letter is \sQuote{\code{W}} for weighted graphs, i.e. graphs with the
+\code{weight} edge attribute set. The fourth letter is \sQuote{\code{B}} for
+bipartite graphs, i.e. for graphs with the \code{type} vertex attribute set.
+
+Then, after two dashes, the name of the graph is printed, if it has one,
+i.e. if the \code{name} graph attribute is set.
+
+From the second line, the attributes of the graph are listed, separated by a
+comma. After the attribute names, the kind of the attribute -- graph
+(\sQuote{\code{g}}), vertex (\sQuote{\code{v}}) or edge (\sQuote{\code{e}})
+-- is denoted, and the type of the attribute as well, character
+(\sQuote{\code{c}}), numeric (\sQuote{\code{n}}), logical
+(\sQuote{\code{l}}), or other (\sQuote{\code{x}}).
+
+As of igraph 0.4 \code{str.igraph} and \code{print.igraph} use the
+\code{max.print} option, see \code{\link[base]{options}} for details.
+}
+\examples{
+g <- make_ring(10)
+g
+summary(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/print.igraph.es.Rd b/man/print.igraph.es.Rd
new file mode 100644
index 0000000..9a551dc
--- /dev/null
+++ b/man/print.igraph.es.Rd
@@ -0,0 +1,83 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{print.igraph.es}
+\alias{print.igraph.es}
+\title{Print an edge sequence to the screen}
+\usage{
+\method{print}{igraph.es}(x, full = igraph_opt("print.full"), ...)
+}
+\arguments{
+\item{x}{An edge sequence.}
+
+\item{full}{Whether to show the full sequence, or truncate the output
+to the screen size.}
+
+\item{...}{Currently ignored.}
+}
+\value{
+The edge sequence, invisibly.
+}
+\description{
+For long edge sequences, the printing is truncated to fit to the
+screen. Use \code{print} explicitly and the code{full} argument to
+see the full sequence.
+}
+\details{
+Edge sequences created with the double bracket operator are printed
+differently, together with all attributes of the edges in the sequence,
+as a table.
+}
+\examples{
+# Unnamed graphs
+g <- make_ring(10)
+E(g)
+
+# Named graphs
+g2 <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10])
+E(g2)
+
+# All edges in a long sequence
+g3 <- make_ring(200)
+E(g3)
+E(g3) \%>\% print(full = TRUE)
+
+# Metadata
+g4 <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10]) \%>\%
+  set_edge_attr("weight", value = 1:10) \%>\%
+  set_edge_attr("color", value = "green")
+E(g4)
+E(g4)[[]]
+E(g4)[[1:5]]
+}
+\seealso{
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.vs}}
+}
+
diff --git a/man/print.igraph.vs.Rd b/man/print.igraph.vs.Rd
new file mode 100644
index 0000000..fcf7ff0
--- /dev/null
+++ b/man/print.igraph.vs.Rd
@@ -0,0 +1,81 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{print.igraph.vs}
+\alias{print.igraph.vs}
+\title{Show a vertex sequence on the screen}
+\usage{
+\method{print}{igraph.vs}(x, full = igraph_opt("print.full"), ...)
+}
+\arguments{
+\item{x}{A vertex sequence.}
+
+\item{full}{Whether to show the full sequence, or truncate the output
+to the screen size.}
+
+\item{...}{These arguments are currently ignored.}
+}
+\value{
+The vertex sequence, invisibly.
+}
+\description{
+For long vertex sequences, the printing is truncated to fit to the
+screen. Use \code{print} explicitly and the \code{full} argument to
+see the full sequence.
+}
+\details{
+Vertex sequence created with the double bracket operator are
+printed differently, together with all attributes of the vertices
+in the sequence, as a table.
+}
+\examples{
+# Unnamed graphs
+g <- make_ring(10)
+V(g)
+
+# Named graphs
+g2 <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10])
+V(g2)
+
+# All vertices in the sequence
+g3 <- make_ring(1000)
+V(g3)
+print(V(g3), full = TRUE)
+
+# Metadata
+g4 <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10]) \%>\%
+  set_vertex_attr("color", value = "red")
+V(g4)[[]]
+V(g4)[[2:5, 7:8]]
+}
+\seealso{
+Other vertex and edge sequences: \code{\link{$.igraph.es}},
+  \code{\link{$<-.igraph.es}}, \code{\link{E<-}},
+  \code{\link{[<-.igraph.es}},
+  \code{\link{[[<-.igraph.es}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}},
+  \code{\link{igraph-es-attributes}};
+  \code{\link{$.igraph.vs}}, \code{\link{$<-.igraph.vs}},
+  \code{\link{V<-}}, \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}}; \code{\link{E}};
+  \code{\link{V}}; \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{print.igraph.es}}
+}
+
diff --git a/man/print.igraphHRG.Rd b/man/print.igraphHRG.Rd
new file mode 100644
index 0000000..2d4fe69
--- /dev/null
+++ b/man/print.igraphHRG.Rd
@@ -0,0 +1,66 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{print.igraphHRG}
+\alias{print.igraphHRG}
+\title{Print a hierarchical random graph model to the screen}
+\usage{
+\method{print}{igraphHRG}(x, type = c("auto", "tree", "plain"), level = 3,
+  ...)
+}
+\arguments{
+\item{x}{\code{igraphHRG} object to print.}
+
+\item{type}{How to print the dendrogram, see details below.}
+
+\item{level}{The number of top levels to print from the dendrogram.}
+
+\item{...}{Additional arguments, not used currently.}
+}
+\value{
+The hierarchical random graph model itself, invisibly.
+}
+\description{
+\code{igraphHRG} objects can be printed to the screen in two forms: as
+a tree or as a list, depending on the \code{type} argument of the
+print function. By default the \code{auto} type is used, which selects
+\code{tree} for small graphs and \code{simple} (=list) for bigger
+ones. The \code{tree} format looks like
+ this: \preformatted{Hierarchical random graph, at level 3:
+g1        p=   0
+'- g15    p=0.33  1
+   '- g13 p=0.88  6  3  9  4  2  10 7  5  8
+'- g8     p= 0.5
+   '- g16 p= 0.2  20 14 17 19 11 15 16 13
+   '- g5  p=   0  12 18  }
+This is a graph with 20 vertices, and the
+top three levels of the fitted hierarchical random graph are
+printed. The root node of the HRG is always vertex group #1
+(\sQuote{\code{g1}} in the the printout). Vertex pairs in the left
+subtree of \code{g1} connect to vertices in the right subtree with
+probability zero, according to the fitted model. \code{g1} has two
+subgroups, \code{g15} and \code{g8}. \code{g15} has a subgroup of a
+single vertex (vertex 1), and another larger subgroup that contains
+vertices 6, 3, etc. on lower levels, etc.
+The \code{plain} printing is simpler and faster to produce, but less
+visual: \preformatted{Hierarchical random graph:
+g1  p=0.0 -> g12 g10   g2  p=1.0 -> 7 10      g3  p=1.0 -> g18 14
+g4  p=1.0 -> g17 15    g5  p=0.4 -> g15 17    g6  p=0.0 -> 1 4
+g7  p=1.0 -> 11 16     g8  p=0.1 -> g9 3      g9  p=0.3 -> g11 g16
+g10 p=0.2 -> g4 g5     g11 p=1.0 -> g6 5      g12 p=0.8 -> g8 8
+g13 p=0.0 -> g14 9     g14 p=1.0 -> 2 6       g15 p=0.2 -> g19 18
+g16 p=1.0 -> g13 g2    g17 p=0.5 -> g7 13     g18 p=1.0 -> 12 19
+g19 p=0.7 -> g3 20}
+It lists the two subgroups of each internal node, in
+as many columns as the screen width allows.
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg_tree}}; \code{\link{hrg}},
+  \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}}
+}
+
diff --git a/man/print.igraphHRGConsensus.Rd b/man/print.igraphHRGConsensus.Rd
new file mode 100644
index 0000000..3153cdc
--- /dev/null
+++ b/man/print.igraphHRGConsensus.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{print.igraphHRGConsensus}
+\alias{print.igraphHRGConsensus}
+\title{Print a hierarchical random graph consensus tree to the screen}
+\usage{
+\method{print}{igraphHRGConsensus}(x, ...)
+}
+\arguments{
+\item{x}{\code{igraphHRGConsensus} object to print.}
+
+\item{...}{Ignored.}
+}
+\value{
+The input object, invisibly, to allow method chaining.
+}
+\description{
+Consensus dendrograms (\code{igraphHRGConsensus} objects) are printed
+simply by listing the children of each internal node of the
+dendrogram: \preformatted{HRG consensus tree:
+g1 -> 11 12 13 14 15 16 17 18 19 20
+g2 -> 1  2  3  4  5  6  7  8  9  10
+g3 -> g1 g2}
+The root of the dendrogram is \code{g3} (because it has no incoming
+edges), and it has two subgroups, \code{g1} and \code{g2}.
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.game}}, \code{\link{sample_hrg}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg_tree}}; \code{\link{hrg}},
+  \code{\link{hrg.create}}; \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/r_pal.Rd b/man/r_pal.Rd
new file mode 100644
index 0000000..48b00b2
--- /dev/null
+++ b/man/r_pal.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/palette.R
+\name{r_pal}
+\alias{r_pal}
+\title{The default R palette}
+\usage{
+r_pal(n)
+}
+\arguments{
+\item{n}{The number of colors to use, the maximum is eight.}
+}
+\value{
+A character vector of color names.
+}
+\description{
+This is the default R palette, to be able to reproduce the
+colors of older igraph versions. Its colors are appropriate
+for categories, but they are not very attractive.
+}
+\seealso{
+Other palettes: \code{\link{categorical_pal}};
+  \code{\link{diverging_pal}}; \code{\link{sequential_pal}}
+}
+
diff --git a/man/radius.Rd b/man/radius.Rd
new file mode 100644
index 0000000..afc5c3e
--- /dev/null
+++ b/man/radius.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/paths.R
+\name{radius}
+\alias{radius}
+\title{Radius of a graph}
+\usage{
+radius(graph, mode = c("all", "out", "in", "total"))
+}
+\arguments{
+\item{graph}{The input graph, it can be directed or undirected.}
+
+\item{mode}{Character constant, gives whether the shortest paths to or from
+the given vertices should be calculated for directed graphs. If \code{out}
+then the shortest paths \emph{from} the vertex, if \code{in} then \emph{to}
+it will be considered. If \code{all}, the default, then the corresponding
+undirected graph will be used, edge directions will be ignored. This
+argument is ignored for undirected graphs.}
+}
+\value{
+A numeric scalar, the radius of the graph.
+}
+\description{
+The eccentricity of a vertex is its shortest path distance from the
+farthest other node in the graph. The smallest eccentricity in a graph
+is called its radius
+}
+\details{
+The eccentricity of a vertex is calculated by measuring the shortest
+distance from (or to) the vertex, to (or from) all vertices in the
+graph, and taking the maximum.
+
+This implementation ignores vertex pairs that are in different
+components.  Isolate vertices have eccentricity zero.
+}
+\examples{
+g <- make_star(10, mode="undirected")
+eccentricity(g)
+radius(g)
+}
+\references{
+Harary, F. Graph Theory. Reading, MA: Addison-Wesley, p. 35,
+1994.
+}
+\seealso{
+\code{\link{eccentricity}} for the underlying
+  calculations, code{\link{distances}} for general shortest path
+  calculations.
+}
+
diff --git a/man/random_walk.Rd b/man/random_walk.Rd
new file mode 100644
index 0000000..401b1bd
--- /dev/null
+++ b/man/random_walk.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/random_walk.R
+\name{random_walk}
+\alias{random_walk}
+\title{Random walk on a graph}
+\usage{
+random_walk(graph, start, steps, mode = c("out", "in", "all"),
+  stuck = c("return", "error"))
+}
+\arguments{
+\item{graph}{The input graph, might be undirected or directed.}
+
+\item{start}{The start vertex.}
+
+\item{steps}{The number of steps to make.}
+
+\item{mode}{How to follow directed edges. \code{"out"} steps along the
+edge direction, \code{"in"} is opposite to that. \code{"all"} ignores
+edge directions. This argument is ignored for directed graphs.}
+
+\item{stuck}{What to do if the random walk gets stuck. \code{"return"}
+returns the partial walk, \code{"error"} raises an error.}
+}
+\value{
+A vertex sequence containing the vertices along the walk.
+}
+\description{
+Do a random walk. From the given start vertex, take the given number of
+steps, choosing an edge from the actual vertex uniformly randomly. Edge
+directions are observed in directed graphs (see the \code{mode} argument
+as well). Multiple and loop edges are also observed.
+}
+\examples{
+## Stationary distribution of a Markov chain
+g <- make_ring(10, directed = TRUE) \%u\%
+  make_star(11, center = 11) + edge(11, 1)
+
+ec <- eigen_centrality(g, directed = TRUE)$vector
+pg <- page_rank(g, damping = 0.999)$vector
+w <- random_walk(g, start = 1, steps = 10000)
+
+## These are similar, but not exactly the same
+cor(table(w), ec)
+
+## But these are (almost) the same
+cor(table(w), pg)
+}
+
diff --git a/man/read.graph.Rd b/man/read.graph.Rd
deleted file mode 100644
index 6e3e940..0000000
--- a/man/read.graph.Rd
+++ /dev/null
@@ -1,343 +0,0 @@
-\name{read.graph}
-\alias{read.graph}
-\alias{LGL}
-\alias{Pajek}
-\alias{GraphML}
-\alias{GML}
-\alias{DL}
-\alias{UCINET}
-\title{Reading foreign file formats}
-\description{The \code{read.graph} function is able to read graphs in
-  various representations from a file, or from a http
-  connection. Currently some simple formats are supported.}
-\usage{
-read.graph(file, format = c("edgelist", "pajek", "ncol", "lgl",
-        "graphml", "dimacs", "graphdb", "gml", "dl"), \dots)
-}
-\arguments{
-  \item{file}{The connection to read from. This can be a local file, or
-    a \code{http} or \code{ftp} connection. It can also be a character
-    string  with the file name or URI.}
-  \item{format}{Character constant giving the file format. Right now
-    \code{edgelist}, \code{pajek}, \code{graphml}, \code{gml},
-    \code{ncol}, \code{lgl}, \code{dimacs} and \code{graphdb}
-    are supported, the default is \code{edgelist}. As of igraph 0.4 this
-    argument is case insensitive.
-  }
-  \item{\dots}{Additional arguments, see below.}
-}
-\details{
-  The \code{read.graph} function may have additional arguments depending
-  on the file format (the \code{format} argument). See the details
-  separately for each file format, below.
-}
-\section{Edge list format}{
-      This format is a simple text file with numeric vertex ids defining
-      the edges. There is no need to have newline characters between the
-      edges, a simple space will also do.
-      
-      Additional arguments:
-      \describe{
-	\item{n}{The number of vertices in the graph. If it is smaller
-	  than or equal to the largest integer in the file, then it is
-	  ignored; so it is safe to set it to zero (the default).}
-	\item{directed}{Logical scalar, whether to create a directed
-	  graph. The default value is \code{TRUE}.}
-      }
-}
-\section{Pajek format}{
-      Pajek it a popular network analysis program for Windows. (See the
-      Pajek homepage at
-      \url{http://vlado.fmf.uni-lj.si/pub/networks/pajek/}.)
-      It has a quite flexible but not very well
-      documented file format, see the Pajek manual on the Pajek homepage
-      for some information about the file format.
-
-      \code{igraph} implements only a subset of the Pajek format:
-      \itemize{
-	\item Only .net files are supported, Pajek project files (which
-	  can contain many graph and also other type of data) are
-	  not. Poject files might be supported in a forthcoming igraph
-	  release if they turned out to be needed.
-	\item Time events networks are not supported.
-	\item Hypergraphs (graphs with non-binary edges) are not
-	  supported as igraph cannot handle them.
-	\item Graphs containing both directed and undirected edges are
-	  not supported as igraph cannot represent them.
-	\item Graph with multiple edge sets are not supported.
-      }
-
-      From version 0.6.1 igraph supports reading bipartite (two-mode)
-      graphs from Pajek files and adds the \code{type} vertex
-      attribute. A warning is given if invalid edges (edges connecting
-      vertices of the same type) are present in the file.
-      
-      Vertex and edge attributes defined in the Pajek file will be also
-      read and assigned to the graph object to be created. These are
-      mainly parameters for graph visualization, but not exclusively,
-      eg. the file might contain edge weights as well.
-
-      The following vertex attributes might be added:
-      \tabular{ll}{
-	igraph name \tab description, Pajek attribute \cr
-	id 	    \tab Vertex id \cr
-	x, y, z     \tab The \sQuote{x}, \sQuote{y} and \sQuote{z} coordinate of the vertex \cr
-	vertexsize  \tab The size of the vertex when plotted (\code{size} in Pajek). \cr
-	shape 	    \tab The shape of the vertex when plotted. \cr
-	color 	    \tab Vertex color (\code{ic} in Pajek) if given with symbolic name \cr
-	framecolor  \tab Border color (\code{bc} in Pajek) if given with symbolic name \cr
-	labelcolor  \tab Label color (\code{lc} in Pajek) if given with symbolic name \cr
-	xfact, yfact \tab The \code{x_fact} and \code{y_fact} Pajek attributes. \cr
-	labeldist \tab The distance of the label from the vertex. (\code{lr} in Pajek.) \cr
-	labeldegree, \tab \cr
-	labeldegree2 \tab The \code{la} and \code{lphi} Pajek attributes \cr
-	framewidth \tab The width of the border (\code{bw} in Pajek). \cr
-	fontsize  \tab Size of the label font (\code{fos} in Pajek.) \cr
-	rotation \tab The rotation of the vertex (\code{phi} in Pajek). \cr
-	radius \tab Radius, for some vertex shapes (\code{r} in Pajek). \cr
-	diamondratio \tab For the diamond shape (\code{q} in Pajek). \cr
-	type \tab vertex types in bipartite (two-mode) graphs. \cr
-      }
-
-      These igraph attributes are only created if there is at least one vertex
-      in the Pajek file which has the corresponding associated
-      information. Eg. if there are vertex coordinates for at least one vertex
-      then the \sQuote{x}, \sQuote{y} and possibly also \sQuote{z}
-      vertex attributes will be created. For those vertices for which the
-      attribute is not defined, \code{NaN} is assigned. 
-      
-      The following edge attributes might be added:
-      \tabular{ll}{
-	igraph name \tab description, Pajek attribute \cr
-	weight 	\tab Edge weights. \cr
-	label 	\tab \code{l} in Pajek. \cr
-	color 	\tab Edge color, if the color is given with a symbolic name, \code{c} in Pajek. \cr
-	color-red, \tab \cr
-	color-green, \tab \cr
-	color-blue \tab Edge color if it was given in RGB notation, \code{c} in Pajek. \cr
-	edgewidth \tab \code{w} in Pajek. \cr
-	arrowsize \tab \code{s} in Pajek. \cr
-	hook1, hook2 \tab \code{h1} and \code{h2} in Pajek. \cr
-	angle1, angle2 \tab \code{a1} and \code{a2} in Pajek, Bezier curve parameters. \cr
-	velocity1, \tab \cr
-	velocity2 \tab \code{k1} and \code{k2} in Pajek, Bezier curve parameter. \cr
-	arrowpos \tab \code{ap} in Pajek. \cr
-	labelpos \tab \code{lp} in Pajek. \cr
-	labelangle, \tab \cr
-	labelangle2 \tab \code{lr} and \code{lphi} in Pajek. \cr
-	labeldegree \tab \code{la} in Pajek. \cr
-	fontsize \tab \code{fos} in Pajek. \cr
-	arrowtype \tab \code{a} in Pajek. \cr
-	linepattern \tab \code{p} in Pajek. \cr
-	labelcolor \tab \code{lc} in Pajek. \cr
-      }
-      
-      There are no additional arguments for this format.
-}
-\section{GraphML file format}{
-      GraphML is an XML-based file format (an XML application in the XML
-      terminology) to describe graphs. It is a modern format, and can
-      store graphs with an extensible set of vertex and edge attributes,
-      and generalized graphs which igraph cannot handle. Thus igraph
-      supports only a subset of the GraphML language: 
-      \itemize{
-	\item Hypergraphs are not supported.
-	\item Nested graphs are not supported.
-	\item Mixed graphs, ie. graphs with both directed and
-	  undirected edges are not supported. read.graph() sets the
-	  graph directed if this is the default in the GraphML file,
-	  even if all the edges are in fact undirected.
-      }
-
-      See the GraphML homepage at
-      \url{http://graphml.graphdrawing.org} for more information about
-      the GraphML format.       
-      
-      Additional arguments:
-      \describe{
-	\item{index}{If the GraphML file contains more than one graphs,
-	  this argument can be used to select the graph to read. By
-	  default the first graph is read (index 0).}
-      }
-}
-\section{GML file format}{
-      GML is a simple textual format, see
-      \url{http://www.fim.uni-passau.de/en/fim/faculty/chairs/theoretische-informatik/projects.html} for details.
- 
-      Although all syntactically correct GML can be parsed, 
-      we implement only a subset of this format, some attributes might be
-      ignored. Here is a list of all the differences:
-      \itemize{
-	\item Only \code{node} and \code{edge} attributes are 
-	  used, and only if they have a simple type: integer, real or
-	  string. So if an attribute is an array or a record, then it is 
-	  ignored. This is also true if only some values of the
-	  attribute are complex.
-	\item Top level attributes except for \code{Version} and the
-	  first \code{graph} attribute are completely ignored.
-	\item Graph attributes except for \code{node} and
-	  \code{edge} are completely ignored.
-	\item There is no maximum line length.
-	\item There is no maximum keyword length.
-	\item Character entities in strings are not interpreted.
-	\item We allow \code{inf} (infinity) and \code{nan}
-	  (not a number) as a real number. This is case insensitive, so
-	  \code{nan}, \code{NaN} and \code{NAN} are equal.
-      }
-      
-      Please contact us if you cannot live with these
-      limitations of the GML parser.
-
-      There are not additional argument for this format.
-}
-\section{DL file format}{
-      The DL format is a simple textual file format used by the UCINET
-      software. See
-      \url{http://www.analytictech.com/networks/dataentry.htm} for
-      examples. All formats mentioned here is supported by igraph.
-
-      Note the specification does not mention whether the
-      format is case sensitive or not. For igraph DL files are case
-      sensitive, i.e. \sQuote{Larry} and \sQuote{larry} are not the
-      same.
-      
-      Additional arguments:
-      \describe{
-	\item{directed}{Logical scalar, whether to create a directed
-	  graph. The default is to make the graph directed.}
-      }
-}
-\section{NCOL format}{
-      This format is used by the Large Graph Layout program
-      (\url{http://bioinformatics.icmb.utexas.edu/lgl}), and it is
-      simply a symbolic weighted edge list. It is a simple text file
-      with one edge per line. An edge is defined by two symbolic vertex
-      names separated by whitespace. (The symbolic vertex names
-      themselves cannot contain whitespace.) They might followed by an
-      optional number, this will be the weight of the edge; the number
-      can be negative and can be in scientific notation. If there is no
-      weight specified to an edge it is assumed to be zero. 
-
-      The resulting graph is always undirected. LGL cannot deal with
-      files which contain multiple or loop edges, this is however not
-      checked here, as igraph is happy with these.
-
-      Additional arguments:
-      \describe{
-	\item{names}{Logical constant, whether to add the symbolic names
-	  as vertex attributes to the graph. If TRUE the name of the
-	  vertex attribute will be \sQuote{name}.}
-	\item{weights}{Character scalar, specifies whether edge weights
-	  should be added to the graph. Possible values are and their
-	  meaning are: \sQuote{no}, edge weights will not be added;
-	  \sQuote{yes}, edge weights will be added, if they are not
-	  present in the file, then all edges get zero weight;
-	  \sQuote{auto}, edge weights will added if they are present in
-	  the file, otherwise not. The default is \sQuote{auto}.
-	}
-	\item{directed}{Logical constant, whether to create a directed
-	  graph. The default is undirected.} 
-      }
-}
-\section{LGL file format}{
-      The \code{lgl} format is used by the Large Graph Layout
-      visualization software
-      (\url{http://bioinformatics.icmb.utexas.edu/lgl}), it can describe
-      undirected optionally weighted graphs. From the LGL manual:
-      \dQuote{The second format is the LGL file format (.lgl file
-      suffix). This is yet another graph file format that tries to be
-      as stingy as possible with space, yet keeping the edge file in a
-      human readable (not binary) format. The format itself is like
-      the following: \preformatted{	 # vertex1name 
-	vertex2name [optionalWeight]
-	vertex3name [optionalWeight]
-      } Here, the first vertex of an edge is preceded with a pound sign
-      '\#'.  Then each vertex that shares an edge with that vertex is
-      listed one per line on subsequent lines.}
-      
-      LGL cannot handle loop and multiple edges or directed graphs, but
-      in igraph it is not an error to have multiple and loop edges.
-      
-      Additional arguments:
-      \describe{
-	\item{names}{Logical constant, whether to add the symbolic names
-	  as vertex attributes to the graph. If TRUE the name of the
-	  vertex attribute will be \sQuote{name}.}
-	\item{weights}{Character scalar, specifies whether edge weights
-	  should be added to the graph. Possible values are and their
-	  meaning are: \sQuote{no}, edge weights will not be added;
-	  \sQuote{yes}, edge weights will be added, if they are not
-	  present in the file, then all edges get zero weight;
-	  \sQuote{auto}, edge weights will added if they are present in
-	  the file, otherwise not. The default is \sQuote{auto}.
-	}
-      }      
-}
-\section{DIMACS file format}{
-      The DIMACS file format, more specifically the 
-      version for network flow problems, see the files at
-      \url{ftp://dimacs.rutgers.edu/pub/netflow/general-info/}
-
-      This is a line-oriented text file (ASCII) format. The first
-      character of each line defines the type of the line. If the first
-      character is \code{c} the line is a comment line and it is
-      ignored. There is one problem line (\code{p}) in the file, it
-      must appear before any node and arc descriptor lines. The problem
-      line has three fields separated by spaces: the problem type
-      (\code{min}, \code{max} or \code{asn}), the
-      number of vertices and number of edges in the graph.
-      Exactly two node identification lines are expected
-      (\code{n}), one for the source, one for the target vertex.
-      These have two fields: the id of the vertex and the type of the
-      vertex, either \code{s} (=source) or \code{t}
-      (=target). Arc lines start with \code{a} and have three
-      fields: the source vertex, the target vertex and the edge capacity.
-      
-      Vertex ids are numbered from 1.
-
-      The source vertex is assigned to the \code{source}, the target
-      vertex to the \code{target} graph attribute. The edge capacities
-      are assigned to the \code{capacity} edge attribute.
-
-      Additional arguments:
-      \describe{
-	\item{directed}{Logical scalar, whether to create a directed
-	  graph. By default a directed graph is created.
-	}
-      }
-}
-\section{GraphDB format}{
-      This is a binary format, used in the graph database
-      for isomorphism testing. From the (now defunct) graph database
-      homepage:
-
-      \emph{The graphs are stored in a compact binary format, one graph per
-	file. The file is composed of 16 bit words, which are represented
-	using the so-called little-endian convention, i.e. the least
-	significant byte of the word is stored first.}
-      
-      \emph{Then, for each node, the file contains the list of edges coming
-	out of the node itself. The list is represented by a word encoding
-	its length, followed by a word for each edge, representing the
-	destination node of the edge. Node numeration is 0-based, so the
-	first node of the graph has index 0.}
-
-      A copy of the graph database homepage can be found here:
-      \url{http://web.archive.org/web/20090215182331/http://amalfi.dis.unina.it/graph/db/doc/graphdbat.html}.
-      
-      See also \code{\link{graph.graphdb}}.
-      
-      Only unlabelled graphs are implemented.
-
-      Additional attributes:
-      \describe{
-	\item{directed}{Logical scalar. Whether to create a directed
-	  graph.}
-      }
-}
-\value{A graph object.}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{write.graph}} }
-% \examples{}
-\keyword{graphs}
diff --git a/man/read_graph.Rd b/man/read_graph.Rd
new file mode 100644
index 0000000..985e78e
--- /dev/null
+++ b/man/read_graph.Rd
@@ -0,0 +1,60 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/foreign.R
+\name{read_graph}
+\alias{DL}
+\alias{GML}
+\alias{GraphML}
+\alias{LGL}
+\alias{Pajek}
+\alias{UCINET}
+\alias{read.graph}
+\alias{read_graph}
+\title{Reading foreign file formats}
+\usage{
+read_graph(file, format = c("edgelist", "pajek", "ncol", "lgl", "graphml",
+  "dimacs", "graphdb", "gml", "dl"), ...)
+}
+\arguments{
+\item{file}{The connection to read from. This can be a local file, or a
+\code{http} or \code{ftp} connection. It can also be a character string with
+the file name or URI.}
+
+\item{format}{Character constant giving the file format. Right now
+\code{as_edgelist}, \code{pajek}, \code{graphml}, \code{gml}, \code{ncol},
+\code{lgl}, \code{dimacs} and \code{graphdb} are supported, the default is
+\code{edgelist}. As of igraph 0.4 this argument is case insensitive.}
+
+\item{\dots}{Additional arguments, see below.}
+}
+\value{
+A graph object.
+}
+\description{
+The \code{read_graph} function is able to read graphs in various
+representations from a file, or from a http connection. Currently some
+simple formats are supported.
+}
+\details{
+The \code{read_graph} function may have additional arguments depending on
+the file format (the \code{format} argument). See the details separately for
+each file format, below.
+}
+\section{Edge list format}{
+ This format is a simple text file with numeric
+vertex ids defining the edges. There is no need to have newline characters
+between the edges, a simple space will also do.
+
+Additional arguments: \describe{ \item{n}{The number of vertices in the
+graph. If it is smaller than or equal to the largest integer in the file,
+then it is ignored; so it is safe to set it to zero (the default).}
+\item{directed}{Logical scalar, whether to create a directed graph. The
+default value is \code{TRUE}.} }
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{write_graph}}
+}
+\keyword{graphs}
+
diff --git a/man/reciprocity.Rd b/man/reciprocity.Rd
index 6cc6e06..1b7fc4e 100644
--- a/man/reciprocity.Rd
+++ b/man/reciprocity.Rd
@@ -1,43 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{reciprocity}
 \alias{reciprocity}
-\concept{Reciprocity}
 \title{Reciprocity of graphs}
-\description{Calculates the reciprocity of a directed graph.}
 \usage{
-reciprocity(graph, ignore.loops = TRUE, mode = c("default", "ratio")) 
+reciprocity(graph, ignore.loops = TRUE, mode = c("default", "ratio"))
 }
 \arguments{
-  \item{graph}{The graph object.}
-  \item{ignore.loops}{Logical constant, whether to ignore loop edges.}
-  \item{mode}{See below.}
+\item{graph}{The graph object.}
+
+\item{ignore.loops}{Logical constant, whether to ignore loop edges.}
+
+\item{mode}{See below.}
+}
+\value{
+A numeric scalar between zero and one.
+}
+\description{
+Calculates the reciprocity of a directed graph.
 }
 \details{
-The measure of reciprocity defines the proporsion of mutual
-connections, in a directed graph. It is most commonly defined as
-the probability that the opposite counterpart of a directed edge is
-also included in the graph. Or in adjacency matrix notation: 
-\eqn{\sum_{ij} (A\cdot A')_{ij}}{sum(i, j, (A.*A')ij) / sum(i, j, Aij)},
-where \eqn{A\cdot A'}{A.*A'} is the element-wise product of matrix
-\eqn{A} and its transpose. This measure is calculated if the \code{mode}
-argument is \code{default}.
+The measure of reciprocity defines the proporsion of mutual connections, in
+a directed graph. It is most commonly defined as the probability that the
+opposite counterpart of a directed edge is also included in the graph. Or in
+adjacency matrix notation: \eqn{\sum_{ij} (A\cdot A')_{ij}}{sum(i, j,
+(A.*A')ij) / sum(i, j, Aij)}, where \eqn{A\cdot A'}{A.*A'} is the
+element-wise product of matrix \eqn{A} and its transpose. This measure is
+calculated if the \code{mode} argument is \code{default}.
 
-Prior to igraph version 0.6, another measure was implemented,
-defined as the probability of mutual connection between a vertex
-pair, if we know that there is a (possibly non-mutual) connection
-between them. In other words, (unordered) vertex pairs are
-classified into three groups: (1) not-connected, (2)
-non-reciprocaly connected, (3) reciprocally connected. 
-The result is the size of group (3), divided by the sum of group
-sizes (2)+(3). This measure is calculated if \code{mode} is
-\code{ratio}.
+Prior to igraph version 0.6, another measure was implemented, defined as the
+probability of mutual connection between a vertex pair, if we know that
+there is a (possibly non-mutual) connection between them. In other words,
+(unordered) vertex pairs are classified into three groups: (1)
+not-connected, (2) non-reciprocaly connected, (3) reciprocally connected.
+The result is the size of group (3), divided by the sum of group sizes
+(2)+(3). This measure is calculated if \code{mode} is \code{ratio}.
 }
-\value{A numeric scalar between zero and one.}
-% \references{}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and
-  Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
 \examples{
-g <- random.graph.game(20, 5/20, directed=TRUE)
+g <- sample_gnp(20, 5/20, directed=TRUE)
 reciprocity(g)
 }
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com}
+}
 \keyword{graphs}
+
diff --git a/man/rep.igraph.Rd b/man/rep.igraph.Rd
new file mode 100644
index 0000000..4256799
--- /dev/null
+++ b/man/rep.igraph.Rd
@@ -0,0 +1,31 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{rep.igraph}
+\alias{*.igraph}
+\alias{rep.igraph}
+\title{Replicate a graph multiple times}
+\usage{
+\method{rep}{igraph}(x, n, mark = TRUE, ...)
+
+\method{*}{igraph}(x, n)
+}
+\arguments{
+\item{x}{The input graph.}
+
+\item{n}{Number of times to replicate it.}
+
+\item{mark}{Whether to mark the vertices with a \code{which} attribute,
+an integer number denoting which replication the vertex is coming
+from.}
+
+\item{...}{Additional arguments to satisfy S3 requirements,
+  currently ignored.}
+}
+\description{
+The new graph will contain the input graph the given number
+of times, as unconnected components.
+}
+\examples{
+rings <- make_ring(5) * 5
+}
+
diff --git a/man/rev.igraph.es.Rd b/man/rev.igraph.es.Rd
new file mode 100644
index 0000000..1462296
--- /dev/null
+++ b/man/rev.igraph.es.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{rev.igraph.es}
+\alias{rev.igraph.es}
+\title{Reverse the order in an edge sequence}
+\usage{
+\method{rev}{igraph.es}(x)
+}
+\arguments{
+\item{x}{The edge sequence to reverse.}
+}
+\value{
+The reversed edge sequence.
+}
+\description{
+Reverse the order in an edge sequence
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+E(g)
+E(g) \%>\% rev()
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/rev.igraph.vs.Rd b/man/rev.igraph.vs.Rd
new file mode 100644
index 0000000..84d0f9a
--- /dev/null
+++ b/man/rev.igraph.vs.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{rev.igraph.vs}
+\alias{rev.igraph.vs}
+\title{Reverse the order in a vertex sequence}
+\usage{
+\method{rev}{igraph.vs}(x)
+}
+\arguments{
+\item{x}{The vertex sequence to reverse.}
+}
+\value{
+The reversed vertex sequence.
+}
+\description{
+Reverse the order in a vertex sequence
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+V(g) \%>\% rev()
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/rewire.Rd b/man/rewire.Rd
index 7d67a5e..9a86fc4 100644
--- a/man/rewire.Rd
+++ b/man/rewire.Rd
@@ -1,34 +1,32 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/rewire.R
 \name{rewire}
 \alias{rewire}
-\title{Graph rewiring}
-\description{Randomly rewires a graph while preserving the degree
-  distribution.}
+\title{Rewiring edges of a graph}
 \usage{
-rewire(graph, mode = c("simple", "loops"), niter = 100) 
+rewire(graph, with)
 }
 \arguments{
-  \item{graph}{The graph to be rewired.}
-  \item{mode}{The rewiring algorithm to be used. It can be one of the
-    following: \code{simple}: simple rewiring algorithm which
-    chooses two arbitrary edges in each step (namely (a,b) and (c,d))
-    and substitutes them with (a,d) and (c,b) if they don't yet exist,
-    avoiding the creation or destruction of loop edges or \code{loops}:
-    similar to \code{simple} but allows the creation and destruction of
-    loop edges.}
-  \item{niter}{Number of rewiring trials to perform.}
+\item{graph}{The graph to rewire}
+
+\item{with}{A function call to one of the rewiring methods,
+see details below.}
 }
-\details{
-This function generates a new graph based on the original one by
-randomly rewiring edges while preserving the original graph's degree
-distribution.
+\value{
+The rewired graph.
+}
+\description{
+See the links below for the implemented rewiring methods.
 }
-\value{A new graph object.}
-% \references{}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and
-  Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{degree.sequence.game}}}
 \examples{
-g <- graph.ring(20)
-g2 <- rewire(g, niter=3)
+g <- make_ring(10)
+g \%>\%
+  rewire(each_edge(p = .1, loops = FALSE)) \%>\%
+  plot(layout=layout_in_circle)
+str(rewire(g, with = keeping_degseq(niter = vcount(g) * 10)))
+}
+\seealso{
+Other rewiring functions: \code{\link{each_edge}};
+  \code{\link{keeping_degseq}}
 }
-\keyword{graphs}
+
diff --git a/man/rewire.edges.Rd b/man/rewire.edges.Rd
deleted file mode 100644
index f086e3e..0000000
--- a/man/rewire.edges.Rd
+++ /dev/null
@@ -1,33 +0,0 @@
-\name{rewire.edges}
-\alias{rewire.edges}
-\title{Rewires the endpoints of the edges of a graph randomly}
-\description{This function rewires the endpoints of the edges with a
-  constant probability uniformly randomly to a new vertex in a graph. } 
-\usage{
-rewire.edges(graph, prob, loops=FALSE, multiple=FALSE)
-}
-\arguments{
-  \item{graph}{The input graph}
-  \item{prob}{The rewiring probability, a real number between zero and
-    one.}
-  \item{loops}{Logical scalar, whether loop edges are allowed in the
-    rewired graph.}
-  \item{multiple}{Logical scalar, whether multiple edges are allowed
-    int the generated graph.}
-}
-\details{
-  Note that this function might create graphs with multiple and/or loop
-  edges.
-}
-\value{A new graph object.}
-%\references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-%\seealso{}
-\examples{
-# Some random shortcuts shorten the distances on a lattice
-g <- graph.lattice( length=100, dim=1, nei=5 )
-average.path.length(g)
-g <- rewire.edges( g, prob=0.05 )
-average.path.length(g)
-}
-\keyword{graphs}
diff --git a/man/rglplot.Rd b/man/rglplot.Rd
index 27732ec..d46811c 100644
--- a/man/rglplot.Rd
+++ b/man/rglplot.Rd
@@ -1,35 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/plot.R
 \name{rglplot}
 \alias{rglplot}
 \alias{rglplot.igraph}
-\concept{Visualization}
 \title{3D plotting of graphs with OpenGL}
-\description{Using the \code{rgl} package, \code{rglplot} plots a graph
-  in 3D. The plot can be zoomed, rotated, shifted, etc. but the
-  coordinates of the vertices is fixed.}
 \usage{
-rglplot(x, \dots)
+rglplot(x, ...)
 }
 \arguments{
-  \item{x}{The graph to plot.}
-  \item{\dots}{Additional arguments, see \code{\link{igraph.plotting}}
-    for the details}
+\item{x}{The graph to plot.}
+
+\item{\dots}{Additional arguments, see \code{\link{igraph.plotting}} for the
+details}
+}
+\value{
+\code{NULL}, invisibly.
+}
+\description{
+Using the \code{rgl} package, \code{rglplot} plots a graph in 3D. The plot
+can be zoomed, rotated, shifted, etc. but the coordinates of the vertices is
+fixed.
 }
 \details{
-  Note that \code{rglplot} is considered to be highly experimental. It
-  is not very useful either. See \code{\link{igraph.plotting}} for the
-  possible arguments.
-}
-\value{\code{NULL}, invisibly.}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{igraph.plotting}},
-  \code{\link{plot.igraph}} for the 2D version,
-  \code{\link{tkplot}} for interactive graph drawing in 2D.}
+Note that \code{rglplot} is considered to be highly experimental. It is not
+very useful either. See \code{\link{igraph.plotting}} for the possible
+arguments.
+}
 \examples{
 \dontrun{
-g <- graph.lattice( c(5,5,5) )
-coords <- layout.fruchterman.reingold(g, dim=3)
+g <- make_lattice( c(5,5,5) )
+coords <- layout_with_fr(g, dim=3)
 rglplot(g, layout=coords)
 }
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{igraph.plotting}}, \code{\link{plot.igraph}} for the 2D
+version, \code{\link{tkplot}} for interactive graph drawing in 2D.
+}
 \keyword{graphs}
+
diff --git a/man/running.mean.Rd b/man/running.mean.Rd
deleted file mode 100644
index 1f8e4c6..0000000
--- a/man/running.mean.Rd
+++ /dev/null
@@ -1,28 +0,0 @@
-\name{running.mean}
-\alias{running.mean}
-\title{Running mean of a time series}
-\description{\code{running.mean} calculates the running mean in a vector
-  with the given bin width.}
-\usage{
-running.mean(v, binwidth)
-}
-\arguments{
-  \item{v}{The numeric vector.}
-  \item{binwidth}{Numeric constant, the size of the bin, should be
-    meaningful, ie. smaller than the length of \code{v}. }
-}
-\details{The running mean of \code{v} is a \code{w}
-  vector of length \code{length(v)-binwidth+1}. The first element of
-  \code{w} id the average of the first \code{binwidth} elements of
-  \code{v}, the second element of \code{w} is the average of elements
-  \code{2:(binwidth+1)}, etc.}
-\value{
-  A numeric vector of length \code{length(v)-binwidth+1}
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-running.mean(1:100, 10)
-}
-\keyword{manip}
diff --git a/man/running_mean.Rd b/man/running_mean.Rd
new file mode 100644
index 0000000..8b95bf2
--- /dev/null
+++ b/man/running_mean.Rd
@@ -0,0 +1,36 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/other.R
+\name{running_mean}
+\alias{running.mean}
+\alias{running_mean}
+\title{Running mean of a time series}
+\usage{
+running_mean(v, binwidth)
+}
+\arguments{
+\item{v}{The numeric vector.}
+
+\item{binwidth}{Numeric constant, the size of the bin, should be meaningful,
+ie. smaller than the length of \code{v}.}
+}
+\value{
+A numeric vector of length \code{length(v)-binwidth+1}
+}
+\description{
+\code{running_mean} calculates the running mean in a vector with the given
+bin width.
+}
+\details{
+The running mean of \code{v} is a \code{w} vector of length
+\code{length(v)-binwidth+1}. The first element of \code{w} id the average of
+the first \code{binwidth} elements of \code{v}, the second element of
+\code{w} is the average of elements \code{2:(binwidth+1)}, etc.
+}
+\examples{
+running_mean(1:100, 10)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{manip}
+
diff --git a/man/sample_.Rd b/man/sample_.Rd
new file mode 100644
index 0000000..7e6666d
--- /dev/null
+++ b/man/sample_.Rd
@@ -0,0 +1,30 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{sample_}
+\alias{sample_}
+\title{Sample from a random graph model}
+\usage{
+sample_(...)
+}
+\arguments{
+\item{...}{Parameters, see details below.}
+}
+\description{
+Generic function for sampling from network models.
+}
+\details{
+TODO
+}
+\examples{
+pref_matrix <- cbind(c(0.8, 0.1), c(0.1, 0.7))
+blocky <- sample_(sbm(n = 20, pref.matrix = pref_matrix,
+  block.sizes = c(10, 10)))
+
+blocky2 <- pref_matrix \%>\%
+  sample_sbm(n = 20, block.sizes = c(10, 10))
+
+## Arguments are passed on from sample_ to sample_sbm
+blocky3 <- pref_matrix \%>\%
+  sample_(sbm(), n = 20, block.sizes = c(10, 10))
+}
+
diff --git a/man/sample_bipartite.Rd b/man/sample_bipartite.Rd
new file mode 100644
index 0000000..9b1e572
--- /dev/null
+++ b/man/sample_bipartite.Rd
@@ -0,0 +1,74 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_bipartite}
+\alias{bipartite}
+\alias{bipartite.random.game}
+\alias{sample_bipartite}
+\title{Bipartite random graphs}
+\usage{
+sample_bipartite(n1, n2, type = c("gnp", "gnm"), p, m, directed = FALSE,
+  mode = c("out", "in", "all"))
+
+bipartite(...)
+}
+\arguments{
+\item{n1}{Integer scalar, the number of bottom vertices.}
+
+\item{n2}{Integer scalar, the number of top vertices.}
+
+\item{type}{Character scalar, the type of the graph, \sQuote{gnp} creates a
+$G(n,p)$ graph, \sQuote{gnm} creates a $G(n,m)$ graph. See details below.}
+
+\item{p}{Real scalar, connection probability for $G(n,p)$ graphs. Should not
+be given for $G(n,m)$ graphs.}
+
+\item{m}{Integer scalar, the number of edges for $G(n,p)$ graphs. Should not
+be given for $G(n,p)$ graphs.}
+
+\item{directed}{Logical scalar, whether to create a directed graph. See also
+the \code{mode} argument.}
+
+\item{mode}{Character scalar, specifies how to direct the edges in directed
+graphs. If it is \sQuote{out}, then directed edges point from bottom
+vertices to top vertices. If it is \sQuote{in}, edges point from top
+vertices to bottom vertices. \sQuote{out} and \sQuote{in} do not generate
+mutual edges. If this argument is \sQuote{all}, then each edge direction is
+considered independently and mutual edges might be generated. This argument
+is ignored for undirected graphs.}
+
+\item{...}{Passed to \code{sample_bipartite}.}
+}
+\value{
+A bipartite igraph graph.
+}
+\description{
+Generate bipartite graphs using the Erdos-Renyi model
+}
+\details{
+Similarly to unipartite (one-mode) networks, we can define the $G(n,p)$, and
+$G(n,m)$ graph classes for bipartite graphs, via their generating process.
+In $G(n,p)$ every possible edge between top and bottom vertices is realized
+with probablity $p$, independently of the rest of the edges. In $G(n,m)$, we
+uniformly choose $m$ edges to realize.
+}
+\examples{
+## empty graph
+sample_bipartite(10, 5, p=0)
+
+## full graph
+sample_bipartite(10, 5, p=1)
+
+## random bipartite graph
+sample_bipartite(10, 5, p=.1)
+
+## directed bipartite graph, G(n,m)
+sample_bipartite(10, 5, type="Gnm", m=20, directed=TRUE, mode="all")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{sample_gnp}} for the unipartite version.
+}
+\keyword{graphs}
+
diff --git a/man/sample_correlated_gnp.Rd b/man/sample_correlated_gnp.Rd
new file mode 100644
index 0000000..cc56316
--- /dev/null
+++ b/man/sample_correlated_gnp.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_correlated_gnp}
+\alias{sample_correlated_gnp}
+\title{Generate a new random graph from a given graph by randomly
+adding/removing edges}
+\usage{
+sample_correlated_gnp(old.graph, corr, p = old.graph$p, permutation = NULL)
+}
+\arguments{
+\item{old.graph}{The original graph.}
+
+\item{corr}{A scalar in the unit interval, the target Pearson
+correlation between the adjacency matrices of the original the generated
+graph (the adjacency matrix being used as a vector).}
+
+\item{p}{A numeric scalar, the probability of an edge between two
+vertices, it must in the open (0,1) interval.}
+
+\item{permutation}{A numeric vector, a permutation vector that is
+applied on the vertices of the first graph, to get the second graph.  If
+\code{NULL}, the vertices are not permuted.}
+}
+\value{
+An unweighted graph of the same size as \code{old.graph} such
+that the correlation coefficient between the entries of the two
+adjacency matrices is \code{corr}.  Note each pair of corresponding
+matrix entries is a pair of correlated Bernoulli random variables.
+}
+\description{
+Sample a new graph by perturbing the adjacency matrix of a given graph
+and shuffling its vertices.
+}
+\details{
+Please see the reference given below.
+}
+\examples{
+g <- sample_gnp(1000, .1)
+g2 <- sample_correlated_gnp(g, corr = 0.5)
+cor(as.vector(g[]), as.vector(g2[]))
+g
+g2
+}
+\references{
+Lyzinski, V., Fishkind, D. E., Priebe, C. E. (2013).  Seeded
+graph matching for correlated Erdos-Renyi graphs.
+\url{http://arxiv.org/abs/1304.7844}
+}
+\seealso{
+\code{\link{sample_correlated_gnp_pair}},
+  \code{\link{sample_gnp}}
+}
+
diff --git a/man/sample_correlated_gnp_pair.Rd b/man/sample_correlated_gnp_pair.Rd
new file mode 100644
index 0000000..eae691b
--- /dev/null
+++ b/man/sample_correlated_gnp_pair.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_correlated_gnp_pair}
+\alias{sample_correlated_gnp_pair}
+\title{Sample a pair of correlated G(n,p) random graphs}
+\usage{
+sample_correlated_gnp_pair(n, corr, p, directed = FALSE, permutation = NULL)
+}
+\arguments{
+\item{n}{Numeric scalar, the number of vertices for the sampled graphs.}
+
+\item{corr}{A scalar in the unit interval, the target Pearson correlation
+between the adjacency matrices of the original the generated graph (the
+adjacency matrix being used as a vector).}
+
+\item{p}{A numeric scalar, the probability of an edge between two vertices,
+it must in the open (0,1) interval.}
+
+\item{directed}{Logical scalar, whether to generate directed graphs.}
+
+\item{permutation}{A numeric vector, a permutation vector that is applied on
+the vertices of the first graph, to get the second graph.  If \code{NULL},
+the vertices are not permuted.}
+}
+\value{
+A list of two igraph objects, named \code{graph1} and
+\code{graph2}, which are two graphs whose adjacency matrix entries are
+correlated with \code{corr}.
+}
+\description{
+Sample a new graph by perturbing the adjacency matrix of a given graph and
+shuffling its vertices.
+}
+\details{
+Please see the reference given below.
+}
+\examples{
+gg <- sample_correlated_gnp_pair(n = 10, corr = .8, p = .5,
+           directed = FALSE)
+gg
+cor(as.vector(gg[[1]][]), as.vector(gg[[2]][]))
+}
+\references{
+Lyzinski, V., Fishkind, D. E., Priebe, C. E. (2013).  Seeded
+graph matching for correlated Erdos-Renyi graphs.
+\url{http://arxiv.org/abs/1304.7844}
+}
+\seealso{
+\code{\link{sample_correlated_gnp}},
+  \code{\link{sample_gnp}}.
+}
+\keyword{graphs}
+\keyword{graphs,random}
+
diff --git a/man/sample_degseq.Rd b/man/sample_degseq.Rd
new file mode 100644
index 0000000..e4b1e78
--- /dev/null
+++ b/man/sample_degseq.Rd
@@ -0,0 +1,99 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_degseq}
+\alias{degree.sequence.game}
+\alias{degseq}
+\alias{sample_degseq}
+\title{Generate random graphs with a given degree sequence}
+\usage{
+sample_degseq(out.deg, in.deg = NULL, method = c("simple", "vl",
+  "simple.no.multiple"))
+
+degseq(...)
+}
+\arguments{
+\item{out.deg}{Numeric vector, the sequence of degrees (for undirected
+graphs) or out-degrees (for directed graphs). For undirected graphs its sum
+should be even. For directed graphs its sum should be the same as the sum of
+\code{in.deg}.}
+
+\item{in.deg}{For directed graph, the in-degree sequence. By default this is
+\code{NULL} and an undirected graph is created.}
+
+\item{method}{Character, the method for generating the graph. Right now the
+\dQuote{simple}, \dQuote{simple.no.multiple} and \dQuote{vl} methods are
+implemented.}
+
+\item{...}{Passed to \code{sample_degree}.}
+}
+\value{
+The new graph object.
+}
+\description{
+It is often useful to create a graph with given vertex degrees. This is
+exactly what \code{sample_degseq} does.
+}
+\details{
+The \dQuote{simple} method connects the out-stubs of the edges (undirected
+graphs) or the out-stubs and in-stubs (directed graphs) together. This way
+loop edges and also multiple edges may be generated. This method is not
+adequate if one needs to generate simple graphs with a given degree
+sequence. The multiple and loop edges can be deleted, but then the degree
+sequence is distorted and there is nothing to ensure that the graphs are
+sampled uniformly.
+
+The \dQuote{simple.no.multiple} method is similar to \dQuote{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 eventually succeed if the provided degree sequence is
+graphical, but there is no upper bound on the number of iterations.
+
+The \dQuote{vl} method is a more sophisticated generator. The algorithm and
+the implementation was done by Fabien Viger and Matthieu Latapy. This
+generator always generates undirected, connected simple graphs, it is an
+error to pass the \code{in.deg} argument to it.  The algorithm relies on
+first creating an initial (possibly unconnected) simple undirected graph
+with the given degree sequence (if this is possible at all). Then some
+rewiring is done to make the graph connected. Finally a Monte-Carlo
+algorithm is used to randomize the graph. The \dQuote{vl} samples from the
+undirected, connected simple graphs unformly. See
+\url{http://www-rp.lip6.fr/~latapy/FV/generation.html} for details.
+}
+\examples{
+## The simple generator
+g <- sample_degseq(rep(2,100))
+degree(g)
+is_simple(g)   # sometimes TRUE, but can be FALSE
+g2 <- sample_degseq(1:10, 10:1)
+degree(g2, mode="out")
+degree(g2, mode="in")
+
+## The vl generator
+g3 <- sample_degseq(rep(2,100), method="vl")
+degree(g3)
+is_simple(g3)  # always TRUE
+
+## Exponential degree distribution
+## Note, that we correct the degree sequence if its sum is odd
+degs <- sample(1:100, 100, replace=TRUE, prob=exp(-0.5*(1:100)))
+if (sum(degs) \%\% 2 != 0) { degs[1] <- degs[1] + 1 }
+g4 <- sample_degseq(degs, method="vl")
+all(degree(g4) == degs)
+
+## Power-law degree distribution
+## Note, that we correct the degree sequence if its sum is odd
+degs <- sample(1:100, 100, replace=TRUE, prob=(1:100)^-2)
+if (sum(degs) \%\% 2 != 0) { degs[1] <- degs[1] + 1 }
+g5 <- sample_degseq(degs, method="vl")
+all(degree(g5) == degs)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{sample_gnp}}, \code{\link{sample_pa}},
+\code{\link{simplify}} to get rid of the multiple and/or loops edges.
+}
+\keyword{graphs}
+
diff --git a/man/sample_dirichlet.Rd b/man/sample_dirichlet.Rd
new file mode 100644
index 0000000..3ce54d2
--- /dev/null
+++ b/man/sample_dirichlet.Rd
@@ -0,0 +1,38 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/embedding.R
+\name{sample_dirichlet}
+\alias{sample_dirichlet}
+\title{Sample from a Dirichlet distribution}
+\usage{
+sample_dirichlet(n, alpha)
+}
+\arguments{
+\item{n}{Integer scalar, the sample size.}
+
+\item{alpha}{Numeric vector, the vector of \eqn{\alpha}{alpha} parameter for
+the Dirichlet distribution.}
+}
+\value{
+A \code{dim} (length of the \code{alpha} vector for
+\code{sample_dirichlet}) times \code{n} matrix, whose columns are the sample
+vectors.
+}
+\description{
+Sample finite-dimensional vectors to use as latent position vectors in
+random dot product graphs
+}
+\details{
+\code{sample_dirichlet} generates samples from the Dirichlet distribution
+with given \eqn{\alpha}{alpha} parameter. The sample is drawn from
+\code{length(alpha)-1}-simplex.
+}
+\examples{
+lpvs.dir    <- sample_dirichlet(n=20, alpha=rep(1, 10))
+RDP.graph.2 <- sample_dot_product(lpvs.dir)
+colSums(lpvs.dir)
+}
+\seealso{
+Other latent position vector samplers: \code{\link{sample_sphere_surface}};
+  \code{\link{sample_sphere_volume}}
+}
+
diff --git a/man/sample_dot_product.Rd b/man/sample_dot_product.Rd
new file mode 100644
index 0000000..46095a0
--- /dev/null
+++ b/man/sample_dot_product.Rd
@@ -0,0 +1,58 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_dot_product}
+\alias{dot_product}
+\alias{sample_dot_product}
+\title{Generate random graphs according to the random dot product graph model}
+\usage{
+sample_dot_product(vecs, directed = FALSE)
+}
+\arguments{
+\item{vecs}{A numeric matrix in which each latent position vector is a
+column.}
+
+\item{directed}{A logical scalar, TRUE if the generated graph should be
+directed.}
+
+\item{\dots}{Passed to \code{sample_dot_product}.}
+}
+\value{
+An igraph graph object which is the generated random dot product
+graph.
+}
+\description{
+In this model, each vertex is represented by a latent position vector.
+Probability of an edge between two vertices are given by the dot product of
+their latent position vectors.
+}
+\details{
+The dot product of the latent position vectors should be in the [0,1]
+interval, otherwise a warning is given. For negative dot products, no edges
+are added; dot products that are larger than one always add an edge.
+}
+\examples{
+## A randomly generated  graph
+lpvs <- matrix(rnorm(200), 20, 10)
+lpvs <- apply(lpvs, 2, function(x) { return (abs(x)/sqrt(sum(x^2))) })
+g <- sample_dot_product(lpvs)
+g
+
+## Sample latent vectors from the surface of the unit sphere
+lpvs2 <- sample_sphere_surface(dim=5, n=20)
+g2 <- sample_dot_product(lpvs2)
+g2
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Christine Leigh Myers Nickel: Random dot product graphs, a model
+for social networks. Dissertation, Johns Hopkins University, Maryland, USA,
+2006.
+}
+\seealso{
+\code{\link{sample_dirichlet}}, \code{\link{sample_sphere_surface}}
+and \code{\link{sample_sphere_volume}} for sampling position vectors.
+}
+\keyword{graphs}
+
diff --git a/man/sample_fitness.Rd b/man/sample_fitness.Rd
new file mode 100644
index 0000000..3fc739c
--- /dev/null
+++ b/man/sample_fitness.Rd
@@ -0,0 +1,79 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_fitness}
+\alias{sample_fitness}
+\alias{static.fitness.game}
+\title{Random graphs from vertex fitness scores}
+\usage{
+sample_fitness(no.of.edges, fitness.out, fitness.in = NULL, loops = FALSE,
+  multiple = FALSE)
+}
+\arguments{
+\item{no.of.edges}{The number of edges in the generated graph.}
+
+\item{fitness.out}{A numeric vector containing the fitness of each vertex.
+For directed graphs, this specifies the out-fitness of each vertex.}
+
+\item{fitness.in}{If \code{NULL} (the default), the generated graph will be
+undirected. If not \code{NULL}, then it should be a numeric vector and it
+specifies the in-fitness of each vertex.
+
+If this argument is not \code{NULL}, then a directed graph is generated,
+otherwise an undirected one.}
+
+\item{loops}{Logical scalar, whether to allow loop edges in the graph.}
+
+\item{multiple}{Logical scalar, whether to allow multiple edges in the
+graph.}
+}
+\value{
+An igraph graph, directed or undirected.
+}
+\description{
+This function generates a non-growing random graph with edge probabilities
+proportional to node fitness scores.
+}
+\details{
+This game generates a directed or undirected random graph where the
+probability of an edge between vertices \eqn{i} and \eqn{j} depends on the
+fitness scores of the two vertices involved. For undirected graphs, each
+vertex has a single fitness score. For directed graphs, each vertex has an
+out- and an in-fitness, and the probability of an edge from \eqn{i} to
+\eqn{j} depends on the out-fitness of vertex \eqn{i} and the in-fitness of
+vertex \eqn{j}.
+
+The generation process goes as follows. We start from \eqn{N} disconnected
+nodes (where \eqn{N} is given by the length of the fitness vector). Then we
+randomly select two vertices \eqn{i} and \eqn{j}, with probabilities
+proportional to their fitnesses. (When the generated graph is directed,
+\eqn{i} is selected according to the out-fitnesses and \eqn{j} is selected
+according to the in-fitnesses). If the vertices are not connected yet (or if
+multiple edges are allowed), we connect them; otherwise we select a new
+pair. This is repeated until the desired number of links are created.
+
+It can be shown that the \emph{expected} degree of each vertex will be
+proportional to its fitness, although the actual, observed degree will not
+be. If you need to generate a graph with an exact degree sequence, consider
+\code{\link{sample_degseq}} instead.
+
+This model is commonly used to generate static scale-free networks. To
+achieve this, you have to draw the fitness scores from the desired power-law
+distribution. Alternatively, you may use \code{\link{sample_fitness_pl}}
+which generates the fitnesses for you with a given exponent.
+}
+\examples{
+N <- 10000
+g <- sample_fitness(5*N, sample((1:50)^-2, N, replace=TRUE))
+degree_distribution(g)
+\dontrun{plot(degree_distribution(g, cumulative=TRUE), log="xy")}
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Goh K-I, Kahng B, Kim D: Universal behaviour of load
+distribution in scale-free networks. \emph{Phys Rev Lett} 87(27):278701,
+2001.
+}
+\keyword{graphs}
+
diff --git a/man/sample_fitness_pl.Rd b/man/sample_fitness_pl.Rd
new file mode 100644
index 0000000..46e75b7
--- /dev/null
+++ b/man/sample_fitness_pl.Rd
@@ -0,0 +1,86 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_fitness_pl}
+\alias{sample_fitness_pl}
+\alias{static.power.law.game}
+\title{Scale-free random graphs, from vertex fitness scores}
+\usage{
+sample_fitness_pl(no.of.nodes, no.of.edges, exponent.out, exponent.in = -1,
+  loops = FALSE, multiple = FALSE, finite.size.correction = TRUE)
+}
+\arguments{
+\item{no.of.nodes}{The number of vertices in the generated graph.}
+
+\item{no.of.edges}{The number of edges in the generated graph.}
+
+\item{exponent.out}{Numeric scalar, the power law exponent of the degree
+distribution. For directed graphs, this specifies the exponent of the
+out-degree distribution. It must be greater than or equal to 2. If you pass
+\code{Inf} here, you will get back an Erdos-Renyi random network.}
+
+\item{exponent.in}{Numeric scalar. If negative, the generated graph will be
+undirected. If greater than or equal to 2, this argument specifies the
+exponent of the in-degree distribution. If non-negative but less than 2, an
+error will be generated.}
+
+\item{loops}{Logical scalar, whether to allow loop edges in the generated
+graph.}
+
+\item{multiple}{Logical scalar, whether to allow multiple edges in the
+generated graph.}
+
+\item{finite.size.correction}{Logical scalar, whether to use the proposed
+finite size correction of Cho et al., see references below.}
+}
+\value{
+An igraph graph, directed or undirected.
+}
+\description{
+This function generates a non-growing random graph with expected power-law
+degree distributions.
+}
+\details{
+This game generates a directed or undirected random graph where the degrees
+of vertices follow power-law distributions with prescribed exponents. For
+directed graphs, the exponents of the in- and out-degree distributions may
+be specified separately.
+
+The game simply uses \code{\link{sample_fitness}} with appropriately
+constructed fitness vectors. In particular, the fitness of vertex \eqn{i} is
+\eqn{i^{-alpha}}{i^(-alpha)}, where \eqn{alpha = 1/(gamma-1)} and gamma is
+the exponent given in the arguments.
+
+To remove correlations between in- and out-degrees in case of directed
+graphs, the in-fitness vector will be shuffled after it has been set up and
+before \code{\link{sample_fitness}} is called.
+
+Note that significant finite size effects may be observed for exponents
+smaller than 3 in the original formulation of the game. This function
+provides an argument that lets you remove the finite size effects by
+assuming that the fitness of vertex \eqn{i} is
+\eqn{(i+i_0-1)^{-alpha}}{(i+i0-1)^(-alpha)} where \eqn{i_0}{i0} is a
+constant chosen appropriately to ensure that the maximum degree is less than
+the square root of the number of edges times the average degree; see the
+paper of Chung and Lu, and Cho et al for more details.
+}
+\examples{
+g <- sample_fitness_pl(10000, 30000, 2.2, 2.3)
+\dontrun{plot(degree_distribution(g, cumulative=TRUE, mode="out"), log="xy")}
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\references{
+Goh K-I, Kahng B, Kim D: Universal behaviour of load
+distribution in scale-free networks. \emph{Phys Rev Lett} 87(27):278701,
+2001.
+
+Chung F and Lu L: Connected components in a random graph with given degree
+sequences. \emph{Annals of Combinatorics} 6, 125-145, 2002.
+
+Cho YS, Kim JS, Park J, Kahng B, Kim D: Percolation transitions in
+scale-free networks under the Achlioptas process. \emph{Phys Rev Lett}
+103:135702, 2009.
+}
+\keyword{graphs}
+
diff --git a/man/sample_forestfire.Rd b/man/sample_forestfire.Rd
new file mode 100644
index 0000000..b154cd7
--- /dev/null
+++ b/man/sample_forestfire.Rd
@@ -0,0 +1,79 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_forestfire}
+\alias{forest.fire.game}
+\alias{sample_forestfire}
+\title{Forest Fire Network Model}
+\usage{
+sample_forestfire(nodes, fw.prob, bw.factor = 1, ambs = 1,
+  directed = TRUE)
+}
+\arguments{
+\item{nodes}{The number of vertices in the graph.}
+
+\item{fw.prob}{The forward burning probability, see details below.}
+
+\item{bw.factor}{The backward burning ratio. The backward burning
+probability is calculated as \code{bw.factor*fw.prob}.}
+
+\item{ambs}{The number of ambassador vertices.}
+
+\item{directed}{Logical scalar, whether to create a directed graph.}
+}
+\value{
+A simple graph, possibly directed if the \code{directed} argument is
+\code{TRUE}.
+}
+\description{
+This is a growing network model, which resembles of how the forest fire
+spreads by igniting trees close by.
+}
+\details{
+The forest fire model intends to reproduce the following network
+characteristics, observed in real networks: \itemize{ \item Heavy-tailed
+in-degree distribution.  \item Heavy-tailed out-degree distribution.  \item
+Communities.  \item Densification power-law. The network is densifying in
+time, according to a power-law rule.  \item Shrinking diameter. The diameter
+of the network decreases in time.  }
+
+The network is generated in the following way. One vertex is added at a
+time. This vertex connects to (cites) \code{ambs} vertices already present
+in the network, chosen uniformly random. Now, for each cited vertex \eqn{v}
+we do the following procedure: \enumerate{ \item We generate two random
+number, \eqn{x} and \eqn{y}, that are geometrically distributed with means
+\eqn{p/(1-p)} and \eqn{rp(1-rp)}. (\eqn{p} is \code{fw.prob}, \eqn{r} is
+\code{bw.factor}.) The new vertex cites \eqn{x} outgoing neighbors and
+\eqn{y} incoming neighbors of \eqn{v}, from those which are not yet cited by
+the new vertex. If there are less than \eqn{x} or \eqn{y} such vertices
+available then we cite all of them.  \item The same procedure is applied to
+all the newly cited vertices.  }
+}
+\note{
+The version of the model in the published paper is incorrect in the
+sense that it cannot generate the kind of graphs the authors claim. A
+corrected version is available from
+\url{http://www.cs.cmu.edu/~jure/pubs/powergrowth-tkdd.pdf}, our
+implementation is based on this.
+}
+\examples{
+g <- sample_forestfire(10000, fw.prob=0.37, bw.factor=0.32/0.37)
+dd1 <- degree_distribution(g, mode="in")
+dd2 <- degree_distribution(g, mode="out")
+plot(seq(along=dd1)-1, dd1, log="xy")
+points(seq(along=dd2)-1, dd2, col=2, pch=2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Jure Leskovec, Jon Kleinberg and Christos Faloutsos. Graphs over
+time: densification laws, shrinking diameters and possible explanations.
+\emph{KDD '05: Proceeding of the eleventh ACM SIGKDD international
+conference on Knowledge discovery in data mining}, 177--187, 2005.
+}
+\seealso{
+\code{\link{barabasi.game}} for the basic preferential attachment
+model.
+}
+\keyword{graphs}
+
diff --git a/man/sample_gnm.Rd b/man/sample_gnm.Rd
new file mode 100644
index 0000000..c619dea
--- /dev/null
+++ b/man/sample_gnm.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_gnm}
+\alias{gnm}
+\alias{sample_gnm}
+\title{Generate random graphs according to the G(n,m) Erdos-Renyi model}
+\usage{
+sample_gnm(n, m, directed = FALSE, loops = FALSE)
+
+gnm(...)
+}
+\arguments{
+\item{n}{The number of vertices in the graph.}
+
+\item{m}{The number of edges in the graph.}
+
+\item{directed}{Logical, whether the graph will be directed, defaults to
+FALSE.}
+
+\item{loops}{Logical, whether to add loop edges, defaults to FALSE.}
+
+\item{...}{Passed to \code{sample_app}.}
+}
+\value{
+A graph object.
+}
+\description{
+This model is very simple, every possible edge is created with the same
+constant probability.
+}
+\details{
+The graph has \sQuote{n} vertices and \sQuote{m} edges,
+and the \sQuote{m} edges are chosen uniformly randomly from the set of all
+possible edges. This set includes loop edges as well if the \code{loops}
+parameter is TRUE.
+}
+\examples{
+g <- sample_gnm(1000, 1000)
+degree_distribution(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
+Mathematicae} 6, 290--297 (1959).
+}
+\seealso{
+\code{\link{sample_gnp}}, \code{\link{sample_pa}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_gnp.Rd b/man/sample_gnp.Rd
new file mode 100644
index 0000000..750c527
--- /dev/null
+++ b/man/sample_gnp.Rd
@@ -0,0 +1,51 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_gnp}
+\alias{gnp}
+\alias{sample_gnp}
+\title{Generate random graphs according to the G(n,p) Erdos-Renyi model}
+\usage{
+sample_gnp(n, p, directed = FALSE, loops = FALSE)
+
+gnp(...)
+}
+\arguments{
+\item{n}{The number of vertices in the graph.}
+
+\item{p}{The probability for drawing an edge between two
+arbitrary vertices (G(n,p) graph).}
+
+\item{directed}{Logical, whether the graph will be directed, defaults to
+FALSE.}
+
+\item{loops}{Logical, whether to add loop edges, defaults to FALSE.}
+
+\item{...}{Passed to \code{sample_app}.}
+}
+\value{
+A graph object.
+}
+\description{
+This model is very simple, every possible edge is created with the same
+constant probability.
+}
+\details{
+The graph has \sQuote{n} vertices and for each edge the
+probability that it is present in the graph is \sQuote{p}.
+}
+\examples{
+g <- sample_gnp(1000, 1/1000)
+degree_distribution(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Erdos, P. and Renyi, A., On random graphs, \emph{Publicationes
+Mathematicae} 6, 290--297 (1959).
+}
+\seealso{
+\code{\link{sample_gnm}}, \code{\link{sample_pa}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_grg.Rd b/man/sample_grg.Rd
new file mode 100644
index 0000000..e80eedc
--- /dev/null
+++ b/man/sample_grg.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_grg}
+\alias{grg}
+\alias{grg.game}
+\alias{sample_grg}
+\title{Geometric random graphs}
+\usage{
+sample_grg(nodes, radius, torus = FALSE, coords = FALSE)
+
+grg(...)
+}
+\arguments{
+\item{nodes}{The number of vertices in the graph.}
+
+\item{radius}{The radius within which the vertices will be connected by an
+edge.}
+
+\item{torus}{Logical constant, whether to use a torus instead of a square.}
+
+\item{coords}{Logical scalar, whether to add the positions of the vertices
+as vertex attributes called \sQuote{\code{x}} and \sQuote{\code{y}}.}
+
+\item{...}{Passed to \code{sample_grg}.}
+}
+\value{
+A graph object. If \code{coords} is \code{TRUE} then with vertex
+attributes \sQuote{\code{x}} and \sQuote{\code{y}}.
+}
+\description{
+Generate a random graph based on the distance of random point on a unit
+square
+}
+\details{
+First a number of points are dropped on a unit square, these points
+correspond to the vertices of the graph to create. Two points will be
+connected with an undirected edge if they are closer to each other in
+Euclidean norm than a given radius. If the \code{torus} argument is
+\code{TRUE} then a unit area torus is used instead of a square.
+}
+\examples{
+g <- sample_grg(1000, 0.05, torus=FALSE)
+g2 <- sample_grg(1000, 0.05, torus=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}, first version was
+written by Keith Briggs (\url{http://keithbriggs.info/}).
+}
+\seealso{
+\code{\link{sample_gnp}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_growing.Rd b/man/sample_growing.Rd
new file mode 100644
index 0000000..1c9af5b
--- /dev/null
+++ b/man/sample_growing.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_growing}
+\alias{growing}
+\alias{growing.random.game}
+\alias{sample_growing}
+\title{Growing random graph generation}
+\usage{
+sample_growing(n, m = 1, directed = TRUE, citation = FALSE)
+
+growing(...)
+}
+\arguments{
+\item{n}{Numeric constant, number of vertices in the graph.}
+
+\item{m}{Numeric constant, number of edges added in each time step.}
+
+\item{directed}{Logical, whether to create a directed graph.}
+
+\item{citation}{Logical. If \code{TRUE} a citation graph is created, ie. in
+each time step the added edges are originating from the new vertex.}
+
+\item{...}{Passed to \code{sample_app}.}
+}
+\value{
+A new graph object.
+}
+\description{
+This function creates a random graph by simulating its stochastic evolution.
+}
+\details{
+This is discrete time step model, in each time step a new vertex is added to
+the graph and \code{m} new edges are created. If \code{citation} is
+\code{FALSE} these edges are connecting two uniformly randomly chosen
+vertices, otherwise the edges are connecting new vertex to uniformly
+randomly chosen old vertices.
+}
+\examples{
+g <- sample_growing(500, citation=FALSE)
+g2 <- sample_growing(500, citation=TRUE)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{sample_pa}}, \code{\link{sample_gnp}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_hierarchical_sbm.Rd b/man/sample_hierarchical_sbm.Rd
new file mode 100644
index 0000000..cbd0b2d
--- /dev/null
+++ b/man/sample_hierarchical_sbm.Rd
@@ -0,0 +1,60 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_hierarchical_sbm}
+\alias{hierarchical_sbm}
+\alias{sample_hierarchical_sbm}
+\title{Sample the hierarchical stochastic block model}
+\usage{
+sample_hierarchical_sbm(n, m, rho, C, p)
+}
+\arguments{
+\item{n}{Integer scalar, the number of vertices.}
+
+\item{m}{Integer scalar, the number of vertices per block. \code{n / m} must
+be integer. Alternatively, an integer vector of block sizes, if not all the
+blocks have equal sizes.}
+
+\item{rho}{Numeric vector, the fraction of vertices per cluster, within a
+block. Must sum up to 1, and \code{rho * m} must be integer for all elements
+of rho. Alternatively a list of rho vectors, one for each block, if they are
+not the same for all blocks.}
+
+\item{C}{A square, symmetric numeric matrix, the Bernoulli rates for the
+clusters within a block. Its size must mach the size of the \code{rho}
+vector. Alternatively, a list of square matrices, if the Bernoulli rates
+differ in different blocks.}
+
+\item{p}{Numeric scalar, the Bernoulli rate of connections between vertices
+in different blocks.}
+
+\item{\dots}{Passed to \code{sample_hierarchical_sbm}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Sampling from a hierarchical stochastic block model of networks.
+}
+\details{
+The function generates a random graph according to the hierarchical
+stochastic block model.
+}
+\examples{
+## Ten blocks with three clusters each
+C <- matrix(c(1  , 3/4,   0,
+              3/4,   0, 3/4,
+              0  , 3/4, 3/4), nrow=3)
+g <- sample_hierarchical_sbm(100, 10, rho=c(3, 3, 4)/10, C=C, p=1/20)
+g
+if (require(Matrix)) { image(g[]) }
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{sbm.game}}
+}
+\keyword{graphs}
+\keyword{graphs,}
+\keyword{random}
+
diff --git a/man/sample_hrg.Rd b/man/sample_hrg.Rd
new file mode 100644
index 0000000..e245c42
--- /dev/null
+++ b/man/sample_hrg.Rd
@@ -0,0 +1,30 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/hrg.R
+\name{sample_hrg}
+\alias{hrg.game}
+\alias{sample_hrg}
+\title{Sample from a hierarchical random graph model}
+\usage{
+sample_hrg(hrg)
+}
+\arguments{
+\item{hrg}{A hierarchical random graph model.}
+}
+\value{
+An igraph graph.
+}
+\description{
+\code{sample_hrg} samples a graph from a given hierarchical random graph
+model.
+}
+\seealso{
+Other hierarchical random graph functions: \code{\link{consensus_tree}},
+  \code{\link{hrg.consensus}}; \code{\link{fit_hrg}},
+  \code{\link{hrg.fit}}; \code{\link{hrg-methods}};
+  \code{\link{hrg.predict}}, \code{\link{predict_edges}};
+  \code{\link{hrg_tree}}; \code{\link{hrg}},
+  \code{\link{hrg.create}};
+  \code{\link{print.igraphHRGConsensus}};
+  \code{\link{print.igraphHRG}}
+}
+
diff --git a/man/sample_islands.Rd b/man/sample_islands.Rd
new file mode 100644
index 0000000..7bf882b
--- /dev/null
+++ b/man/sample_islands.Rd
@@ -0,0 +1,39 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_islands}
+\alias{interconnected.islands.game}
+\alias{sample_islands}
+\title{A graph with subgraphs that are each a random graph.}
+\usage{
+sample_islands(islands.n, islands.size, islands.pin, n.inter)
+}
+\arguments{
+\item{islands.n}{The number of islands in the graph.}
+
+\item{islands.size}{The size of islands in the graph.}
+
+\item{islands.pin}{The probability to create each possible edge into each
+island.}
+
+\item{n.inter}{The number of edges to create between two islands.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Create a number of Erdos-Renyi random graphs with identical parameters, and
+connect them with the specified number of edges.
+}
+\examples{
+g <- sample_islands(3, 10, 5/10, 1)
+oc <- cluster_optimal(g)
+oc
+}
+\author{
+Samuel Thiriot (\url{https://www.linkedin.com/in/samthiriot})
+}
+\seealso{
+\code{\link{sample_gnp}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_k_regular.Rd b/man/sample_k_regular.Rd
new file mode 100644
index 0000000..9895345
--- /dev/null
+++ b/man/sample_k_regular.Rd
@@ -0,0 +1,54 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_k_regular}
+\alias{k.regular.game}
+\alias{sample_k_regular}
+\title{Create a random regular graph}
+\usage{
+sample_k_regular(no.of.nodes, k, directed = FALSE, multiple = FALSE)
+}
+\arguments{
+\item{no.of.nodes}{Integer scalar, the number of vertices in the generated
+graph.}
+
+\item{k}{Integer scalar, the degree of each vertex in the graph, or the
+out-degree and in-degree in a directed graph.}
+
+\item{directed}{Logical scalar, whether to create a directed graph.}
+
+\item{multiple}{Logical scalar, whether multiple edges are allowed.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Generate a random graph where each vertex has the same degree.
+}
+\details{
+This game generates a directed or undirected random graph where the degrees
+of vertices are equal to a predefined constant k. For undirected graphs, at
+least one of k and the number of vertices must be even.
+
+The game simply uses \code{\link{sample_degseq}} with appropriately
+constructed degree sequences.
+}
+\examples{
+## A simple ring
+ring <- sample_k_regular(10, 2)
+plot(ring)
+
+## k-regular graphs on 10 vertices, with k=1:9
+k10 <- lapply(1:9, sample_k_regular, no.of.nodes=10)
+
+layout(matrix(1:9, nrow=3, byrow=TRUE))
+sapply(k10, plot, vertex.label=NA)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com}
+}
+\seealso{
+\code{\link{sample_degseq}} for a generator with prescribed degree
+sequence.
+}
+\keyword{graphs}
+
diff --git a/man/sample_last_cit.Rd b/man/sample_last_cit.Rd
new file mode 100644
index 0000000..712c15e
--- /dev/null
+++ b/man/sample_last_cit.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_last_cit}
+\alias{cit_cit_types}
+\alias{cit_types}
+\alias{cited.type.game}
+\alias{citing.cited.type.game}
+\alias{last_cit}
+\alias{lastcit.game}
+\alias{sample_cit_cit_types}
+\alias{sample_cit_types}
+\alias{sample_last_cit}
+\title{Random citation graphs}
+\usage{
+sample_last_cit(n, edges = 1, agebins = n/7100, pref = (1:(agebins +
+  1))^-3, directed = TRUE)
+
+last_cit(...)
+
+sample_cit_types(n, edges = 1, types = rep(0, n), pref = rep(1,
+  length(types)), directed = TRUE, attr = TRUE)
+
+cit_types(...)
+
+sample_cit_cit_types(n, edges = 1, types = rep(0, n), pref = matrix(1,
+  nrow = length(types), ncol = length(types)), directed = TRUE, attr = TRUE)
+
+cit_cit_types(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{edges}{Number of edges per step.}
+
+\item{agebins}{Number of aging bins.}
+
+\item{pref}{Vector (\code{sample_last_cit} and \code{sample_cit_types} or
+matrix (\code{sample_cit_cit_types}) giving the (unnormalized) citation
+probabilities for the different vertex types.}
+
+\item{directed}{Logical scalar, whether to generate directed networks.}
+
+\item{...}{Passed to the actual constructor.}
+
+\item{types}{Vector of length \sQuote{\code{n}}, the types of the vertices.
+Types are numbered from zero.}
+
+\item{attr}{Logical scalar, whether to add the vertex types to the generated
+graph as a vertex attribute called \sQuote{\code{type}}.}
+}
+\value{
+A new graph.
+}
+\description{
+\code{sample_last_cit} creates a graph, where vertices age, and
+gain new connections based on how long ago their last citation
+happened.
+}
+\details{
+\code{sample_cit_cit_types} is a stochastic block model where the
+graph is growing.
+
+\code{sample_cit_types} is similarly a growing stochastic block model,
+but the probability of an edge depends on the (potentiall) cited
+vertex only.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/sample_motifs.Rd b/man/sample_motifs.Rd
new file mode 100644
index 0000000..1d65552
--- /dev/null
+++ b/man/sample_motifs.Rd
@@ -0,0 +1,51 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/motifs.R
+\name{sample_motifs}
+\alias{graph.motifs.est}
+\alias{sample_motifs}
+\title{Graph motifs}
+\usage{
+sample_motifs(graph, size = 3, cut.prob = rep(0, size),
+  sample.size = vcount(graph)/10, sample = NULL)
+}
+\arguments{
+\item{graph}{Graph object, the input graph.}
+
+\item{size}{The size of the motif, currently 3 and 4 are supported only.}
+
+\item{cut.prob}{Numeric vector giving the probabilities that the search
+graph is cut at a certain level. Its length should be the same as the size
+of the motif (the \code{size} argument). By default no cuts are made.}
+
+\item{sample.size}{The number of vertices to use as a starting point for
+finding motifs. Only used if the \code{sample} argument is \code{NULL}.}
+
+\item{sample}{If not \code{NULL} then it specifies the vertices to use as a
+starting point for finding motifs.}
+}
+\value{
+A numeric scalar, an estimate for the total number of motifs in
+  the graph.
+}
+\description{
+Graph motifs are small connected subgraphs with a well-defined
+structure.  These functions search a graph for various motifs.
+}
+\details{
+\code{sample_motifs} estimates the total number of motifs of a given
+size in a graph based on a sample.
+}
+\examples{
+g <- barabasi.game(100)
+motifs(g, 3)
+count_motifs(g, 3)
+sample_motifs(g, 3)
+}
+\seealso{
+\code{\link{isomorphism_class}}
+
+Other graph motifs: \code{\link{count_motifs}},
+  \code{\link{graph.motifs.no}};
+  \code{\link{graph.motifs}}, \code{\link{motifs}}
+}
+
diff --git a/man/sample_pa.Rd b/man/sample_pa.Rd
new file mode 100644
index 0000000..bd30d72
--- /dev/null
+++ b/man/sample_pa.Rd
@@ -0,0 +1,122 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_pa}
+\alias{ba.game}
+\alias{barabasi.game}
+\alias{pa}
+\alias{sample_pa}
+\title{Generate scale-free graphs according to the Barabasi-Albert model}
+\usage{
+sample_pa(n, power = 1, m = NULL, out.dist = NULL, out.seq = NULL,
+  out.pref = FALSE, zero.appeal = 1, directed = TRUE,
+  algorithm = c("psumtree", "psumtree-multiple", "bag"), start.graph = NULL)
+
+pa(...)
+}
+\arguments{
+\item{n}{Number of vertices.}
+
+\item{power}{The power of the preferential attachment, the default is one,
+ie. linear preferential attachment.}
+
+\item{m}{Numeric constant, the number of edges to add in each time step This
+argument is only used if both \code{out.dist} and \code{out.seq} are omitted
+or NULL.}
+
+\item{out.dist}{Numeric vector, the distribution of the number of edges to
+add in each time step. This argument is only used if the \code{out.seq}
+argument is omitted or NULL.}
+
+\item{out.seq}{Numeric vector giving the number of edges to add in each time
+step. Its first element is ignored as no edges are added in the first time
+step.}
+
+\item{out.pref}{Logical, if true the total degree is used for calculating
+the citation probability, otherwise the in-degree is used.}
+
+\item{zero.appeal}{The \sQuote{attractiveness} of the vertices with no
+adjacent edges. See details below.}
+
+\item{directed}{Whether to create a directed graph.}
+
+\item{algorithm}{The algorithm to use for the graph generation.
+\code{psumtree} uses a partial prefix-sum tree to generate the graph, this
+algorithm can handle any \code{power} and \code{zero.appeal} values and
+never generates multiple edges.  \code{psumtree-multiple} also uses a
+partial prefix-sum tree, but the generation of multiple edges is allowed.
+Before the 0.6 version igraph used this algorithm if \code{power} was not
+one, or \code{zero.appeal} was not one.  \code{bag} is the algorithm that
+was previously (before version 0.6) used if \code{power} was one and
+\code{zero.appeal} was one as well. It works by putting the ids of the
+vertices into a bag (mutliset, really), exactly as many times as their
+(in-)degree, plus once more. Then the required number of cited vertices are
+drawn from the bag, with replacement. This method might generate multiple
+edges. It only works if \code{power} and \code{zero.appeal} are equal one.}
+
+\item{start.graph}{\code{NULL} or an igraph graph. If a graph, then the
+supplied graph is used as a starting graph for the preferential attachment
+algorithm. The graph should have at least one vertex. If a graph is supplied
+here and the \code{out.seq} argument is not \code{NULL}, then it should
+contain the out degrees of the new vertices only, not the ones in the
+\code{start.graph}.}
+
+\item{...}{Passed to \code{sample_pa}.}
+}
+\value{
+A graph object.
+}
+\description{
+The BA-model is a very simple stochastic algorithm for building a graph.
+}
+\details{
+This is a simple stochastic algorithm to generate a graph. It is a discrete
+time step model and in each time step a single vertex is added.
+
+We start with a single vertex and no edges in the first time step. Then we
+add one vertex in each time step and the new vertex initiates some edges to
+old vertices. The probability that an old vertex is chosen is given by
+\deqn{P[i] \sim k_i^\alpha+a}{P[i] ~ k[i]^alpha + a} where \eqn{k_i}{k[i]}
+is the in-degree of vertex \eqn{i} in the current time step (more precisely
+the number of adjacent edges of \eqn{i} which were not initiated by \eqn{i}
+itself) and \eqn{\alpha}{alpha} and \eqn{a} are parameters given by the
+\code{power} and \code{zero.appeal} arguments.
+
+The number of edges initiated in a time step is given by the \code{m},
+\code{out.dist} and \code{out.seq} arguments. If \code{out.seq} is given and
+not NULL then it gives the number of edges to add in a vector, the first
+element is ignored, the second is the number of edges to add in the second
+time step and so on. If \code{out.seq} is not given or null and
+\code{out.dist} is given and not NULL then it is used as a discrete
+distribution to generate the number of edges in each time step. Its first
+element is the probability that no edges will be added, the second is the
+probability that one edge is added, etc. (\code{out.dist} does not need to
+sum up to one, it normalized automatically.) \code{out.dist} should contain
+non-negative numbers and at east one element should be positive.
+
+If both \code{out.seq} and \code{out.dist} are omitted or NULL then \code{m}
+will be used, it should be a positive integer constant and \code{m} edges
+will be added in each time step.
+
+\code{sample_pa} generates a directed graph by default, set
+\code{directed} to \code{FALSE} to generate an undirected graph. Note that
+even if an undirected graph is generated \eqn{k_i}{k[i]} denotes the number
+of adjacent edges not initiated by the vertex itself and not the total (in-
++ out-) degree of the vertex, unless the \code{out.pref} argument is set to
+\code{TRUE}.
+}
+\examples{
+g <- sample_pa(10000)
+degree_distribution(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Barabasi, A.-L. and Albert R. 1999. Emergence of scaling in
+random networks \emph{Science}, 286 509--512.
+}
+\seealso{
+\code{\link{sample_gnp}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_pa_age.Rd b/man/sample_pa_age.Rd
new file mode 100644
index 0000000..844e3d6
--- /dev/null
+++ b/man/sample_pa_age.Rd
@@ -0,0 +1,135 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_pa_age}
+\alias{aging.ba.game}
+\alias{aging.barabasi.game}
+\alias{aging.prefatt.game}
+\alias{pa_age}
+\alias{sample_pa_age}
+\title{Generate an evolving random graph with preferential attachment and aging}
+\usage{
+sample_pa_age(n, pa.exp, aging.exp, m = NULL, aging.bin = 300,
+  out.dist = NULL, out.seq = NULL, out.pref = FALSE, directed = TRUE,
+  zero.deg.appeal = 1, zero.age.appeal = 0, deg.coef = 1, age.coef = 1,
+  time.window = NULL)
+
+pa_age(...)
+}
+\arguments{
+\item{n}{The number of vertices in the graph.}
+
+\item{pa.exp}{The preferantial attachment exponent, see the details below.}
+
+\item{aging.exp}{The exponent of the aging, usually a non-positive number,
+see details below.}
+
+\item{m}{The number of edges each new vertex creates (except the very first
+vertex). This argument is used only if both the \code{out.dist} and
+\code{out.seq} arguments are NULL.}
+
+\item{aging.bin}{The number of bins to use for measuring the age of
+vertices, see details below.}
+
+\item{out.dist}{The discrete distribution to generate the number of edges to
+add in each time step if \code{out.seq} is NULL. See details below.}
+
+\item{out.seq}{The number of edges to add in each time step, a vector
+containing as many elements as the number of vertices. See details below.}
+
+\item{out.pref}{Logical constant, whether to include edges not initiated by
+the vertex as a basis of preferential attachment. See details below.}
+
+\item{directed}{Logical constant, whether to generate a directed graph. See
+details below.}
+
+\item{zero.deg.appeal}{The degree-dependent part of the
+\sQuote{attractiveness} of the vertices with no adjacent edges. See also
+details below.}
+
+\item{zero.age.appeal}{The age-dependent part of the \sQuote{attrativeness}
+of the vertices with age zero. It is usually zero, see details below.}
+
+\item{deg.coef}{The coefficient of the degree-dependent
+\sQuote{attractiveness}. See details below.}
+
+\item{age.coef}{The coefficient of the age-dependent part of the
+\sQuote{attractiveness}. See details below.}
+
+\item{time.window}{Integer constant, if NULL only adjacent added in the last
+\code{time.windows} time steps are counted as a basis of the preferential
+attachment. See also details below.}
+
+\item{...}{Passed to \code{sample_pa_age}.}
+}
+\value{
+A new graph.
+}
+\description{
+This function creates a random graph by simulating its evolution. Each time
+a new vertex is added it creates a number of links to old vertices and the
+probability that an old vertex is cited depends on its in-degree
+(preferential attachment) and age.
+}
+\details{
+This is a discrete time step model of a growing graph. We start with a
+network containing a single vertex (and no edges) in the first time step.
+Then in each time step (starting with the second) a new vertex is added and
+it initiates a number of edges to the old vertices in the network. The
+probability that an old vertex is connected to is proportional to \deqn{P[i]
+\sim (c\cdot k_i^\alpha+a)(d\cdot l_i^\beta+b)\cdot }{% P[i] ~ (c k[i]^alpha
++ a) (d l[i]^beta + a)}
+
+Here \eqn{k_i}{k[i]} is the in-degree of vertex \eqn{i} in the current time
+step and \eqn{l_i}{l[i]} is the age of vertex \eqn{i}. The age is simply
+defined as the number of time steps passed since the vertex is added, with
+the extension that vertex age is divided to be in \code{aging.bin} bins.
+
+\eqn{c}, \eqn{\alpha}{alpha}, \eqn{a}, \eqn{d}, \eqn{\beta}{beta} and
+\eqn{b} are parameters and they can be set via the following arguments:
+\code{pa.exp} (\eqn{\alpha}{alpha}, mandatory argument), \code{aging.exp}
+(\eqn{\beta}{beta}, mandatory argument), \code{zero.deg.appeal} (\eqn{a},
+optional, the default value is 1), \code{zero.age.appeal} (\eqn{b},
+optional, the default is 0), \code{deg.coef} (\eqn{c}, optional, the default
+is 1), and \code{age.coef} (\eqn{d}, optional, the default is 1).
+
+The number of edges initiated in each time step is governed by the \code{m},
+\code{out.seq} and \code{out.pref} parameters. If \code{out.seq} is given
+then it is interpreted as a vector giving the number of edges to be added in
+each time step. It should be of length \code{n} (the number of vertices),
+and its first element will be ignored. If \code{out.seq} is not given (or
+NULL) and \code{out.dist} is given then it will be used as a discrete
+probability distribution to generate the number of edges. Its first element
+gives the probability that zero edges are added at a time step, the second
+element is the probability that one edge is added, etc. (\code{out.seq}
+should contain non-negative numbers, but if they don't sum up to 1, they
+will be normalized to sum up to 1. This behavior is similar to the
+\code{prob} argument of the \code{sample} command.)
+
+By default a directed graph is generated, but it \code{directed} is set to
+\code{FALSE} then an undirected is created. Even if an undirected graph is
+generaed \eqn{k_i}{k[i]} denotes only the adjacent edges not initiated by
+the vertex itself except if \code{out.pref} is set to \code{TRUE}.
+
+If the \code{time.window} argument is given (and not NULL) then
+\eqn{k_i}{k[i]} means only the adjacent edges added in the previous
+\code{time.window} time steps.
+
+This function might generate graphs with multiple edges.
+}
+\examples{
+# The maximum degree for graph with different aging exponents
+g1 <- sample_pa_age(10000, pa.exp=1, aging.exp=0, aging.bin=1000)
+g2 <- sample_pa_age(10000, pa.exp=1, aging.exp=-1,   aging.bin=1000)
+g3 <- sample_pa_age(10000, pa.exp=1, aging.exp=-3,   aging.bin=1000)
+max(degree(g1))
+max(degree(g2))
+max(degree(g3))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{sample_pa}}, \code{\link{sample_gnp}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_pref.Rd b/man/sample_pref.Rd
new file mode 100644
index 0000000..3adb123
--- /dev/null
+++ b/man/sample_pref.Rd
@@ -0,0 +1,87 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_pref}
+\alias{asym_pref}
+\alias{asymmetric.preference.game}
+\alias{pref}
+\alias{preference.game}
+\alias{sample_asym_pref}
+\alias{sample_pref}
+\title{Trait-based random generation}
+\usage{
+sample_pref(nodes, types, type.dist = rep(1, types), fixed.sizes = FALSE,
+  pref.matrix = matrix(1, types, types), directed = FALSE, loops = FALSE)
+
+pref(...)
+
+sample_asym_pref(nodes, types, type.dist.matrix = matrix(1, types, types),
+  pref.matrix = matrix(1, types, types), loops = FALSE)
+
+asym_pref(...)
+}
+\arguments{
+\item{nodes}{The number of vertices in the graphs.}
+
+\item{types}{The number of different vertex types.}
+
+\item{type.dist}{The distribution of the vertex types, a numeric vector of
+length \sQuote{types} containing non-negative numbers. The vector will be
+normed to obtain probabilities.}
+
+\item{fixed.sizes}{Fix the number of vertices with a given vertex type
+label. The \code{type.dist} argument gives the group sizes (i.e. number of
+vertices with the different labels) in this case.}
+
+\item{pref.matrix}{A square matrix giving the preferences of the vertex
+types. The matrix has \sQuote{types} rows and columns.}
+
+\item{directed}{Logical constant, whether to create a directed graph.}
+
+\item{loops}{Logical constant, whether self-loops are allowed in the graph.}
+
+\item{...}{Passed to the constructor, \code{sample_pref} or
+\code{sample_asym_pref}.}
+
+\item{type.dist.matrix}{The joint distribution of the in- and out-vertex
+types.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Generation of random graphs based on different vertex types.
+}
+\details{
+Both models generate random graphs with given vertex types. For
+\code{sample_pref} the probability that two vertices will be connected
+depends on their type and is given by the \sQuote{pref.matrix} argument.
+This matrix should be symmetric to make sense but this is not checked. The
+distribution of the different vertes types is given by the
+\sQuote{type.dist} vector.
+
+For \code{sample_asym_pref} each vertex has an in-type and an
+out-type and a directed graph is created. The probability that a directed
+edge is realized from a vertex with a given out-type to a vertex with a
+given in-type is given in the \sQuote{pref.matrix} argument, which can be
+asymmetric. The joint distribution for the in- and out-types is given in the
+\sQuote{type.dist.matrix} argument.
+}
+\examples{
+pf <- matrix( c(1, 0, 0, 1), nr=2)
+g <- sample_pref(20, 2, pref.matrix=pf)
+\dontrun{tkplot(g, layout=layout_with_fr)}
+
+pf <- matrix( c(0, 1, 0, 0), nr=2)
+g <- sample_asym_pref(20, 2, pref.matrix=pf)
+\dontrun{tkplot(g, layout=layout_in_circle)}
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com} for the R interface
+}
+\seealso{
+\code{\link{sample_traits}}.
+\code{\link{sample_traits_callaway}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_sbm.Rd b/man/sample_sbm.Rd
new file mode 100644
index 0000000..400bcd1
--- /dev/null
+++ b/man/sample_sbm.Rd
@@ -0,0 +1,57 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_sbm}
+\alias{sample_sbm}
+\alias{sbm}
+\alias{sbm.game}
+\title{Sample stochastic block model}
+\usage{
+sample_sbm(n, pref.matrix, block.sizes, directed = FALSE, loops = FALSE)
+}
+\arguments{
+\item{n}{Number of vertices in the graph.}
+
+\item{pref.matrix}{The matrix giving the Bernoulli rates.  This is a
+\eqn{K\times K}{KxK} matrix, where \eqn{K} is the number of groups. The
+probability of creating an edge between vertices from groups \eqn{i} and
+\eqn{j} is given by element \eqn{(i,j)}. For undirected graphs, this matrix
+must be symmetric.}
+
+\item{block.sizes}{Numeric vector giving the number of vertices in each
+group. The sum of the vector must match the number of vertices.}
+
+\item{directed}{Logical scalar, whether to generate a directed graph.}
+
+\item{loops}{Logical scalar, whether self-loops are allowed in the graph.}
+
+\item{\dots}{Passed to \code{sample_sbm}.}
+}
+\value{
+An igraph graph.
+}
+\description{
+Sampling from the stochastic block model of networks
+}
+\details{
+This function samples graphs from a stochastic block model by (doing the
+equivalent of) Bernoulli trials for each potential edge with the
+probabilities given by the Bernoulli rate matrix, \code{pref.matrix}.
+}
+\examples{
+## Two groups with not only few connection between groups
+pm <- cbind( c(.1, .001), c(.001, .05) )
+g <- sample_sbm(1000, pref.matrix=pm, block.sizes=c(300,700))
+g
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Faust, K., & Wasserman, S. (1992a). Blockmodels: Interpretation
+and evaluation. \emph{Social Networks}, 14, 5--61.
+}
+\seealso{
+\code{\link{sample_gnp}}, \code{\link{sample_gnm}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_seq.Rd b/man/sample_seq.Rd
new file mode 100644
index 0000000..76b6d02
--- /dev/null
+++ b/man/sample_seq.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/other.R
+\name{sample_seq}
+\alias{igraph.sample}
+\alias{sample_seq}
+\title{Sampling a random integer sequence}
+\usage{
+sample_seq(low, high, length)
+}
+\arguments{
+\item{low}{The lower limit of the interval (inclusive).}
+
+\item{high}{The higher limit of the interval (inclusive).}
+
+\item{length}{The length of the sample.}
+}
+\value{
+An increasing numeric vector containing integers, the sample.
+}
+\description{
+This function provides a very efficient way to pull an integer random sample
+sequence from an integer interval.
+}
+\details{
+The algorithm runs in \code{O(length)} expected time, even if
+\code{high-low} is big. It is much faster (but of course less general) than
+the builtin \code{sample} function of R.
+}
+\examples{
+rs <- sample_seq(1, 100000000, 10)
+rs
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Jeffrey Scott Vitter: An Efficient Algorithm for Sequential
+Random Sampling, \emph{ACM Transactions on Mathematical Software}, 13/1,
+58--67.
+}
+\keyword{datagen}
+
diff --git a/man/sample_smallworld.Rd b/man/sample_smallworld.Rd
new file mode 100644
index 0000000..aa7ceff
--- /dev/null
+++ b/man/sample_smallworld.Rd
@@ -0,0 +1,61 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_smallworld}
+\alias{sample_smallworld}
+\alias{smallworld}
+\alias{watts.strogatz.game}
+\title{The Watts-Strogatz small-world model}
+\usage{
+sample_smallworld(dim, size, nei, p, loops = FALSE, multiple = FALSE)
+
+smallworld(...)
+}
+\arguments{
+\item{dim}{Integer constant, the dimension of the starting lattice.}
+
+\item{size}{Integer constant, the size of the lattice along each dimension.}
+
+\item{nei}{Integer constant, the neighborhood within which the vertices of
+the lattice will be connected.}
+
+\item{p}{Real constant between zero and one, the rewiring probability.}
+
+\item{loops}{Logical scalar, whether loops edges are allowed in the
+generated graph.}
+
+\item{multiple}{Logical scalar, whether multiple edges are allowed int the
+generated graph.}
+
+\item{...}{Passed to \code{sample_smallworld}.}
+}
+\value{
+A graph object.
+}
+\description{
+Generate a graph according to the Watts-Strogatz network model.
+}
+\details{
+First a lattice is created with the given \code{dim}, \code{size} and
+\code{nei} arguments. Then the edges of the lattice are rewired uniformly
+randomly with probability \code{p}.
+
+Note that this function might create graphs with loops and/or multiple
+edges. You can use \code{\link{simplify}} to get rid of these.
+}
+\examples{
+g <- sample_smallworld(1, 100, 5, 0.05)
+mean_distance(g)
+transitivity(g, type="average")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Duncan J Watts and Steven H Strogatz: Collective dynamics of
+\sQuote{small world} networks, Nature 393, 440-442, 1998.
+}
+\seealso{
+\code{\link{make_lattice}}, \code{\link{rewire}}
+}
+\keyword{graphs}
+
diff --git a/man/sample_sphere_surface.Rd b/man/sample_sphere_surface.Rd
new file mode 100644
index 0000000..a7b970f
--- /dev/null
+++ b/man/sample_sphere_surface.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/embedding.R
+\name{sample_sphere_surface}
+\alias{sample_sphere_surface}
+\title{Sample vectors uniformly from the surface of a sphere}
+\usage{
+sample_sphere_surface(dim, n = 1, radius = 1, positive = TRUE)
+}
+\arguments{
+\item{dim}{Integer scalar, the dimension of the random vectors.}
+
+\item{n}{Integer scalar, the sample size.}
+
+\item{radius}{Numeric scalar, the radius of the sphere to sample.}
+
+\item{positive}{Logical scalar, whether to sample from the positive orthant
+of the sphere.}
+}
+\value{
+A \code{dim} (length of the \code{alpha} vector for
+\code{sample_dirichlet}) times \code{n} matrix, whose columns are the sample
+vectors.
+}
+\description{
+Sample finite-dimensional vectors to use as latent position vectors in
+random dot product graphs
+}
+\details{
+\code{sample_sphere_surface} generates uniform samples from \eqn{S^{dim-1}}
+(the \code{(dim-1)}-sphere) with radius \code{radius}, i.e. the Euclidean
+norm of the samples equal \code{radius}.
+}
+\examples{
+lpvs.sph    <- sample_sphere_surface(dim=10, n=20, radius=1)
+RDP.graph.3 <- sample_dot_product(lpvs.sph)
+vec.norm    <- apply(lpvs.sph, 2, function(x) { sum(x^2) })
+vec.norm
+}
+\seealso{
+Other latent position vector samplers: \code{\link{sample_dirichlet}};
+  \code{\link{sample_sphere_volume}}
+}
+
diff --git a/man/sample_sphere_volume.Rd b/man/sample_sphere_volume.Rd
new file mode 100644
index 0000000..d891c70
--- /dev/null
+++ b/man/sample_sphere_volume.Rd
@@ -0,0 +1,43 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/embedding.R
+\name{sample_sphere_volume}
+\alias{sample_sphere_volume}
+\title{Sample vectors uniformly from the volume of a sphere}
+\usage{
+sample_sphere_volume(dim, n = 1, radius = 1, positive = TRUE)
+}
+\arguments{
+\item{dim}{Integer scalar, the dimension of the random vectors.}
+
+\item{n}{Integer scalar, the sample size.}
+
+\item{radius}{Numeric scalar, the radius of the sphere to sample.}
+
+\item{positive}{Logical scalar, whether to sample from the positive orthant
+of the sphere.}
+}
+\value{
+A \code{dim} (length of the \code{alpha} vector for
+\code{sample_dirichlet}) times \code{n} matrix, whose columns are the sample
+vectors.
+}
+\description{
+Sample finite-dimensional vectors to use as latent position vectors in
+random dot product graphs
+}
+\details{
+\code{sample_sphere_volume} generates uniform samples from \eqn{S^{dim-1}}
+(the \code{(dim-1)}-sphere) i.e. the Euclidean norm of the samples is
+smaller or equal to \code{radius}.
+}
+\examples{
+lpvs.sph.vol <- sample_sphere_volume(dim=10, n=20, radius=1)
+RDP.graph.4  <- sample_dot_product(lpvs.sph.vol)
+vec.norm     <- apply(lpvs.sph.vol, 2, function(x) { sum(x^2) })
+vec.norm
+}
+\seealso{
+Other latent position vector samplers: \code{\link{sample_dirichlet}};
+  \code{\link{sample_sphere_surface}}
+}
+
diff --git a/man/sample_traits_callaway.Rd b/man/sample_traits_callaway.Rd
new file mode 100644
index 0000000..9112659
--- /dev/null
+++ b/man/sample_traits_callaway.Rd
@@ -0,0 +1,73 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/games.R
+\name{sample_traits_callaway}
+\alias{callaway.traits.game}
+\alias{establishment.game}
+\alias{sample_traits}
+\alias{sample_traits_callaway}
+\alias{traits}
+\alias{traits_callaway}
+\title{Graph generation based on different vertex types}
+\usage{
+sample_traits_callaway(nodes, types, edge.per.step = 1, type.dist = rep(1,
+  types), pref.matrix = matrix(1, types, types), directed = FALSE)
+
+traits_callaway(...)
+
+sample_traits(nodes, types, k = 1, type.dist = rep(1, types),
+  pref.matrix = matrix(1, types, types), directed = FALSE)
+
+traits(...)
+}
+\arguments{
+\item{nodes}{The number of vertices in the graph.}
+
+\item{types}{The number of different vertex types.}
+
+\item{edge.per.step}{The number of edges to add to the graph per time step.}
+
+\item{type.dist}{The distribution of the vertex types. This is assumed to be
+stationary in time.}
+
+\item{pref.matrix}{A matrix giving the preferences of the given vertex
+types. These should be probabilities, ie. numbers between zero and one.}
+
+\item{directed}{Logical constant, whether to generate directed graphs.}
+
+\item{...}{Passed to the constructor, \code{sample_traits} or
+\code{sample_traits_callaway}.}
+
+\item{k}{The number of trials per time step, see details below.}
+}
+\value{
+A new graph object.
+}
+\description{
+These functions implement evolving network models based on different vertex
+types.
+}
+\details{
+For \code{sample_traits_callaway} the simulation goes like this: in each
+discrete time step a new vertex is added to the graph. The type of this
+vertex is generated based on \code{type.dist}. Then two vertices are
+selected uniformly randomly from the graph. The probability that they will
+be connected depends on the types of these vertices and is taken from
+\code{pref.matrix}. Then another two vertices are selected and this is
+repeated \code{edges.per.step} times in each time step.
+
+For \code{sample_traits} the simulation goes like this: a single vertex is
+added at each time step. This new vertex tries to connect to \code{k}
+vertices in the graph. The probability that such a connection is realized
+depends on the types of the vertices involved and is taken from
+\code{pref.matrix}.
+}
+\examples{
+# two types of vertices, they like only themselves
+g1 <- sample_traits_callaway(1000, 2, pref.matrix=matrix( c(1,0,0,1), nc=2))
+g2 <- sample_traits(1000, 2, k=2, pref.matrix=matrix( c(1,0,0,1), nc=2))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/sbm.game.Rd b/man/sbm.game.Rd
deleted file mode 100644
index 49a34f7..0000000
--- a/man/sbm.game.Rd
+++ /dev/null
@@ -1,43 +0,0 @@
-\name{sbm.game}
-\alias{sbm.game}
-\concept{Stochastic block model}
-\concept{Random graph model}
-\title{Sample stochastic block model}
-\description{Sampling from the stochastic block model of networks}
-\usage{
-sbm.game (n, pref.matrix, block.sizes, directed = FALSE, loops = FALSE) 
-}
-\arguments{
-  \item{n}{Number of vertices in the graph.}
-  \item{pref.matrix}{The matrix giving the Bernoulli rates.
-    This is a \eqn{K\times K}{KxK} matrix, where \eqn{K} is the number
-    of groups. The probability of creating an edge between vertices from
-    groups \eqn{i} and \eqn{j} is given by element \eqn{(i,j)}. For
-    undirected graphs, this matrix must be symmetric.}
-  \item{block.sizes}{Numeric vector giving the number of vertices in
-    each group. The sum of the vector must match the number of vertices.}
-  \item{directed}{Logical scalar, whether to generate a directed
-    graph.}
-  \item{loops}{Logical scalar, whether self-loops are allowed in the
-    graph.}
-}
-\details{
-  This function samples graphs from a stochastic block
-  model by (doing the equivalent of) Bernoulli
-  trials for each potential edge with the probabilities
-  given by the Bernoulli rate matrix, \code{pref.matrix}.
-}
-\value{An igraph graph.}
-\references{
-  Faust, K., & Wasserman, S. (1992a). Blockmodels:
-  Interpretation and evaluation. \emph{Social Networks}, 14, 5--61.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{random.graph.game}}}
-\examples{
-## Two groups with not only few connection between groups
-pm <- cbind( c(.1, .001), c(.001, .05) )
-g <- sbm.game(1000, pref.matrix=pm, block.sizes=c(300,700))
-g
-}
-\keyword{graphs}
diff --git a/man/scan_stat.Rd b/man/scan_stat.Rd
new file mode 100644
index 0000000..d0cc769
--- /dev/null
+++ b/man/scan_stat.Rd
@@ -0,0 +1,64 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scan.R
+\name{scan_stat}
+\alias{scan_stat}
+\title{Scan statistics on a time series of graphs}
+\usage{
+scan_stat(graphs, tau = 1, ell = 0, locality = c("us", "them"), ...)
+}
+\arguments{
+\item{graphs}{A list of igraph graph objects. They must be all directed
+or all undirected and they must have the same number of vertices.}
+
+\item{tau}{The number of previous time steps to consider for the
+time-dependent normalization for individual vertices.  In other words,
+the current locality statistics of each vertex will be compared to this
+many previous time steps of the same vertex to decide whether it is
+significantly larger.}
+
+\item{ell}{The number of previous time steps to consider
+for the aggregated scan statistics. This is essentially a smoothing
+parameter.}
+
+\item{locality}{Whether to calculate the \sQuote{us} or \sQuote{them}
+statistics.}
+
+\item{...}{Extra arguments are passed to \code{\link{local_scan}}.}
+}
+\value{
+A list with entries:
+  \item{stat}{The scan statistics in each time step. It is \code{NA}
+    for the initial \code{tau + ell} time steps.}
+  \item{arg_max_v}{The (numeric) vertex ids for the vertex with
+    the largest locality statistics, at each time step. It is \code{NA}
+    for the initial \code{tau + ell} time steps.}
+}
+\description{
+Calculate scan statistics on a time series of graphs.
+This is done by calculating the local scan statistics for
+each graph and each vertex, and then normalizing across the
+vertices and across the time steps.
+}
+\examples{
+## Generate a bunch of SBMs, with the last one being different
+num_t <- 20
+block_sizes <- c(10, 5, 5)
+p_ij <- list(p = 0.1, h = 0.9, q = 0.9)
+
+P0 <- matrix(p_ij$p, 3, 3)
+P0[2, 2] <- p_ij$h
+PA <- P0
+PA[3, 3] <- p_ij$q
+num_v <- sum(block_sizes)
+
+tsg <- replicate(num_t - 1, P0, simplify = FALSE) \%>\%
+  append(list(PA)) \%>\%
+  lapply(sample_sbm, n = num_v, block.sizes = block_sizes, directed = TRUE)
+
+scan_stat(graphs = tsg, k = 1, tau = 4, ell = 2)
+scan_stat(graphs = tsg, locality = "them", k = 1, tau = 4, ell = 2)
+}
+\seealso{
+Other scan statistics: \code{\link{local_scan}}
+}
+
diff --git a/man/scg-method.Rd b/man/scg-method.Rd
new file mode 100644
index 0000000..644077a
--- /dev/null
+++ b/man/scg-method.Rd
@@ -0,0 +1,52 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scg.R
+\name{scg-method}
+\alias{scg-method}
+\title{Spectral Coarse Graining}
+\description{
+Functions to perform the Spectral Coarse Graining (SCG) of matrices and
+graphs.
+}
+\section{Introduction}{
+ The SCG functions provide a framework, called
+Spectral Coarse Graining (SCG), for reducing large graphs while preserving
+their \emph{spectral-related features}, that is features closely related
+with the eigenvalues and eigenvectors of a graph matrix (which for now can
+be the adjacency, the stochastic, or the Laplacian matrix).
+
+Common examples of such features comprise the first-passage-time of random
+walkers on Markovian graphs, thermodynamic properties of lattice models in
+statistical physics (e.g. Ising model), and the epidemic threshold of
+epidemic network models (SIR and SIS models).
+
+SCG differs from traditional clustering schemes by producing a
+\emph{coarse-grained graph} (not just a partition of the vertices),
+representative of the original one. As shown in [1], Principal Component
+Analysis can be viewed as a particular SCG, called \emph{exact SCG}, where
+the matrix to be coarse-grained is the covariance matrix of some data set.
+
+SCG should be of interest to practitioners of various fields dealing with
+problems where matrix eigenpairs play an important role, as for instance is
+the case of dynamical processes on networks.
+}
+\author{
+David Morton de Lachapelle,
+\url{http://people.epfl.ch/david.morton}.
+}
+\references{
+D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+Shrinking Matrices while Preserving their Eigenpairs with Application to the
+Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+Matrix Analysis and Applications}, 2008.
+\url{http://people.epfl.ch/david.morton}
+
+D. Gfeller, and P. De Los Rios, Spectral Coarse Graining and Synchronization
+in Oscillator Networks. \emph{Physical Review Letters}, \bold{100}(17),
+2008.  \url{http://arxiv.org/abs/0708.2055}
+
+D. Gfeller, and P. De Los Rios, Spectral Coarse Graining of Complex
+Networks, \emph{Physical Review Letters}, \bold{99}(3), 2007.
+\url{http://arxiv.org/abs/0706.0812}
+}
+\keyword{graphs}
+
diff --git a/man/scg.Rd b/man/scg.Rd
index 875f6e1..dba8d43 100644
--- a/man/scg.Rd
+++ b/man/scg.Rd
@@ -1,145 +1,140 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scg.R
 \name{scg}
 \alias{scg}
-\concept{Spectral coarse graining}
 \title{All-in-one Function for the SCG of Matrices and Graphs}
-\description{
-  This function handles all the steps involved in the Spectral Coarse
-  Graining (SCG) of some matrices and graphs as described in the
-  reference below.
-}
 \usage{
 scg(X, ev, nt, groups = NULL, mtype = c("symmetric", "laplacian",
-      "stochastic"), algo = c("optimum", "interv_km", "interv",
-      "exact_scg"), norm = c("row", "col"), direction = c("default",
-      "left", "right"), evec = NULL, p = NULL, use.arpack = FALSE,
-    maxiter = 300, sparse = getIgraphOpt("sparsematrices"), output =
-    c("default", "matrix", "graph"), semproj = FALSE, epairs = FALSE,
-    stat.prob = FALSE) 
+  "stochastic"), algo = c("optimum", "interv_km", "interv", "exact_scg"),
+  norm = c("row", "col"), direction = c("default", "left", "right"),
+  evec = NULL, p = NULL, use.arpack = FALSE, maxiter = 300,
+  sparse = igraph_opt("sparsematrices"), output = c("default", "matrix",
+  "graph"), semproj = FALSE, epairs = FALSE, stat.prob = FALSE)
 }
 \arguments{
-  \item{X}{The input graph or square matrix. Can be of class
-    \code{igraph}, \code{matrix} or \code{Matrix}.} 
-  \item{ev}{A vector of positive integers giving the indexes of the
-    eigenpairs to be preserved. For real eigenpairs, 1 designates the
-    eigenvalue with largest algebraic value, 2 the one with second
-    largest algebraic value, etc. In the complex case, it is the
-    magnitude that matters.}
-  \item{nt}{A vector of positive integers of length one or equal
-    to \code{length(ev)}. When \code{algo} = \dQuote{optimum},
-    \code{nt} contains the number of groups used to partition
-    each eigenvector separately. When \code{algo} is equal to
-    \dQuote{interv\_km} or \dQuote{interv}, \code{nt} contains
-    the number of intervals used to partition each eigenvector. The same
-    partition size or number of intervals is used for each eigenvector
-    if \code{nt} is a single integer. When \code{algo} =
-    \dQuote{exact\_cg} this parameter is ignored.}
-  \item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)} integers
-    labeling each group vertex in the partition. If this parameter is
-    supplied most part of the function is bypassed.}
-  \item{mtype}{Character scalar. The type of semi-projector to be
-    used for the SCG. For now \dQuote{symmetric}, \dQuote{laplacian} and
-    \dQuote{stochastic} are available.}
-  \item{algo}{Character scalar. The algorithm used to solve the SCG
-    problem. Possible values are \dQuote{optimum}, \dQuote{interv\_km},
-    \dQuote{interv} and \dQuote{exact\_scg}.}
-  \item{norm}{Character scalar. Either \dQuote{row} or \dQuote{col}. If
-    set to \dQuote{row} the rows of the Laplacian matrix sum up to zero
-    and the rows of the stochastic matrix sum up to one; otherwise it is
-    the columns.}  
-  \item{direction}{Character scalar. When set to \dQuote{right},
-    resp. \dQuote{left}, the parameters \code{ev} and \code{evec} refer
-    to right, resp. left eigenvectors. When passed \dQuote{default} it
-    is the SCG described in the reference below that is applied (common
-    usage). This argument is currently not implemented, and right
-    eigenvectors are always used.}
-  \item{evec}{A numeric matrix of (eigen)vectors to be preserved by the
-    coarse graining (the vectors are to be stored column-wise in
-    \code{evec}). If supplied, the eigenvectors should correspond to the
-    indexes in \code{ev} as no cross-check will be done.}
-  \item{p}{A probability vector of length \code{nrow(X)} (or
-    \code{vcount(X)}). \code{p} is the stationary probability
-    distribution of a Markov chain when \code{mtype} =
-    \dQuote{stochastic}. This parameter is ignored in all other cases.}
- \item{use.arpack}{Logical scalar. When set to \code{TRUE} uses the
-   function \code{\link{arpack}} to compute
-   eigenpairs. This parameter should be set to \code{TRUE} if one deals
-   with large (over a few thousands) AND sparse graphs or matrices. This
-   argument is not implemented currently and LAPACK is used for solving
-   the eigenproblems. }
-  \item{maxiter}{A positive integer giving the maximum number of
-    iterations for the k-means algorithm when \code{algo} =
-    \dQuote{interv\_km}. This parameter is ignored in all other cases.}
-  \item{sparse}{Logical scalar. Whether to return sparse matrices in the
-    result, if matrices are requested.}
-  \item{output}{Character scalar. Set this parameter to \dQuote{default}
-    to retrieve a coarse-grained object of the same class as \code{X}.}
-  \item{semproj}{Logical scalar. Set this parameter to \code{TRUE} to
-    retrieve the semi-projectors of the SCG.}
-  \item{epairs}{Logical scalar. Set this to \code{TRUE} to collect the
-    eigenpairs computed by \code{scg}.}
-  \item{stat.prob}{Logical scalar. This is to collect the stationary
-    probability \code{p} when dealing with stochastic matrices.}
-}
-\details{
-  Please see \link{SCG} for an introduction.
-  
-  In the following \eqn{V} is the matrix of eigenvectors for which the
-  SCG is solved. \eqn{V} is calculated from \code{X}, if it is not given
-  in the \code{evec} argument.
-  
-  The algorithm \dQuote{optimum} solves exactly the SCG problem for each
-  eigenvector in \code{V}. The running time of this algorithm is
-  \eqn{O(\max nt \cdot m^2)}{O(max(nt) m^2)} for the symmetric and
-  laplacian matrix problems (i.e. when \code{mtype} is
-  \dQuote{symmetric} or \dQuote{laplacian}. It is \eqn{O(m^3)} for the
-  stochastic problem. Here \eqn{m} is the number of rows in \code{V}.
-  In all three cases, the memory usage is \eqn{O(m^2)}.
-
-  The algorithms \dQuote{interv} and \dQuote{interv\_km} solve
-  approximately the SCG problem by performing a (for now) constant
-  binning of the components of the eigenvectors, that is
-  \code{nt[i]} constant-size bins are used to partition
-  \code{V[,i]}. When \code{algo} = \dQuote{interv\_km}, the (Lloyd)
-  k-means algorithm is run on each partition obtained by \dQuote{interv}
-  to improve accuracy. 
-
-  Once a minimizing partition (either exact or approximate) has been
-  found for each eigenvector, the final grouping is worked out as
-  follows: two vertices are grouped together in the final partition if
-  they are grouped together in each minimizing partition. In general the
-  size of the final partition is not known in advance when
-  \code{ncol(V)}>1. 
-
-  Finally, the algorithm \dQuote{exact\_scg} groups the vertices with
-  equal components in each eigenvector. The last three algorithms
-  essentially have linear running time and memory load.
+\item{X}{The input graph or square matrix. Can be of class \code{igraph},
+\code{matrix} or \code{Matrix}.}
+
+\item{ev}{A vector of positive integers giving the indexes of the eigenpairs
+to be preserved. For real eigenpairs, 1 designates the eigenvalue with
+largest algebraic value, 2 the one with second largest algebraic value, etc.
+In the complex case, it is the magnitude that matters.}
+
+\item{nt}{A vector of positive integers of length one or equal to
+\code{length(ev)}. When \code{algo} = \dQuote{optimum}, \code{nt} contains
+the number of groups used to partition each eigenvector separately. When
+\code{algo} is equal to \dQuote{interv\_km} or \dQuote{interv}, \code{nt}
+contains the number of intervals used to partition each eigenvector. The
+same partition size or number of intervals is used for each eigenvector if
+\code{nt} is a single integer. When \code{algo} = \dQuote{exact\_cg} this
+parameter is ignored.}
+
+\item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)} integers
+labeling each group vertex in the partition. If this parameter is supplied
+most part of the function is bypassed.}
+
+\item{mtype}{Character scalar. The type of semi-projector to be used for the
+SCG. For now \dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic}
+are available.}
+
+\item{algo}{Character scalar. The algorithm used to solve the SCG problem.
+Possible values are \dQuote{optimum}, \dQuote{interv\_km}, \dQuote{interv}
+and \dQuote{exact\_scg}.}
+
+\item{norm}{Character scalar. Either \dQuote{row} or \dQuote{col}. If set to
+\dQuote{row} the rows of the Laplacian matrix sum up to zero and the rows of
+the stochastic matrix sum up to one; otherwise it is the columns.}
+
+\item{direction}{Character scalar. When set to \dQuote{right}, resp.
+\dQuote{left}, the parameters \code{ev} and \code{evec} refer to right,
+resp. left eigenvectors. When passed \dQuote{default} it is the SCG
+described in the reference below that is applied (common usage). This
+argument is currently not implemented, and right eigenvectors are always
+used.}
+
+\item{evec}{A numeric matrix of (eigen)vectors to be preserved by the coarse
+graining (the vectors are to be stored column-wise in \code{evec}). If
+supplied, the eigenvectors should correspond to the indexes in \code{ev} as
+no cross-check will be done.}
+
+\item{p}{A probability vector of length \code{nrow(X)} (or
+\code{vcount(X)}). \code{p} is the stationary probability distribution of a
+Markov chain when \code{mtype} = \dQuote{stochastic}. This parameter is
+ignored in all other cases.}
+
+\item{use.arpack}{Logical scalar. When set to \code{TRUE} uses the function
+\code{\link{arpack}} to compute eigenpairs. This parameter should be set to
+\code{TRUE} if one deals with large (over a few thousands) AND sparse graphs
+or matrices. This argument is not implemented currently and LAPACK is used
+for solving the eigenproblems.}
+
+\item{maxiter}{A positive integer giving the maximum number of iterations
+for the k-means algorithm when \code{algo} = \dQuote{interv\_km}. This
+parameter is ignored in all other cases.}
+
+\item{sparse}{Logical scalar. Whether to return sparse matrices in the
+result, if matrices are requested.}
+
+\item{output}{Character scalar. Set this parameter to \dQuote{default} to
+retrieve a coarse-grained object of the same class as \code{X}.}
+
+\item{semproj}{Logical scalar. Set this parameter to \code{TRUE} to retrieve
+the semi-projectors of the SCG.}
+
+\item{epairs}{Logical scalar. Set this to \code{TRUE} to collect the
+eigenpairs computed by \code{scg}.}
+
+\item{stat.prob}{Logical scalar. This is to collect the stationary
+probability \code{p} when dealing with stochastic matrices.}
 }
 \value{
-  \item{Xt}{The coarse-grained graph, or matrix, possibly a sparse matrix.}
-  \item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)} integers
-    giving the group label of each object (vertex) in the partition.}
-  \item{L}{The semi-projector \eqn{L} if \code{semproj = TRUE}.}
-  \item{R}{The semi-projector \eqn{R} if \code{semproj = TRUE}.}
-  \item{values}{The computed eigenvalues if \code{epairs = TRUE}.}
-  \item{vectors}{The computed or supplied eigenvectors if \code{epairs =
-      TRUE}.}
-  \item{p}{The stationary probability vector if \code{mtype =
-      stochastic} and \code{stat.prob = TRUE}. For other matrix types
-    this is missing.}
+\item{Xt}{The coarse-grained graph, or matrix, possibly a sparse
+matrix.} \item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)}
+integers giving the group label of each object (vertex) in the partition.}
+\item{L}{The semi-projector \eqn{L} if \code{semproj = TRUE}.} \item{R}{The
+semi-projector \eqn{R} if \code{semproj = TRUE}.} \item{values}{The computed
+eigenvalues if \code{epairs = TRUE}.} \item{vectors}{The computed or
+supplied eigenvectors if \code{epairs = TRUE}.} \item{p}{The stationary
+probability vector if \code{mtype = stochastic} and \code{stat.prob = TRUE}.
+For other matrix types this is missing.}
 }
-\references{
-D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios, Shrinking
-  Matrices while Preserving their Eigenpairs with Application to the
-  Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
-    Matrix Analysis and Applications}, 2008.
-  \url{http://people.epfl.ch/david.morton} 
+\description{
+This function handles all the steps involved in the Spectral Coarse Graining
+(SCG) of some matrices and graphs as described in the reference below.
 }
-\author{David Morton de Lachapelle, \url{http://people.epfl.ch/david.morton}.}
-\seealso{\link{SCG} for an introduction.
-  \code{\link{scgNormEps}}, \code{\link{scgGrouping}} and
-  \code{\link{scgSemiProjectors}}.}
-\examples{
+\details{
+Please see \link{scg-method} for an introduction.
+
+In the following \eqn{V} is the matrix of eigenvectors for which the SCG is
+solved. \eqn{V} is calculated from \code{X}, if it is not given in the
+\code{evec} argument.
+
+The algorithm \dQuote{optimum} solves exactly the SCG problem for each
+eigenvector in \code{V}. The running time of this algorithm is \eqn{O(\max
+nt \cdot m^2)}{O(max(nt) m^2)} for the symmetric and laplacian matrix
+problems (i.e. when \code{mtype} is \dQuote{symmetric} or
+\dQuote{laplacian}. It is \eqn{O(m^3)} for the stochastic problem. Here
+\eqn{m} is the number of rows in \code{V}.  In all three cases, the memory
+usage is \eqn{O(m^2)}.
+
+The algorithms \dQuote{interv} and \dQuote{interv\_km} solve approximately
+the SCG problem by performing a (for now) constant binning of the components
+of the eigenvectors, that is \code{nt[i]} constant-size bins are used to
+partition \code{V[,i]}. When \code{algo} = \dQuote{interv\_km}, the (Lloyd)
+k-means algorithm is run on each partition obtained by \dQuote{interv} to
+improve accuracy.
 
+Once a minimizing partition (either exact or approximate) has been found for
+each eigenvector, the final grouping is worked out as follows: two vertices
+are grouped together in the final partition if they are grouped together in
+each minimizing partition. In general the size of the final partition is not
+known in advance when \code{ncol(V)}>1.
+
+Finally, the algorithm \dQuote{exact\_scg} groups the vertices with equal
+components in each eigenvector. The last three algorithms essentially have
+linear running time and memory load.
+}
+\examples{
 ## We are not running these examples any more, because they
 ## take a long time (~20 seconds) to run and this is against the CRAN
 ## repository policy. Copy and paste them by hand to your R prompt if
@@ -147,12 +142,12 @@ D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios, Shrinking
 
 \dontrun{
 # SCG of a toy network
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
+g <- make_full_graph(5) \%du\% make_full_graph(5) \%du\% make_full_graph(5)
+g <- add_edges(g, c(1,6, 1,11, 6, 11))
 cg <- scg(g, 1, 3, algo="exact_scg")
 
 #plot the result
-layout <- layout.kamada.kawai(g)
+layout <- layout_with_kk(g)
 nt <- vcount(cg$Xt)
 col <- rainbow(nt)
 vsize <- table(cg$groups)
@@ -161,9 +156,9 @@ ewidth <- round(E(cg$Xt)$weight,2)
 op <- par(mfrow=c(1,2))
 plot(g, vertex.color = col[cg$groups], vertex.size = 20,
 		vertex.label = NA, layout = layout)
-plot(cg$Xt, edge.width = ewidth, edge.label = ewidth, 
+plot(cg$Xt, edge.width = ewidth, edge.label = ewidth,
 	vertex.color = col, vertex.size = 20*vsize/max(vsize),
-	vertex.label=NA, layout = layout.kamada.kawai)
+	vertex.label=NA, layout = layout_with_kk)
 par(op)
 
 ## SCG of real-world network
@@ -178,7 +173,7 @@ cg <- scg(immuno, ev= n-(1:9), nt=interv, mtype="laplacian",
 ## are the eigenvalues well-preserved?
 gt <- cg$Xt
 nt <- vcount(gt)
-Lt <- graph.laplacian(gt)
+Lt <- laplacian_matrix(gt)
 evalt <- eigen(Lt, only.values=TRUE)$values[nt-(1:9)]
 res <- cbind(interv, cg$values, evalt)
 res <- round(res,5)
@@ -187,26 +182,42 @@ rownames(res) <- c("N-1","N-2","N-3","N-4","N-5","N-6","N-7","N-8","N-9")
 print(res)
 
 ## use SCG to get the communities
-com <- scg(graph.laplacian(immuno), ev=n-c(1,2), nt=2)$groups
+com <- scg(laplacian_matrix(immuno), ev=n-c(1,2), nt=2)$groups
 col <- rainbow(max(com))
-layout <- layout.auto(immuno)
+layout <- layout_nicely(immuno)
 
 plot(immuno, layout=layout, vertex.size=3, vertex.color=col[com],
                 vertex.label=NA)
 
 ## display the coarse-grained graph
 gt <- simplify(as.undirected(gt))
-layout.cg <- layout.kamada.kawai(gt)
-com.cg <- scg(graph.laplacian(gt), nt-c(1,2), 2)$groups
+layout.cg <- layout_with_kk(gt)
+com.cg <- scg(laplacian_matrix(gt), nt-c(1,2), 2)$groups
 vsize <- sqrt(as.vector(table(cg$groups)))
 
 op <- par(mfrow=c(1,2))
 plot(immuno, layout=layout, vertex.size=3, vertex.color=col[com],
                 vertex.label=NA)
-plot(gt, layout=layout.cg, vertex.size=15*vsize/max(vsize), 
+plot(gt, layout=layout.cg, vertex.size=15*vsize/max(vsize),
                 vertex.color=col[com.cg],vertex.label=NA)
 par(op)
 
 }
 }
+\author{
+David Morton de Lachapelle,
+\url{http://people.epfl.ch/david.morton}.
+}
+\references{
+D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+Shrinking Matrices while Preserving their Eigenpairs with Application to the
+Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+Matrix Analysis and Applications}, 2008.
+\url{http://people.epfl.ch/david.morton}
+}
+\seealso{
+\link{scg-method} for an introduction.  \code{\link{scg_eps}},
+\code{\link{scg_group}} and \code{\link{scg_semi_proj}}.
+}
 \keyword{graphs}
+
diff --git a/man/scg.grouping.Rd b/man/scg.grouping.Rd
deleted file mode 100644
index 85d4399..0000000
--- a/man/scg.grouping.Rd
+++ /dev/null
@@ -1,127 +0,0 @@
-\name{scgGrouping}
-\alias{scgGrouping}
-\title{SCG Problem Solver}
-\description{
-  This function solves the Spectral Coarse Graining (SCG) problem;
-  either exactly, or approximately but faster.
-}
-\usage{
-scgGrouping(V, nt, mtype = c("symmetric", "laplacian",
-          "stochastic"), algo = c("optimum", "interv_km",
-          "interv","exact_scg"), p = NULL, maxiter = 100)
-}
-\arguments{
-  \item{V}{A numeric matrix of (eigen)vectors to be preserved by the
-    coarse graining (the vectors are to be stored column-wise in
-    \code{V}).} 
-  \item{nt}{A vector of positive integers of length one or equal to
-    \code{length(ev)}. When \code{algo} = \dQuote{optimum}, \code{nt}
-    contains the number of groups used to partition each eigenvector
-    separately. When \code{algo} is equal to \dQuote{interv\_km} or
-    \dQuote{interv}, \code{nt} contains the number of intervals used to
-    partition each eigenvector. The same partition size or number of
-    intervals is used for each eigenvector if \code{nt} is a single
-    integer. When \code{algo} = \dQuote{exact\_cg} this parameter is
-    ignored.}
-  \item{mtype}{The type of semi-projectors used in the SCG. For now
-    \dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic} are
-    available.}
-  \item{algo}{The algorithm used to solve the SCG problem. Possible
-    values are \dQuote{optimum}, \dQuote{interv\_km}, \dQuote{interv}
-    and \dQuote{exact\_scg}.} 
-  \item{p}{A probability vector of length equal to
-    \code{nrow(V)}. \code{p} is the stationary probability distribution
-    of a Markov chain when \code{mtype} = \dQuote{stochastic}. This
-    parameter is ignored in all other cases.}
-  \item{maxiter}{A positive
-    integer giving the maximum number of iterations of the k-means
-    algorithm when \code{algo} = \dQuote{interv\_km}. This parameter is
-    ignored in all other cases.} 
-}
-\details{
-  The algorithm \dQuote{optimum} solves exactly the SCG problem for each
-  eigenvector in \code{V}. The running time of this algorithm is
-  \eqn{O(\max nt \cdot m^2)}{O(max(nt) m^2)} for the symmetric and
-  laplacian matrix problems (i.e. when \code{mtype} is
-  \dQuote{symmetric} or \dQuote{laplacian}. It is \eqn{O(m^3)} for the
-  stochastic problem. Here \eqn{m} is the number of rows in \code{V}.
-  In all three cases, the memory usage is \eqn{O(m^2)}.
-
-  The algorithms \dQuote{interv} and \dQuote{interv\_km} solve
-  approximately the SCG problem by performing a (for now) constant
-  binning of the components of the eigenvectors, that is \code{nt[i]}
-  constant-size bins are used to partition \code{V[,i]}. When
-  \code{algo} = \dQuote{interv\_km}, the (Lloyd) k-means algorithm is
-  run on each partition obtained by \dQuote{interv} to improve
-  accuracy. 
-
-  Once a minimizing partition (either exact or approximate) has been
-  found for each eigenvector, the final grouping is worked out as
-  follows: two vertices are grouped together in the final partition if
-  they are grouped together in each minimizing partition. In general the
-  size of the final partition is not known in advance when
-  \code{ncol(V)}>1. 
-
-  Finally, the algorithm \dQuote{exact\_scg} groups the vertices with
-  equal components in each eigenvector. The last three algorithms
-  essentially have linear running time and memory load.
-}
-\value{
-  A vector of \code{nrow(V)} integers giving the group label of each
-  object (vertex) in the partition.
-}
-\references{
-D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios, Shrinking
-  Matrices while Preserving their Eigenpairs with Application to the
-  Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
-    Matrix Analysis and Applications}, 2008.
-  \url{http://people.epfl.ch/david.morton}
-}
-\author{David Morton de Lachapelle \email{david.morton at epfl.ch},
-  \email{david.mortondelachapelle at swissquote.ch}} 
-\seealso{\link{SCG} for a detailed introduction. \code{\link{scg}},
-  \code{\link{scgNormEps}}}
-\examples{
-
-## We are not running these examples any more, because they
-## take a long time to run and this is against the CRAN repository
-## policy. Copy and paste them by hand to your R prompt if
-## you want to run them.
-
-\dontrun{
-# eigenvectors of a random symmetric matrix
-M <- matrix(rexp(10^6), 10^3, 10^3)
-M <- (M + t(M))/2
-V <- eigen(M, symmetric=TRUE)$vectors[,c(1,2)]
-
-# displays size of the groups in the final partition
-gr <- scgGrouping(V, nt=c(2,3))
-col <- rainbow(max(gr))
-plot(table(gr), col=col, main="Group size", xlab="group", ylab="size")
-
-## comparison with the grouping obtained by kmeans
-## for a partition of same size
-gr.km <- kmeans(V,centers=max(gr), iter.max=100, nstart=100)$cluster
-op <- par(mfrow=c(1,2))
-plot(V[,1], V[,2], col=col[gr],
-	main = "SCG grouping",
-	xlab = "1st eigenvector",
-	ylab = "2nd eigenvector")
-plot(V[,1], V[,2], col=col[gr.km],
-	main = "K-means grouping",
-	xlab = "1st eigenvector",
-	ylab = "2nd eigenvector")
-par(op)
-## kmeans disregards the first eigenvector as it
-## spreads a much smaller range of values than the second one
-
-### comparing optimal and k-means solutions
-### in the one-dimensional case.
-x <- rexp(2000, 2)
-gr.true <- scgGrouping(cbind(x), 100)
-gr.km <- kmeans(x, 100, 100, 300)$cluster
-scgNormEps(cbind(x), gr.true)
-scgNormEps(cbind(x), gr.km)
-}
-}
-\keyword{graphs}
diff --git a/man/scg_eps.Rd b/man/scg_eps.Rd
new file mode 100644
index 0000000..11a67a1
--- /dev/null
+++ b/man/scg_eps.Rd
@@ -0,0 +1,59 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scg.R
+\name{scg_eps}
+\alias{scgNormEps}
+\alias{scg_eps}
+\title{Error of the spectral coarse graining (SCG) approximation}
+\usage{
+scg_eps(V, groups, mtype = c("symmetric", "laplacian", "stochastic"),
+  p = NULL, norm = c("row", "col"))
+}
+\arguments{
+\item{V}{A numeric matrix of (eigen)vectors assumed normalized.  The vectors
+are to be stored column-wise in \code{V}).}
+
+\item{groups}{A vector of \code{nrow(V)} integers labeling each group vertex
+in the partition.}
+
+\item{mtype}{The type of semi-projector used for the SCG. For now
+\dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic} are
+available.}
+
+\item{p}{A probability vector of length \code{nrow(V)}.  \code{p} is the
+stationary probability distribution of a Markov chain when \code{mtype} =
+\dQuote{stochastic}. This parameter is ignored otherwise.}
+
+\item{norm}{Either \dQuote{row} or \dQuote{col}. If set to \dQuote{row} the
+rows of the Laplacian matrix sum to zero and the rows of the stochastic
+matrix sum to one; otherwise it is the columns.}
+}
+\value{
+\code{scg_eps} returns with a numeric vector whose \eqn{i}th
+component is \eqn{\Vert v_i-Pv_i\Vert}{|v[i]-Pv[i]|} (see Details).
+}
+\description{
+\code{scg_eps} computes \eqn{\Vert v_i-Pv_i\Vert}{|v[i]-Pv[i]|}, where
+\eqn{v_i}{v[i]} is the \eqn{i}th eigenvector in \code{V} and \eqn{P} is the
+projector corresponding to the \code{mtype} argument.
+}
+\examples{
+v <- rexp(20)
+km <- kmeans(v,5)
+sum(km$withinss)
+scg_eps(cbind(v), km$cluster)^2
+}
+\author{
+David Morton de Lachapelle,
+\url{http://people.epfl.ch/david.morton}.
+}
+\references{
+D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+Shrinking Matrices while Preserving their Eigenpairs with Application to the
+Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+Matrix Analysis and Applications}, 2008.
+\url{http://people.epfl.ch/david.morton}
+}
+\seealso{
+\link{scg-method} and \code{\link{scg}}.
+}
+
diff --git a/man/scg_extra.Rd b/man/scg_extra.Rd
deleted file mode 100644
index df99c52..0000000
--- a/man/scg_extra.Rd
+++ /dev/null
@@ -1,51 +0,0 @@
-\name{scgExtra}
-\alias{scgNormEps}
-\title{SCG Extra Functions}
-\description{
-  Some useful functions to perform general actions in Spectral Coarse
-  Graining (SCG).
-}
-\usage{
-scgNormEps(V, groups, mtype = c("symmetric", "laplacian",
-          "stochastic"), p = NULL, norm = c("row", "col"))
-}
-\arguments{
-  \item{V}{A numeric matrix of (eigen)vectors assumed normalized.
-    The vectors are to be stored column-wise in \code{V}).}
-  \item{groups}{A vector of \code{nrow(V)} integers labeling 
-    each group vertex in the partition.}
-  \item{mtype}{The type of semi-projector used for the SCG. For 
-    now \dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic}
-    are available.} 
-  \item{p}{A probability vector of length \code{nrow(V)}.
-    \code{p} is the stationary probability distribution of a Markov chain 
-    when \code{mtype} = \dQuote{stochastic}. This parameter is ignored otherwise.}
-  \item{norm}{Either \dQuote{row} or \dQuote{col}. If set to \dQuote{row} 
-    the rows of the Laplacian matrix sum to zero and the rows of the 
-    stochastic matrix sum to one; otherwise it is the columns.}
-}
-\details{
- \code{scgNormEps} computes \eqn{\Vert v_i-Pv_i\Vert}{|v[i]-Pv[i]|},
-   where \eqn{v_i}{v[i]} is the \eqn{i}th eigenvector in \code{V} and
-   \eqn{P} is the projector corresponding to the \code{mtype} argument.
-}
-\value{
-  \code{normEps} returns with a numeric vector whose \eqn{i}th component is 
-  \eqn{\Vert v_i-Pv_i\Vert}{|v[i]-Pv[i]|} (see Details).
-}
-\references{
-  D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios, Shrinking
-  Matrices while Preserving their Eigenpairs with Application to the
-  Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
-    Matrix Analysis and Applications}, 2008. 
-  \url{http://people.epfl.ch/david.morton}
-}
-\author{David Morton de Lachapelle, \url{http://people.epfl.ch/david.morton}.}
-\seealso{\link{SCG} and \code{\link{scg}}. }
-\examples{
-v <- rexp(20)
-km <- kmeans(v,5)
-sum(km$withinss)
-scgNormEps(cbind(v), km$cluster)^2
-}
-\keyword{graphs}
diff --git a/man/scg_group.Rd b/man/scg_group.Rd
new file mode 100644
index 0000000..c3d4312
--- /dev/null
+++ b/man/scg_group.Rd
@@ -0,0 +1,133 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scg.R
+\name{scg_group}
+\alias{scgGrouping}
+\alias{scg_group}
+\title{SCG Problem Solver}
+\usage{
+scg_group(V, nt, mtype = c("symmetric", "laplacian", "stochastic"),
+  algo = c("optimum", "interv_km", "interv", "exact_scg"), p = NULL,
+  maxiter = 100)
+}
+\arguments{
+\item{V}{A numeric matrix of (eigen)vectors to be preserved by the coarse
+graining (the vectors are to be stored column-wise in \code{V}).}
+
+\item{nt}{A vector of positive integers of length one or equal to
+\code{length(ev)}. When \code{algo} = \dQuote{optimum}, \code{nt} contains
+the number of groups used to partition each eigenvector separately. When
+\code{algo} is equal to \dQuote{interv\_km} or \dQuote{interv}, \code{nt}
+contains the number of intervals used to partition each eigenvector. The
+same partition size or number of intervals is used for each eigenvector if
+\code{nt} is a single integer. When \code{algo} = \dQuote{exact\_cg} this
+parameter is ignored.}
+
+\item{mtype}{The type of semi-projectors used in the SCG. For now
+\dQuote{symmetric}, \dQuote{laplacian} and \dQuote{stochastic} are
+available.}
+
+\item{algo}{The algorithm used to solve the SCG problem. Possible values are
+\dQuote{optimum}, \dQuote{interv\_km}, \dQuote{interv} and
+\dQuote{exact\_scg}.}
+
+\item{p}{A probability vector of length equal to \code{nrow(V)}. \code{p} is
+the stationary probability distribution of a Markov chain when \code{mtype}
+= \dQuote{stochastic}. This parameter is ignored in all other cases.}
+
+\item{maxiter}{A positive integer giving the maximum number of iterations of
+the k-means algorithm when \code{algo} = \dQuote{interv\_km}. This parameter
+is ignored in all other cases.}
+}
+\value{
+A vector of \code{nrow(V)} integers giving the group label of each
+object (vertex) in the partition.
+}
+\description{
+This function solves the Spectral Coarse Graining (SCG) problem; either
+exactly, or approximately but faster.
+}
+\details{
+The algorithm \dQuote{optimum} solves exactly the SCG problem for each
+eigenvector in \code{V}. The running time of this algorithm is \eqn{O(\max
+nt \cdot m^2)}{O(max(nt) m^2)} for the symmetric and laplacian matrix
+problems (i.e. when \code{mtype} is \dQuote{symmetric} or
+\dQuote{laplacian}. It is \eqn{O(m^3)} for the stochastic problem. Here
+\eqn{m} is the number of rows in \code{V}.  In all three cases, the memory
+usage is \eqn{O(m^2)}.
+
+The algorithms \dQuote{interv} and \dQuote{interv\_km} solve approximately
+the SCG problem by performing a (for now) constant binning of the components
+of the eigenvectors, that is \code{nt[i]} constant-size bins are used to
+partition \code{V[,i]}. When \code{algo} = \dQuote{interv\_km}, the (Lloyd)
+k-means algorithm is run on each partition obtained by \dQuote{interv} to
+improve accuracy.
+
+Once a minimizing partition (either exact or approximate) has been found for
+each eigenvector, the final grouping is worked out as follows: two vertices
+are grouped together in the final partition if they are grouped together in
+each minimizing partition. In general the size of the final partition is not
+known in advance when \code{ncol(V)}>1.
+
+Finally, the algorithm \dQuote{exact\_scg} groups the vertices with equal
+components in each eigenvector. The last three algorithms essentially have
+linear running time and memory load.
+}
+\examples{
+## We are not running these examples any more, because they
+## take a long time to run and this is against the CRAN repository
+## policy. Copy and paste them by hand to your R prompt if
+## you want to run them.
+
+\dontrun{
+# eigenvectors of a random symmetric matrix
+M <- matrix(rexp(10^6), 10^3, 10^3)
+M <- (M + t(M))/2
+V <- eigen(M, symmetric=TRUE)$vectors[,c(1,2)]
+
+# displays size of the groups in the final partition
+gr <- scg_group(V, nt=c(2,3))
+col <- rainbow(max(gr))
+plot(table(gr), col=col, main="Group size", xlab="group", ylab="size")
+
+## comparison with the grouping obtained by kmeans
+## for a partition of same size
+gr.km <- kmeans(V,centers=max(gr), iter.max=100, nstart=100)$cluster
+op <- par(mfrow=c(1,2))
+plot(V[,1], V[,2], col=col[gr],
+	main = "SCG grouping",
+	xlab = "1st eigenvector",
+	ylab = "2nd eigenvector")
+plot(V[,1], V[,2], col=col[gr.km],
+	main = "K-means grouping",
+	xlab = "1st eigenvector",
+	ylab = "2nd eigenvector")
+par(op)
+## kmeans disregards the first eigenvector as it
+## spreads a much smaller range of values than the second one
+
+### comparing optimal and k-means solutions
+### in the one-dimensional case.
+x <- rexp(2000, 2)
+gr.true <- scg_group(cbind(x), 100)
+gr.km <- kmeans(x, 100, 100, 300)$cluster
+scg_eps(cbind(x), gr.true)
+scg_eps(cbind(x), gr.km)
+}
+}
+\author{
+David Morton de Lachapelle \email{david.morton at epfl.ch},
+\email{david.mortondelachapelle at swissquote.ch}
+}
+\references{
+D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+Shrinking Matrices while Preserving their Eigenpairs with Application to the
+Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+Matrix Analysis and Applications}, 2008.
+\url{http://people.epfl.ch/david.morton}
+}
+\seealso{
+\link{scg-method} for a detailed introduction. \code{\link{scg}},
+\code{\link{scg_eps}}
+}
+\keyword{graphs}
+
diff --git a/man/scg_semi_proj.Rd b/man/scg_semi_proj.Rd
new file mode 100644
index 0000000..29fb313
--- /dev/null
+++ b/man/scg_semi_proj.Rd
@@ -0,0 +1,100 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scg.R
+\name{scg_semi_proj}
+\alias{scgSemiProjectors}
+\alias{scg_semi_proj}
+\title{Semi-Projectors}
+\usage{
+scg_semi_proj(groups, mtype = c("symmetric", "laplacian", "stochastic"),
+  p = NULL, norm = c("row", "col"), sparse = igraph_opt("sparsematrices"))
+}
+\arguments{
+\item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)} integers giving
+the group label of every vertex in the partition.}
+
+\item{mtype}{The type of semi-projectors. For now \dQuote{symmetric},
+\dQuote{laplacian} and \dQuote{stochastic} are available.}
+
+\item{p}{A probability vector of length \code{length(gr)}. \code{p} is the
+stationary probability distribution of a Markov chain when \code{mtype} =
+\dQuote{stochastic}. This parameter is ignored in all other cases.}
+
+\item{norm}{Either \dQuote{row} or \dQuote{col}. If set to \dQuote{row} the
+rows of the Laplacian matrix sum up to zero and the rows of the stochastic
+sum up to one; otherwise it is the columns.}
+
+\item{sparse}{Logical scalar, whether to return sparse matrices.}
+}
+\value{
+\item{L}{The semi-projector \eqn{L}.} \item{R}{The semi-projector
+\eqn{R}.}
+}
+\description{
+A function to compute the \eqn{L} and \eqn{R} semi-projectors for a given
+partition of the vertices.
+}
+\details{
+The three types of semi-projectors are defined as follows.  Let
+\eqn{\gamma(j)}{gamma(j)} label the group of vertex \eqn{j} in a partition
+of all the vertices.
+
+The symmetric semi-projectors are defined as \deqn{L_{\alpha j}=R_{\alpha
+j}= }{% L[alpha,j] = R[alpha,j] = 1/sqrt(|alpha|)
+delta[alpha,gamma(j)],}\deqn{
+\frac{1}{\sqrt{|\alpha|}}\delta_{\alpha\gamma(j)},}{% L[alpha,j] =
+R[alpha,j] = 1/sqrt(|alpha|) delta[alpha,gamma(j)],} the (row) Laplacian
+semi-projectors as \deqn{L_{\alpha
+j}=\frac{1}{|\alpha|}\delta_{\alpha\gamma(j)}\,\,\,\, }{% L[alpha,j] =
+1/|alpha| delta[alpha,gamma(j)] and R[alpha,j] =
+delta[alpha,gamma(j)],}\deqn{ \textrm{and}\,\,\,\, R_{\alpha
+j}=\delta_{\alpha\gamma(j)},}{% L[alpha,j] = 1/|alpha| delta[alpha,gamma(j)]
+and R[alpha,j] = delta[alpha,gamma(j)],} and the (row) stochastic
+semi-projectors as \deqn{L_{\alpha
+j}=\frac{p_{1}(j)}{\sum_{k\in\gamma(j)}p_{1}(k)}\,\,\,\, }{% L[alpha,j] =
+p[1][j] / sum(p[1][k]; k in gamma(j)) delta[alpha,gamma(j)] and R[alpha,j] =
+delta[alpha,gamma(j)],}\deqn{ \textrm{and}\,\,\,\, R_{\alpha
+j}=\delta_{\alpha\gamma(j)\delta_{\alpha\gamma(j)}},}{% L[alpha,j] = p[1][j]
+/ sum(p[1][k]; k in gamma(j)) delta[alpha,gamma(j)] and R[alpha,j] =
+delta[alpha,gamma(j)],} where \eqn{p_1}{p[1]} is the (left) eigenvector
+associated with the one-eigenvalue of the stochastic matrix. \eqn{L} and
+\eqn{R} are defined in a symmetric way when \code{norm = col}. All these
+semi-projectors verify various properties described in the reference.
+}
+\examples{
+library(Matrix)
+# compute the semi-projectors and projector for the partition
+# provided by a community detection method
+g <- barabasi.game(20, m=1.5)
+eb <- cluster_edge_betweenness(g)
+memb <- membership(eb)
+lr <- scg_semi_proj(memb)
+#In the symmetric case L = R
+tcrossprod(lr$R)  # same as lr$R \%*\% t(lr$R)
+P <- crossprod(lr$R)  # same as t(lr$R) \%*\% lr$R
+#P is an orthogonal projector
+isSymmetric(P)
+sum( (P \%*\% P-P)^2 )
+
+## use L and R to coarse-grain the graph Laplacian
+lr <- scg_semi_proj(memb, mtype="laplacian")
+L <- laplacian_matrix(g)
+Lt <- lr$L \%*\% L \%*\% t(lr$R)
+## or better lr$L \%*\% tcrossprod(L,lr$R)
+rowSums(Lt)
+}
+\author{
+David Morton de Lachapelle,
+\url{http://people.epfl.ch/david.morton}.
+}
+\references{
+D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,
+Shrinking Matrices while Preserving their Eigenpairs with Application to the
+Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM Journal on
+Matrix Analysis and Applications}, 2008.
+\url{http://people.epfl.ch/david.morton}
+}
+\seealso{
+\link{scg-method} for a detailed introduction. \code{\link{scg}},
+\code{\link{scg_eps}}, \code{\link{scg_group}}
+}
+
diff --git a/man/semiProjectors.Rd b/man/semiProjectors.Rd
deleted file mode 100644
index 9a36f1d..0000000
--- a/man/semiProjectors.Rd
+++ /dev/null
@@ -1,92 +0,0 @@
-\name{scgSemiProjectors}
-\alias{scgSemiProjectors}
-\title{Semi-Projectors}
-\description{
-  A function to compute the \eqn{L} and \eqn{R} semi-projectors for a
-  given partition of the vertices.
-}
-\usage{
-scgSemiProjectors(groups, mtype = c("symmetric", "laplacian",
-                    "stochastic"), p = NULL, norm = c("row", "col"),
-                  sparse = getIgraphOpt("sparsematrices"))
-}
-\arguments{
-  \item{groups}{A vector of \code{nrow(X)} or \code{vcount(X)} integers
-    giving the group label of every vertex in the partition.}
-  \item{mtype}{The type of semi-projectors. For now \dQuote{symmetric},
-    \dQuote{laplacian} and \dQuote{stochastic} are available.}
-  \item{p}{A probability vector of length \code{length(gr)}. \code{p} is
-    the stationary probability distribution of a Markov chain when
-    \code{mtype} = \dQuote{stochastic}. This parameter is ignored in
-    all other cases.} 
-  \item{norm}{Either \dQuote{row} or \dQuote{col}. If set to
-    \dQuote{row} the rows of the Laplacian matrix sum up to zero 
-    and the rows of the stochastic sum up to one; otherwise it is the
-    columns.}
-  \item{sparse}{Logical scalar, whether to return sparse matrices.}
-}
-\details{
-  The three types of semi-projectors are defined as follows.
-  Let \eqn{\gamma(j)}{gamma(j)} label the group of vertex \eqn{j} in a
-  partition of all the vertices.
- 
-  The symmetric semi-projectors are defined as
-  \deqn{L_{\alpha j}=R_{\alpha j}=
-    \frac{1}{\sqrt{|\alpha|}}\delta_{\alpha\gamma(j)},}{%
-    L[alpha,j] = R[alpha,j] = 1/sqrt(|alpha|) delta[alpha,gamma(j)],}
-  the (row) Laplacian semi-projectors as
-  \deqn{L_{\alpha j}=\frac{1}{|\alpha|}\delta_{\alpha\gamma(j)}\,\,\,\,
-    \textrm{and}\,\,\,\, R_{\alpha j}=\delta_{\alpha\gamma(j)},}{%
-    L[alpha,j] = 1/|alpha| delta[alpha,gamma(j)] and
-    R[alpha,j] = delta[alpha,gamma(j)],}
-  and the (row) stochastic semi-projectors as
-  \deqn{L_{\alpha j}=\frac{p_{1}(j)}{\sum_{k\in\gamma(j)}p_{1}(k)}\,\,\,\,
-      \textrm{and}\,\,\,\, R_{\alpha j}=\delta_{\alpha\gamma(j)\delta_{\alpha\gamma(j)}},}{%
-      L[alpha,j] = p[1][j] / sum(p[1][k]; k in gamma(j))
-      delta[alpha,gamma(j)] and 
-      R[alpha,j] = delta[alpha,gamma(j)],}
-  where \eqn{p_1}{p[1]} is the (left) eigenvector associated with the
-  one-eigenvalue of the stochastic matrix. \eqn{L} and \eqn{R} are
-  defined in a symmetric way when \code{norm = col}. All these
-  semi-projectors verify various properties described in the
-  reference.
-}
-\value{
- \item{L}{The semi-projector \eqn{L}.}
- \item{R}{The semi-projector \eqn{R}.}
-}
-\references{
-  D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios, Shrinking
-  Matrices while Preserving their Eigenpairs with Application to the
-  Spectral Coarse Graining of Graphs. Submitted to \emph{SIAM
-    Journal on Matrix Analysis and Applications}, 2008. 
-  \url{http://people.epfl.ch/david.morton}
-}
-\author{David Morton de Lachapelle, \url{http://people.epfl.ch/david.morton}.}
-\seealso{\link{SCG} for a detailed introduction. \code{\link{scg}},
-  \code{\link{scgNormEps}}, \code{\link{scgGrouping}}}
-\examples{
-library(Matrix)
-# compute the semi-projectors and projector for the partition
-# provided by a community detection method
-g <- barabasi.game(20, m=1.5)
-eb <- edge.betweenness.community(g)
-memb <- membership(eb)
-lr <- scgSemiProjectors(memb)
-#In the symmetric case L = R
-tcrossprod(lr$R)  # same as lr$R %*% t(lr$R)
-P <- crossprod(lr$R)  # same as t(lr$R) %*% lr$R
-#P is an orthogonal projector
-isSymmetric(P)
-sum( (P \%*\% P-P)^2 )
-
-## use L and R to coarse-grain the graph Laplacian
-lr <- scgSemiProjectors(memb, mtype="laplacian")
-L <- graph.laplacian(g)
-Lt <- lr$L \%*\% L \%*\% t(lr$R)
-## or better lr$L \%*\% tcrossprod(L,lr$R)
-rowSums(Lt)
-}
-\keyword{array}
-\keyword{graphs}
-
diff --git a/man/sequential_pal.Rd b/man/sequential_pal.Rd
new file mode 100644
index 0000000..9f5c890
--- /dev/null
+++ b/man/sequential_pal.Rd
@@ -0,0 +1,41 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/palette.R
+\name{sequential_pal}
+\alias{sequential_pal}
+\title{Sequential palette}
+\usage{
+sequential_pal(n)
+}
+\arguments{
+\item{n}{The number of colors in the palette. The maximum is nine
+currently.}
+}
+\value{
+A character vector of RGB color codes.
+}
+\description{
+This is the \sQuote{OrRd} palette from \url{http://colorbrewer2.org}.
+It has at most nine colors.
+}
+\details{
+Use this palette, if vertex colors mark some ordinal quantity, e.g. some
+centrality measure, or some ordinal vertex covariate, like the age of
+people, or their seniority level.
+}
+\examples{
+\dontrun{
+library(igraphdata)
+data(karate)
+karate <- karate \%>\%
+  add_layout_(with_kk()) \%>\%
+  set_vertex_attr("size", value = 10)
+
+V(karate)$color <- scales::dscale(degree(karate) \%>\% cut(5), sequential_pal)
+plot(karate)
+}
+}
+\seealso{
+Other palettes: \code{\link{categorical_pal}};
+  \code{\link{diverging_pal}}; \code{\link{r_pal}}
+}
+
diff --git a/man/set_edge_attr.Rd b/man/set_edge_attr.Rd
new file mode 100644
index 0000000..4bf4513
--- /dev/null
+++ b/man/set_edge_attr.Rd
@@ -0,0 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{set_edge_attr}
+\alias{set.edge.attribute}
+\alias{set_edge_attr}
+\title{Set edge attributes}
+\usage{
+set_edge_attr(graph, name, index = E(graph), value)
+}
+\arguments{
+\item{graph}{The graph}
+
+\item{name}{The name of the attribute to set.}
+
+\item{index}{An optional edge sequence to set the attributes of
+a subset of edges.}
+
+\item{value}{The new value of the attribute for all (or \code{index})
+edges.}
+}
+\value{
+The graph, with the edge attribute added or set.
+}
+\description{
+Set edge attributes
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_edge_attr("label", value = LETTERS[1:10])
+g
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/set_graph_attr.Rd b/man/set_graph_attr.Rd
new file mode 100644
index 0000000..aed4b51
--- /dev/null
+++ b/man/set_graph_attr.Rd
@@ -0,0 +1,71 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{set_graph_attr}
+\alias{set.graph.attribute}
+\alias{set_graph_attr}
+\title{Set a graph attribute}
+\usage{
+set_graph_attr(graph, name, value)
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{The name of the attribute to set.}
+
+\item{value}{New value of the attribute.}
+}
+\value{
+The graph with the new graph attribute added or set.
+}
+\description{
+An existing attribute with the same name is overwritten.
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_graph_attr("layout", layout_with_fr)
+g
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/set_vertex_attr.Rd b/man/set_vertex_attr.Rd
new file mode 100644
index 0000000..a741d44
--- /dev/null
+++ b/man/set_vertex_attr.Rd
@@ -0,0 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{set_vertex_attr}
+\alias{set.vertex.attribute}
+\alias{set_vertex_attr}
+\title{Set vertex attributes}
+\usage{
+set_vertex_attr(graph, name, index = V(graph), value)
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{The name of the attribute to set.}
+
+\item{index}{An optional vertex sequence to set the attributes
+of a subset of vertices.}
+
+\item{value}{The new value of the attribute for all (or \code{index})
+vertices.}
+}
+\value{
+The graph, with the vertex attribute added or set.
+}
+\description{
+Set vertex attributes
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_vertex_attr("label", value = LETTERS[1:10])
+g
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/shapes.Rd b/man/shapes.Rd
new file mode 100644
index 0000000..14550bd
--- /dev/null
+++ b/man/shapes.Rd
@@ -0,0 +1,261 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/plot.shapes.R
+\name{shapes}
+\alias{add.vertex.shape}
+\alias{add_shape}
+\alias{igraph.shape.noclip}
+\alias{igraph.shape.noplot}
+\alias{igraph.vertex.shapes}
+\alias{shape_noclip}
+\alias{shape_noplot}
+\alias{shapes}
+\alias{vertex.shapes}
+\title{Various vertex shapes when plotting igraph graphs}
+\usage{
+shapes(shape = NULL)
+
+shape_noclip(coords, el, params, end = c("both", "from", "to"))
+
+shape_noplot(coords, v = NULL, params)
+
+add_shape(shape, clip = shape_noclip, plot = shape_noplot,
+  parameters = list())
+}
+\arguments{
+\item{shape}{Character scalar, name of a vertex shape. If it is
+\code{NULL} for \code{shapes}, then the names of all defined
+vertex shapes are returned.}
+
+\item{coords,el,params,end,v}{See parameters of the clipping/plotting
+functions below.}
+
+\item{clip}{An R function object, the clipping function.}
+
+\item{plot}{An R function object, the plotting function.}
+
+\item{parameters}{Named list, additional plot/vertex/edge
+parameters. The element named define the new parameters, and the
+elements themselves define their default values.
+Vertex parameters should have a prefix
+\sQuote{\code{vertex.}}, edge parameters a prefix
+\sQuote{\code{edge.}}. Other general plotting parameters should have
+a prefix \sQuote{\code{plot.}}. See Details below.}
+}
+\value{
+\code{shapes} returns a character vector if the
+   \code{shape} argument is \code{NULL}. It returns a named list with
+   entries named \sQuote{clip} and \sQuote{plot}, both of them R
+   functions.
+
+   \code{add_shape} returns \code{TRUE}, invisibly.
+
+   \code{shape_noclip} returns the appropriate columns of its
+   \code{coords} argument.
+}
+\description{
+Starting from version 0.5.1 igraph supports different
+vertex shapes when plotting graphs.
+}
+\details{
+In igraph a vertex shape is defined by two functions: 1) provides
+information about the size of the shape for clipping the edges and 2)
+plots the shape if requested. These functions are called \dQuote{shape
+  functions} in the rest of this manual page. The first one is the
+clipping function and the second is the plotting function.
+
+The clipping function has the following arguments:
+\describe{
+  \item{coords}{A matrix with four columns, it contains the
+    coordinates of the vertices for the edge list supplied in the
+    \code{el} argument.}
+  \item{el}{A matrix with two columns, the edges of which some end
+    points will be clipped. It should have the same number of rows as
+    \code{coords}.}
+  \item{params}{This is a function object that can be called to query
+    vertex/edge/plot graphical parameters. The first argument of the
+    function is \dQuote{\code{vertex}}, \dQuote{\code{edge}} or
+    \dQuote{\code{plot}} to decide the type of the parameter, the
+    second is a character string giving the name of the
+    parameter. E.g.
+    \preformatted{
+	params("vertex", "size")
+    }
+  }
+  \item{end}{Character string, it gives which end points will be
+    used. Possible values are \dQuote{\code{both}},
+    \dQuote{\code{from}} and \dQuote{\code{to}}. If
+    \dQuote{\code{from}} the function is expected to clip the
+    first column in the \code{el} edge list, \dQuote{\code{to}}
+    selects the second column, \dQuote{\code{both}} selects both.}
+}
+
+The clipping function should return a matrix
+with the same number of rows as the \code{el} arguments.
+If \code{end} is \code{both} then the matrix must have four
+columns, otherwise two. The matrix contains the modified coordinates,
+with the clipping applied.
+
+The plotting function has the following arguments:
+\describe{
+  \item{coords}{The coordinates of the vertices, a matrix with two
+    columns.}
+  \item{v}{The ids of the vertices to plot. It should match the number
+    of rows in the \code{coords} argument.}
+  \item{params}{The same as for the clipping function, see above.}
+}
+
+The return value of the plotting function is not used.
+
+\code{shapes} can be used to list the names of all installed
+vertex shapes, by calling it without arguments, or setting the
+\code{shape} argument to \code{NULL}. If a shape name is given, then
+the clipping and plotting functions of that shape are returned in a
+named list.
+
+\code{add_shape} can be used to add new vertex shapes to
+igraph. For this one must give the clipping and plotting functions of
+the new shape. It is also possible to list the plot/vertex/edge
+parameters, in the \code{parameters} argument, that the clipping
+and/or plotting functions can make use of. An example would be a
+generic regular polygon shape, which can have a parameter for the
+number of sides.
+
+\code{shape_noclip} is a very simple clipping function that the
+user can use in their own shape definitions. It does no clipping, the
+edges will be drawn exactly until the listed vertex position
+coordinates.
+
+\code{shape_noplot} is a very simple (and probably not very
+useful) plotting function, that does not plot anything.
+}
+\examples{
+# all vertex shapes, minus "raster", that might not be available
+shapes <- setdiff(shapes(), "")
+g <- make_ring(length(shapes))
+set.seed(42)
+plot(g, vertex.shape=shapes, vertex.label=shapes, vertex.label.dist=1,
+     vertex.size=15, vertex.size2=15,
+     vertex.pie=lapply(shapes, function(x) if (x=="pie") 2:6 else 0),
+     vertex.pie.color=list(heat.colors(5)))
+
+# add new vertex shape, plot nothing with no clipping
+add_shape("nil")
+plot(g, vertex.shape="nil")
+
+#################################################################
+# triangle vertex shape
+mytriangle <- function(coords, v=NULL, params) {
+  vertex.color <- params("vertex", "color")
+  if (length(vertex.color) != 1 && !is.null(v)) {
+    vertex.color <- vertex.color[v]
+  }
+  vertex.size <- 1/200 * params("vertex", "size")
+  if (length(vertex.size) != 1 && !is.null(v)) {
+    vertex.size <- vertex.size[v]
+  }
+
+  symbols(x=coords[,1], y=coords[,2], bg=vertex.color,
+          stars=cbind(vertex.size, vertex.size, vertex.size),
+          add=TRUE, inches=FALSE)
+}
+# clips as a circle
+add_shape("triangle", clip=shapes("circle")$clip,
+                 plot=mytriangle)
+plot(g, vertex.shape="triangle", vertex.color=rainbow(vcount(g)),
+     vertex.size=seq(10,20,length=vcount(g)))
+
+#################################################################
+# generic star vertex shape, with a parameter for number of rays
+mystar <- function(coords, v=NULL, params) {
+  vertex.color <- params("vertex", "color")
+  if (length(vertex.color) != 1 && !is.null(v)) {
+    vertex.color <- vertex.color[v]
+  }
+  vertex.size  <- 1/200 * params("vertex", "size")
+  if (length(vertex.size) != 1 && !is.null(v)) {
+    vertex.size <- vertex.size[v]
+  }
+  norays <- params("vertex", "norays")
+  if (length(norays) != 1 && !is.null(v)) {
+    norays <- norays[v]
+  }
+
+  mapply(coords[,1], coords[,2], vertex.color, vertex.size, norays,
+         FUN=function(x, y, bg, size, nor) {
+           symbols(x=x, y=y, bg=bg,
+                   stars=matrix(c(size,size/2), nrow=1, ncol=nor*2),
+                   add=TRUE, inches=FALSE)
+         })
+}
+# no clipping, edges will be below the vertices anyway
+add_shape("star", clip=shape_noclip,
+                 plot=mystar, parameters=list(vertex.norays=5))
+plot(g, vertex.shape="star", vertex.color=rainbow(vcount(g)),
+     vertex.size=seq(10,20,length=vcount(g)))
+plot(g, vertex.shape="star", vertex.color=rainbow(vcount(g)),
+     vertex.size=seq(10,20,length=vcount(g)),
+     vertex.norays=rep(4:8, length=vcount(g)))
+
+#################################################################
+# Pictures as vertices.
+# Similar musicians from last.fm, we start from an artist and
+# will query two levels. We will use the XML, png and jpeg packages
+# for this, so these must be available. Otherwise the example is
+# skipped
+
+loadIfYouCan <- function(pkg) suppressWarnings(do.call(require, list(pkg)))
+
+if (loadIfYouCan("XML") && loadIfYouCan("png") &&
+    loadIfYouCan("jpeg")) {
+  url <- paste(sep="",
+               'http://ws.audioscrobbler.com/',
+               '2.0/?method=artist.getinfo&artist=\%s',
+               '&api_key=1784468ada3f544faf9172ee8b99fca3')
+  getartist <- function(artist) {
+    cat("Downloading from last.fm. ... ")
+    txt <- readLines(sprintf(url, URLencode(artist)))
+    xml <- xmlTreeParse(txt, useInternal=TRUE)
+    img <- xpathSApply(xml, "/lfm/artist/image[@size='medium'][1]",
+                       xmlValue)
+    if (img != "") {
+      con <- url(img, open="rb")
+      bin <- readBin(con, what="raw", n=10^6)
+      close(con)
+      if (grepl("\\\\\\\\.png$", img)) {
+        rast <- readPNG(bin, native=TRUE)
+      } else if (grepl("\\\\\\\\.jpe?g$", img)) {
+        rast <- readJPEG(bin, native=TRUE)
+      } else {
+        rast <- as.raster(matrix())
+      }
+    } else {
+      rast <- as.raster(numeric())
+    }
+    sim <- xpathSApply(xml, "/lfm/artist/similar/artist/name", xmlValue)
+    cat("done.\\\\n")
+    list(name=artist, image=rast, similar=sim)
+  }
+
+  ego <- getartist("Placebo")
+  similar <- lapply(ego$similar, getartist)
+
+  edges1 <- cbind(ego$name, ego$similar)
+  edges2 <- lapply(similar, function(x) cbind(x$name, x$similar))
+  edges3 <- rbind(edges1, do.call(rbind, edges2))
+  edges <- edges3[ edges3[,1] \%in\% c(ego$name, ego$similar) &
+                   edges3[,2] \%in\% c(ego$name, ego$similar), ]
+
+  musnet <- simplify(graph_from_data_frame(edges, dir=FALSE,
+                     vertices=data.frame(name=c(ego$name, ego$similar))))
+  str(musnet)
+
+  V(musnet)$raster <- c(list(ego$image), lapply(similar, "[[", "image"))
+  plot(musnet, layout=layout_as_star, vertex.shape="raster",
+       vertex.label=V(musnet)$name, margin=.2,
+       vertex.size=50, vertex.size2=50,
+       vertex.label.dist=2, vertex.label.degree=0)
+} else {
+  message("You need the `XML', `png' and `jpeg' packages to run this")
+}
+}
+
diff --git a/man/shortest.paths.Rd b/man/shortest.paths.Rd
deleted file mode 100644
index 51152a0..0000000
--- a/man/shortest.paths.Rd
+++ /dev/null
@@ -1,196 +0,0 @@
-\name{shortest.paths}
-\alias{shortest.paths}
-\alias{get.shortest.paths}
-\alias{get.all.shortest.paths}
-\alias{average.path.length}
-\alias{path.length.hist}
-\concept{Shortest path}
-\concept{Geodesic}
-\title{Shortest (directed or undirected) paths between vertices}
-\description{\code{shortest.paths} calculates the length of all the
-  shortest paths from or to the vertices in the
-  network. \code{get.shortest.paths} calculates one shortest path (the
-  path itself, and not just its length) from or to the given vertex.}
-\usage{
-shortest.paths(graph, v=V(graph), to=V(graph),
-      mode = c("all", "out", "in"),
-      weights = NULL, algorithm = c("automatic", "unweighted",
-                                    "dijkstra", "bellman-ford",
-                                    "johnson"))
-get.shortest.paths(graph, from, to=V(graph), mode = c("out", "all",
-      "in"), weights = NULL, output=c("vpath", "epath", "both"),
-      predecessors = FALSE, inbound.edges = FALSE)
-get.all.shortest.paths(graph, from, to = V(graph), mode = c("out", 
-      "all", "in"), weights=NULL) 
-average.path.length(graph, directed=TRUE, unconnected=TRUE)
-path.length.hist (graph, directed = TRUE)
-}
-\arguments{
-  \item{graph}{The graph to work on.}
-  \item{v}{Numeric vector, the vertices from which the shortest
-    paths will be calculated.}
-  \item{to}{Numeric vector, the vertices to which the shortest paths
-    will be calculated. By default it includes all vertices. Note that
-    for \code{shortest.paths} every vertex must be included here at most
-    once. (This is not required for \code{get.shortest.paths}.}
-  \item{mode}{Character constant, gives whether the shortest paths to or
-    from the given vertices should be calculated for directed graphs. If
-    \code{out} then the shortest paths \emph{from} the vertex, if
-    \code{in} then \emph{to} it will be considered. If \code{all}, the
-    default, then the corresponding undirected graph will be used,
-    ie. not directed paths are searched. This argument is ignored for
-    undirected graphs.}
-  \item{weights}{Possibly a numeric vector giving edge weights. If this
-    is \code{NULL} and the graph has a \code{weight} edge attribute,
-    then the attribute is used. If this is \code{NA} then no weights are
-    used (even if the graph has a \code{weight} attribute).}
-  \item{algorithm}{Which algorithm to use for the calculation. By
-    default igraph tries to select the fastest suitable algorithm. If
-    there are no weights, then an unweighted breadth-first search is used,
-    otherwise if all weights are positive, then Dijkstra's algorithm is
-    used. If there are negative weights and we do the calculation for
-    more than 100 sources, then Johnson's algorithm is used. Otherwise
-    the Bellman-Ford algorithm is used. You can override igraph's choice
-    by explicitly giving this parameter. Note that the igraph C core
-    might still override your choice in obvious cases, i.e. if there are
-    no edge weights, then the unweighted algorithm will be used,
-    regardless of this argument.
-  }
-  \item{from}{Numeric constant, the vertex from or to the shortest paths
-    will be calculated. Note that right now this is not a vector of
-    vertex ids, but only a single vertex.}
-  \item{output}{Character scalar, defines how to report the shortest
-    paths. \dQuote{vpath} means that the vertices along the paths are
-    reported, this form was used prior to igraph version
-    0.6. \dQuote{epath} means that the edges along the paths are
-    reported. \dQuote{both} means that both forms are returned, in a
-    named list with components \dQuote{vpath} and \dQuote{epath}.}
-  \item{predecessors}{Logical scalar, whether to return the predecessor
-    vertex for each vertex. The predecessor of vertex \code{i} in the
-    tree is the vertex from which vertex \code{i} was reached. The
-    predecessor of the start vertex (in the \code{from} argument) is
-    itself by definition. If the predecessor is zero, it means that the
-    given vertex was not reached from the source during the search. Note
-    that the search terminates if all the vertices in \code{to} are
-    reached.}
-  \item{inbound.edges}{Logical scalar, whether to return the inbound
-    edge for each vertex. The inbound edge of vertex \code{i} in the tree
-    is the edge via which vertex \code{i} was reached. The start vertex
-    and vertices that were not reached during the search will have zero
-    in the corresponding entry of the vector. Note that the search
-    terminates if all the vertices in \code{to} are reached.}
-  \item{directed}{Whether to consider directed paths in directed graphs,
-    this argument is ignored for undirected graphs.}
-  \item{unconnected}{What to do if the graph is unconnected (not
-    strongly connected if directed paths are considered). If TRUE only
-    the lengths of the existing paths are considered and averaged; if
-    FALSE the length of the missing paths are counted having length
-    \code{vcount(graph)}, one longer than the longest possible geodesic
-    in the network.}
-}
-\details{
-  The shortest path, or geodesic between two pair of vertices is a path
-  with the minimal number of vertices. The functions documented in this
-  manual page all calculate shortest paths between vertex pairs.
-  
-  \code{shortest.paths} calculates the lengths of pairwise shortest
-  paths from a set of vertices (\code{from}) to another set of vertices
-  (\code{to}). It uses different algorithms, depending on the
-  \code{argorithm} argument and the \code{weight} edge attribute of the
-  graph. The implemented algorithms are breadth-first search
-  (\sQuote{\code{unweighted}}), this only works for unweighted graphs;
-  the Dijkstra algorithm (\sQuote{\code{dijkstra}}), this works for
-  graphs with non-negative edge weights; the Bellman-Ford algorithm
-  (\sQuote{\code{bellman-ford}}), and Johnson's algorithm
-  (\sQuote{\code{"johnson"}}). The latter two algorithms work with
-  arbitrary edge weights, but (naturally) only for graphs that don't
-  have a negative cycle.
-
-  igraph can choose automatically between algorithms, and chooses the
-  most efficient one that is appropriate for the supplied weights (if
-  any). For automatic algorithm selection, supply
-  \sQuote{\code{automatic}} as the \code{algorithm} argument. (This is
-  also the default.)
-
-  \code{get.shortest.paths} calculates a single shortest path (i.e. the
-  path itself, not just its length) between the source vertex
-  given in \code{from}, to the target vertices given in
-  \code{to}. \code{get.shortest.paths} uses breadth-first search for
-  unweighted graphs and Dijkstra's algorithm for weighted graphs. The
-  latter only works if the edge weights are non-negative.
-
-  \code{get.all.shortest.paths} calculates \emph{all} shortest paths
-  between pairs of vertices. More precisely, between the \code{from}
-  vertex to the vertices given in \code{to}. It uses a breadth-first
-  search for unweighted graphs and Dijkstra's algorithm for weighted
-  ones. The latter only supports non-negative edge weights.
-
-  \code{average.path.length} calculates the average path length in a
-  graph, by calculating the shortest paths between all pairs of vertices
-  (both ways for directed graphs). This function does not consider edge
-  weights currently and uses a breadth-first search.
-  
-  \code{path.length.hist} calculates a histogram, by calculating the
-  shortest path length between each pair of vertices. For directed
-  graphs both directions are considered, so every pair of vertices
-  appears twice in the histogram.
-}
-\value{
-  For \code{shortest.paths} a numeric matrix with \code{length(to)}
-  columns and \code{length(v)} rows. The shortest path length from a vertex to
-  itself is always zero. For unreachable vertices \code{Inf} is included.
-
-  For \code{get.shortest.paths} a named list with four entries is
-  returned:
-  \item{vpath}{This itself is a list, of length \code{length(to)};
-    list element \code{i} contains the vertex ids on
-    the path from vertex \code{from} to vertex \code{to[i]} (or the other way
-    for directed graphs depending on the \code{mode} argument). The vector
-    also contains \code{from} and \code{i} as the first and last
-    elements. If \code{from} is the same as \code{i} then it is only
-    included once. If there is no path between two vertices then a
-    numeric vector of length zero is returned as the list element. If
-    this output is not requested in the \code{output} argument, then it
-    will be \code{NULL}.}
-  \item{epath}{This is a list similar to \code{vpath}, but the vectors
-    of the list contain the edge ids along the shortest paths, instead
-    of the vertex ids. This entry is set to \code{NULL} if it is not
-    requested in the \code{output} argument.}
-  \item{predecessors}{Numeric vector, the predecessor of each vertex in the
-  \code{to} argument, or \code{NULL} if it was not requested.}
-  \item{inbound_edges}{Numeric vector, the inbound edge for each vertex,
-    or \code{NULL}, if it was not requested.}
-  
-  For \code{get.all.shortest.paths} a list is returned, each list
-  element contains a shortest path from \code{from} to a vertex in
-  \code{to}. The shortest paths to the same vertex are collected into
-  consecutive elements of the list.
-  
-  For \code{average.path.length} a single number is returned.
-
-  \code{path.length.hist} returns a named list with two entries:
-  \code{res} is a numeric vector, the histogram of distances,
-  \code{unconnected} is a numeric scalar, the number of pairs for which
-  the first vertex is not reachable from the second. The sum of the two
-  entries is always \eqn{n(n-1)} for directed graphs and \eqn{n(n-1)/2}
-  for undirected graphs.
-}
-\references{ West, D.B. (1996). \emph{Introduction to Graph Theory.} Upper
-  Saddle River, N.J.: Prentice Hall. }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-%\seealso{}
-\examples{
-g <- graph.ring(10)
-shortest.paths(g)
-get.shortest.paths(g, 5)
-get.all.shortest.paths(g, 1, 6:8)
-average.path.length(g)
-## Weighted shortest paths
-el <- matrix(nc=3, byrow=TRUE,
-             c(1,2,0, 1,3,2, 1,4,1, 2,3,0, 2,5,5, 2,6,2, 3,2,1, 3,4,1,
-               3,7,1, 4,3,0, 4,7,2, 5,6,2, 5,8,8, 6,3,2, 6,7,1, 6,9,1,
-               6,10,3, 8,6,1, 8,9,1, 9,10,4) )
-g2 <- add.edges(graph.empty(10), t(el[,1:2]), weight=el[,3])
-shortest.paths(g2, mode="out")
-}
-\keyword{graphs}
diff --git a/man/similarity.Rd b/man/similarity.Rd
index f67cd02..02f1a14 100644
--- a/man/similarity.Rd
+++ b/man/similarity.Rd
@@ -1,64 +1,75 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/similarity.R
 \name{similarity}
-\alias{similarity.jaccard}
+\alias{similarity}
 \alias{similarity.dice}
 \alias{similarity.invlogweighted}
-\concept{Vertex similarity}
+\alias{similarity.jaccard}
 \title{Similarity measures of two vertices}
-\description{
-  These functions calculates similarity scores for vertices based on
-  their connection patterns.
-}
 \usage{
-similarity.jaccard(graph, vids = V(graph), mode = c("all", "out", "in",
-      "total"), loops = FALSE) 
-similarity.dice(graph, vids = V(graph), mode = c("all", "out", "in",
-      "total"), loops = FALSE)
-similarity.invlogweighted(graph, vids = V(graph),
-       mode = c("all", "out", "in", "total"))
+similarity(graph, vids = V(graph), mode = c("all", "out", "in", "total"),
+  loops = FALSE, method = c("jaccard", "dice", "invlogweighted"))
 }
 \arguments{
-  \item{graph}{The input graph.}
-  \item{vids}{The vertex ids for which the similarity is calculated.}
-  \item{mode}{The type of neighboring vertices to use for the
-    calculation, possible values: \sQuote{\code{out}},
-    \sQuote{\code{in}}, \sQuote{\code{all}}.}
-  \item{loops}{Whether to include vertices themselves in the neighbor
-    sets.}
-}
-\details{
- The Jaccard similarity coefficient of two vertices is the number of common
- neighbors divided by the number of vertices that are neighbors of at
- least one of the two vertices being
- considered. \code{similarity.jaccard} calculates
- the pairwise Jaccard similarities for some (or all) of the vertices.
+\item{graph}{The input graph.}
+
+\item{vids}{The vertex ids for which the similarity is calculated.}
 
- The Dice similarity coefficient of two vertices is twice the number of common
- neighbors divided by the sum of the degrees of the
- vertices. \code{similarity.dice} calculates the pairwise Dice
- similarities for some (or all) of the vertices.
+\item{mode}{The type of neighboring vertices to use for the calculation,
+possible values: \sQuote{\code{out}}, \sQuote{\code{in}},
+\sQuote{\code{all}}.}
 
- The inverse log-weighted similarity of two vertices is the number of
- their common neighbors, weighted by the inverse logarithm of their degrees.
- It is based on the assumption that two vertices should be considered
- more similar if they share a low-degree common neighbor, since high-degree
- common neighbors are more likely to appear even by pure chance.
- Isolated vertices will have zero similarity to any other vertex.
- Self-similarities are not calculated.
- See the following paper for more details: Lada A. Adamic and Eytan Adar:
- Friends and neighbors on the Web. Social Networks, 25(3):211-230, 2003.
+\item{loops}{Whether to include vertices themselves in the neighbor
+sets.}
+
+\item{method}{The method to use.}
 }
 \value{
-  A \code{length(vids)} by \code{length(vids)} numeric matrix containing
-  the similarity scores.
+A \code{length(vids)} by \code{length(vids)} numeric matrix
+  containing the similarity scores. This argument is ignored by the
+  \code{invlogweighted} method.
+}
+\description{
+These functions calculates similarity scores for vertices based on their
+connection patterns.
+}
+\details{
+The Jaccard similarity coefficient of two vertices is the number of common
+neighbors divided by the number of vertices that are neighbors of at least
+one of the two vertices being considered. The \code{jaccard} method
+calculates the pairwise Jaccard similarities for some (or all) of the
+vertices.
+
+The Dice similarity coefficient of two vertices is twice the number of
+common neighbors divided by the sum of the degrees of the vertices.
+Methof \code{dice} calculates the pairwise Dice similarities for some
+(or all) of the vertices.
+
+The inverse log-weighted similarity of two vertices is the number of their
+common neighbors, weighted by the inverse logarithm of their degrees.  It is
+based on the assumption that two vertices should be considered more similar
+if they share a low-degree common neighbor, since high-degree common
+neighbors are more likely to appear even by pure chance.  Isolated vertices
+will have zero similarity to any other vertex.  Self-similarities are not
+calculated.  See the following paper for more details: Lada A. Adamic and
+Eytan Adar: Friends and neighbors on the Web. Social Networks,
+25(3):211-230, 2003.
 }
-\references{Lada A. Adamic and Eytan Adar:
- Friends and neighbors on the Web. \emph{Social Networks}, 25(3):211-230, 2003.}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
-  \email{csardi.gabor at gmail.com} for the manual page.}
-\seealso{\code{\link{cocitation}} and \code{\link{bibcoupling}}}
 \examples{
-g <- graph.ring(5)
-similarity.dice(g)
-similarity.jaccard(g)
+g <- make_ring(5)
+similarity(g, method = "dice")
+similarity(g, method = "jaccard")
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+  \email{csardi.gabor at gmail.com} for the manual page.
+}
+\references{
+Lada A. Adamic and Eytan Adar: Friends and neighbors on the Web.
+  \emph{Social Networks}, 25(3):211-230, 2003.
+}
+\seealso{
+\code{\link{cocitation}} and \code{\link{bibcoupling}}
 }
 \keyword{graphs}
+
diff --git a/man/simplified.Rd b/man/simplified.Rd
new file mode 100644
index 0000000..6ed3dcb
--- /dev/null
+++ b/man/simplified.Rd
@@ -0,0 +1,22 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{simplified}
+\alias{simplified}
+\title{Constructor modifier to drop multiple and loop edges}
+\usage{
+simplified()
+}
+\description{
+Constructor modifier to drop multiple and loop edges
+}
+\examples{
+sample_(pa(10, m = 3, algorithm = "bag"))
+sample_(pa(10, m = 3, algorithm = "bag"), simplified())
+}
+\seealso{
+Other constructor modifiers: \code{\link{with_edge_}};
+  \code{\link{with_graph_}}; \code{\link{with_vertex_}};
+  \code{\link{without_attr}}; \code{\link{without_loops}};
+  \code{\link{without_multiples}}
+}
+
diff --git a/man/simplify.Rd b/man/simplify.Rd
index d57ac68..a56582a 100644
--- a/man/simplify.Rd
+++ b/man/simplify.Rd
@@ -1,50 +1,61 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/simple.R
 \name{simplify}
-\alias{simplify}
 \alias{is.simple}
-\concept{Simple graph}
+\alias{is_simple}
+\alias{simplify}
 \title{Simple graphs}
-\description{Simple graphs are graphs which do not contain loop and
-  multiple edges.}
 \usage{
 simplify(graph, remove.multiple = TRUE, remove.loops = TRUE,
-         edge.attr.comb = getIgraphOpt("edge.attr.comb"))
-is.simple(graph)
+  edge.attr.comb = igraph_opt("edge.attr.comb"))
+
+is_simple(graph)
 }
 \arguments{
-  \item{graph}{The graph to work on.}
-  \item{remove.loops}{Logical, whether the loop edges are to be
-    removed.}
-  \item{remove.multiple}{Logical, whether the multiple edges are to be
-    removed.}
-  \item{edge.attr.comb}{Specifies what to do with edge attributes, if
-    \code{remove.multiple=TRUE}. In this case many edges might be mapped
-    to a single one in the new graph, and their attributes are
-    combined. Please see \code{\link{attribute.combination}} for details
-    on this.}
+\item{graph}{The graph to work on.}
+
+\item{remove.multiple}{Logical, whether the multiple edges are to be
+removed.}
+
+\item{remove.loops}{Logical, whether the loop edges are to be removed.}
+
+\item{edge.attr.comb}{Specifies what to do with edge attributes, if
+\code{remove.multiple=TRUE}. In this case many edges might be mapped to a
+single one in the new graph, and their attributes are combined. Please see
+\code{\link{attribute.combination}} for details on this.}
+}
+\value{
+A new graph object with the edges deleted.
+}
+\description{
+Simple graphs are graphs which do not contain loop and multiple edges.
 }
 \details{
-  A loop edge is an edge for which the two endpoints are the same
-  vertex. Two edges are multiple edges if they have exactly the same two
-  endpoints (for directed graphs order does matter). A graph is simple
-  is it does not contain loop edges and multiple edges.
+A loop edge is an edge for which the two endpoints are the same
+vertex. Two edges are multiple edges if they have exactly the same two
+endpoints (for directed graphs order does matter). A graph is simple is
+it does not contain loop edges and multiple edges.
 
-  \code{is.simple} checks whether a graph is simple.
+\code{is_simple} checks whether a graph is simple.
 
-  \code{simplify} removes the loop and/or multiple edges from a graph.
-  If both \code{remove.loops} and \code{remove.multiple} are \code{TRUE}
-  the function returns a simple graph.
-}
-\value{A new graph object with the edges deleted. }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{is.loop}}, \code{\link{is.multiple}} and
-  \code{\link{count.multiple}}, \code{\link{delete.edges}},
-  \code{\link{delete.vertices}}}
+\code{simplify} removes the loop and/or multiple edges from a graph.  If
+both \code{remove.loops} and \code{remove.multiple} are \code{TRUE} the
+function returns a simple graph.
+}
 \examples{
 g <- graph( c(1,2,1,2,3,3) )
-is.simple(g)
-is.simple(simplify(g, remove.loops=FALSE))
-is.simple(simplify(g, remove.multiple=FALSE))
-is.simple(simplify(g))
+is_simple(g)
+is_simple(simplify(g, remove.loops=FALSE))
+is_simple(simplify(g, remove.multiple=FALSE))
+is_simple(simplify(g))
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{which_loop}}, \code{\link{which_multiple}} and
+\code{\link{count_multiple}}, \code{\link{delete_edges}},
+\code{\link{delete_vertices}}
 }
 \keyword{graphs}
+
diff --git a/man/sir.Rd b/man/sir.Rd
index f3bacbc..af032d1 100644
--- a/man/sir.Rd
+++ b/man/sir.Rd
@@ -1,101 +1,113 @@
-\name{sir}
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/epi.R, R/sir.R
+\name{time_bins.sir}
 \alias{median.sir}
 \alias{quantile.sir}
+\alias{sir}
 \alias{time_bins}
 \alias{time_bins.sir}
-\alias{sir}
-\concept{SIR model}
-\concept{Dynamics on graph}
 \title{SIR model on graphs}
-\description{Run simulations for an SIR (susceptible-infected-recovered)
-  model, on a graph}
 \usage{
-sir(graph, beta, gamma, no.sim=100)
-\S3method{time_bins}{sir}(x, middle=TRUE)
-\S3method{median}{sir}(x, na.rm=FALSE)
-\S3method{quantile}{sir}(x, comp=c("NI", "NS", "NR"), prob, \dots)
+\method{time_bins}{sir}(x, middle = TRUE)
+
+\method{median}{sir}(x, na.rm = FALSE)
+
+\method{quantile}{sir}(x, comp = c("NI", "NS", "NR"), prob, ...)
+
+sir(graph, beta, gamma, no.sim = 100)
 }
 \arguments{
-  \item{graph}{The graph to run the model on. If directed, then edge
-    directions are ignored and a warning is given.}
-  \item{beta}{Non-negative scalar. The rate of infection of an
-    individual that is susceptible and has a single infected
-    neighbor. The infection rate of a susceptible individual with n
-    infected neighbors is n times beta. Formally
-    this is the rate parameter of an exponential distribution.}
-  \item{gamma}{Positive scalar. The rate of recovery of an infected
-    individual. Formally, this is the rate parameter of an exponential
-    distribution.}
-  \item{no.sim}{Integer scalar, the number simulation runs to perform.}
-  \item{x}{A \code{sir} object, returned by the \code{sir} function.}
-  \item{middle}{Logical scalar, whether to return the middle of the time
-    bins, or the boundaries.}
-  \item{na.rm}{Logical scalar, whether to ignore \code{NA} values.
-    \code{sir} objects do not contain any \code{NA} values currently,
-    so this argument is effectively ignored.}
-  \item{comp}{Character scalar. The component to calculate the quantile
-    of. \code{NI} is infected agents, \code{NS} is susceptibles,
-    \code{NR} stands for recovered.}
-  \item{prob}{Numeric vector of probabilities, in [0,1], they specify
-    the quantiles to calculate. }
-  \item{\dots}{Additional arguments, ignored currently.}
-}
-\details{
-  The SIR model is a simple model from epidemiology. The individuals
-  of the population might be in three states: susceptible, infected
-  and recovered. Recovered people are assumed to be immune to the 
-  disease. Susceptibles become infected with a rate that depends on
-  their number of infected neigbors. Infected people become recovered
-  with a constant rate.
+\item{x}{A \code{sir} object, returned by the \code{sir} function.}
+
+\item{middle}{Logical scalar, whether to return the middle of the time bins,
+or the boundaries.}
 
-  The function \code{sir} simulates the model.
+\item{na.rm}{Logical scalar, whether to ignore \code{NA} values.  \code{sir}
+objects do not contain any \code{NA} values currently, so this argument is
+effectively ignored.}
 
-  Function \code{time_bins} bins the simulation steps, using the
-  Freedman-Diaconis heuristics to determine the bin width.
+\item{comp}{Character scalar. The component to calculate the quantile of.
+\code{NI} is infected agents, \code{NS} is susceptibles, \code{NR} stands
+for recovered.}
 
-  Function \code{median} and \code{quantile} calculate the median and
-  quantiles of the results, respectively, in bins calculated with
-  \code{time_bins}.
+\item{prob}{Numeric vector of probabilities, in [0,1], they specify the
+quantiles to calculate.}
+
+\item{graph}{The graph to run the model on. If directed, then edge
+directions are ignored and a warning is given.}
+
+\item{beta}{Non-negative scalar. The rate of infection of an individual that
+is susceptible and has a single infected neighbor. The infection rate of a
+susceptible individual with n infected neighbors is n times beta. Formally
+this is the rate parameter of an exponential distribution.}
+
+\item{gamma}{Positive scalar. The rate of recovery of an infected
+individual. Formally, this is the rate parameter of an exponential
+distribution.}
+
+\item{no.sim}{Integer scalar, the number simulation runs to perform.}
+
+\item{\dots}{Additional arguments, ignored currently.}
 }
 \value{
-  For \code{sir} the results are returned in an object of class
-  \sQuote{\code{sir}}, which is a list, with one element for each
-  simulation. Each simulation is itself a list with the following
-  elements. They are all numeric vectors, with equal length:
-  \itemize{
-    \item{times}{The times of the events.}
-    \item{NS}{The number of susceptibles in the population, over time.}
-    \item{NI}{The number of infected individuals in the population, over
-      time.}
-    \item{NR}{The number of recovered individuals in the population,
-      over time.}
-  }
-
-  Function \code{time_bins} returns a numeric vector, the middle or the
-  boundaries of the time bins, depending on the \code{middle} argument.
-
-  \code{median} returns a list of three named numeric vectors,
-  \code{NS}, \code{NI} and \code{NR}. The names within the vectors are
-  created from the time bins.
-
-  \code{quantile} returns the same vector as \code{median} (but only
-  one, the one requested) if only one quantile is requested. If multiple
-  quantiles are requested, then a list of these vectors is returned, one
-  for each quantile.
+For \code{sir} the results are returned in an object of class
+\sQuote{\code{sir}}, which is a list, with one element for each simulation.
+Each simulation is itself a list with the following elements. They are all
+numeric vectors, with equal length: \describe{
+  \item{times}{The times of the events.}
+  \item{NS}{The number of susceptibles in the population, over time.}
+  \item{NI}{The number of infected individuals in the population, over
+    time.}
+  \item{NR}{The number of recovered individuals in the population, over
+    time.}
 }
-\references{
-  Bailey, Norman T. J. (1975). The mathematical theory of infectious
-  diseases and its applications (2nd ed.). London: Griffin.
+
+Function \code{time_bins} returns a numeric vector, the middle or the
+boundaries of the time bins, depending on the \code{middle} argument.
+
+\code{median} returns a list of three named numeric vectors, \code{NS},
+\code{NI} and \code{NR}. The names within the vectors are created from the
+time bins.
+
+\code{quantile} returns the same vector as \code{median} (but only one, the
+one requested) if only one quantile is requested. If multiple quantiles are
+requested, then a list of these vectors is returned, one for each quantile.
 }
-\author{
-  Gabor Csardi \email{csardi.gabor at gmail.com}. Eric Kolaczyk
-  (\url{http://math.bu.edu/people/kolaczyk/}) wrote the initial
-  version in R.
+\description{
+Run simulations for an SIR (susceptible-infected-recovered) model, on a
+graph
+}
+\details{
+The SIR model is a simple model from epidemiology. The individuals of the
+population might be in three states: susceptible, infected and recovered.
+Recovered people are assumed to be immune to the disease. Susceptibles
+become infected with a rate that depends on their number of infected
+neigbors. Infected people become recovered with a constant rate.
+
+The function \code{sir} simulates the model.
+
+Function \code{time_bins} bins the simulation steps, using the
+Freedman-Diaconis heuristics to determine the bin width.
+
+Function \code{median} and \code{quantile} calculate the median and
+quantiles of the results, respectively, in bins calculated with
+\code{time_bins}.
 }
-\seealso{\code{\link{plot.sir}} to conveniently plot the results}
 \examples{
-g <- erdos.renyi.game(100, 100, type="gnm")
+g <- sample_gnm(100, 100)
 sm <- sir(g, beta=5, gamma=1)
 plot(sm)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}. Eric Kolaczyk
+(\url{http://math.bu.edu/people/kolaczyk/}) wrote the initial version in R.
+}
+\references{
+Bailey, Norman T. J. (1975). The mathematical theory of
+infectious diseases and its applications (2nd ed.). London: Griffin.
+}
+\seealso{
+\code{\link{plot.sir}} to conveniently plot the results
+}
 \keyword{graphs}
+
diff --git a/man/spectrum.Rd b/man/spectrum.Rd
new file mode 100644
index 0000000..d29bc5a
--- /dev/null
+++ b/man/spectrum.Rd
@@ -0,0 +1,79 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{spectrum}
+\alias{graph.eigen}
+\alias{igraph.eigen.default}
+\alias{spectrum}
+\title{Eigenvalues and eigenvectors of the adjacency matrix of a graph}
+\usage{
+spectrum(graph, algorithm = c("arpack", "auto", "lapack", "comp_auto",
+  "comp_lapack", "comp_arpack"), which = list(), options = arpack_defaults)
+}
+\arguments{
+\item{graph}{The input graph, can be directed or undirected.}
+
+\item{algorithm}{The algorithm to use. Currently only \code{arpack} is
+implemented, which uses the ARPACK solver. See also \code{\link{arpack}}.}
+
+\item{which}{A list to specify which eigenvalues and eigenvectors to
+calculate. By default the leading (i.e. largest magnitude) eigenvalue and
+the corresponding eigenvector is calculated.}
+
+\item{options}{Options for the ARPACK solver. See
+\code{\link{arpack_defaults}}.}
+}
+\value{
+Depends on the algorithm used.
+
+For \code{arpack} a list with three entries is returned: \item{options}{See
+the return value for \code{arpack} for a complete description.}
+\item{values}{Numeric vector, the eigenvalues.} \item{vectors}{Numeric
+matrix, with the eigenvectors as columns.}
+}
+\description{
+Calculate selected eigenvalues and eigenvectors of a (supposedly sparse)
+graph.
+}
+\details{
+The \code{which} argument is a list and it specifies which eigenvalues and
+corresponding eigenvectors to calculate: There are eight options:
+\enumerate{ \item Eigenvalues with the largest magnitude. Set \code{pos} to
+\code{LM}, and \code{howmany} to the number of eigenvalues you want.  \item
+Eigenvalues with the smallest magnitude. Set \code{pos} to \code{SM} and
+\code{howmany} to the number of eigenvalues you want.  \item Largest
+eigenvalues. Set \code{pos} to \code{LA} and \code{howmany} to the number of
+eigenvalues you want.  \item Smallest eigenvalues. Set \code{pos} to
+\code{SA} and \code{howmany} to the number of eigenvalues you want.  \item
+Eigenvalues from both ends of the spectrum. Set \code{pos} to \code{BE} and
+\code{howmany} to the number of eigenvalues you want. If \code{howmany} is
+odd, then one more eigenvalue is returned from the larger end.  \item
+Selected eigenvalues. This is not (yet) implemented currently.  \item
+Eigenvalues in an interval. This is not (yet) implemented.  \item All
+eigenvalues. This is not implemented yet. The standard \code{eigen} function
+does a better job at this, anyway.  }
+
+Note that ARPACK might be unstable for graphs with multiple components, e.g.
+graphs with isolate vertices.
+}
+\examples{
+## Small example graph, leading eigenvector by default
+kite <- make_graph("Krackhardt_kite")
+spectrum(kite)[c("values", "vectors")]
+
+## Double check
+eigen(as_adj(kite, sparse=FALSE))$vectors[,1]
+
+## Should be the same as 'eigen_centrality' (but rescaled)
+cor(eigen_centrality(kite)$vector, spectrum(kite)$vectors)
+
+## Smallest eigenvalues
+spectrum(kite, which=list(pos="SM", howmany=2))$values
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{as_adj}} to create a (sparse) adjacency matrix.
+}
+\keyword{graphs}
+
diff --git a/man/spinglass.community.Rd b/man/spinglass.community.Rd
deleted file mode 100644
index a3abd5e..0000000
--- a/man/spinglass.community.Rd
+++ /dev/null
@@ -1,144 +0,0 @@
-\name{spinglass.community}
-\alias{spinglass.community}
-\concept{Statistical mechanics}
-\concept{Spin-glass}
-\concept{Community structure}
-\title{Finding communities in graphs based on statistical meachanics}
-\description{This function tries to find communities in graphs via
-  a spin-glass model and simulated annealing.}
-\usage{
-spinglass.community(graph, weights=NULL, vertex=NULL, spins=25,
-                    parupdate=FALSE, start.temp=1, stop.temp=0.01,
-                    cool.fact=0.99, update.rule=c("config", "random",
-                    "simple"), gamma=1, implementation=c("orig", "neg"),
-                    gamma.minus=1)
-}
-\arguments{
-  \item{graph}{The input graph, can be directed but the direction of the
-    edges is neglected.}
-  \item{weights}{The weights of the edges. Either a numeric vector or
-    \code{NULL}. If it is null and the input graph has a \sQuote{weight}
-    edge attribute then that will be used. If \code{NULL} and no such
-    attribute is present then the edges will have equal weights. Set
-    this to \code{NA} if the graph was a \sQuote{weight} edge attribute,
-    but you don't want to use it for community detection.}
-  \item{vertex}{This parameter can be used to calculate the community of
-      a given vertex without calculating all communities. Note that if
-      this argument is present then some other arguments are ignored.}
-  \item{spins}{Integer constant, the number of spins to use. This is the
-    upper limit for the number of communities. It is not a problem to
-    supply a (reasonably) big number here, in which case some
-    spin states will be unpopulated. }
-  \item{parupdate}{Logical constant, whether to update the spins of the
-    vertices in parallel (synchronously) or not. This argument is
-    ignored if the second form of the function is used (ie. the
-    \sQuote{\code{vertex}} argument is present). It is also not
-    implemented in the \dQuote{neg} implementation.}
-  \item{start.temp}{Real constant, the start temperature.
-    This argument is ignored if the second form of the
-    function is used (ie. the \sQuote{\code{vertex}} argument is
-    present). } 
-  \item{stop.temp}{Real constant, the stop temperature. The simulation
-    terminates if the temperature lowers below this level.
-    This argument is ignored if the second form of the
-    function is used (ie. the \sQuote{\code{vertex}} argument is
-    present). } 
-  \item{cool.fact}{Cooling factor for the simulated annealing.
-    This argument is ignored if the second form of the
-    function is used (ie. the \sQuote{\code{vertex}} argument is
-    present). }     
-  \item{update.rule}{Character constant giving the \sQuote{null-model}
-    of the simulation. Possible values: \dQuote{simple} and
-    \dQuote{config}. \dQuote{simple} uses a random graph with the same
-    number of edges as the baseline probability and \dQuote{config} uses
-    a random graph with the same vertex degrees as the input graph.}
-  \item{gamma}{Real constant, the gamma argument of the algorithm. This
-    specifies the balance between the importance of present and
-    non-present edges in a community. Roughly, a comunity is a set of
-    vertices having many edges inside the community and few edges
-    outside the community. The default 1.0 value makes existing and
-    non-existing links equally important. Smaller values make the
-    existing links, greater values the missing links more important.}
-  \item{implementation}{Character scalar. Currently igraph contains two
-    implementations for the Spin-glass community finding algorithm. The
-    faster original implementation is the default. The other
-    implementation, that takes into account negative weights, can be
-    chosen by supplying \sQuote{neg} here.}
-  \item{gamma.minus}{Real constant, the gamma.minus parameter of
-    the algorithm. This specifies the balance between the importance of
-    present and non-present negative weighted edges in a
-    community. Smaller values of gamma.minus, leads to communities with
-    lesser negative intra-connectivity. If this argument is set to zero,
-    the algorithm reduces to a graph coloring algorithm, using the
-    number of spins as the number of colors. This argument is ignored if
-    the \sQuote{orig} implementation is chosen.}
-}
-\details{
-  This function tries to find communities in a graph. A community is a
-  set of nodes with many edges inside the community and  few edges
-  between outside it (i.e. between the community itself and the rest of
-  the graph.)
-
-  This idea is reversed for edges having a negative weight, 
-  ie. few negative edges inside a community and many negative edges
-  between communities. Note that only the \sQuote{neg} implementation
-  supports negative edge weights.
-
-  The \code{spinglass.cummunity} function can solve two problems related
-  to community detection. If the \code{vertex} argument is not given (or
-  it is \code{NULL}), then the regular community detection problem is
-  solved (approximately), i.e. partitioning the vertices into
-  communities, by optimizing the an energy function.
-
-  If the \code{vertex} argument is given and it is not \code{NULL}, then
-  it must be a vertex id, and the same energy function is used to find
-  the community of the the given vertex. See also the examples below.
-}
-\value{
-  If the \code{vertex} argument is not given, ie. the first form is used
-  then a \code{\link{spinglass.community}} returns a
-  \code{\link{communities}} object. 
-
-  If the \code{vertex} argument is present, ie. the second form is used
-  then a named list is returned with the following components:
-  \item{community}{Numeric vector giving the ids of the vertices in
-    the same community as \code{vertex}.}
-  \item{cohesion}{The cohesion score of the result, see references.}
-  \item{adhesion}{The adhesion score of the result, see references.}
-  \item{inner.links}{The number of edges within the community of
-    \code{vertex}.}
-  \item{outer.links}{The number of edges between the community of
-    \code{vertex} and the rest of the graph. }
-}
-\references{
-  J. Reichardt and S. Bornholdt: Statistical Mechanics of Community
-  Detection, \emph{Phys. Rev. E}, 74, 016110 (2006),
-  \url{http://arxiv.org/abs/cond-mat/0603718}
-
-  M. E. J. Newman and M. Girvan: Finding and evaluating community
-  structure in networks, \emph{Phys. Rev. E} 69, 026113 (2004)
-
-  V.A. Traag and Jeroen Bruggeman: Community detection in networks 
-  with positive and negative links, \url{http://arxiv.org/abs/0811.2329}
-  (2008).
-  
-}
-\author{Jorg Reichardt
-  (\url{http://theorie.physik.uni-wuerzburg.de/~reichardt/}) for the
-  original code and Gabor Csardi \email{csardi.gabor at gmail.com} for the
-  igraph glue code.
-  
-  Changes to the original function for including the
-  possibility of negative ties were implemented 
-  by Vincent Traag (\url{http://www.traag.net/}).}
-\seealso{\code{\link{communities}}, \code{\link{clusters}}}
-\examples{
-  g <- erdos.renyi.game(10, 5/10) \%du\% erdos.renyi.game(9, 5/9)
-  g <- add.edges(g, c(1, 12))
-  g <- induced.subgraph(g, subcomponent(g, 1))
-  spinglass.community(g, spins=2)
-  spinglass.community(g, vertex=1)
-}
-\keyword{graphs}
-
-    
\ No newline at end of file
diff --git a/man/split_join_distance.Rd b/man/split_join_distance.Rd
new file mode 100644
index 0000000..83edcf2
--- /dev/null
+++ b/man/split_join_distance.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/community.R
+\name{split_join_distance}
+\alias{split_join_distance}
+\title{Split-join distance of two community structures}
+\usage{
+split_join_distance(comm1, comm2)
+}
+\arguments{
+\item{comm1}{The first community structure.}
+
+\item{comm2}{The second community structure.}
+}
+\value{
+Two integer numbers, see details below.
+}
+\description{
+The split-join distance between partitions A and B is the sum of the
+projection distance of A from B and the projection distance of B from
+A. The projection distance is an asymmetric measure and it is defined as
+follows:
+}
+\details{
+First, each set in partition A is evaluated against all sets in
+partition B. For each set in partition A, the best matching set in
+partition B is found and the overlap size is calculated. (Matching is
+quantified by the size of the overlap between the two sets). Then, the
+maximal overlap sizes for each set in A are summed together and
+subtracted from the number of elements in A.
+
+The split-join distance will be returned as two numbers, the first is
+the projection distance of the first partition from the
+second, while the second number is the projection distance of the second
+partition from the first. This makes it easier to detect whether a
+partition is a subpartition of the other, since in this case, the
+corresponding distance will be zero.
+}
+\references{
+van Dongen S: Performance criteria for graph clustering and Markov
+cluster experiments. Technical Report INS-R0012, National Research
+Institute for Mathematics and Computer Science in the Netherlands,
+Amsterdam, May 2000.
+}
+
diff --git a/man/srand.Rd b/man/srand.Rd
index 2c4fd70..76ddc08 100644
--- a/man/srand.Rd
+++ b/man/srand.Rd
@@ -1,35 +1,18 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/other.R
 \name{srand}
 \alias{srand}
-\title{Set random seed of the C library's RNG}
-\description{Set the random seed of the C library's RNG, for a new
-  sequence of pseudo-random numbers.}
+\title{Deprecated function, used to set random seed of the C library's RNG}
 \usage{
 srand(seed)
 }
 \arguments{
-  \item{seed}{Numeric scalar, the new random seed. It must be
-    non-negative and will be converted to an integer.}
+\item{seed}{Ignored.}
 }
-\details{
-  Note that this function has nothing to do with R's random number
-  generator, see \code{set.seed} for that.
-
-  Some package (e.g. ngspatial) use internal C code and generate random
-  numbers using the standard C library's built-in random number
-  generator instead of using R's RNGs. The \code{srand} function is
-  provided to set the random seed for these packages. It simply calls
-  the standard C function \code{srand}, with the supplied integer seed
-  value.
-
-  Note that the standard C library's RNGs are typically of very bad
-  quality, and also slower than R's RNGs. It is not worth using
-  them, really, other than taking over some legacy C code that already
-  uses them, and that would be difficult to rewrite to use R's RNGs.
+\description{
+Deprecated function, used to set random seed of the C library's RNG
 }
-\value{
-  \code{NULL}, invisibly.
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
 }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-% \examples{}
+
diff --git a/man/st_cuts.Rd b/man/st_cuts.Rd
new file mode 100644
index 0000000..4548231
--- /dev/null
+++ b/man/st_cuts.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{st_cuts}
+\alias{stCuts}
+\alias{st_cuts}
+\title{List all (s,t)-cuts of a graph}
+\usage{
+st_cuts(graph, source, target)
+}
+\arguments{
+\item{graph}{The input graph. It must be directed.}
+
+\item{source}{The source vertex.}
+
+\item{target}{The target vertex.}
+}
+\value{
+A list with entries: \item{cuts}{A list of numeric vectors
+containing edge ids. Each vector is an \eqn{(s,t)}-cut.}
+\item{partition1s}{A list of numeric vectors containing vertex ids, they
+correspond to the edge cuts. Each vertex set is a generator of the
+corresponding cut, i.e. in the graph \eqn{G=(V,E)}, the vertex set \eqn{X}
+and its complementer \eqn{V-X}, generates the cut that contains exactly the
+edges that go from \eqn{X} to \eqn{V-X}.}
+}
+\description{
+List all (s,t)-cuts in a directed graph.
+}
+\details{
+Given a \eqn{G} directed graph and two, different and non-ajacent vertices,
+\eqn{s} and \eqn{t}, an \eqn{(s,t)}-cut is a set of edges, such that after
+removing these edges from \eqn{G} there is no directed path from \eqn{s} to
+\eqn{t}.
+}
+\examples{
+# A very simple graph
+g <- graph_from_literal(a -+ b -+ c -+ d -+ e)
+st_cuts(g, source="a", target="e")
+
+# A somewhat more difficult graph
+g2 <- graph_from_literal(s --+ a:b, a:b --+ t,
+                   a --+ 1:2:3, 1:2:3 --+ b)
+st_cuts(g2, source="s", target="t")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+JS Provan and DR Shier: A Paradigm for listing (s,t)-cuts in
+graphs, \emph{Algorithmica} 15, 351--372, 1996.
+}
+\seealso{
+\code{\link{st_min_cuts}} to list all minimum cuts.
+}
+\keyword{graphs}
+
diff --git a/man/st_min_cuts.Rd b/man/st_min_cuts.Rd
new file mode 100644
index 0000000..0bb0a8d
--- /dev/null
+++ b/man/st_min_cuts.Rd
@@ -0,0 +1,66 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{st_min_cuts}
+\alias{stMincuts}
+\alias{st_min_cuts}
+\title{List all minimum \eqn{(s,t)}-cuts of a graph}
+\usage{
+st_min_cuts(graph, source, target, capacity = NULL)
+}
+\arguments{
+\item{graph}{The input graph. It must be directed.}
+
+\item{source}{The id of the source vertex.}
+
+\item{target}{The id of the target vertex.}
+
+\item{capacity}{Numeric vector giving the edge capacities. If this is
+\code{NULL} and the graph has a \code{weight} edge attribute, then this
+attribute defines the edge capacities. For forcing unit edge capacities,
+even for graphs that have a \code{weight} edge attribute, supply \code{NA}
+here.}
+}
+\value{
+A list with entries: \item{value}{Numeric scalar, the size of the
+minimum cut(s).} \item{cuts}{A list of numeric vectors containing edge ids.
+Each vector is a minimum \eqn{(s,t)}-cut.} \item{partition1s}{A list of
+numeric vectors containing vertex ids, they correspond to the edge cuts.
+Each vertex set is a generator of the corresponding cut, i.e. in the graph
+\eqn{G=(V,E)}, the vertex set \eqn{X} and its complementer \eqn{V-X},
+generates the cut that contains exactly the edges that go from \eqn{X} to
+\eqn{V-X}.}
+}
+\description{
+Listing all minimum \eqn{(s,t)}-cuts of a directed graph, for given \eqn{s}
+and \eqn{t}.
+}
+\details{
+Given a \eqn{G} directed graph and two, different and non-ajacent vertices,
+\eqn{s} and \eqn{t}, an \eqn{(s,t)}-cut is a set of edges, such that after
+removing these edges from \eqn{G} there is no directed path from \eqn{s} to
+\eqn{t}.
+
+The size of an \eqn{(s,t)}-cut is defined as the sum of the capacities (or
+weights) in the cut. For unweighed (=equally weighted) graphs, this is
+simply the number of edges.
+
+An \eqn{(s,t)}-cut is minimum if it is of the smallest possible size.
+}
+\examples{
+# A difficult graph, from the Provan-Shier paper
+g <- graph_from_literal(s --+ a:b, a:b --+ t,
+               a --+ 1:2:3:4:5, 1:2:3:4:5 --+ b)
+st_min_cuts(g, source="s", target="t")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+JS Provan and DR Shier: A Paradigm for listing (s,t)-cuts in
+graphs, \emph{Algorithmica} 15, 351--372, 1996.
+}
+\seealso{
+\code{\link{st_cuts}}, \code{\link{min_separators}}
+}
+\keyword{graphs}
+
diff --git a/man/static.fitness.game.Rd b/man/static.fitness.game.Rd
deleted file mode 100644
index 8804073..0000000
--- a/man/static.fitness.game.Rd
+++ /dev/null
@@ -1,73 +0,0 @@
-\name{static.fitness.game}
-\alias{static.fitness.game}
-\concept{Random graph model}
-\title{Random graphs from vertex fitness scores}
-\description{
-  This function generates a non-growing random graph with edge probabilities
-  proportional to node fitness scores.
-}
-\usage{
-static.fitness.game (no.of.edges, fitness.out, fitness.in,
-                     loops = FALSE, multiple = FALSE) 
-
-}
-\arguments{
-  \item{no.of.edges}{The number of edges in the generated graph.}
-  \item{fitness.out}{A numeric vector containing the fitness of each
-    vertex. For directed graphs, this specifies the out-fitness
-    of each vertex.}
-  \item{fitness.in}{If \code{NULL} (the default), the generated graph
-    will be undirected. If not \code{NULL}, then it should be a numeric
-    vector and it specifies the in-fitness of each vertex.
-
-    If this argument is not \code{NULL}, then a directed graph is
-    generated, otherwise an undirected one.
-  }
-  \item{loops}{Logical scalar, whether to allow loop edges in the
-    graph.}
-  \item{multiple}{Logical scalar, whether to allow multiple edges in the
-    graph.}
-}
-\details{
-  This game generates a directed or undirected random graph where the
-  probability of an edge between vertices \eqn{i} and \eqn{j} depends on
-  the fitness scores of the two vertices involved. For undirected graphs,
-  each vertex has a single fitness score. For directed graphs, each
-  vertex has an out- and an in-fitness, and the probability of an edge
-  from \eqn{i} to \eqn{j} depends on the out-fitness of vertex \eqn{i}
-  and the in-fitness of vertex \eqn{j}.
-  
-  The generation process goes as follows. We start from \eqn{N}
-  disconnected nodes (where \eqn{N} is given by the length of the fitness
-  vector). Then we randomly select two vertices \eqn{i} and \eqn{j}, with
-  probabilities proportional to their fitnesses. (When the generated
-  graph is directed, \eqn{i} is selected according to the out-fitnesses
-  and \eqn{j} is selected according to the in-fitnesses). If the
-  vertices are not connected yet (or if multiple edges are allowed), we 
-  connect them; otherwise we select a new pair. This is repeated until
-  the desired number of links are created.
-  
-  It can be shown that the \emph{expected} degree of each vertex will be
-  proportional to its fitness, although the actual, observed degree will not
-  be. If you need to generate a graph with an exact degree sequence, consider
-  \code{\link{degree.sequence.game}} instead.
-  
-  This model is commonly used to generate static scale-free networks. To
-  achieve this, you have to draw the fitness scores from the desired power-law
-  distribution. Alternatively, you may use
-  \code{\link{static.power.law.game}} which generates the fitnesses for
-  you with a given exponent.
-}
-\value{An igraph graph, directed or undirected.}
-\references{
-  Goh K-I, Kahng B, Kim D: Universal behaviour of load distribution
-  in scale-free networks. \emph{Phys Rev Lett} 87(27):278701, 2001.
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com}}
-\examples{
-N <- 10000
-g <- static.fitness.game(5*N, sample((1:50)^-2, N, replace=TRUE))
-degree.distribution(g)
-\dontrun{plot(degree.distribution(g, cumulative=TRUE), log="xy")}
-}
-\keyword{graphs}
diff --git a/man/static.power.law.game.Rd b/man/static.power.law.game.Rd
deleted file mode 100644
index f30263f..0000000
--- a/man/static.power.law.game.Rd
+++ /dev/null
@@ -1,78 +0,0 @@
-\name{static.power.law.game}
-\alias{static.power.law.game}
-\concept{Random graph model}
-\title{Scale-free random graphs, from vertex fitness scores}
-\description{
-  This function generates a non-growing random graph with expected
-  power-law degree distributions.
-}
-\usage{
-static.power.law.game (no.of.nodes, no.of.edges, exponent.out,
-                       exponent.in = -1, loops = FALSE,
-                       multiple = FALSE, finite.size.correction = TRUE) 
-}
-\arguments{
-  \item{no.of.nodes}{The number of vertices in the generated graph.}
-  \item{no.of.edges}{The number of edges in the generated graph.}
-  \item{exponent.out}{Numeric scalar, the power law exponent of the
-    degree distribution. For directed graphs, this specifies the
-    exponent of the out-degree distribution. It must be greater than or
-    equal to 2. If you pass \code{Inf} here, you will get back an
-    Erdos-Renyi random network.}
-  \item{exponent.in}{Numeric scalar. If negative, the generated graph
-    will be undirected. If greater than or equal to 2, this argument
-    specifies the exponent of the in-degree distribution. If
-    non-negative but less than 2, an error will be generated.}
-  \item{loops}{Logical scalar, whether to allow loop edges in the
-    generated graph.}
-  \item{multiple}{Logical scalar, whether to allow multiple edges in the
-    generated graph.}
-  \item{finite.size.correction}{Logical scalar, whether to use the
-    proposed finite size correction of Cho et al., see references
-    below.}
-}
-\details{
- This game generates a directed or undirected random graph where the
- degrees of vertices follow power-law distributions with prescribed
- exponents. For directed graphs, the exponents of the in- and out-degree
- distributions may be specified separately.
-
- The game simply uses \code{\link{static.fitness.game}} with appropriately
- constructed fitness vectors. In particular, the fitness of vertex
- \eqn{i} is \eqn{i^{-alpha}}{i^(-alpha)}, where \eqn{alpha = 1/(gamma-1)}
- and gamma is the exponent given in the arguments.
-
- To remove correlations between in- and out-degrees in case of directed
- graphs, the in-fitness vector will be shuffled after it has been set up
- and before \code{\link{static.fitness.game}} is called.
-
- Note that significant finite size effects may be observed for exponents
- smaller than 3 in the original formulation of the game. This function
- provides an argument that lets you remove the finite size effects by
- assuming that the fitness of vertex \eqn{i} is 
- \eqn{(i+i_0-1)^{-alpha}}{(i+i0-1)^(-alpha)}
- where \eqn{i_0}{i0} is a constant chosen appropriately to ensure that
- the maximum degree is less than the square root of the number of edges
- times the average degree; see the paper of Chung and Lu, and Cho et al
- for more details.
-}
-\value{An igraph graph, directed or undirected.}
-\references{
-  Goh K-I, Kahng B, Kim D: Universal behaviour of load distribution
-  in scale-free networks. \emph{Phys Rev Lett} 87(27):278701, 2001.
-
- Chung F and Lu L: Connected components in a random graph with given
- degree sequences. \emph{Annals of Combinatorics} 6, 125-145, 2002.
-
- Cho YS, Kim JS, Park J, Kahng B, Kim D: Percolation transitions in
- scale-free networks under the Achlioptas process. \emph{Phys Rev Lett}
- 103:135702, 2009.
-}
-\author{Tamas Nepusz \email{ntamas at gmail.com}}
-\examples{
-g <- static.power.law.game(10000, 30000, 2.2, 2.3)
-\dontrun{plot(degree.distribution(g, cumulative=TRUE, mode="out"), log="xy")}
-}
-\keyword{graphs}
- 
-  
diff --git a/man/stochasticMatrix.Rd b/man/stochasticMatrix.Rd
deleted file mode 100644
index e23613a..0000000
--- a/man/stochasticMatrix.Rd
+++ /dev/null
@@ -1,49 +0,0 @@
-\name{get.stochastic}
-\alias{get.stochastic}
-\title{Stochastic matrix of a graph}
-\description{Retrieves the stochastic matrix of a graph of class
-  \code{igraph}.
-}
-\usage{
-get.stochastic(graph, column.wise = FALSE, sparse =
-      getIgraphOpt("sparsematrices"))
-}
-\arguments{
-  \item{graph}{The input graph. Must be of class \code{igraph}.}
-  \item{column.wise}{If \code{FALSE}, then the rows of the stochastic
-    matrix sum up to one; otherwise it is the columns.}
-  \item{sparse}{Logical scalar, whether to return a sparse matrix. The
-    \code{Matrix} package is needed for sparse matrices.}
-}
-\details{
-  Let \eqn{M} be an \eqn{n \times n}{n x n} adjacency matrix with real
-  non-negative entries. Let us define
-  \eqn{D = \textrm{diag}(\sum_{i}M_{1i}, \dots, \sum_{i}M_{ni})}{%
-    D=diag( sum(M[1,i], i), ..., sum(M[n,i], i) )}
-  
-  The (row) stochastic matrix is defined as
-  \deqn{W = D^{-1}M,}{W = inv(D) M,}
-  where it is assumed that \eqn{D} is non-singular.
-  Column stochastic matrices are defined in a symmetric way.
-}
-
-\value{
- A regular \R matrix or a matrix of class \code{Matrix} if a
- \code{sparse} argument was \code{TRUE}.
-}
-
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{get.adjacency}}}
-\examples{
-library(Matrix)
-## g is a large sparse graph
-g <- barabasi.game(n = 10^5, power = 2, directed = FALSE)
-W <- get.stochastic(g, sparse=TRUE)
-
-## a dense matrix here would probably not fit in the memory
-class(W)
-
-## may not be exactly 1, due to numerical errors
-max(abs(rowSums(W))-1)
-}
-\keyword{graphs}
diff --git a/man/stochastic_matrix.Rd b/man/stochastic_matrix.Rd
new file mode 100644
index 0000000..ea3b95d
--- /dev/null
+++ b/man/stochastic_matrix.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/scg.R
+\name{stochastic_matrix}
+\alias{get.stochastic}
+\alias{stochastic_matrix}
+\title{Stochastic matrix of a graph}
+\usage{
+stochastic_matrix(graph, column.wise = FALSE,
+  sparse = igraph_opt("sparsematrices"))
+}
+\arguments{
+\item{graph}{The input graph. Must be of class \code{igraph}.}
+
+\item{column.wise}{If \code{FALSE}, then the rows of the stochastic matrix
+sum up to one; otherwise it is the columns.}
+
+\item{sparse}{Logical scalar, whether to return a sparse matrix. The
+\code{Matrix} package is needed for sparse matrices.}
+}
+\value{
+A regular matrix or a matrix of class \code{Matrix} if a
+\code{sparse} argument was \code{TRUE}.
+}
+\description{
+Retrieves the stochastic matrix of a graph of class \code{igraph}.
+}
+\details{
+Let \eqn{M} be an \eqn{n \times n}{n x n} adjacency matrix with real
+non-negative entries. Let us define \eqn{D = \textrm{diag}(\sum_{i}M_{1i},
+\dots, \sum_{i}M_{ni})}{D=diag( sum(M[1,i], i), ..., sum(M[n,i], i) )}
+
+The (row) stochastic matrix is defined as \deqn{W = D^{-1}M,}{W = inv(D) M,}
+where it is assumed that \eqn{D} is non-singular.  Column stochastic
+matrices are defined in a symmetric way.
+}
+\examples{
+library(Matrix)
+## g is a large sparse graph
+g <- barabasi.game(n = 10^5, power = 2, directed = FALSE)
+W <- stochastic_matrix(g, sparse=TRUE)
+
+## a dense matrix here would probably not fit in the memory
+class(W)
+
+## may not be exactly 1, due to numerical errors
+max(abs(rowSums(W))-1)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{as_adj}}
+}
+\keyword{graphs}
+
diff --git a/man/strength.Rd b/man/strength.Rd
new file mode 100644
index 0000000..ce4f5ab
--- /dev/null
+++ b/man/strength.Rd
@@ -0,0 +1,56 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{strength}
+\alias{graph.strength}
+\alias{strength}
+\title{Strength or weighted vertex degree}
+\usage{
+strength(graph, vids = V(graph), mode = c("all", "out", "in", "total"),
+  loops = TRUE, weights = NULL)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{vids}{The vertices for which the strength will be calculated.}
+
+\item{mode}{Character string, \dQuote{out} for out-degree, \dQuote{in} for
+in-degree or \dQuote{all} for the sum of the two. For undirected graphs this
+argument is ignored.}
+
+\item{loops}{Logical; whether the loop edges are also counted.}
+
+\item{weights}{Weight vector. If the graph has a \code{weight} edge
+attribute, then this is used by default. If the graph does not have a
+\code{weight} edge attribute and this argument is \code{NULL}, then a
+warning is given and \code{\link{degree}} is called.}
+}
+\value{
+A numeric vector giving the strength of the vertices.
+}
+\description{
+Summing up the edge weights of the adjacent edges for each vertex.
+}
+\examples{
+g <- make_star(10)
+E(g)$weight <- seq(ecount(g))
+strength(g)
+strength(g, mode="out")
+strength(g, mode="in")
+
+# No weights, a warning is given
+g <- make_ring(10)
+strength(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras,
+Alessandro Vespignani: The architecture of complex weighted networks, Proc.
+Natl. Acad. Sci. USA 101, 3747 (2004)
+}
+\seealso{
+\code{\link{degree}} for the unweighted version.
+}
+\keyword{graphs}
+
diff --git a/man/structure.info.Rd b/man/structure.info.Rd
deleted file mode 100644
index c321a40..0000000
--- a/man/structure.info.Rd
+++ /dev/null
@@ -1,88 +0,0 @@
-\name{structure.info}
-\alias{vcount}
-\alias{ecount}
-\alias{neighbors}
-\alias{incident}
-\alias{is.directed}
-\alias{are.connected}
-\alias{get.edge}
-\alias{get.edges}
-\title{Gaining information about graph structure}
-\description{Functions for exploring the basic structure of a network:
-  number of vertices and edges, the neighbors of a node, test whether
-  two vertices are connected by an edge.
-}
-\usage{
-vcount(graph)
-ecount(graph)
-neighbors(graph, v, mode = 1)
-incident(graph, v, mode=c("all", "out", "in", "total"))
-is.directed(graph)
-are.connected(graph, v1, v2)
-get.edge(graph, id)
-get.edges(graph, es)
-}
-\arguments{
-  \item{graph}{The graph.}
-  \item{v}{The vertex of which the adjacent vertices or incident edges
-    are queried.}
-  \item{mode}{Character string, specifying the type of adjacent vertices
-    or incident edges to list in a directed graph. If \dQuote{out}, then
-    only outgoing edges (or their corresponding vertices) are
-    considered; \dQuote{in} considers incoming edges; \sQuote{all}
-    ignores edge directions. This argument is ignored for undirected
-    graphs.}
-  \item{v1}{The id of the first vertex. For directed graphs only edges
-    pointing from \code{v1} to \code{v2} are searched.}
-  \item{v2}{The id of the second vertex. For directed graphs only edges
-    pointing from \code{v1} to \code{v2} are searched.}
-  \item{id}{A numeric edge id.}
-  \item{es}{An edge sequence.}
-}
-\details{
-  These functions provide the basic structural information of a graph.
-
-  \code{vcount} gives the number of vertices in the graph.
-
-  \code{ecount} gives the number of edges in the graph.
-
-  \code{neighbors} gives the neighbors of a vertex. The vertices
-  connected by multiple edges are listed as many times as the number of
-  connecting edges.
-
-  \code{incident} gives the incident edges of a vertex.
-  
-  \code{is.directed} gives whether the graph is directed or not. It just
-  gives its \code{directed} attribute.
-  
-  \code{are.connected} decides whether there is an edge from \code{v1}
-  to \code{v2}. 
-
-  \code{get.edge} returns the end points of the edge with the supplied
-  edge id. For directed graph the source vertex comes first, for
-  undirected graphs, the order is arbitrary.
-
-  \code{get.edges} returns a matrix with the endpoints of the edges in
-  the edge sequence argument. 
-}
-\value{
-  \code{vcount} and \code{ecount} return integer
-  constants. \code{neighbors} returns an integer
-  vector. \code{is.directed} and \code{are.connected} return boolean
-  constants. \code{get.edge} returns a numeric vector of length two.
-  \code{get.edges} returns a two-column matrix.
-}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph}}}
-\examples{
-g <- graph.ring(10)
-vcount(g)
-ecount(g)
-neighbors(g, 5)
-incident(g, 5)
-are.connected(g, 1, 2)
-are.connected(g, 2, 4)
-get.edges(g, 1:6)
-}
-\keyword{graphs}
diff --git a/man/sub-.igraph.Rd b/man/sub-.igraph.Rd
new file mode 100644
index 0000000..cae9b93
--- /dev/null
+++ b/man/sub-.igraph.Rd
@@ -0,0 +1,130 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/indexing.R
+\name{[.igraph}
+\alias{[.igraph}
+\title{Query and manipulate a graph as it were an adjacency matrix}
+\usage{
+\method{[}{igraph}(x, i, j, ..., from, to,
+  sparse = igraph_opt("sparsematrices"), edges = FALSE, drop = TRUE,
+  attr = if (is_weighted(x)) "weight" else NULL)
+}
+\arguments{
+\item{x}{The graph.}
+
+\item{i}{Index. Vertex ids or names or logical vectors. See details
+below.}
+
+\item{j}{Index. Vertex ids or names or logical vectors. See details
+below.}
+
+\item{...}{Currently ignored.}
+
+\item{from}{A numeric or character vector giving vertex ids or
+names. Together with the \code{to} argument, it can be used to
+query/set a sequence of edges. See details below. This argument cannot
+be present together with any of the \code{i} and \code{j} arguments
+and if it is present, then the \code{to} argument must be present as
+well.}
+
+\item{to}{A numeric or character vector giving vertex ids or
+names. Together with the \code{from} argument, it can be used to
+query/set a sequence of edges. See details below. This argument cannot
+be present together with any of the \code{i} and \code{j} arguments
+and if it is present, then the \code{from} argument must be present as
+well.}
+
+\item{sparse}{Logical scalar, whether to return sparse matrices.}
+
+\item{edges}{Logical scalar, whether to return edge ids.}
+
+\item{drop}{Ignored.}
+
+\item{attr}{If not \code{NULL}, then it should be the name of an edge
+attribute. This attribute is queried and returned.}
+}
+\value{
+A scalar or matrix. See details below.
+}
+\description{
+Query and manipulate a graph as it were an adjacency matrix
+}
+\details{
+The single bracket indexes the (possibly weighted) adjacency matrix of
+the graph. Here is what you can do with it:
+
+\enumerate{
+\item Check whether there is an edge between two vertices (\eqn{v}
+  and \eqn{w}) in the graph: \preformatted{  graph[v, w]}
+   A numeric scalar is returned, one if the edge exists, zero
+    otherwise.
+  \item Extract the (sparse) adjacency matrix of the graph, or part of
+    it: \preformatted{  graph[]
+graph[1:3,5:6]
+graph[c(1,3,5),]}
+    The first variants returns the full adjacency matrix, the other
+    two return part of it.
+  \item The \code{from} and \code{to} arguments can be used to check
+    the existence of many edges. In this case, both \code{from} and
+    \code{to} must be present and they must have the same length. They
+    must contain vertex ids or names. A numeric vector is returned, of
+    the same length as \code{from} and \code{to}, it contains ones
+    for existing edges edges and zeros for non-existing ones.
+    Example: \preformatted{  graph[from=1:3, to=c(2,3,5)]}.
+  \item For weighted graphs, the \code{[} operator returns the edge
+    weights. For non-esistent edges zero weights are returned. Other
+    edge attributes can be queried as well, by giving the \code{attr}
+    argument.
+  \item Querying edge ids instead of the existance of edges or edge
+    attributes. E.g. \preformatted{  graph[1, 2, edges=TRUE]}
+    returns the id of the edge between vertices 1 and 2, or zero if
+    there is no such edge.
+  \item Adding one or more edges to a graph. For this the element(s) of
+    the imaginary adjacency matrix must be set to a non-zero numeric
+    value (or \code{TRUE}): \preformatted{  graph[1, 2] <- 1
+graph[1:3,1] <- 1
+graph[from=1:3, to=c(2,3,5)] <- TRUE}
+    This does not affect edges that are already present in the graph,
+    i.e. no multiple edges are created.
+  \item Adding weighted edges to a graph. The \code{attr} argument
+    contains the name of the edge attribute to set, so it does not
+    have to be \sQuote{weight}: \preformatted{  graph[1, 2, attr="weight"]<- 5
+graph[from=1:3, to=c(2,3,5)] <- c(1,-1,4)}
+    If an edge is already present in the network, then only its
+    weigths or other attribute are updated. If the graph is already
+    weighted, then the \code{attr="weight"} setting is implicit, and
+    one does not need to give it explicitly.
+  \item Deleting edges. The replacement syntax allow the deletion of
+    edges, by specifying \code{FALSE} or \code{NULL} as the
+    replacement value: \preformatted{  graph[v, w] <- FALSE}
+    removes the edge from vertex \eqn{v} to vertex \eqn{w}.
+    As this can be used to delete edges between two sets of vertices,
+    either pairwise: \preformatted{  graph[from=v, to=w] <- FALSE}
+    or not: \preformatted{  graph[v, w] <- FALSE }
+    if \eqn{v} and \eqn{w} are vectors of edge ids or names.
+}
+
+\sQuote{\code{[}} allows logical indices and negative indices as well,
+with the usual R semantics. E.g. \preformatted{  graph[degree(graph)==0, 1] <- 1}
+adds an edge from every isolate vertex to vertex one,
+and \preformatted{  G <- make_empty_graph(10)
+G[-1,1] <- TRUE}
+ creates a star graph.
+
+Of course, the indexing operators support vertex names,
+so instead of a numeric vertex id a vertex can also be given to
+\sQuote{\code{[}} and \sQuote{\code{[[}}.
+}
+\seealso{
+Other structural queries: \code{\link{[[.igraph}};
+  \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{neighbors}};
+  \code{\link{tail_of}}
+}
+
diff --git a/man/sub-sub-.igraph.Rd b/man/sub-sub-.igraph.Rd
new file mode 100644
index 0000000..9800e6d
--- /dev/null
+++ b/man/sub-sub-.igraph.Rd
@@ -0,0 +1,86 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/indexing.R
+\name{[[.igraph}
+\alias{[[.igraph}
+\title{Query and manipulate a graph as it were an adjacency list}
+\usage{
+\method{[[}{igraph}(x, i, j, from, to, ..., directed = TRUE, edges = FALSE,
+  exact = TRUE)
+}
+\arguments{
+\item{x}{The graph.}
+
+\item{i}{Index, integer, character or logical, see details below.}
+
+\item{j}{Index, integer, character or logical, see details below.}
+
+\item{from}{A numeric or character vector giving vertex ids or
+names. Together with the \code{to} argument, it can be used to
+query/set a sequence of edges. See details below. This argument cannot
+be present together with any of the \code{i} and \code{j} arguments
+and if it is present, then the \code{to} argument must be present as
+well.}
+
+\item{to}{A numeric or character vector giving vertex ids or
+names. Together with the \code{from} argument, it can be used to
+query/set a sequence of edges. See details below. This argument cannot
+be present together with any of the \code{i} and \code{j} arguments
+and if it is present, then the \code{from} argument must be present as
+well.}
+
+\item{...}{Additional arguments are not used currently.}
+
+\item{directed}{Logical scalar, whether to consider edge directions
+in directed graphs. It is ignored for undirected graphs.}
+
+\item{edges}{Logical scalar, whether to return edge ids.}
+
+\item{exact}{Ignored.}
+}
+\description{
+Query and manipulate a graph as it were an adjacency list
+}
+\details{
+The double bracket operator indexes the (imaginary) adjacency list
+of the graph. This can used for the following operations:
+\enumerate{
+  \item Querying the adjacent vertices for one or more
+    vertices: \preformatted{  graph[[1:3,]]
+graph[[,1:3]]}
+    The first form gives the successors, the second the predessors
+    or the 1:3 vertices. (For undirected graphs they are equivalent.)
+  \item Querying the incident edges for one or more vertices,
+    if the \code{edges} argument is set to
+    \code{TRUE}: \preformatted{  graph[[1:3, , edges=TRUE]]
+graph[[, 1:3, edges=TRUE]]}
+  \item Querying the edge ids between two sets or vertices,
+    if both indices are used. E.g. \preformatted{  graph[[v, w, edges=TRUE]]}
+    gives the edge ids of all the edges that exist from vertices
+    \eqn{v} to vertices \eqn{w}.
+ }
+
+The alternative argument names \code{from} and \code{to} can be used
+instead of the usual \code{i} and \code{j}, to make the code more
+readable: \preformatted{ graph[[from = 1:3]]
+graph[[from = v, to = w, edges = TRUE]]}
+
+\sQuote{\code{[[}} operators allows logical indices and negative indices
+as well, with the usual R semantics.
+
+Vertex names are also supported, so instead of a numeric vertex id a
+vertex can also be given to \sQuote{\code{[}} and \sQuote{\code{[[}}.
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{neighbors}};
+  \code{\link{tail_of}}
+}
+
diff --git a/man/subcomponent.Rd b/man/subcomponent.Rd
new file mode 100644
index 0000000..68ab0fa
--- /dev/null
+++ b/man/subcomponent.Rd
@@ -0,0 +1,44 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{subcomponent}
+\alias{subcomponent}
+\title{In- or out- component of a vertex}
+\usage{
+subcomponent(graph, v, mode = c("all", "out", "in"))
+}
+\arguments{
+\item{graph}{The graph to analyze.}
+
+\item{v}{The vertex to start the search from.}
+
+\item{mode}{Character string, either \dQuote{in}, \dQuote{out} or
+\dQuote{all}. If \dQuote{in} all vertices from which \code{v} is reachable
+are listed. If \dQuote{out} all vertices reachable from \code{v} are
+returned. If \dQuote{all} returns the union of these. It is ignored for
+undirected graphs.}
+}
+\value{
+Numeric vector, the ids of the vertices in the same component as
+\code{v}.
+}
+\description{
+Finds all vertices reachable from a given vertex, or the opposite: all
+vertices from which a given vertex is reachable via a directed path.
+}
+\details{
+A breadh-first search is conducted starting from vertex \code{v}.
+}
+\examples{
+g <- sample_gnp(100, 1/200)
+subcomponent(g, 1, "in")
+subcomponent(g, 1, "out")
+subcomponent(g, 1, "all")
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{components}}
+}
+\keyword{graphs}
+
diff --git a/man/subgraph.Rd b/man/subgraph.Rd
index 265540a..8c42029 100644
--- a/man/subgraph.Rd
+++ b/man/subgraph.Rd
@@ -1,57 +1,69 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{subgraph}
-\alias{subgraph}
 \alias{induced.subgraph}
+\alias{induced_subgraph}
+\alias{subgraph}
 \alias{subgraph.edges}
-\concept{Subgraph}
 \title{Subgraph of a graph}
-\description{\code{subgraph} creates a subgraph of a graph, containing
-  only the specified vertices and all the edges among them.}
 \usage{
-induced.subgraph(graph, vids, impl=c("auto", "copy_and_delete",
-     "create_from_scratch"))
-subgraph.edges(graph, eids, delete.vertices = TRUE)
 subgraph(graph, v)
+
+induced_subgraph(graph, vids, impl = c("auto", "copy_and_delete",
+  "create_from_scratch"))
+
+subgraph.edges(graph, eids, delete.vertices = TRUE)
 }
 \arguments{
-  \item{graph}{The original graph.}
-  \item{vids,v}{Numeric vector, the vertices of the original 
-    graph which will form the subgraph.}
-  \item{impl}{Character scalar, to choose between two 
-    implementation of the subgraph
-    calculation. \sQuote{\code{copy_and_delete}} copies the graph
-    first, and then deletes the vertices and edges that are not
-    included in the result graph. \sQuote{\code{create_from_scratch}}
-    searches for all vertices and edges that must be kept and then
-    uses them to create the graph from scratch. \sQuote{\code{auto}}
-    chooses between the two implementations automatically, using
-    heuristics based on the size of the original and the result
-    graph.}
-  \item{eids}{The edge ids of the edges that will be kept in the
-    result graph.}
-  \item{delete.vertices}{Logical scalar, whether to remove vertices
-    that do not have any adjacent edges in \code{eids}.}
+\item{graph}{The original graph.}
+
+\item{v}{Numeric vector, the vertices of the original graph which will
+form the subgraph.}
+
+\item{vids}{Numeric vector, the vertices of the original graph which will
+form the subgraph.}
+
+\item{impl}{Character scalar, to choose between two implementation of the
+subgraph calculation. \sQuote{\code{copy_and_delete}} copies the graph
+first, and then deletes the vertices and edges that are not included in the
+result graph. \sQuote{\code{create_from_scratch}} searches for all vertices
+and edges that must be kept and then uses them to create the graph from
+scratch. \sQuote{\code{auto}} chooses between the two implementations
+automatically, using heuristics based on the size of the original and the
+result graph.}
+
+\item{eids}{The edge ids of the edges that will be kept in the result graph.}
+
+\item{delete.vertices}{Logical scalar, whether to remove vertices that do
+not have any adjacent edges in \code{eids}.}
+}
+\value{
+A new graph object.
+}
+\description{
+\code{subgraph} creates a subgraph of a graph, containing only the specified
+vertices and all the edges among them.
 }
 \details{
-  \code{induced.subgraph} calculates the induced subgraph of a set of
-  vertices in a graph. This means that exactly the specified vertices
-  and all the edges between then will be kept in the result graph.
-
-  \code{subgraph.edges} calculates the subgraph of a graph. For this
-  function one can specify the vertices and edges to keep. This
-  function will be renamed to \code{subgraph} in the next major
-  version of igraph.
-
-  The \code{subgraph} function does the same as \code{induced.graph}
-  currently (assuming \sQuote{\code{auto}} as the \code{impl}
-  argument), but it is deprecated and will be removed in the next
-  major version of igraph.
+\code{induced_subgraph} calculates the induced subgraph of a set of vertices
+in a graph. This means that exactly the specified vertices and all the edges
+between then will be kept in the result graph.
+
+\code{subgraph.edges} calculates the subgraph of a graph. For this function
+one can specify the vertices and edges to keep. This function will be
+renamed to \code{subgraph} in the next major version of igraph.
+
+The \code{subgraph} function does the same as \code{induced.graph} currently
+(assuming \sQuote{\code{auto}} as the \code{impl} argument), but it is
+deprecated and will be removed in the next major version of igraph.
 }
-\value{A new graph object.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso
 \examples{
-g <- graph.ring(10)
-g2 <- induced.subgraph(g, 1:7)
+g <- make_ring(10)
+g2 <- induced_subgraph(g, 1:7)
 g3 <- subgraph.edges(g, 1:5, 1:5)
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
 \keyword{graphs}
+
diff --git a/man/subgraph.centrality.Rd b/man/subgraph.centrality.Rd
deleted file mode 100644
index 60d5597..0000000
--- a/man/subgraph.centrality.Rd
+++ /dev/null
@@ -1,45 +0,0 @@
-\name{subgraph.centrality}
-\alias{subgraph.centrality}
-\concept{Subgraph centrality}
-\title{Find subgraph centrality scores of network positions}
-\description{Subgraph centrality of a vertex measures the number of
-  subgraphs a vertex participates in, weighting them according to their
-  size.}
-\usage{
-subgraph.centrality (graph, diag=FALSE)
-}
-\arguments{
-  \item{graph}{The input graph, it should be undirected, but the
-    implementation does not check this currently. }
-  \item{diag}{Boolean scalar, whether to include the diagonal of the
-    adjacency matrix in the analysis. Giving \code{FALSE} here
-    effectively eliminates the loops edges from the graph before the
-    calculation.}
-}
-\details{
-  The subgraph centrality of a vertex is defined as the number of closed
-  loops originating at the vertex, where longer loops are exponentially
-  downweighted.
-
-  Currently the calculation is performed by explicitly calculating all
-  eigenvalues and eigenvectors of the adjacency matrix of the
-  graph. This effectively means that the measure can only be calculated
-  for small graphs.
-}
-\value{
-  A numeric vector, the subgraph centrality scores of the vertices.
-}
-\references{
-  Ernesto Estrada, Juan A. Rodriguez-Velazquez: Subgraph centrality in
-  Complex Networks. \emph{Physical Review E} 71, 056103 (2005).
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com} based on the Matlab
-  code by Ernesto Estrada}
-\seealso{\code{\link{evcent}}, \code{\link{page.rank}}}
-\examples{
-g <- ba.game(100, m=4, dir=FALSE)
-sc <- subgraph.centrality(g)
-cor(degree(g), sc)
-}
-\keyword{graphs}
-
diff --git a/man/subgraph_centrality.Rd b/man/subgraph_centrality.Rd
new file mode 100644
index 0000000..cfa33d9
--- /dev/null
+++ b/man/subgraph_centrality.Rd
@@ -0,0 +1,51 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/centrality.R
+\name{subgraph_centrality}
+\alias{subgraph.centrality}
+\alias{subgraph_centrality}
+\title{Find subgraph centrality scores of network positions}
+\usage{
+subgraph_centrality(graph, diag = FALSE)
+}
+\arguments{
+\item{graph}{The input graph, it should be undirected, but the
+implementation does not check this currently.}
+
+\item{diag}{Boolean scalar, whether to include the diagonal of the adjacency
+matrix in the analysis. Giving \code{FALSE} here effectively eliminates the
+loops edges from the graph before the calculation.}
+}
+\value{
+A numeric vector, the subgraph centrality scores of the vertices.
+}
+\description{
+Subgraph centrality of a vertex measures the number of subgraphs a vertex
+participates in, weighting them according to their size.
+}
+\details{
+The subgraph centrality of a vertex is defined as the number of closed loops
+originating at the vertex, where longer loops are exponentially
+downweighted.
+
+Currently the calculation is performed by explicitly calculating all
+eigenvalues and eigenvectors of the adjacency matrix of the graph. This
+effectively means that the measure can only be calculated for small graphs.
+}
+\examples{
+g <- sample_pa(100, m=4, dir=FALSE)
+sc <- subgraph_centrality(g)
+cor(degree(g), sc)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com} based on the Matlab
+code by Ernesto Estrada
+}
+\references{
+Ernesto Estrada, Juan A. Rodriguez-Velazquez: Subgraph
+centrality in Complex Networks. \emph{Physical Review E} 71, 056103 (2005).
+}
+\seealso{
+\code{\link{eigen_centrality}}, \code{\link{page_rank}}
+}
+\keyword{graphs}
+
diff --git a/man/subgraph_isomorphic.Rd b/man/subgraph_isomorphic.Rd
new file mode 100644
index 0000000..921b860
--- /dev/null
+++ b/man/subgraph_isomorphic.Rd
@@ -0,0 +1,128 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{subgraph_isomorphic}
+\alias{graph.subisomorphic.lad}
+\alias{graph.subisomorphic.vf2}
+\alias{is_subgraph_isomorphic_to}
+\alias{subgraph_isomorphic}
+\title{Decide if a graph is subgraph isomorphic to another one}
+\usage{
+subgraph_isomorphic(pattern, target, method = c("auto", "lad", "vf2"), ...)
+
+is_subgraph_isomorphic_to(pattern, target, method = c("auto", "lad", "vf2"),
+  ...)
+}
+\arguments{
+\item{pattern}{The smaller graph, it might be directed or
+undirected. Undirected graphs are treated as directed graphs with
+mutual edges.}
+
+\item{target}{The bigger graph, it might be directed or
+undirected. Undirected graphs are treated as directed graphs with
+mutual edges.}
+
+\item{method}{The method to use. Possible values: \sQuote{auto},
+\sQuote{lad}, \sQuote{vf2}. See their details below.}
+
+\item{...}{Additional arguments, passed to the various methods.}
+}
+\value{
+Logical scalar, \code{TRUE} if the \code{pattern} is
+  isomorphic to a (possibly induced) subgraph of \code{target}.
+}
+\description{
+Decide if a graph is subgraph isomorphic to another one
+}
+\section{\sQuote{auto} method}{
+
+This method currently selects \sQuote{lad}, always, as it seems
+to be superior on most graphs.
+}
+
+\section{\sQuote{lad} method}{
+
+This is the LAD algorithm by Solnon, see the reference below. It has
+the following extra arguments:
+\describe{
+  \item{domains}{If not \code{NULL}, then it specifies matching
+    restrictions. It must be a list of \code{target} vertex sets, given
+    as numeric vertex ids or symbolic vertex names. The length of the
+    list must be \code{vcount(pattern)} and for each vertex in
+    \code{pattern} it gives the allowed matching vertices in
+    \code{target}. Defaults to \code{NULL}.}
+  \item{induced}{Logical scalar, whether to search for an induced
+    subgraph. It is \code{FALSE} by default.}
+  \item{time.limit}{The processor time limit for the computation, in
+    seconds. It defaults to \code{Inf}, which means no limit.}
+}
+}
+
+\section{\sQuote{vf2} method}{
+
+This method uses the VF2 algorithm by Cordella, Foggia et al., see
+references below. It supports vertex and edge colors and have the
+following extra arguments:
+\describe{
+  \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+    colors of the vertices for colored graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} vertex attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments. See also examples
+    below.}
+  \item{edge.color1, edge.color2}{Optional integer vectors giving the
+    colors of the edges for edge-colored (sub)graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} edge attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments.}
+}
+}
+\examples{
+# A LAD example
+pattern <- make_graph(~ 1:2:3:4:5,
+                      1 - 2:5, 2 - 1:5:3, 3 - 2:4, 4 - 3:5, 5 - 4:2:1)
+target <- make_graph(~ 1:2:3:4:5:6:7:8:9,
+                    1 - 2:5:7, 2 - 1:5:3, 3 - 2:4, 4 - 3:5:6:8:9,
+                    5 - 1:2:4:6:7, 6 - 7:5:4:9, 7 - 1:5:6,
+                    8 - 4:9, 9 - 6:4:8)
+domains <- list(`1` = c(1,3,9), `2` = c(5,6,7,8), `3` = c(2,4,6,7,8,9),
+                `4` = c(1,3,9), `5` = c(2,4,8,9))
+subgraph_isomorphisms(pattern, target)
+subgraph_isomorphisms(pattern, target, induced = TRUE)
+subgraph_isomorphisms(pattern, target, domains = domains)
+
+# Directed LAD example
+pattern <- make_graph(~ 1:2:3, 1 -+ 2:3)
+uring <- make_ring(10)
+dring <- make_ring(10, directed = TRUE)
+subgraph_isomorphic(pattern, uring)
+subgraph_isomorphic(pattern, dring)
+}
+\references{
+LP Cordella,  P Foggia, C Sansone, and M Vento: An improved algorithm
+ for matching large graphs, \emph{Proc. of the 3rd IAPR TC-15 Workshop
+ on Graphbased Representations in Pattern Recognition}, 149--159, 2001.
+
+ C. Solnon: AllDifferent-based Filtering for Subgraph Isomorphism,
+ \emph{Artificial Intelligence} 174(12-13):850--864, 2010.
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}};
+  \code{\link{graph.get.subisomorphisms.vf2}},
+  \code{\link{subgraph_isomorphisms}};
+  \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}}
+}
+
diff --git a/man/subgraph_isomorphisms.Rd b/man/subgraph_isomorphisms.Rd
new file mode 100644
index 0000000..9ca4948
--- /dev/null
+++ b/man/subgraph_isomorphisms.Rd
@@ -0,0 +1,89 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/topology.R
+\name{subgraph_isomorphisms}
+\alias{graph.get.subisomorphisms.vf2}
+\alias{subgraph_isomorphisms}
+\title{All isomorphic mappings between a graph and subgraphs of another graph}
+\usage{
+subgraph_isomorphisms(pattern, target, method = c("lad", "vf2"), ...)
+}
+\arguments{
+\item{pattern}{The smaller graph, it might be directed or
+undirected. Undirected graphs are treated as directed graphs with
+mutual edges.}
+
+\item{target}{The bigger graph, it might be directed or
+undirected. Undirected graphs are treated as directed graphs with
+mutual edges.}
+
+\item{method}{The method to use. Possible values: \sQuote{auto},
+\sQuote{lad}, \sQuote{vf2}. See their details below.}
+
+\item{...}{Additional arguments, passed to the various methods.}
+}
+\value{
+A list of vertex sequences, corresponding to all
+  mappings from the first graph to the second.
+}
+\description{
+All isomorphic mappings between a graph and subgraphs of another graph
+}
+\section{\sQuote{lad} method}{
+
+This is the LAD algorithm by Solnon, see the reference below. It has
+the following extra arguments:
+\describe{
+  \item{domains}{If not \code{NULL}, then it specifies matching
+    restrictions. It must be a list of \code{target} vertex sets, given
+    as numeric vertex ids or symbolic vertex names. The length of the
+    list must be \code{vcount(pattern)} and for each vertex in
+    \code{pattern} it gives the allowed matching vertices in
+    \code{target}. Defaults to \code{NULL}.}
+  \item{induced}{Logical scalar, whether to search for an induced
+    subgraph. It is \code{FALSE} by default.}
+  \item{time.limit}{The processor time limit for the computation, in
+    seconds. It defaults to \code{Inf}, which means no limit.}
+}
+}
+
+\section{\sQuote{vf2} method}{
+
+This method uses the VF2 algorithm by Cordella, Foggia et al., see
+references below. It supports vertex and edge colors and have the
+following extra arguments:
+\describe{
+  \item{vertex.color1, vertex.color2}{Optional integer vectors giving the
+    colors of the vertices for colored graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} vertex attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments. See also examples
+    below.}
+  \item{edge.color1, edge.color2}{Optional integer vectors giving the
+    colors of the edges for edge-colored (sub)graph isomorphism. If they
+    are not given, but the graph has a \dQuote{color} edge attribute,
+    then it will be used. If you want to ignore these attributes, then
+    supply \code{NULL} for both of these arguments.}
+}
+}
+\seealso{
+Other graph isomorphism: \code{\link{count_isomorphisms}},
+  \code{\link{graph.count.isomorphisms.vf2}};
+  \code{\link{count_subgraph_isomorphisms}},
+  \code{\link{graph.count.subisomorphisms.vf2}};
+  \code{\link{graph.get.isomorphisms.vf2}},
+  \code{\link{isomorphisms}}; \code{\link{graph.isoclass}},
+  \code{\link{graph.isoclass.subgraph}},
+  \code{\link{isomorphism_class}};
+  \code{\link{graph.isocreate}},
+  \code{\link{graph_from_isomorphism_class}};
+  \code{\link{graph.isomorphic}},
+  \code{\link{graph.isomorphic.34}},
+  \code{\link{graph.isomorphic.bliss}},
+  \code{\link{graph.isomorphic.vf2}},
+  \code{\link{is_isomorphic_to}}, \code{\link{isomorphic}};
+  \code{\link{graph.subisomorphic.lad}},
+  \code{\link{graph.subisomorphic.vf2}},
+  \code{\link{is_subgraph_isomorphic_to}},
+  \code{\link{subgraph_isomorphic}}
+}
+
diff --git a/man/tail_of.Rd b/man/tail_of.Rd
new file mode 100644
index 0000000..8c1063b
--- /dev/null
+++ b/man/tail_of.Rd
@@ -0,0 +1,34 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/basic.R
+\name{tail_of}
+\alias{tail_of}
+\title{Tails of the edge(s) in a graph}
+\usage{
+tail_of(graph, es)
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{es}{The edges to query.}
+}
+\value{
+A vertex sequence with the tail(s) of the edge(s).
+}
+\description{
+For undirected graphs, head and tail is not defined.  In this case
+\code{tail_of} returns vertices incident to the supplied edges, and
+\code{head_of} returns the other end(s) of the edge(s).
+}
+\seealso{
+Other structural queries: \code{\link{[.igraph}};
+  \code{\link{[[.igraph}}; \code{\link{adjacent_vertices}};
+  \code{\link{are.connected}}, \code{\link{are_adjacent}};
+  \code{\link{ecount}}, \code{\link{gsize}};
+  \code{\link{ends}}, \code{\link{get.edge}},
+  \code{\link{get.edges}}; \code{\link{get.edge.ids}};
+  \code{\link{gorder}}, \code{\link{vcount}};
+  \code{\link{head_of}}; \code{\link{incident_edges}};
+  \code{\link{incident}}; \code{\link{is.directed}},
+  \code{\link{is_directed}}; \code{\link{neighbors}}
+}
+
diff --git a/man/tkigraph.Rd b/man/tkigraph.Rd
index 0414720..57b8d2b 100644
--- a/man/tkigraph.Rd
+++ b/man/tkigraph.Rd
@@ -1,20 +1,27 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/socnet.R
 \name{tkigraph}
 \alias{tkigraph}
-\concept{GUI}
 \title{Experimental basic igraph GUI}
-\description{This functions starts an experimental GUI to some igraph
-  functions. The GUI was written in Tcl/Tk, so it is cross platform.}
 \usage{
 tkigraph()
 }
-%\arguments{}
+\value{
+Returns \code{NULL}, invisibly.
+}
+\description{
+This functions starts an experimental GUI to some igraph functions. The GUI
+was written in Tcl/Tk, so it is cross platform.
+}
 \details{
-  \code{tkigraph} has its own online help system, please see that for
-  the details about how to use it.
+\code{tkigraph} has its own online help system, please see that for the
+details about how to use it.
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{tkplot}} for interactive plotting of graphs.
 }
-\value{Returns \code{NULL}, invisibly.}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
-\seealso{\code{\link{tkplot}} for interactive plotting of graphs.}
-% \examples{}
 \keyword{graphs}
+
diff --git a/man/tkplot.Rd b/man/tkplot.Rd
index 21d5128..158b317 100644
--- a/man/tkplot.Rd
+++ b/man/tkplot.Rd
@@ -1,167 +1,199 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/tkplot.R
 \name{tkplot}
+\alias{tk_canvas}
+\alias{tk_center}
+\alias{tk_close}
+\alias{tk_coords}
+\alias{tk_fit}
+\alias{tk_off}
+\alias{tk_postscript}
+\alias{tk_reshape}
+\alias{tk_rotate}
+\alias{tk_set_coords}
 \alias{tkplot}
+\alias{tkplot.canvas}
+\alias{tkplot.center}
 \alias{tkplot.close}
-\alias{tkplot.off}
-\alias{tkplot.fit.to.screen}
-\alias{tkplot.reshape}
 \alias{tkplot.export.postscript}
-\alias{tkplot.canvas}
+\alias{tkplot.fit.to.screen}
 \alias{tkplot.getcoords}
-\alias{tkplot.setcoords}
-\alias{tkplot.center}
+\alias{tkplot.off}
+\alias{tkplot.reshape}
 \alias{tkplot.rotate}
-\concept{Visualization}
+\alias{tkplot.setcoords}
 \title{Interactive plotting of graphs}
-\description{\code{tkplot} and its companion functions serve as an
-  interactive graph drawing facility. Not all parameters of the plot can
-  be changed interactively right now though, eg. the colors of vertices,
-  edges, and also others have to be pre-defined.}
 \usage{
-tkplot(graph, canvas.width=450, canvas.height=450, \dots)
-
-tkplot.close(tkp.id, window.close = TRUE) 
-tkplot.off()
-tkplot.fit.to.screen(tkp.id, width = NULL, height = NULL)
-tkplot.reshape(tkp.id, newlayout, \dots)
-tkplot.export.postscript(tkp.id)
-tkplot.canvas(tkp.id)
-tkplot.getcoords(tkp.id, norm = FALSE)
-tkplot.setcoords(tkp.id, coords)
-tkplot.center(tkp.id)
-tkplot.rotate(tkp.id, degree = NULL, rad = NULL)
+tkplot(graph, canvas.width = 450, canvas.height = 450, ...)
+
+tk_close(tkp.id, window.close = TRUE)
+
+tk_off()
+
+tk_fit(tkp.id, width = NULL, height = NULL)
+
+tk_center(tkp.id)
+
+tk_reshape(tkp.id, newlayout, ..., params)
+
+tk_postscript(tkp.id)
+
+tk_coords(tkp.id, norm = FALSE)
+
+tk_set_coords(tkp.id, coords)
+
+tk_rotate(tkp.id, degree = NULL, rad = NULL)
+
+tk_canvas(tkp.id)
 }
 \arguments{
-  \item{graph}{The \code{graph} to plot.}
-  \item{canvas.width,canvas.height}{The size of the tkplot
-    drawing area.}
-  \item{tkp.id}{The id of the tkplot window to close/reshape/etc.}
-  \item{window.close}{Leave this on the default value.}
-  \item{width}{The width of the rectangle for generating new
-    coordinates.}
-  \item{height}{The height of the rectangle for generating new
-    coordinates.}
-  \item{newlayout}{The new layout, see the \code{layout} parameter of
-    tkplot.}
-  \item{norm}{Logical, should we norm the coordinates.}
-  \item{coords}{Two-column numeric matrix, the new coordinates
-    of the vertices, in absolute coordinates.}
-  \item{degree}{The degree to rotate the plot.}
-  \item{rad}{The degree to rotate the plot, in radian.}
-  \item{\dots}{Additional plotting parameters. See
-    \link{igraph.plotting} for the complete list.}
-}
-\details{
-  \code{tkplot} is an interactive graph drawing facility. It is not very
-  well developed at this stage, but it should be still useful.
-
-  It's handling should be quite straightforward most of the time, here
-  are some remarks and hints.
-
-  There are different popup menus, activated by the right mouse button,
-  for vertices and edges. Both operate on the current selection if the
-  vertex/edge under the cursor is part of the selection and operate on
-  the vertex/edge under the cursor if it is not.
-
-  One selection can be active at a time, either a vertex or an edge
-  selection. A vertex/edge can be added to a selection by holding the
-  \code{control} key while clicking on it with the left mouse
-  button. Doing this again deselect the vertex/edge.
-
-  Selections can be made also from the \code{Select} menu. The `Select
-  some vertices' dialog allows to give an expression for the vertices to
-  be selected: this can be a list of numeric R expessions separated by
-  commas, like `\code{1,2:10,12,14,15}' for example. Similarly in the
-  `Select some edges' dialog two such lists can be given and all edges
-  connecting a vertex in the first list to one in the second list will
-  be selected.
-
-  In the color dialog a color name like 'orange' or RGB notation can
-  also be used.
-
-  The \code{tkplot} command creates a new Tk window with the graphical
-  representation of \code{graph}. The command returns an integer number,
-  the tkplot id. The other commands utilize this id to be able to
-  query or manipulate the plot.
-
-  \code{tkplot.close} closes the Tk plot with id \code{tkp.id}.
-
-  \code{tkplot.off} closes all Tk plots.
-
-  \code{tkplot.fit.to.screen} fits the plot to the given rectange
-  (\code{width} and \code{height}), if some of these are \code{NULL}
-  the actual phisical width od height of the plot window is used.
-
-  \code{tkplot.reshape} applies a new layout to the plot, its optional
-  parameters will be collected to a list analogous to \code{layout.par}.
-
-  \code{tkplot.export.postscript} creates a dialog window for saving the
-  plot in postscript format.
-
-  \code{tkplot.canvas} returns the Tk canvas object that belongs to a
-  graph plot. The canvas can be directly manipulated then, eg. labels
-  can be added, it could be saved to a file programatically, etc. See an
-  example below.
-  
-  \code{tkplot.getcoords} returns the coordinates of the vertices in a
-  matrix. Each row corresponds to one vertex.
-
-  \code{tkplot.setcoords} sets the coordinates of the vertices. A
-  two-column matrix specifies the new positions, with each row
-  corresponding to a single vertex.
-  
-  \code{tkplot.center} shifts the figure to the center of its plot window.
-
-  \code{tkplot.rotate} rotates the figure, its parameter can be given
-  either in degrees or in radians.
+\item{graph}{The \code{graph} to plot.}
+
+\item{canvas.width,canvas.height}{The size of the tkplot drawing area.}
+
+\item{tkp.id}{The id of the tkplot window to close/reshape/etc.}
+
+\item{window.close}{Leave this on the default value.}
+
+\item{width}{The width of the rectangle for generating new coordinates.}
+
+\item{height}{The height of the rectangle for generating new coordinates.}
+
+\item{newlayout}{The new layout, see the \code{layout} parameter of tkplot.}
+
+\item{params}{Extra parameters in a list, to pass to the layout function.}
+
+\item{norm}{Logical, should we norm the coordinates.}
+
+\item{coords}{Two-column numeric matrix, the new coordinates of the
+vertices, in absolute coordinates.}
+
+\item{degree}{The degree to rotate the plot.}
+
+\item{rad}{The degree to rotate the plot, in radian.}
+
+\item{\dots}{Additional plotting parameters. See \link{igraph.plotting} for
+the complete list.}
 }
 \value{
-  \code{tkplot} returns an integer, the id of the plot, this can be used
-  to manipulate it from the command line.
+\code{tkplot} returns an integer, the id of the plot, this can be
+used to manipulate it from the command line.
 
-  \code{tkplot.canvas} retuns \code{tkwin} object, the Tk canvas.
-  
-  \code{tkplot.getcoords} returns a matrix with the coordinates.
+\code{tk_canvas} retuns \code{tkwin} object, the Tk canvas.
 
-  \code{tkplot.close}, \code{tkplot.off}, \code{tkplot.fit.to.screen},
-  \code{tkplot.reshape}, \code{tkplot.export.postscript},
-  \code{tkplot.center} and \code{tkplot.rotate} return \code{NULL}
-  invisibly. 
+\code{tk_coords} returns a matrix with the coordinates.
+
+\code{tk_close}, \code{tk_off}, \code{tk_fit},
+\code{tk_reshape}, \code{tk_postscript}, \code{tk_center}
+and \code{tk_rotate} return \code{NULL} invisibly.
+}
+\description{
+\code{tkplot} and its companion functions serve as an interactive graph
+drawing facility. Not all parameters of the plot can be changed
+interactively right now though, eg. the colors of vertices, edges, and also
+others have to be pre-defined.
+}
+\details{
+\code{tkplot} is an interactive graph drawing facility. It is not very well
+developed at this stage, but it should be still useful.
+
+It's handling should be quite straightforward most of the time, here are
+some remarks and hints.
+
+There are different popup menus, activated by the right mouse button, for
+vertices and edges. Both operate on the current selection if the vertex/edge
+under the cursor is part of the selection and operate on the vertex/edge
+under the cursor if it is not.
+
+One selection can be active at a time, either a vertex or an edge selection.
+A vertex/edge can be added to a selection by holding the \code{control} key
+while clicking on it with the left mouse button. Doing this again deselect
+the vertex/edge.
+
+Selections can be made also from the \code{Select} menu. The `Select some
+vertices' dialog allows to give an expression for the vertices to be
+selected: this can be a list of numeric R expessions separated by commas,
+like `\code{1,2:10,12,14,15}' for example. Similarly in the `Select some
+edges' dialog two such lists can be given and all edges connecting a vertex
+in the first list to one in the second list will be selected.
+
+In the color dialog a color name like 'orange' or RGB notation can also be
+used.
+
+The \code{tkplot} command creates a new Tk window with the graphical
+representation of \code{graph}. The command returns an integer number, the
+tkplot id. The other commands utilize this id to be able to query or
+manipulate the plot.
+
+\code{tk_close} closes the Tk plot with id \code{tkp.id}.
+
+\code{tk_off} closes all Tk plots.
+
+\code{tk_fit} fits the plot to the given rectange
+(\code{width} and \code{height}), if some of these are \code{NULL} the
+actual phisical width od height of the plot window is used.
+
+\code{tk_reshape} applies a new layout to the plot, its optional
+parameters will be collected to a list analogous to \code{layout.par}.
+
+\code{tk_postscript} creates a dialog window for saving the plot
+in postscript format.
+
+\code{tk_canvas} returns the Tk canvas object that belongs to a graph
+plot. The canvas can be directly manipulated then, eg. labels can be added,
+it could be saved to a file programatically, etc. See an example below.
+
+\code{tk_coords} returns the coordinates of the vertices in a matrix.
+Each row corresponds to one vertex.
+
+\code{tk_set_coords} sets the coordinates of the vertices. A two-column
+matrix specifies the new positions, with each row corresponding to a single
+vertex.
+
+\code{tk_center} shifts the figure to the center of its plot window.
+
+\code{tk_rotate} rotates the figure, its parameter can be given either
+in degrees or in radians.
 }
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{plot.igraph}}, \code{\link{layout}}}
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 \dontrun{tkplot(g)}
 
 \dontrun{
 ## Saving a tkplot() to a file programatically
-g <- graph.star(10, center=10) \%u\% graph.ring(9, directed=TRUE)
+g <- make_star(10, center=10) \%u\% make_ring(9, directed=TRUE)
 E(g)$width <- sample(1:10, ecount(g), replace=TRUE)
-lay <- layout.auto(g)
+lay <- layout_nicely(g)
 
 id <- tkplot(g, layout=lay)
-canvas <- tkplot.canvas(id)
+canvas <- tk_canvas(id)
 tkpostscript(canvas, file="/tmp/output.eps")
-tkplot.close(id)
+tk_close(id)
 }
 
 \dontrun{
 ## Setting the coordinates and adding a title label
-g <- graph.ring(10)
-id <- tkplot(graph.ring(10), canvas.width=450, canvas.height=500)
+g <- make_ring(10)
+id <- tkplot(make_ring(10), canvas.width=450, canvas.height=500)
 
-canvas <- tkplot.canvas(id)
+canvas <- tk_canvas(id)
 padding <- 20
-coords <- layout.norm(layout.circle(g), 0+padding, 450-padding,
+coords <- norm_coords(layout_in_circle(g), 0+padding, 450-padding,
                       50+padding, 500-padding)
-tkplot.setcoords(id, coords)
+tk_set_coords(id, coords)
 
 width <- as.numeric(tkcget(canvas, "-width"))
 height <- as.numeric(tkcget(canvas, "-height"))
 tkcreate(canvas, "text", width/2, 25, text="My title",
-         justify="center", font=tkfont.create(family="helvetica"
+         justify="center", font=tcltk::tkfont.create(family="helvetica"
                              ,size=20,weight="bold"))
 }
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{plot.igraph}}, \code{\link{layout}}
+}
 \keyword{graphs}
+
diff --git a/man/topo_sort.Rd b/man/topo_sort.Rd
new file mode 100644
index 0000000..a57febd
--- /dev/null
+++ b/man/topo_sort.Rd
@@ -0,0 +1,42 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{topo_sort}
+\alias{topo_sort}
+\alias{topological.sort}
+\title{Topological sorting of vertices in a graph}
+\usage{
+topo_sort(graph, mode = c("out", "all", "in"))
+}
+\arguments{
+\item{graph}{The input graph, should be directed}
+
+\item{mode}{Specifies how to use the direction of the edges.  For
+\dQuote{\code{out}}, the sorting order ensures that each node comes before
+all nodes to which it has edges, so nodes with no incoming edges go first.
+For \dQuote{\code{in}}, it is quite the opposite: each node comes before all
+nodes from which it receives edges. Nodes with no outgoing edges go first.}
+}
+\value{
+A numeric vector containing vertex ids in topologically sorted
+order.
+}
+\description{
+A topological sorting of a directed acyclic graph is a linear ordering of
+its nodes where each node comes before all nodes to which it has edges.
+}
+\details{
+Every DAG has at least one topological sort, and may have many.  This
+function returns a possible topological sort among them. If the graph is not
+acyclic (it has at least one cycle), a partial topological sort is returned
+and a warning is issued.
+}
+\examples{
+g <- barabasi.game(100)
+topo_sort(g)
+}
+\author{
+Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
+\email{csardi.gabor at gmail.com} for the R interface
+}
+\keyword{graphs}
+
diff --git a/man/topological.sort.Rd b/man/topological.sort.Rd
deleted file mode 100644
index 2c72a53..0000000
--- a/man/topological.sort.Rd
+++ /dev/null
@@ -1,39 +0,0 @@
-\name{topological.sort}
-\alias{topological.sort}
-\concept{Topological sort}
-\title{Topological sorting of vertices in a graph}
-\description{
-  A topological sorting of a directed acyclic graph is a linear ordering
-  of its nodes where each node comes before all nodes to which it has
-  edges. 
-}
-\usage{
-topological.sort(graph, mode=c("out", "all", "in"))
-}
-\arguments{
-  \item{graph}{The input graph, should be directed}
-  \item{mode}{Specifies how to use the direction of the edges.
-    For \dQuote{\code{out}}, the sorting order ensures that each node comes
-    before all nodes to which it has edges, so nodes with no incoming
-    edges go first. For \dQuote{\code{in}}, it is quite the opposite: each
-    node comes before all nodes from which it receives edges. Nodes 
-    with no outgoing edges go first.}
-}
-\details{
-  Every DAG has at least one topological sort, and may have many.
-  This function returns a possible topological sort among them. If the
-  graph is not acyclic (it has at least one cycle), a partial topological
-  sort is returned and a warning is issued.}
-\value{
-  A numeric vector containing vertex ids in topologically sorted order.
-}
-%\references{
-%}
-\author{Tamas Nepusz \email{ntamas at gmail.com} and Gabor Csardi
-  \email{csardi.gabor at gmail.com} for the R interface} 
-%\seealso{}
-\examples{
-g <- barabasi.game(100)
-topological.sort(g)
-}
-\keyword{graphs}
diff --git a/man/traits.Rd b/man/traits.Rd
deleted file mode 100644
index ca3cd12..0000000
--- a/man/traits.Rd
+++ /dev/null
@@ -1,53 +0,0 @@
-\name{traits}
-\alias{callaway.traits.game}
-\alias{establishment.game}
-\title{Graph generation based on different vertex types}
-\description{These functions implement evolving network models based on
-  different vertex types.
-}
-\usage{
-callaway.traits.game (nodes, types, edge.per.step = 1, type.dist = rep(1, 
-    types), pref.matrix = matrix(1, types, types), directed = FALSE)
-establishment.game(nodes, types, k = 1, type.dist = rep(1, types),
-    pref.matrix = matrix(1, types, types), directed = FALSE)
-}
-\arguments{
-  \item{nodes}{The number of vertices in the graph.}
-  \item{types}{The number of different vertex types.}
-  \item{edge.per.step}{The number of edges to add to the graph per time step.}
-  \item{type.dist}{The distribution of the vertex types. This is assumed
-    to be stationary in time.}
-  \item{pref.matrix}{A matrix giving the preferences of the given vertex
-    types. These should be probabilities, ie. numbers between zero and
-    one.}
-  \item{directed}{Logical constant, whether to generate directed
-    graphs.}
-  \item{k}{The number of trials per time step, see details below.}
-}
-\details{
-  For \code{callaway.traits.game} the simulation goes like this: in each
-  discrete time step a new vertex is added to the graph. The type of
-  this vertex is generated based on \code{type.dist}. Then two vertices are
-  selected uniformly randomly from the graph. The probability that they
-  will be connected depends on the types of these vertices and is taken
-  from \code{pref.matrix}. Then another two vertices are selected and
-  this is repeated \code{edges.per.step} times in each time step.
-
-  For \code{establishment.game} the simulation goes like this: a single
-  vertex is added at each time step. This new vertex tries to connect to
-  \code{k} vertices in the graph. The probability that such a connection is
-  realized depends on the types of the vertices involved and is taken
-  from \code{pref.matrix}.
-}
-\value{
-  A new graph object.
-}
-% \references{}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-# two types of vertices, they like only themselves
-g1 <- callaway.traits.game(1000, 2, pref.matrix=matrix( c(1,0,0,1), nc=2))
-g2 <- establishment.game(1000, 2, k=2, pref.matrix=matrix( c(1,0,0,1), nc=2))
-}
-\keyword{graphs}
diff --git a/man/transitivity.Rd b/man/transitivity.Rd
index 47494da..d7c7399 100644
--- a/man/transitivity.Rd
+++ b/man/transitivity.Rd
@@ -1,124 +1,115 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
 \name{transitivity}
 \alias{transitivity}
-\concept{Transitivity}
-\concept{Clustering coefficient}
 \title{Transitivity of a graph}
-\description{Transitivity measures the probability that the adjacent
-  vertices of a vertex are connected. This is sometimes also called the
-  clustering coefficient. }
 \usage{
-transitivity(graph, type=c("undirected", "global", "globalundirected",
-       "localundirected", "local", "average", "localaverage",
-       "localaverageundirected", "barrat", "weighted"), vids=NULL,
-       weights=NULL, isolates=c("NaN", "zero"))
+transitivity(graph, type = c("undirected", "global", "globalundirected",
+  "localundirected", "local", "average", "localaverage",
+  "localaverageundirected", "barrat", "weighted"), vids = NULL,
+  weights = NULL, isolates = c("NaN", "zero"))
 }
 \arguments{
-  \item{graph}{The graph to analyze.}
-  \item{type}{The type of the transitivity to calculate. Possible
-    values:
-    \describe{
-      \item{\code{global}}{The global transitivity of an
-	undirected graph (directed graphs are considered as undirected ones
-	as well). This is simply the ratio of the triangles and the
-	connected triples in the graph. For directed graph the direction
-	of the edges is ignored. }
-      \item{\code{local}}{The local transitivity of an undirected graph,
-	this is calculated for each vertex given in the \code{vids}
-	argument. The local transitivity of a vertex is the ratio of the
-	triangles connected to the vertex and the triples centered on
-	the vertex. For directed graph the direction of the edges is
-	ignored. }
-      \item{\code{undirected}}{This is the same as \code{global}.}
-      \item{\code{globalundirected}}{This is the same as \code{global}.}
-      \item{\code{localundirected}}{This is the same as \code{local}.}
-      \item{\code{barrat}}{The weighted transitivity as defined
-	A. Barrat. See details below.}
-      \item{\code{weighted}}{The same as \code{barrat}.}
-    }
-  }
-  \item{vids}{The vertex ids for the local transitivity will be
-    calculated. This will be ignored for global transitivity types.
-    The default value is \code{NULL}, in this case all vertices are
-    considered. It is slightly faster to supply \code{NULL} here than
-    \code{V(graph)}.    
-  }
-  \item{weights}{Optional weights for weighted transitivity. It is
-    ignored for other transitivity measures. If it is \code{NULL} (the
-    default) and the graph has a \code{weight} edge attribute, then it
-    is used automatically.
-  }
-  \item{isolates}{Character scalar, defines how to treat vertices with
-    degree zero and one. If it is \sQuote{\code{NaN}} then they local
-    transitivity is reported as \code{NaN} and they are not included in
-    the averaging, for the transitivity types that calculate an
-    average. If there are no vertices with degree
-    two or higher, then the averaging will still result \code{NaN}. If
-    it is \sQuote{\code{zero}}, then we report 0 transitivity for them,
-    and they are included in the averaging, if an average is
-    calculated.
-  }
-}
-\details{
-   Note that there are essentially two classes of transitivity measures,
-   one is a vertex-level, the other a graph level property.
+\item{graph}{The graph to analyze.}
 
-   There are several generalizations of transitivity to weighted graphs,
-   here we use the definition by A. Barrat, this is a local vertex-level
-   quantity, its formula is
+\item{type}{The type of the transitivity to calculate. Possible values:
+\describe{ \item{"global"}{The global transitivity of an undirected
+graph (directed graphs are considered as undirected ones as well). This is
+simply the ratio of the triangles and the connected triples in the graph.
+For directed graph the direction of the edges is ignored. }
+\item{"local"}{The local transitivity of an undirected graph, this is
+calculated for each vertex given in the \code{vids} argument. The local
+transitivity of a vertex is the ratio of the triangles connected to the
+vertex and the triples centered on the vertex. For directed graph the
+direction of the edges is ignored. } \item{"undirected"}{This is the
+same as \code{global}.} \item{"globalundirected"}{This is the same as
+\code{global}.} \item{"localundirected"}{This is the same as
+\code{local}.} \item{"barrat"}{The weighted transitivity as defined A.
+Barrat. See details below.} \item{"weighted"}{The same as
+\code{barrat}.} }}
 
-   \deqn{C_i^w=\frac{1}{s_i(k_i-1)}\sum_{j,h}\frac{w_{ij}+w_{ih}}{2}a_{ij}a_{ih}a_{jh}}{
-     weighted C_i = 1/s_i 1/(k_i-1) sum( (w_ij+w_ih)/2 a_ij a_ih a_jh, j, h)}
+\item{vids}{The vertex ids for the local transitivity will be calculated.
+This will be ignored for global transitivity types.  The default value is
+\code{NULL}, in this case all vertices are considered. It is slightly faster
+to supply \code{NULL} here than \code{V(graph)}.}
 
-   \eqn{s_i}{s_i} is the strength of vertex \eqn{i}{i}, see
-   \code{\link{graph.strength}}, \eqn{a_{ij}}{a_ij} are elements of the
-   adjacency matrix, \eqn{k_i}{k_i} is the vertex degree,
-   \eqn{w_{ij}}{w_ij} are the weights.
-   
-   This formula gives back the normal not-weighted local transitivity if
-   all the edge weights are the same.
+\item{weights}{Optional weights for weighted transitivity. It is ignored for
+other transitivity measures. If it is \code{NULL} (the default) and the
+graph has a \code{weight} edge attribute, then it is used automatically.}
 
-   The \code{barrat} type of transitivity does not work for graphs with
-   multiple and/or loop edges. If you want to calculate it for a
-   directed graph, call \code{\link{as.undirected}} with the
-   \code{collapse} mode first.
+\item{isolates}{Character scalar, defines how to treat vertices with degree
+zero and one. If it is \sQuote{\code{NaN}} then they local transitivity is
+reported as \code{NaN} and they are not included in the averaging, for the
+transitivity types that calculate an average. If there are no vertices with
+degree two or higher, then the averaging will still result \code{NaN}. If it
+is \sQuote{\code{zero}}, then we report 0 transitivity for them, and they
+are included in the averaging, if an average is calculated.}
 }
 \value{
-  For \sQuote{\code{global}} a single number, or \code{NaN} if there are no
-  connected triples in the graph.
+For \sQuote{\code{global}} a single number, or \code{NaN} if there
+are no connected triples in the graph.
 
-  For \sQuote{\code{local}} a vector of transitivity scores, one for
-  each vertex in \sQuote{\code{vids}}.
+For \sQuote{\code{local}} a vector of transitivity scores, one for each
+vertex in \sQuote{\code{vids}}.
+}
+\description{
+Transitivity measures the probability that the adjacent vertices of a vertex
+are connected. This is sometimes also called the clustering coefficient.
 }
-\references{ Wasserman, S., and Faust, K. (1994). \emph{Social Network
-    Analysis: Methods and Applications.} Cambridge: Cambridge University
-  Press.
+\details{
+Note that there are essentially two classes of transitivity measures, one is
+a vertex-level, the other a graph level property.
+
+There are several generalizations of transitivity to weighted graphs, here
+we use the definition by A. Barrat, this is a local vertex-level quantity,
+its formula is
+
+\deqn{C_i^w=\frac{1}{s_i(k_i-1)}\sum_{j,h}\frac{w_{ij}+w_{ih}}{2}a_{ij}a_{ih}a_{jh}}{
+weighted C_i = 1/s_i 1/(k_i-1) sum( (w_ij+w_ih)/2 a_ij a_ih a_jh, j, h)}
 
-  Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras, Alessandro
-  Vespignani: The architecture of complex weighted networks,
-  Proc. Natl. Acad. Sci. USA 101, 3747 (2004)
+\eqn{s_i}{s_i} is the strength of vertex \eqn{i}{i}, see
+\code{\link{strength}}, \eqn{a_{ij}}{a_ij} are elements of the
+adjacency matrix, \eqn{k_i}{k_i} is the vertex degree, \eqn{w_{ij}}{w_ij}
+are the weights.
+
+This formula gives back the normal not-weighted local transitivity if all
+the edge weights are the same.
+
+The \code{barrat} type of transitivity does not work for graphs with
+multiple and/or loop edges. If you want to calculate it for a directed
+graph, call \code{\link{as.undirected}} with the \code{collapse} mode first.
 }
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 transitivity(g)
-g2 <- erdos.renyi.game(1000, 10/1000)
+g2 <- sample_gnp(1000, 10/1000)
 transitivity(g2)   # this is about 10/1000
 
 # Weighted version, the figure from the Barrat paper
-gw <- graph.formula(A-B:C:D:E, B-C:D, C-D)
+gw <- graph_from_literal(A-B:C:D:E, B-C:D, C-D)
 E(gw)$weight <- 1
 E(gw)[ V(gw)[name == "A"] \%--\% V(gw)[name == "E" ] ]$weight <- 5
 transitivity(gw, vids="A", type="local")
 transitivity(gw, vids="A", type="weighted")
 
 # Weighted reduces to "local" if weights are the same
-gw2 <- erdos.renyi.game(1000, 10/1000)
+gw2 <- sample_gnp(1000, 10/1000)
 E(gw2)$weight <- 1
 t1 <- transitivity(gw2, type="local")
 t2 <- transitivity(gw2, type="weighted")
 all(is.na(t1) == is.na(t2))
 all(na.omit(t1 == t2))
 }
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Wasserman, S., and Faust, K. (1994). \emph{Social Network
+Analysis: Methods and Applications.} Cambridge: Cambridge University Press.
+
+Alain Barrat, Marc Barthelemy, Romualdo Pastor-Satorras, Alessandro
+Vespignani: The architecture of complex weighted networks, Proc. Natl. Acad.
+Sci. USA 101, 3747 (2004)
+}
 \keyword{graphs}
 
diff --git a/man/triad.census.Rd b/man/triad.census.Rd
deleted file mode 100644
index da3f215..0000000
--- a/man/triad.census.Rd
+++ /dev/null
@@ -1,56 +0,0 @@
-\name{triad.census}
-\alias{triad.census}
-\concept{Triad census}
-\title{Triad census, subgraphs with three vertices}
-\description{This function counts the different subgraphs of three
-  vertices in a graph.}
-\usage{
-triad.census(graph)
-}
-\arguments{
-  \item{graph}{The input graph, it should be directed. An undirected
-    graph results a warning, and undefined results.}
-}
-\details{
-  Triad census was defined by David and Leinhardt (see References
-  below). Every triple of vertices (A, B, C) are classified into the 16
-  possible states:
-  \describe{
-    \item{003}{A,B,C, the empty graph.}
-    \item{012}{A->B, C, the graph with a single directed edge.}
-    \item{102}{A<->B, C, the graph with a mutual connection between two
-      vertices.}
-    \item{021D}{A<-B->C, the out-star.}
-    \item{021U}{A->B<-C, the in-star.}
-    \item{021C}{A->B->C, directed line.}
-    \item{111D}{A<->B<-C.}
-    \item{111U}{A<->B->C.}
-    \item{030T}{A->B<-C, A->C.}
-    \item{030C}{A<-B<-C, A->C.}
-    \item{201}{A<->B<->C.}
-    \item{120D}{A<-B->C, A<->C.}
-    \item{120U}{A->B<-C, A<->C.}
-    \item{120C}{A->B->C, A<->C.}
-    \item{210}{A->B<->C, A<->C.}
-    \item{300}{A<->B<->C, A<->C, the complete graph.}
-  }
-
-  This functions uses the RANDESU motif finder algorithm to find and
-  count the subgraphs, see \code{\link{graph.motifs}}. 
-}
-\value{A numeric vector, the subgraph counts, in the order given in the
-  above description.}
-\references{
-  See also Davis, J.A. and Leinhardt, S.  (1972).  The Structure of
-  Positive Interpersonal Relations in Small Groups.  In J. Berger
-  (Ed.), Sociological Theories in Progress, Volume 2, 218-251. 
-  Boston: Houghton Mifflin.
-}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{dyad.census}} for classifying binary relationships,
-  \code{\link{graph.motifs}} for the underlying implementation.}
-\examples{
-g <- erdos.renyi.game(15, 45, type="gnm", dir=TRUE)
-triad.census(g)
-}
-\keyword{graphs}
diff --git a/man/triad_census.Rd b/man/triad_census.Rd
new file mode 100644
index 0000000..287e287
--- /dev/null
+++ b/man/triad_census.Rd
@@ -0,0 +1,55 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/motifs.R
+\name{triad_census}
+\alias{triad.census}
+\alias{triad_census}
+\title{Triad census, subgraphs with three vertices}
+\usage{
+triad_census(graph)
+}
+\arguments{
+\item{graph}{The input graph, it should be directed. An undirected graph
+results a warning, and undefined results.}
+}
+\value{
+A numeric vector, the subgraph counts, in the order given in the
+above description.
+}
+\description{
+This function counts the different subgraphs of three vertices in a graph.
+}
+\details{
+Triad census was defined by David and Leinhardt (see References below).
+Every triple of vertices (A, B, C) are classified into the 16 possible
+states: \describe{ \item{003}{A,B,C, the empty graph.} \item{012}{A->B, C,
+the graph with a single directed edge.} \item{102}{A<->B, C, the graph with
+a mutual connection between two vertices.} \item{021D}{A<-B->C, the
+out-star.} \item{021U}{A->B<-C, the in-star.} \item{021C}{A->B->C, directed
+line.} \item{111D}{A<->B<-C.} \item{111U}{A<->B->C.} \item{030T}{A->B<-C,
+A->C.} \item{030C}{A<-B<-C, A->C.} \item{201}{A<->B<->C.}
+\item{120D}{A<-B->C, A<->C.} \item{120U}{A->B<-C, A<->C.}
+\item{120C}{A->B->C, A<->C.} \item{210}{A->B<->C, A<->C.}
+\item{300}{A<->B<->C, A<->C, the complete graph.} }
+
+This functions uses the RANDESU motif finder algorithm to find and count the
+subgraphs, see \code{\link{motifs}}.
+}
+\examples{
+g <- sample_gnm(15, 45, directed = TRUE)
+triad_census(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+See also Davis, J.A. and Leinhardt, S.  (1972).  The Structure
+of Positive Interpersonal Relations in Small Groups.  In J. Berger (Ed.),
+Sociological Theories in Progress, Volume 2, 218-251.  Boston: Houghton
+Mifflin.
+}
+\seealso{
+\code{\link{dyad_census}} for classifying binary relationships,
+\code{\link{motifs}} for the underlying implementation.
+}
+\keyword{graphs}
+
diff --git a/man/undocumented.Rd b/man/undocumented.Rd
deleted file mode 100644
index a5ba9af..0000000
--- a/man/undocumented.Rd
+++ /dev/null
@@ -1,40 +0,0 @@
-\name{igraph.undocumented}
-\alias{cited.type.game}
-\alias{citing.cited.type.game}
-\alias{lastcit.game}
-\title{Undocumented and unsupportted igraph functions}
-\description{These functions are still in the alpha stage or
-  their arguments are expected to change, so they're not documented yet.
-  They are also not very useful for the general audience.
-}
-\usage{
-lastcit.game(n, edges=1, agebins=n/7100, pref=(1:(agebins+1))^-3,
-     directed=TRUE)
-cited.type.game(n, edges=1, types=rep(0, n),
-     pref=rep(1, length(types)),
-     directed=TRUE, attr=TRUE)
-citing.cited.type.game(n, edges=1, types=rep(0, n),
-    pref=matrix(1, nrow=length(types), ncol=length(types)),
-    directed=TRUE, attr=TRUE)
-}
-\arguments{
-  \item{n}{Number of vertices.}
-  \item{edges}{Number of edges per step.}
-  \item{agebins}{Number of aging bins.}
-  \item{pref}{Vector (\code{lastcit.game} and \code{cited.type.game} or
-    matrix (\code{citing.cited.type.game}) giving the (unnormalized)
-    citation probabilities for the different vertex types.} 
-  \item{directed}{Logical scalar, whether to generate directed
-    networks.}
-  \item{types}{Vector of length \sQuote{\code{n}}, the types of the
-    vertices. Types are numbered from zero.}
-  \item{attr}{Logical scalar, whether to add the vertex types to the
-    generated graph as a vertex attribute called \sQuote{\code{type}}. }
-}
-%\details{}
-\value{A new graph.}
-%\references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-%\seealso{}
-%\examples{}
-\keyword{graphs}
diff --git a/man/unfold.tree.Rd b/man/unfold.tree.Rd
deleted file mode 100644
index 6d288fd..0000000
--- a/man/unfold.tree.Rd
+++ /dev/null
@@ -1,48 +0,0 @@
-\name{unfold.tree}
-\alias{unfold.tree}
-\concept{Tree}
-\concept{Forest}
-\concept{Breadth-first search}
-\title{Convert a general graph into a forest}
-\description{
-Perform a breadth-first search on a graph and convert it into a tree or
-forest by replicating vertices that were found more than once.
-}
-\usage{
-unfold.tree(graph, mode = c("all", "out", "in", "total"), roots) 
-}
-\arguments{
-  \item{graph}{The input graph, it can be either directed or
-    undirected.}
-  \item{mode}{Character string, defined the types of the paths used for
-    the breadth-first search. \dQuote{out} follows the outgoing,
-    \dQuote{in} the incoming edges, \dQuote{all} and \dQuote{total} both
-    of them. This argument is ignored for undirected graphs.}
-  \item{roots}{A vector giving the vertices from which the breadth-first
-    search is performed. Typically it contains one vertex per component.}
-}
-\details{
-  A forest is a graph, whose components are trees.
-  
-  The \code{roots} vector can be calculated by simply doing a
-  topological sort in all components of the graph, see the examples
-  below.
-}
-\value{
-  A list with two components:
-  \item{tree}{The result, an \code{igraph} object, a tree or a forest.}
-  \item{vertex_index}{A numeric vector, it gives a mapping from the
-    vertices of the new graph to the vertices of the old graph.}
-}
-% \references{}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-% \seealso{}
-\examples{
-g <- graph.tree(10) %du% graph.tree(10)
-V(g)$id <- seq_len(vcount(g))-1
-roots <- sapply(decompose.graph(g), function(x) {
-            V(x)$id[ topological.sort(x)[1]+1 ] })
-tree <- unfold.tree(g, roots=roots)
-}
-\keyword{graphs}
-
diff --git a/man/unfold_tree.Rd b/man/unfold_tree.Rd
new file mode 100644
index 0000000..2666fca
--- /dev/null
+++ b/man/unfold_tree.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{unfold_tree}
+\alias{unfold.tree}
+\alias{unfold_tree}
+\title{Convert a general graph into a forest}
+\usage{
+unfold_tree(graph, mode = c("all", "out", "in", "total"), roots)
+}
+\arguments{
+\item{graph}{The input graph, it can be either directed or undirected.}
+
+\item{mode}{Character string, defined the types of the paths used for the
+breadth-first search. \dQuote{out} follows the outgoing, \dQuote{in} the
+incoming edges, \dQuote{all} and \dQuote{total} both of them. This argument
+is ignored for undirected graphs.}
+
+\item{roots}{A vector giving the vertices from which the breadth-first
+search is performed. Typically it contains one vertex per component.}
+}
+\value{
+A list with two components: \item{tree}{The result, an \code{igraph}
+object, a tree or a forest.} \item{vertex_index}{A numeric vector, it gives
+a mapping from the vertices of the new graph to the vertices of the old
+graph.}
+}
+\description{
+Perform a breadth-first search on a graph and convert it into a tree or
+forest by replicating vertices that were found more than once.
+}
+\details{
+A forest is a graph, whose components are trees.
+
+The \code{roots} vector can be calculated by simply doing a topological sort
+in all components of the graph, see the examples below.
+}
+\examples{
+g <- make_tree(10) \%du\% make_tree(10)
+V(g)$id <- seq_len(vcount(g))-1
+roots <- sapply(decompose(g), function(x) {
+            V(x)$id[ topo_sort(x)[1]+1 ] })
+tree <- unfold_tree(g, roots=roots)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/union.Rd b/man/union.Rd
new file mode 100644
index 0000000..ea69192
--- /dev/null
+++ b/man/union.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{union}
+\alias{union}
+\title{Union of two or more sets}
+\usage{
+union(...)
+}
+\arguments{
+\item{...}{Arguments, their number and interpretation depends on
+the function that implements \code{union}.}
+}
+\value{
+Depends on the function that implements this method.
+}
+\description{
+This is an S3 generic function. See \code{methods("union")}
+for the actual implementations for various S3 classes. Initially
+it is implemented for igraph graphs and igraph vertex and edge
+sequences. See
+\code{\link{union.igraph}}, and
+\code{\link{union.igraph.vs}}.
+}
+
diff --git a/man/union.igraph.Rd b/man/union.igraph.Rd
new file mode 100644
index 0000000..0ece324
--- /dev/null
+++ b/man/union.igraph.Rd
@@ -0,0 +1,59 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{union.igraph}
+\alias{\%u\%}
+\alias{graph.union}
+\alias{union.igraph}
+\title{Union of graphs}
+\usage{
+\method{union}{igraph}(..., byname = "auto")
+}
+\arguments{
+\item{byname}{A logical scalar, or the character scalar \code{auto}. Whether
+to perform the operation based on symbolic vertex names. If it is
+\code{auto}, that means \code{TRUE} if all graphs are named and \code{FALSE}
+otherwise. A warning is generated if \code{auto} and some (but not all)
+graphs are named.}
+
+\item{\dots}{Graph objects or lists of graph objects.}
+}
+\value{
+A new graph object.
+}
+\description{
+The union of two or more graphs are created. The graphs may have identical
+or overlapping vertex sets.
+}
+\details{
+\code{union} creates the union of two or more graphs.  Edges which are
+included in at least one graph will be part of the new graph. This function
+can be also used via the \%u\% operator.
+
+If the \code{byname} argument is \code{TRUE} (or \code{auto} and all graphs
+are named), then the operation is performed on symbolic vertex names instead
+of the internal numeric vertex ids.
+
+\code{union} keeps the attributes of all graphs. All graph, vertex and
+edge attributes are copied to the result. If an attribute is present in
+multiple graphs and would result a name clash, then this attribute is
+renamed by adding suffixes: _1, _2, etc.
+
+The \code{name} vertex attribute is treated specially if the operation is
+performed based on symbolic vertex names. In this case \code{name} must be
+present in all graphs, and it is not renamed in the result graph.
+
+An error is generated if some input graphs are directed and others are
+undirected.
+}
+\examples{
+## Union of two social networks with overlapping sets of actors
+net1 <- graph_from_literal(D-A:B:F:G, A-C-F-A, B-E-G-B, A-B, F-G,
+                  H-F:G, H-I-J)
+net2 <- graph_from_literal(D-A:F:Y, B-A-X-F-H-Z, F-Y)
+str(net1 \%u\% net2)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\keyword{graphs}
+
diff --git a/man/union.igraph.es.Rd b/man/union.igraph.es.Rd
new file mode 100644
index 0000000..6ddebab
--- /dev/null
+++ b/man/union.igraph.es.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{union.igraph.es}
+\alias{union.igraph.es}
+\title{Union of edge sequences}
+\usage{
+\method{union}{igraph.es}(...)
+}
+\arguments{
+\item{...}{The edge sequences to take the union of.}
+}
+\value{
+An edge sequence that contains all edges in the given
+sequences, exactly once.
+}
+\description{
+Union of edge sequences
+}
+\details{
+They must belong to the same graph. Note that this function has
+\sQuote{set} semantics and the multiplicity of edges is lost in the
+result. (This is to match the behavior of the based \code{unique}
+function.)
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+union(E(g)[1:6], E(g)[5:9], E(g)['A|J'])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/union.igraph.vs.Rd b/man/union.igraph.vs.Rd
new file mode 100644
index 0000000..59c13d8
--- /dev/null
+++ b/man/union.igraph.vs.Rd
@@ -0,0 +1,49 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{union.igraph.vs}
+\alias{union.igraph.vs}
+\title{Union of vertex sequences}
+\usage{
+\method{union}{igraph.vs}(...)
+}
+\arguments{
+\item{...}{The vertex sequences to take the union of.}
+}
+\value{
+A vertex sequence that contains all vertices in the given
+sequences, exactly once.
+}
+\description{
+Union of vertex sequences
+}
+\details{
+They must belong to the same graph. Note that this function has
+\sQuote{set} semantics and the multiplicity of vertices is lost in the
+result. (This is to match the behavior of the based \code{unique}
+function.)
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+union(V(g)[1:6], V(g)[5:10])
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{unique.igraph.es}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/unique.igraph.es.Rd b/man/unique.igraph.es.Rd
new file mode 100644
index 0000000..ca9ae9d
--- /dev/null
+++ b/man/unique.igraph.es.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{unique.igraph.es}
+\alias{unique.igraph.es}
+\title{Remove duplicate edges from an edge sequence}
+\usage{
+\method{unique}{igraph.es}(x, incomparables = FALSE, ...)
+}
+\arguments{
+\item{x}{An edge sequence.}
+
+\item{incomparables}{a vector of values that cannot be compared.
+Passed to base function \code{duplicated}. See details there.}
+
+\item{...}{Passed to base function \code{duplicated()}.}
+}
+\value{
+An edge sequence with the duplicate vertices removed.
+}
+\description{
+Remove duplicate edges from an edge sequence
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+E(g)[1, 1:5, 1:10, 5:10]
+E(g)[1, 1:5, 1:10, 5:10] \%>\% unique()
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.vs}}
+}
+
diff --git a/man/unique.igraph.vs.Rd b/man/unique.igraph.vs.Rd
new file mode 100644
index 0000000..eb64562
--- /dev/null
+++ b/man/unique.igraph.vs.Rd
@@ -0,0 +1,48 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/iterators.R
+\name{unique.igraph.vs}
+\alias{unique.igraph.vs}
+\title{Remove duplicate vertices from a vertex sequence}
+\usage{
+\method{unique}{igraph.vs}(x, incomparables = FALSE, ...)
+}
+\arguments{
+\item{x}{A vertex sequence.}
+
+\item{incomparables}{a vector of values that cannot be compared.
+Passed to base function \code{duplicated}. See details there.}
+
+\item{...}{Passed to base function \code{duplicated()}.}
+}
+\value{
+A vertex sequence with the duplicate vertices removed.
+}
+\description{
+Remove duplicate vertices from a vertex sequence
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10]))
+V(g)[1, 1:5, 1:10, 5:10]
+V(g)[1, 1:5, 1:10, 5:10] \%>\% unique()
+}
+\seealso{
+Other vertex and edge sequence operations: \code{\link{[.igraph.es}},
+  \code{\link{\%--\%}}, \code{\link{\%->\%}},
+  \code{\link{\%<-\%}}, \code{\link{igraph-es-indexing}};
+  \code{\link{[.igraph.vs}},
+  \code{\link{igraph-vs-indexing}};
+  \code{\link{[[.igraph.es}},
+  \code{\link{igraph-es-indexing2}};
+  \code{\link{[[.igraph.vs}},
+  \code{\link{igraph-vs-indexing2}};
+  \code{\link{c.igraph.es}}; \code{\link{c.igraph.vs}};
+  \code{\link{difference.igraph.es}};
+  \code{\link{difference.igraph.vs}};
+  \code{\link{intersection.igraph.es}};
+  \code{\link{intersection.igraph.vs}};
+  \code{\link{rev.igraph.es}}; \code{\link{rev.igraph.vs}};
+  \code{\link{union.igraph.es}};
+  \code{\link{union.igraph.vs}};
+  \code{\link{unique.igraph.es}}
+}
+
diff --git a/man/upgrade_graph.Rd b/man/upgrade_graph.Rd
new file mode 100644
index 0000000..d625285
--- /dev/null
+++ b/man/upgrade_graph.Rd
@@ -0,0 +1,32 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/versions.R
+\name{upgrade_graph}
+\alias{upgrade_graph}
+\title{Igraph data structure versions}
+\usage{
+upgrade_graph(graph)
+}
+\arguments{
+\item{graph}{The input graph.}
+}
+\value{
+The graph in the current format.
+}
+\description{
+Igraph's internal data representation changes sometimes between
+versions. This means that it is not possible to use igraph objects
+that were created (and possibly saved to a file) with an older
+igraph version.
+}
+\details{
+\code{\link{graph_version}} queries the current data format,
+or the data format of a possibly older igraph graph.
+
+\code{upgrade_graph} can convert an older data format
+to the current one.
+}
+\seealso{
+graph_version to check the current data format version
+or the version of a graph.
+}
+
diff --git a/man/vertex.Rd b/man/vertex.Rd
new file mode 100644
index 0000000..e6aa142
--- /dev/null
+++ b/man/vertex.Rd
@@ -0,0 +1,50 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/operators.R
+\name{vertex}
+\alias{vertex}
+\alias{vertices}
+\title{Helper function for adding and deleting vertices}
+\usage{
+vertex(...)
+
+vertices(...)
+}
+\arguments{
+\item{...}{See details below.}
+}
+\value{
+A special object that can be used with together with
+  igraph graphs and the plus and minus operators.
+}
+\description{
+This is a helper function that simplifies adding and deleting
+vertices to/from graphs.
+}
+\details{
+\code{vertices} is an alias for \code{vertex}.
+
+When adding vertices via \code{+}, all unnamed arguments are interpreted
+as vertex names of the new vertices. Named arguments are interpreted as
+vertex attributes for the new vertices.
+
+When deleting vertices via \code{-}, all arguments of \code{vertex} (or
+\code{vertices}) are concatenated via \code{c()} and passed to
+\code{\link{delete_vertices}}.
+}
+\examples{
+g <- make_(ring(10), with_vertex_(name = LETTERS[1:10])) +
+  vertices('X', 'Y')
+g
+plot(g)
+}
+\seealso{
+Other functions for manipulating graph structure: \code{\link{+.igraph}};
+  \code{\link{-.igraph}}, \code{\link{igraph-minus}};
+  \code{\link{add.edges}}, \code{\link{add_edges}};
+  \code{\link{add.vertices}}, \code{\link{add_vertices}};
+  \code{\link{delete.edges}}, \code{\link{delete_edges}};
+  \code{\link{delete.vertices}},
+  \code{\link{delete_vertices}}; \code{\link{edge}},
+  \code{\link{edges}}; \code{\link{path}}
+}
+
diff --git a/man/vertex.connectivity.Rd b/man/vertex.connectivity.Rd
deleted file mode 100644
index 1f00431..0000000
--- a/man/vertex.connectivity.Rd
+++ /dev/null
@@ -1,86 +0,0 @@
-\name{vertex.connectivity}
-\alias{vertex.connectivity}
-\alias{vertex.disjoint.paths}
-\alias{graph.cohesion}
-\concept{Vertex connectivity}
-\concept{Vertex-disjoint paths}
-\concept{Graph cohesion}
-\title{Vertex connectivity.}
-\description{The vertex connectivity of a graph or two vertices, this is
-  recently also called group cohesion.}
-\usage{
-vertex.connectivity(graph, source=NULL, target=NULL, checks=TRUE)
-vertex.disjoint.paths(graph, source, target)
-graph.cohesion(graph, checks=TRUE)
-}
-\arguments{
-  \item{graph}{The input graph.}
-  \item{source}{The id of the source vertex, for
-    \code{vertex.connectivity} it can be \code{NULL}, see details
-    below.}
-  \item{target}{The id of the target vertex, for
-    \code{vertex.connectivity} it can be \code{NULL}, see details
-    below.}
-  \item{checks}{Logical constant. Whether to check that the graph is
-    connected and also the degree of the vertices. If the graph is
-    not (strongly) connected then the connectivity is obviously zero. Otherwise
-    if the minimum degree is one then the vertex connectivity is also
-    one. It is a good idea to perform these checks, as they can be
-    done quickly compared to the connectivity calculation itself. 
-    They were suggested by Peter McMahan, thanks Peter.}
-}
-\details{
-  The vertex connectivity of two vertices (\code{source} and
-  \code{target}) in a directed graph is the minimum number of vertices
-  needed to remove from the graph to eliminate all (directed) paths from
-  \code{source} to \code{target}. \code{vertex.connectivity} 
-  calculates this quantity if both the \code{source} and \code{target}
-  arguments are given and they're not \code{NULL}.
-
-  The vertex connectivity of a graph is the minimum vertex connectivity
-  of all (ordered) pairs of vertices in the graph. In other words this
-  is the minimum number of vertices needed to remove to make the graph
-  not strongly connected. (If the graph is not strongly connected then
-  this is zero.) \code{vertex.connectivity} calculates this quantitty if
-  neither the \code{source} nor \code{target} arguments are
-  given. (Ie. they are both \code{NULL}.)
-
-  A set of vertex disjoint directed paths from \code{source} to \code{vertex}
-  is a set of directed paths between them whose vertices do not contain common
-  vertices (apart from \code{source} and \code{target}). The maximum number of
-  vertex disjoint paths between two vertices is the same as their vertex
-  connectivity in most cases (if the two vertices are not connected by an edge).
-
-  The cohesion of a graph (as defined by White and Harary, see
-  references), is the vertex connectivity of the graph. This is
-  calculated by \code{graph.cohesion}.
-
-  These three functions essentially calculate the same measure(s), more
-  precisely \code{vertex.connectivity} is the most general, the other
-  two are included only for the ease of using more descriptive function
-  names.
-}
-\value{
-  A scalar real value.
-}
-\references{White, Douglas R and Frank Harary 2001. The Cohesiveness of
-  Blocks In Social Networks: Node Connectivity and Conditional Density.
-  \emph{Sociological Methodology} 31 (1) : 305-359.}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.maxflow}}, \code{\link{edge.connectivity}},
-  \code{\link{edge.disjoint.paths}}, \code{\link{graph.adhesion}}}
-\examples{
-g <- barabasi.game(100, m=1)
-g <- delete.edges(g, E(g)[ 100 \%--\% 1 ])
-g2 <- barabasi.game(100, m=5)
-g2 <- delete.edges(g2, E(g2)[ 100 \%--\% 1])
-vertex.connectivity(g, 100, 1)
-vertex.connectivity(g2, 100, 1)
-vertex.disjoint.paths(g2, 100, 1)
-
-g <- erdos.renyi.game(50, 5/50)
-g <- as.directed(g)
-g <- induced.subgraph(g, subcomponent(g, 1))
-graph.cohesion(g)
-}
-\keyword{graphs}
diff --git a/man/vertex.shape.pie.Rd b/man/vertex.shape.pie.Rd
index 0482d01..18bb782 100644
--- a/man/vertex.shape.pie.Rd
+++ b/man/vertex.shape.pie.Rd
@@ -29,7 +29,7 @@
 \author{ Gabor Csardi \email{csardi.gabor at gmail.com} }
 \seealso{ \code{\link{igraph.plotting}}, \code{\link{plot.igraph}} }
 \examples{
-g <- graph.ring(10)
+g <- make_ring(10)
 values <- lapply(1:10, function(x) sample(1:10,3))
 if (interactive()) {
   plot(g, vertex.shape="pie", vertex.pie=values,
diff --git a/man/vertex_attr-set.Rd b/man/vertex_attr-set.Rd
new file mode 100644
index 0000000..82c955c
--- /dev/null
+++ b/man/vertex_attr-set.Rd
@@ -0,0 +1,79 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{vertex_attr<-}
+\alias{vertex.attributes<-}
+\alias{vertex_attr<-}
+\title{Set one or more vertex attributes}
+\usage{
+vertex_attr(graph, name, index = V(graph)) <- value
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{The name of the vertex attribute to set. If missing,
+then \code{value} must be a named list, and its entries are
+set as vertex attributes.}
+
+\item{index}{An optional vertex sequence to set the attributes
+of a subset of vertices.}
+
+\item{value}{The new value of the attribute(s) for all
+(or \code{index}) vertices.}
+}
+\value{
+The graph, with the vertex attribute(s) added or set.
+}
+\description{
+Set one or more vertex attributes
+}
+\examples{
+g <- make_ring(10)
+vertex_attr(g) <- list(name = LETTERS[1:10],
+                        color = rep("yellow", gorder(g)))
+vertex_attr(g, "label") <- V(g)$name
+g
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}}
+}
+
diff --git a/man/vertex_attr.Rd b/man/vertex_attr.Rd
new file mode 100644
index 0000000..4698cae
--- /dev/null
+++ b/man/vertex_attr.Rd
@@ -0,0 +1,76 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{vertex_attr}
+\alias{get.vertex.attribute}
+\alias{vertex.attributes}
+\alias{vertex_attr}
+\title{Query vertex attributes of a graph}
+\usage{
+vertex_attr(graph, name, index = V(graph))
+}
+\arguments{
+\item{graph}{The graph.}
+
+\item{name}{Name of the attribute to query. If missing, then
+all vertex attributes are returned in a list.}
+
+\item{index}{A vertex sequence, to query the attribute only
+for these vertices.}
+}
+\value{
+The value of the vertex attribute, or the list of
+  all vertex attributes, if \code{name} is missing.
+}
+\description{
+Query vertex attributes of a graph
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_vertex_attr("color", value = "red") \%>\%
+  set_vertex_attr("label", value = letters[1:10])
+vertex_attr(g, "label")
+vertex_attr(g)
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{list.vertex.attributes}},
+  \code{\link{vertex_attr_names}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/vertex_attr_names.Rd b/man/vertex_attr_names.Rd
new file mode 100644
index 0000000..f14ce0e
--- /dev/null
+++ b/man/vertex_attr_names.Rd
@@ -0,0 +1,68 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/attributes.R
+\name{vertex_attr_names}
+\alias{list.vertex.attributes}
+\alias{vertex_attr_names}
+\title{List names of vertex attributes}
+\usage{
+vertex_attr_names(graph)
+}
+\arguments{
+\item{graph}{The graph.}
+}
+\value{
+Character vector, the names of the vertex attributes.
+}
+\description{
+List names of vertex attributes
+}
+\examples{
+g <- make_ring(10) \%>\%
+  set_vertex_attr("name", value = LETTERS[1:10]) \%>\%
+  set_vertex_attr("color", value = rep("green", 10))
+vertex_attr_names(g)
+plot(g)
+}
+\seealso{
+Other graph attributes: \code{\link{$.igraph.vs}},
+  \code{\link{$<-.igraph.vs}}, \code{\link{V<-}},
+  \code{\link{[<-.igraph.vs}},
+  \code{\link{[[<-.igraph.vs}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}},
+  \code{\link{igraph-vs-attributes}};
+  \code{\link{$.igraph}}, \code{\link{$<-.igraph}},
+  \code{\link{igraph-dollar}}, \code{\link{igraph-dollar}};
+  \code{\link{attributes}}, \code{\link{graph_attr_names}},
+  \code{\link{list.graph.attributes}};
+  \code{\link{delete_edge_attr}},
+  \code{\link{remove.edge.attribute}};
+  \code{\link{delete_graph_attr}},
+  \code{\link{remove.graph.attribute}};
+  \code{\link{delete_vertex_attr}},
+  \code{\link{remove.vertex.attribute}};
+  \code{\link{edge.attributes<-}},
+  \code{\link{edge_attr<-}}; \code{\link{edge.attributes}},
+  \code{\link{edge_attr}},
+  \code{\link{get.edge.attribute}};
+  \code{\link{edge_attr_names}},
+  \code{\link{list.edge.attributes}};
+  \code{\link{get.graph.attribute}},
+  \code{\link{graph.attributes}}, \code{\link{graph_attr}};
+  \code{\link{get.vertex.attribute}},
+  \code{\link{vertex.attributes}},
+  \code{\link{vertex_attr}};
+  \code{\link{graph.attributes<-}},
+  \code{\link{graph_attr<-}};
+  \code{\link{set.edge.attribute}},
+  \code{\link{set_edge_attr}};
+  \code{\link{set.graph.attribute}},
+  \code{\link{set_graph_attr}};
+  \code{\link{set.vertex.attribute}},
+  \code{\link{set_vertex_attr}};
+  \code{\link{vertex.attributes<-}},
+  \code{\link{vertex_attr<-}}
+}
+
diff --git a/man/vertex_connectivity.Rd b/man/vertex_connectivity.Rd
new file mode 100644
index 0000000..af2b3d9
--- /dev/null
+++ b/man/vertex_connectivity.Rd
@@ -0,0 +1,101 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/flow.R
+\name{vertex_connectivity}
+\alias{cohesion}
+\alias{cohesion.igraph}
+\alias{graph.cohesion}
+\alias{vertex.connectivity}
+\alias{vertex.disjoint.paths}
+\alias{vertex_connectivity}
+\alias{vertex_disjoint_paths}
+\title{Vertex connectivity.}
+\usage{
+vertex_connectivity(graph, source = NULL, target = NULL, checks = TRUE)
+
+\method{cohesion}{igraph}(x, checks = TRUE, ...)
+}
+\arguments{
+\item{graph,x}{The input graph.}
+
+\item{source}{The id of the source vertex, for \code{vertex_connectivity} it
+can be \code{NULL}, see details below.}
+
+\item{target}{The id of the target vertex, for \code{vertex_connectivity} it
+can be \code{NULL}, see details below.}
+
+\item{checks}{Logical constant. Whether to check that the graph is connected
+and also the degree of the vertices. If the graph is not (strongly)
+connected then the connectivity is obviously zero. Otherwise if the minimum
+degree is one then the vertex connectivity is also one. It is a good idea to
+perform these checks, as they can be done quickly compared to the
+connectivity calculation itself.  They were suggested by Peter McMahan,
+thanks Peter.}
+
+\item{...}{Ignored.}
+}
+\value{
+A scalar real value.
+}
+\description{
+The vertex connectivity of a graph or two vertices, this is recently also
+called group cohesion.
+}
+\details{
+The vertex connectivity of two vertices (\code{source} and \code{target}) in
+a directed graph is the minimum number of vertices needed to remove from the
+graph to eliminate all (directed) paths from \code{source} to \code{target}.
+\code{vertex_connectivity} calculates this quantity if both the
+\code{source} and \code{target} arguments are given and they're not
+\code{NULL}.
+
+The vertex connectivity of a graph is the minimum vertex connectivity of all
+(ordered) pairs of vertices in the graph. In other words this is the minimum
+number of vertices needed to remove to make the graph not strongly
+connected. (If the graph is not strongly connected then this is zero.)
+\code{vertex_connectivity} calculates this quantitty if neither the
+\code{source} nor \code{target} arguments are given. (Ie. they are both
+\code{NULL}.)
+
+A set of vertex disjoint directed paths from \code{source} to \code{vertex}
+is a set of directed paths between them whose vertices do not contain common
+vertices (apart from \code{source} and \code{target}). The maximum number of
+vertex disjoint paths between two vertices is the same as their vertex
+connectivity in most cases (if the two vertices are not connected by an
+edge).
+
+The cohesion of a graph (as defined by White and Harary, see references), is
+the vertex connectivity of the graph. This is calculated by
+\code{cohesion}.
+
+These three functions essentially calculate the same measure(s), more
+precisely \code{vertex_connectivity} is the most general, the other two are
+included only for the ease of using more descriptive function names.
+}
+\examples{
+g <- barabasi.game(100, m=1)
+g <- delete_edges(g, E(g)[ 100 \%--\% 1 ])
+g2 <- barabasi.game(100, m=5)
+g2 <- delete_edges(g2, E(g2)[ 100 \%--\% 1])
+vertex_connectivity(g, 100, 1)
+vertex_connectivity(g2, 100, 1)
+vertex_disjoint_paths(g2, 100, 1)
+
+g <- sample_gnp(50, 5/50)
+g <- as.directed(g)
+g <- induced_subgraph(g, subcomponent(g, 1))
+cohesion(g)
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+White, Douglas R and Frank Harary 2001. The Cohesiveness of
+Blocks In Social Networks: Node Connectivity and Conditional Density.
+\emph{Sociological Methodology} 31 (1) : 305-359.
+}
+\seealso{
+\code{\link{max_flow}}, \code{\link{edge_connectivity}},
+\code{\link{edge_disjoint_paths}}, \code{\link{adhesion}}
+}
+\keyword{graphs}
+
diff --git a/man/walktrap.community.Rd b/man/walktrap.community.Rd
deleted file mode 100644
index b252941..0000000
--- a/man/walktrap.community.Rd
+++ /dev/null
@@ -1,60 +0,0 @@
-\name{walktrap.community}
-\alias{walktrap.community}
-\concept{Random walk}
-\concept{Community structure}
-\title{Community strucure via short random walks}
-\description{This function tries to find densely connected subgraphs,
-  also called communities in a graph via random walks. The idea is that
-  short random walks tend to stay in the same community.
-}
-\usage{
-walktrap.community(graph, weights = E(graph)$weight, steps = 4, merges =
-          TRUE, modularity = TRUE, membership = TRUE)
-}
-\arguments{
-  \item{graph}{The input graph, edge directions are ignored in directed
-    graphs.}
-  \item{weights}{The edge weights.}
-  \item{steps}{The length of the random walks to perform.}
-  \item{merges}{Logical scalar, whether to include the merge matrix in
-    the result.}
-  \item{modularity}{Logical scalar, whether to include the vector of the
-    modularity scores in the result. If the \code{membership} argument
-    is true, then it will be always calculated.}
-  \item{membership}{Logical scalar, whether to calculate the membership
-    vector for the split corresponding to the highest modularity value.}
-}
-\details{
-  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
-}
-\value{
-  \code{walktrap.community} returns a \code{\link{communities}}
-  object, please see the \code{\link{communities}} manual page for
-  details.
-}
-\references{Pascal Pons, Matthieu Latapy: Computing
-  communities in large networks using random walks, 
-  http://arxiv.org/abs/physics/0512106
-}
-\author{Pascal Pons (\url{http://psl.pons.free.fr/}) and Gabor Csardi
-  \email{csardi.gabor at gmail.com} for the R and igraph interface}
-\seealso{
-  See \code{\link{communities}} on getting the actual membership vector,
-  merge matrix, modularity score, etc.
-  
-  \code{\link{modularity}} and 
-  \code{\link{fastgreedy.community}},
-  \code{\link{spinglass.community}},
-  \code{\link{leading.eigenvector.community}},
-  \code{\link{edge.betweenness.community}} for other community detection
-  methods.
-}
-\examples{
-g <- graph.full(5) \%du\% graph.full(5) \%du\% graph.full(5)
-g <- add.edges(g, c(1,6, 1,11, 6, 11))
-walktrap.community(g)
-}
-\keyword{graphs}
diff --git a/man/watts.strogatz.game.Rd b/man/watts.strogatz.game.Rd
deleted file mode 100644
index fe058de..0000000
--- a/man/watts.strogatz.game.Rd
+++ /dev/null
@@ -1,44 +0,0 @@
-\name{watts.strogatz.game}
-\alias{watts.strogatz.game}
-\concept{Small-world model}
-\concept{Watts-strogatz model}
-\title{The Watts-Strogatz small-world model}
-\description{Generate a graph according to the Watts-Strogatz network
-  model.}
-\usage{
-watts.strogatz.game(dim, size, nei, p, loops = FALSE, multiple = FALSE)
-}
-\arguments{
-  \item{dim}{Integer constant, the dimension of the starting lattice.}
-  \item{size}{Integer constant, the size of the lattice along each
-    dimension.}
-  \item{nei}{Integer constant, the neighborhood within which the
-    vertices of the lattice will be connected.}
-  \item{p}{Real constant between zero and one, the rewiring
-    probability. }
-  \item{loops}{Logical scalar, whether loops edges are allowed in the
-    generated graph.}
-  \item{multiple}{Logical scalar, whether multiple edges are allowed
-    int the generated graph.}
-}
-\details{
-  First a lattice is created with the given \code{dim}, \code{size} and
-  \code{nei} arguments. Then the edges of the lattice are rewired
-  uniformly randomly with probability \code{p}.
-
-  Note that this function might create graphs with loops and/or multiple
-  edges. You can use \code{\link{simplify}} to get rid of these.
-}
-\value{A graph object.}
-\references{
-  Duncan J Watts and Steven H Strogatz: Collective dynamics of
-  \sQuote{small world} networks, Nature 393, 440-442, 1998.
-}
-\author{ Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{\code{\link{graph.lattice}}, \code{\link{rewire.edges}}}
-\examples{
-g <- watts.strogatz.game(1, 100, 5, 0.05)
-average.path.length(g)
-transitivity(g, type="average")
-}
-\keyword{graphs}
diff --git a/man/which_multiple.Rd b/man/which_multiple.Rd
new file mode 100644
index 0000000..07179c8
--- /dev/null
+++ b/man/which_multiple.Rd
@@ -0,0 +1,82 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{which_multiple}
+\alias{any_multiple}
+\alias{count.multiple}
+\alias{count_multiple}
+\alias{has.multiple}
+\alias{is.loop}
+\alias{is.multiple}
+\alias{which_loop}
+\alias{which_multiple}
+\title{Find the multiple or loop edges in a graph}
+\usage{
+which_multiple(graph, eids = E(graph))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{eids}{The edges to which the query is restricted. By default this is
+all edges in the graph.}
+}
+\value{
+\code{any_multiple} returns a logical scalar.  \code{which_loop} and
+\code{which_multiple} return a logical vector. \code{count_multiple} returns a
+numeric vector.
+}
+\description{
+A loop edge is an edge from a vertex to itself. An edge is a multiple edge
+if it has exactly the same head and tail vertices as another edge. A graph
+without multiple and loop edges is called a simple graph.
+}
+\details{
+\code{which_loop} decides whether the edges of the graph are loop edges.
+
+\code{any_multiple} decides whether the graph has any multiple edges.
+
+\code{which_multiple} decides whether the edges of the graph are multiple
+edges.
+
+\code{count_multiple} counts the multiplicity of each edge of a graph.
+
+Note that the semantics for \code{which_multiple} and \code{count_multiple} is
+different. \code{which_multiple} gives \code{TRUE} for all occurences of a
+multiple edge except for one. Ie. if there are three \code{i-j} edges in the
+graph then \code{which_multiple} returns \code{TRUE} for only two of them while
+\code{count_multiple} returns \sQuote{3} for all three.
+
+See the examples for getting rid of multiple edges while keeping their
+original multiplicity as an edge attribute.
+}
+\examples{
+# Loops
+g <- graph( c(1,1,2,2,3,3,4,5) )
+which_loop(g)
+
+# Multiple edges
+g <- barabasi.game(10, m=3, algorithm="bag")
+any_multiple(g)
+which_multiple(g)
+count_multiple(g)
+which_multiple(simplify(g))
+all(count_multiple(simplify(g)) == 1)
+
+# Direction of the edge is important
+which_multiple(graph( c(1,2, 2,1) ))
+which_multiple(graph( c(1,2, 2,1), dir=FALSE ))
+
+# Remove multiple edges but keep multiplicity
+g <- barabasi.game(10, m=3, algorithm="bag")
+E(g)$weight <- count_multiple(g)
+g <- simplify(g)
+any(which_multiple(g))
+E(g)$weight
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{simplify}} to eliminate loop and multiple edges.
+}
+\keyword{graphs}
+
diff --git a/man/which_mutual.Rd b/man/which_mutual.Rd
new file mode 100644
index 0000000..5ef0599
--- /dev/null
+++ b/man/which_mutual.Rd
@@ -0,0 +1,47 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/structural.properties.R
+\name{which_mutual}
+\alias{is.mutual}
+\alias{which_mutual}
+\title{Find mutual edges in a directed graph}
+\usage{
+which_mutual(graph, es = E(graph))
+}
+\arguments{
+\item{graph}{The input graph.}
+
+\item{es}{Edge sequence, the edges that will be probed. By default is
+includes all edges in the order of their ids.}
+}
+\value{
+A logical vector of the same length as the number of edges supplied.
+}
+\description{
+This function checks the reciproc pair of the supplied edges.
+}
+\details{
+In a directed graph an (A,B) edge is mutual if the graph also includes a
+(B,A) directed edge.
+
+Note that multi-graphs are not handled properly, i.e. if the graph contains
+two copies of (A,B) and one copy of (B,A), then these three edges are
+considered to be mutual.
+
+Undirected graphs contain only mutual edges by definition.
+}
+\examples{
+g <- sample_gnm(10, 50, directed=TRUE)
+reciprocity(g)
+dyad_census(g)
+which_mutual(g)
+sum(which_mutual(g))/2 == dyad_census(g)$mut
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\seealso{
+\code{\link{reciprocity}}, \code{\link{dyad_census}} if you just
+want some statistics about mutual edges.
+}
+\keyword{graphs}
+
diff --git a/man/with_edge_.Rd b/man/with_edge_.Rd
new file mode 100644
index 0000000..28a826d
--- /dev/null
+++ b/man/with_edge_.Rd
@@ -0,0 +1,28 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{with_edge_}
+\alias{with_edge_}
+\title{Constructor modifier to add edge attributes}
+\usage{
+with_edge_(...)
+}
+\arguments{
+\item{...}{The attributes to add. They must be named.}
+}
+\description{
+Constructor modifier to add edge attributes
+}
+\examples{
+make_(ring(10),
+  with_edge_(
+    color = "red",
+    weight = rep(1:2, 5))) \%>\%
+  plot()
+}
+\seealso{
+Other constructor modifiers: \code{\link{simplified}};
+  \code{\link{with_graph_}}; \code{\link{with_vertex_}};
+  \code{\link{without_attr}}; \code{\link{without_loops}};
+  \code{\link{without_multiples}}
+}
+
diff --git a/man/with_graph_.Rd b/man/with_graph_.Rd
new file mode 100644
index 0000000..f067fa9
--- /dev/null
+++ b/man/with_graph_.Rd
@@ -0,0 +1,24 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{with_graph_}
+\alias{with_graph_}
+\title{Constructor modifier to add graph attributes}
+\usage{
+with_graph_(...)
+}
+\arguments{
+\item{...}{The attributes to add. They must be named.}
+}
+\description{
+Constructor modifier to add graph attributes
+}
+\examples{
+make_(ring(10), with_graph_(name = "10-ring"))
+}
+\seealso{
+Other constructor modifiers: \code{\link{simplified}};
+  \code{\link{with_edge_}}; \code{\link{with_vertex_}};
+  \code{\link{without_attr}}; \code{\link{without_loops}};
+  \code{\link{without_multiples}}
+}
+
diff --git a/man/with_vertex_.Rd b/man/with_vertex_.Rd
new file mode 100644
index 0000000..540fd40
--- /dev/null
+++ b/man/with_vertex_.Rd
@@ -0,0 +1,29 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{with_vertex_}
+\alias{with_vertex_}
+\title{Constructor modifier to add vertex attributes}
+\usage{
+with_vertex_(...)
+}
+\arguments{
+\item{...}{The attributes to add. They must be named.}
+}
+\description{
+Constructor modifier to add vertex attributes
+}
+\examples{
+make_(ring(10),
+  with_vertex_(
+    color = "#7fcdbb",
+    frame.color = "#7fcdbb",
+    name = LETTERS[1:10])) \%>\%
+  plot()
+}
+\seealso{
+Other constructor modifiers: \code{\link{simplified}};
+  \code{\link{with_edge_}}; \code{\link{with_graph_}};
+  \code{\link{without_attr}}; \code{\link{without_loops}};
+  \code{\link{without_multiples}}
+}
+
diff --git a/man/without_attr.Rd b/man/without_attr.Rd
new file mode 100644
index 0000000..10dbb48
--- /dev/null
+++ b/man/without_attr.Rd
@@ -0,0 +1,25 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{without_attr}
+\alias{without_attr}
+\title{Construtor modifier to remove all attributes from a graph}
+\usage{
+without_attr()
+}
+\description{
+Construtor modifier to remove all attributes from a graph
+}
+\examples{
+g1 <- make_ring(10)
+g1
+
+g2 <- make_(ring(10), without_attr())
+g2
+}
+\seealso{
+Other constructor modifiers: \code{\link{simplified}};
+  \code{\link{with_edge_}}; \code{\link{with_graph_}};
+  \code{\link{with_vertex_}}; \code{\link{without_loops}};
+  \code{\link{without_multiples}}
+}
+
diff --git a/man/without_loops.Rd b/man/without_loops.Rd
new file mode 100644
index 0000000..034bfde
--- /dev/null
+++ b/man/without_loops.Rd
@@ -0,0 +1,23 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{without_loops}
+\alias{without_loops}
+\title{Constructor modifier to drop loop edges}
+\usage{
+without_loops()
+}
+\description{
+Constructor modifier to drop loop edges
+}
+\examples{
+# An artificial example
+make_(full_graph(5, loops = TRUE))
+make_(full_graph(5, loops = TRUE), without_loops())
+}
+\seealso{
+Other constructor modifiers: \code{\link{simplified}};
+  \code{\link{with_edge_}}; \code{\link{with_graph_}};
+  \code{\link{with_vertex_}}; \code{\link{without_attr}};
+  \code{\link{without_multiples}}
+}
+
diff --git a/man/without_multiples.Rd b/man/without_multiples.Rd
new file mode 100644
index 0000000..56ae812
--- /dev/null
+++ b/man/without_multiples.Rd
@@ -0,0 +1,22 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/make.R
+\name{without_multiples}
+\alias{without_multiples}
+\title{Constructor modifier to drop multiple edges}
+\usage{
+without_multiples()
+}
+\description{
+Constructor modifier to drop multiple edges
+}
+\examples{
+sample_(pa(10, m = 3, algorithm = "bag"))
+sample_(pa(10, m = 3, algorithm = "bag"), without_multiples())
+}
+\seealso{
+Other constructor modifiers: \code{\link{simplified}};
+  \code{\link{with_edge_}}; \code{\link{with_graph_}};
+  \code{\link{with_vertex_}}; \code{\link{without_attr}};
+  \code{\link{without_loops}}
+}
+
diff --git a/man/write.graph.Rd b/man/write.graph.Rd
deleted file mode 100644
index d89ab71..0000000
--- a/man/write.graph.Rd
+++ /dev/null
@@ -1,194 +0,0 @@
-\name{write.graph}
-\alias{write.graph}
-\title{Writing the graph to a file in some format}
-\description{\code{write.graph} is a general function for exporting
-  graphs to foreign file formats, however not many formats are
-  implemented right now.}
-\usage{
-write.graph(graph, file, format=c("edgelist", "pajek", "ncol",
-       "lgl", "graphml", "dimacs", "gml", "dot", "leda"), \dots)
-}
-\arguments{
-  \item{graph}{The graph to export.}
-  \item{file}{A connection or a string giving the file name to write the
-    graph to.}
-  \item{format}{Character string giving the file format. Right now 
-    \code{pajek}, \code{graphml}, \code{dot},
-    \code{gml}, \code{edgelist}, \code{lgl},
-    \code{ncol} and \code{dimacs} are implemented. As of igraph 0.4 this
-    argument is case insensitive.
-  }
-  \item{\dots}{Other, format specific arguments, see below.}
-}
-\section{Edge list format}{
-  The \code{edgelist} format is a simple text file, with one edge in a
-  line, the two vertex ids separated by a space character. The file is
-  sorted by the first and the second column. This format has no
-  additional arguments.
-}
-\section{Pajek format}{
-  The Pajek format is a text file, see \code{\link{read.graph}} for
-  details. Appropriate vertex and edge attributes are also written to
-  the file. This format has no additional arguments.
-
-  From version 0.6.1 igraph handles bipartite graphs when writing to
-  Pajek files. 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 a bipartite graph is written to a Pajek file, and then
-  read back into igraph.
-}
-\section{GraphML format}{
-  The GraphML format is a flexible XML based format. See
-  \code{\link{read.graph}} for GraphML details. Vertex and edge
-  attributes are also written to the file. Additional argument:
-  \describe{
-    \item{prefixAttr}{Logical scalar, whether you want to add a prefix
-      to the graph, vertex and edge attribute names, to ensure their
-      uniqueness. Defaults to \code{TRUE}.}
-  }
-}
-\section{Dot format}{
-  The dot format is used by the popular GraphViz program. Vertex and
-  edge attributes are written to the file. There are no additional
-  arguments for this format.
-}
-\section{LGL format}{
-  The \code{lgl} format is also a simple text file, this is the
-  format expected by the 'Large Graph Layout' layout generator software.
-  See \link{read.graph} for details.
-  Additional arguments:
-  \describe{
-    \item{names}{If you want to write symbolic vertex names instead of
-      vertex ids, supply the name of the vertex attribute containing the
-      symbolic names here. By default the \sQuote{name} attribute is
-      used if there is one. Supply \code{NULL} if you want to use numeric 
-      vertex ids even if there is a \sQuote{name} vertex attribute.} 
-    \item{weights}{If you want to write edge weights to the file, supply
-      the name of the edge attribute here. By defaults the vertex
-      attribute \sQuote{weights} are used if they are installed.
-      Supply \code{NULL} here if you want to omit the weights.}
-    \item{isolates}{Logical, if \code{TRUE} the isolate vertices are
-      also written to the file, they are omitted by default.}
-  }
-}
-\section{NCOL format}{
-  The \code{ncol} format is also used by LGL, it is a text file, see
-  \link{read.graph} for details.
-  Additional arguments:
-  \describe{
-    \item{names}{If you want to write symbolic vertex names instead of
-      vertex ids, supply the name of the vertex attribute containing the
-      symbolic names here. By default the \sQuote{name} attribute is
-      used if there is one. Supply \code{NULL} if you want to use numeric 
-      vertex ids even if there is a \sQuote{name} vertex attribute.} 
-    \item{weights}{If you want to write edge weights to the file, supply
-      the name of the edge attribute here. By defaults the vertex
-      attribute \sQuote{weights} are used if they are installed.
-      Supply \code{NULL} here if you want to omit the weights.}
-  }
-}
-\section{Dimacs format}{
-  The \code{dimacs} file format, more specifically the 
-  version for network flow problems, see the files at
-  \url{ftp://dimacs.rutgers.edu/pub/netflow/general-info/}
-  
-  This is a line-oriented text file (ASCII) format. The first
-  character of each line defines the type of the line. If the first
-  character is \code{c} the line is a comment line and it is
-  ignored. There is one problem line (\code{p} in the file, it
-  must appear before any node and arc descriptor lines. The problem
-  line has three fields separated by spaces: the problem type
-  (\code{min}, \code{max} or \code{asn}), the
-  number of vertices and number of edges in the graph.
-  Exactly two node identification lines are expected
-  (\code{n}), one for the source, one for the target vertex.
-  These have two fields: the id of the vertex and the type of the
-  vertex, either \code{s} (=source) or \code{t}
-  (=target). Arc lines start with \code{a} and have three
-  fields: the source vertex, the target vertex and the edge capacity.
-  
-  Vertex ids are numbered from 1.
-  
-  Additional arguments:
-  \describe{
-    \item{source}{The id of the source vertex, if \code{NULL} (the
-      default) then it is taken from the \code{source} graph attribute.}
-    \item{target}{The id of the target vertex, if \code{NULL} (the
-      default) then it is taken from the \code{target} graph attribute.}
-    \item{capacity}{A numeric vector giving the edge capacities. If
-      \code{NULL} (the default) then it is taken from the
-      \code{capacity} edge attribute.}
-  }
-}
-\section{GML file format}{
-  GML is a quite general textual format, see 
-  \url{http://www.infosun.fim.uni-passau.de/Graphlet/GML/} for details.
- 
-  The graph, vertex and edges attributes are written to the
-  file as well, if they are numeric of string.
- 
-  As igraph is more forgiving about attribute names, it might 
-  be neccessary to simplify the them before writing to the GML file.
-  This way we'll have a syntactically correct GML file. The following 
-  simple procedure is performed on each attribute name: first the alphanumeric 
-  characters are extracted, the others are ignored. Then if the first character
-  is not a letter then the attribute name is prefixed with <quote>igraph</quote>.
-  Note that this might result identical names for two attributes, igraph 
-  does not check this. 
- 
-  The \dQuote{id} vertex attribute is treated specially. 
-  If the \code{id} argument is not \code{NULL} then it should be a numeric 
-  vector with the vertex ids and the \dQuote{id} vertex attribute is 
-  ignored (if there is one). If \code{id} is 0 and there is a 
-  numeric \code{id} vertex attribute that is used instead. If ids
-  are not specified in either way then the regular igraph vertex ids are used.
- 
-  Note that whichever way vertex ids are specified, their 
-  uniqueness is not checked.
- 
-  If the graph has edge attributes named \dQuote{source}
-  or \dQuote{target} they're silently ignored. GML uses these attributes
-  to specify the edges, so we cannot write them to the file. Rename them 
-  before calling this function if you want to preserve them.
-
-  Additional arguments:
-  \describe{
-    \item{id}{\code{NULL} or a numeric vector giving the vertex ids. See
-      details above.}
-    \item{creator}{A character scalar to be added to the
-      \dQuote{Creator} line in the GML file. If this is \code{NULL} (the
-      default) then the current date and time is added.}
-  }
-}
-\section{LEDA file format}{
-  LEDA is a library for efficient data types and algorithms. 
-  The support for the LEDA format is very basic at the moment; igraph
-  writes only the LEDA graph section which supports one selected vertex
-  and edge attribute and no layout information or visual attributes.
-  See
-  \url{http://www.algorithmic-solutions.info/leda_guide/graphs/leda_native_graph_fileformat.html}
-  for the details of this format.
-
-  Additional arguments:
-  \describe{
-    \item{vertex.attr}{The name of the vertex attribute whose values
-      are to be stored in the output or \code{NULL} if no vertex
-      attribute has to be stored.} 
-    \item{edge.attr}{The name of the edge attribute whose values
-      are to be stored in the output or \code{NULL} if no edge attribute
-      has to be stored.}
-  }
-}
-\value{A NULL, invisibly.}
-\references{Adai AT, Date SV, Wieland S, Marcotte EM. LGL: creating a
-  map of protein function with an algorithm for visualizing very large
-  biological networks. \emph{J Mol Biol.} 2004 Jun 25;340(1):179-90.}
-\author{Gabor Csardi \email{csardi.gabor at gmail.com}}
-\seealso{ \code{\link{read.graph}} }
-\examples{
-g <- graph.ring(10)
-\dontrun{write.graph(g, "/tmp/g.txt", "edgelist")}
-}
-\keyword{graphs}
diff --git a/man/write_graph.Rd b/man/write_graph.Rd
new file mode 100644
index 0000000..44e8cb8
--- /dev/null
+++ b/man/write_graph.Rd
@@ -0,0 +1,53 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/foreign.R
+\name{write_graph}
+\alias{write.graph}
+\alias{write_graph}
+\title{Writing the graph to a file in some format}
+\usage{
+write_graph(graph, file, format = c("edgelist", "pajek", "ncol", "lgl",
+  "graphml", "dimacs", "gml", "dot", "leda"), ...)
+}
+\arguments{
+\item{graph}{The graph to export.}
+
+\item{file}{A connection or a string giving the file name to write the graph
+to.}
+
+\item{format}{Character string giving the file format. Right now
+\code{pajek}, \code{graphml}, \code{dot}, \code{gml}, \code{edgelist},
+\code{lgl}, \code{ncol} and \code{dimacs} are implemented. As of igraph 0.4
+this argument is case insensitive.}
+
+\item{\dots}{Other, format specific arguments, see below.}
+}
+\value{
+A NULL, invisibly.
+}
+\description{
+\code{write_graph} is a general function for exporting graphs to foreign
+file formats, however not many formats are implemented right now.
+}
+\section{Edge list format}{
+ The \code{edgelist} format is a simple text file,
+with one edge in a line, the two vertex ids separated by a space character.
+The file is sorted by the first and the second column. This format has no
+additional arguments.
+}
+\examples{
+g <- make_ring(10)
+\dontrun{write_graph(g, "/tmp/g.txt", "edgelist")}
+}
+\author{
+Gabor Csardi \email{csardi.gabor at gmail.com}
+}
+\references{
+Adai AT, Date SV, Wieland S, Marcotte EM. LGL: creating a map of
+protein function with an algorithm for visualizing very large biological
+networks. \emph{J Mol Biol.} 2004 Jun 25;340(1):179-90.
+}
+\seealso{
+\code{\link{read_graph}}
+}
+\keyword{graphs}
+
diff --git a/src/AMD/Include/amd.h b/src/AMD/Include/amd.h
new file mode 100644
index 0000000..a38fd31
--- /dev/null
+++ b/src/AMD/Include/amd.h
@@ -0,0 +1,411 @@
+/* ========================================================================= */
+/* === AMD:  approximate minimum degree ordering =========================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Version 2.2, Copyright (c) 2007 by Timothy A. Davis,                  */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* AMD finds a symmetric ordering P of a matrix A so that the Cholesky
+ * factorization of P*A*P' has fewer nonzeros and takes less work than the
+ * Cholesky factorization of A.  If A is not symmetric, then it performs its
+ * ordering on the matrix A+A'.  Two sets of user-callable routines are
+ * provided, one for int integers and the other for SuiteSparse_long integers.
+ *
+ * The method is based on the approximate minimum degree algorithm, discussed
+ * in Amestoy, Davis, and Duff, "An approximate degree ordering algorithm",
+ * SIAM Journal of Matrix Analysis and Applications, vol. 17, no. 4, pp.
+ * 886-905, 1996.  This package can perform both the AMD ordering (with
+ * aggressive absorption), and the AMDBAR ordering (without aggressive
+ * absorption) discussed in the above paper.  This package differs from the
+ * Fortran codes discussed in the paper:
+ *
+ *       (1) it can ignore "dense" rows and columns, leading to faster run times
+ *       (2) it computes the ordering of A+A' if A is not symmetric
+ *       (3) it is followed by a depth-first post-ordering of the assembly tree
+ *           (or supernodal elimination tree)
+ *
+ * For historical reasons, the Fortran versions, amd.f and amdbar.f, have
+ * been left (nearly) unchanged.  They compute the identical ordering as
+ * described in the above paper.
+ */
+
+#ifndef AMD_H
+#define AMD_H
+
+/* make it easy for C++ programs to include AMD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* get the definition of size_t: */
+#include <stddef.h>
+
+#include "SuiteSparse_config.h"
+
+int amd_order                  /* returns AMD_OK, AMD_OK_BUT_JUMBLED,
+                                * AMD_INVALID, or AMD_OUT_OF_MEMORY */
+(
+    int n,                     /* A is n-by-n.  n must be >= 0. */
+    const int Ap [ ],          /* column pointers for A, of size n+1 */
+    const int Ai [ ],          /* row indices of A, of size nz = Ap [n] */
+    int P [ ],                 /* output permutation, of size n */
+    double Control [ ],        /* input Control settings, of size AMD_CONTROL */
+    double Info [ ]            /* output Info statistics, of size AMD_INFO */
+) ;
+
+SuiteSparse_long amd_l_order    /* see above for description of arguments */
+(
+    SuiteSparse_long n,
+    const SuiteSparse_long Ap [ ],
+    const SuiteSparse_long Ai [ ],
+    SuiteSparse_long P [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* Input arguments (not modified):
+ *
+ *       n: the matrix A is n-by-n.
+ *       Ap: an int/SuiteSparse_long array of size n+1, containing column
+ *              pointers of A.
+ *       Ai: an int/SuiteSparse_long array of size nz, containing the row
+ *              indices of A, where nz = Ap [n].
+ *       Control:  a double array of size AMD_CONTROL, containing control
+ *           parameters.  Defaults are used if Control is NULL.
+ *
+ * Output arguments (not defined on input):
+ *
+ *       P: an int/SuiteSparse_long array of size n, containing the output
+ *           permutation. If row i is the kth pivot row, then P [k] = i.  In
+ *           MATLAB notation, the reordered matrix is A (P,P).
+ *       Info: a double array of size AMD_INFO, containing statistical
+ *           information.  Ignored if Info is NULL.
+ *
+ * On input, the matrix A is stored in column-oriented form.  The row indices
+ * of nonzero entries in column j are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ *
+ * If the row indices appear in ascending order in each column, and there
+ * are no duplicate entries, then amd_order is slightly more efficient in
+ * terms of time and memory usage.  If this condition does not hold, a copy
+ * of the matrix is created (where these conditions do hold), and the copy is
+ * ordered.  This feature is new to v2.0 (v1.2 and earlier required this
+ * condition to hold for the input matrix).
+ * 
+ * Row indices must be in the range 0 to
+ * n-1.  Ap [0] must be zero, and thus nz = Ap [n] is the number of nonzeros
+ * in A.  The array Ap is of size n+1, and the array Ai is of size nz = Ap [n].
+ * The matrix does not need to be symmetric, and the diagonal does not need to
+ * be present (if diagonal entries are present, they are ignored except for
+ * the output statistic Info [AMD_NZDIAG]).  The arrays Ai and Ap are not
+ * modified.  This form of the Ap and Ai arrays to represent the nonzero
+ * pattern of the matrix A is the same as that used internally by MATLAB.
+ * If you wish to use a more flexible input structure, please see the
+ * umfpack_*_triplet_to_col routines in the UMFPACK package, at
+ * http://www.suitesparse.com.
+ *
+ * Restrictions:  n >= 0.  Ap [0] = 0.  Ap [j] <= Ap [j+1] for all j in the
+ *       range 0 to n-1.  nz = Ap [n] >= 0.  Ai [0..nz-1] must be in the range 0
+ *       to n-1.  Finally, Ai, Ap, and P must not be NULL.  If any of these
+ *       restrictions are not met, AMD returns AMD_INVALID.
+ *
+ * AMD returns:
+ *
+ *       AMD_OK if the matrix is valid and sufficient memory can be allocated to
+ *           perform the ordering.
+ *
+ *       AMD_OUT_OF_MEMORY if not enough memory can be allocated.
+ *
+ *       AMD_INVALID if the input arguments n, Ap, Ai are invalid, or if P is
+ *           NULL.
+ *
+ *       AMD_OK_BUT_JUMBLED if the matrix had unsorted columns, and/or duplicate
+ *           entries, but was otherwise valid.
+ *
+ * The AMD routine first forms the pattern of the matrix A+A', and then
+ * computes a fill-reducing ordering, P.  If P [k] = i, then row/column i of
+ * the original is the kth pivotal row.  In MATLAB notation, the permuted
+ * matrix is A (P,P), except that 0-based indexing is used instead of the
+ * 1-based indexing in MATLAB.
+ *
+ * The Control array is used to set various parameters for AMD.  If a NULL
+ * pointer is passed, default values are used.  The Control array is not
+ * modified.
+ *
+ *       Control [AMD_DENSE]:  controls the threshold for "dense" rows/columns.
+ *           A dense row/column in A+A' can cause AMD to spend a lot of time in
+ *           ordering the matrix.  If Control [AMD_DENSE] >= 0, rows/columns
+ *           with more than Control [AMD_DENSE] * sqrt (n) entries are ignored
+ *           during the ordering, and placed last in the output order.  The
+ *           default value of Control [AMD_DENSE] is 10.  If negative, no
+ *           rows/columns are treated as "dense".  Rows/columns with 16 or
+ *           fewer off-diagonal entries are never considered "dense".
+ *
+ *       Control [AMD_AGGRESSIVE]: controls whether or not to use aggressive
+ *           absorption, in which a prior element is absorbed into the current
+ *           element if is a subset of the current element, even if it is not
+ *           adjacent to the current pivot element (refer to Amestoy, Davis,
+ *           & Duff, 1996, for more details).  The default value is nonzero,
+ *           which means to perform aggressive absorption.  This nearly always
+ *           leads to a better ordering (because the approximate degrees are
+ *           more accurate) and a lower execution time.  There are cases where
+ *           it can lead to a slightly worse ordering, however.  To turn it off,
+ *           set Control [AMD_AGGRESSIVE] to 0.
+ *
+ *       Control [2..4] are not used in the current version, but may be used in
+ *           future versions.
+ *
+ * The Info array provides statistics about the ordering on output.  If it is
+ * not present, the statistics are not returned.  This is not an error
+ * condition.
+ * 
+ *       Info [AMD_STATUS]:  the return value of AMD, either AMD_OK,
+ *           AMD_OK_BUT_JUMBLED, AMD_OUT_OF_MEMORY, or AMD_INVALID.
+ *
+ *       Info [AMD_N]: n, the size of the input matrix
+ *
+ *       Info [AMD_NZ]: the number of nonzeros in A, nz = Ap [n]
+ *
+ *       Info [AMD_SYMMETRY]:  the symmetry of the matrix A.  It is the number
+ *           of "matched" off-diagonal entries divided by the total number of
+ *           off-diagonal entries.  An entry A(i,j) is matched if A(j,i) is also
+ *           an entry, for any pair (i,j) for which i != j.  In MATLAB notation,
+ *                S = spones (A) ;
+ *                B = tril (S, -1) + triu (S, 1) ;
+ *                symmetry = nnz (B & B') / nnz (B) ;
+ *
+ *       Info [AMD_NZDIAG]: the number of entries on the diagonal of A.
+ *
+ *       Info [AMD_NZ_A_PLUS_AT]:  the number of nonzeros in A+A', excluding the
+ *           diagonal.  If A is perfectly symmetric (Info [AMD_SYMMETRY] = 1)
+ *           with a fully nonzero diagonal, then Info [AMD_NZ_A_PLUS_AT] = nz-n
+ *           (the smallest possible value).  If A is perfectly unsymmetric
+ *           (Info [AMD_SYMMETRY] = 0, for an upper triangular matrix, for
+ *           example) with no diagonal, then Info [AMD_NZ_A_PLUS_AT] = 2*nz
+ *           (the largest possible value).
+ *
+ *       Info [AMD_NDENSE]: the number of "dense" rows/columns of A+A' that were
+ *           removed from A prior to ordering.  These are placed last in the
+ *           output order P.
+ *
+ *       Info [AMD_MEMORY]: the amount of memory used by AMD, in bytes.  In the
+ *           current version, this is 1.2 * Info  [AMD_NZ_A_PLUS_AT] + 9*n
+ *           times the size of an integer.  This is at most 2.4nz + 9n.  This
+ *           excludes the size of the input arguments Ai, Ap, and P, which have
+ *           a total size of nz + 2*n + 1 integers.
+ *
+ *       Info [AMD_NCMPA]: the number of garbage collections performed.
+ *
+ *       Info [AMD_LNZ]: the number of nonzeros in L (excluding the diagonal).
+ *           This is a slight upper bound because mass elimination is combined
+ *           with the approximate degree update.  It is a rough upper bound if
+ *           there are many "dense" rows/columns.  The rest of the statistics,
+ *           below, are also slight or rough upper bounds, for the same reasons.
+ *           The post-ordering of the assembly tree might also not exactly
+ *           correspond to a true elimination tree postordering.
+ *
+ *       Info [AMD_NDIV]: the number of divide operations for a subsequent LDL'
+ *           or LU factorization of the permuted matrix A (P,P).
+ *
+ *       Info [AMD_NMULTSUBS_LDL]:  the number of multiply-subtract pairs for a
+ *           subsequent LDL' factorization of A (P,P).
+ *
+ *       Info [AMD_NMULTSUBS_LU]:  the number of multiply-subtract pairs for a
+ *           subsequent LU factorization of A (P,P), assuming that no numerical
+ *           pivoting is required.
+ *
+ *       Info [AMD_DMAX]:  the maximum number of nonzeros in any column of L,
+ *           including the diagonal.
+ *
+ *       Info [14..19] are not used in the current version, but may be used in
+ *           future versions.
+ */    
+
+/* ------------------------------------------------------------------------- */
+/* direct interface to AMD */
+/* ------------------------------------------------------------------------- */
+
+/* amd_2 is the primary AMD ordering routine.  It is not meant to be
+ * user-callable because of its restrictive inputs and because it destroys
+ * the user's input matrix.  It does not check its inputs for errors, either.
+ * However, if you can work with these restrictions it can be faster than
+ * amd_order and use less memory (assuming that you can create your own copy
+ * of the matrix for AMD to destroy).  Refer to AMD/Source/amd_2.c for a
+ * description of each parameter. */
+
+void amd_2
+(
+    int n,
+    int Pe [ ],
+    int Iw [ ],
+    int Len [ ],
+    int iwlen,
+    int pfree,
+    int Nv [ ],
+    int Next [ ], 
+    int Last [ ],
+    int Head [ ],
+    int Elen [ ],
+    int Degree [ ],
+    int W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+void amd_l2
+(
+    SuiteSparse_long n,
+    SuiteSparse_long Pe [ ],
+    SuiteSparse_long Iw [ ],
+    SuiteSparse_long Len [ ],
+    SuiteSparse_long iwlen,
+    SuiteSparse_long pfree,
+    SuiteSparse_long Nv [ ],
+    SuiteSparse_long Next [ ], 
+    SuiteSparse_long Last [ ],
+    SuiteSparse_long Head [ ],
+    SuiteSparse_long Elen [ ],
+    SuiteSparse_long Degree [ ],
+    SuiteSparse_long W [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* amd_valid */
+/* ------------------------------------------------------------------------- */
+
+/* Returns AMD_OK or AMD_OK_BUT_JUMBLED if the matrix is valid as input to
+ * amd_order; the latter is returned if the matrix has unsorted and/or
+ * duplicate row indices in one or more columns.  Returns AMD_INVALID if the
+ * matrix cannot be passed to amd_order.  For amd_order, the matrix must also
+ * be square.  The first two arguments are the number of rows and the number
+ * of columns of the matrix.  For its use in AMD, these must both equal n.
+ *
+ * NOTE: this routine returned TRUE/FALSE in v1.2 and earlier.
+ */
+
+int amd_valid
+(
+    int n_row,                 /* # of rows */
+    int n_col,                 /* # of columns */
+    const int Ap [ ],          /* column pointers, of size n_col+1 */
+    const int Ai [ ]           /* row indices, of size Ap [n_col] */
+) ;
+
+SuiteSparse_long amd_l_valid
+(
+    SuiteSparse_long n_row,
+    SuiteSparse_long n_col,
+    const SuiteSparse_long Ap [ ],
+    const SuiteSparse_long Ai [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* AMD memory manager and printf routines */
+/* ------------------------------------------------------------------------- */
+
+/* The user can redefine these to change the malloc, free, and printf routines
+ * that AMD uses. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN void *(*amd_malloc) (size_t) ;                     /* pointer to malloc */
+EXTERN void (*amd_free) (void *) ;               /* pointer to free */
+EXTERN void *(*amd_realloc) (void *, size_t) ;            /* pointer to realloc */
+EXTERN void *(*amd_calloc) (size_t, size_t) ;             /* pointer to calloc */
+EXTERN int (*amd_printf) (const char *, ...) ;            /* pointer to printf */
+
+/* ------------------------------------------------------------------------- */
+/* AMD Control and Info arrays */
+/* ------------------------------------------------------------------------- */
+
+/* amd_defaults:  sets the default control settings */
+void amd_defaults   (double Control [ ]) ;
+void amd_l_defaults (double Control [ ]) ;
+
+/* amd_control: prints the control settings */
+void amd_control    (double Control [ ]) ;
+void amd_l_control  (double Control [ ]) ;
+
+/* amd_info: prints the statistics */
+void amd_info       (double Info [ ]) ;
+void amd_l_info     (double Info [ ]) ;
+
+#define AMD_CONTROL 5          /* size of Control array */
+#define AMD_INFO 20            /* size of Info array */
+
+/* contents of Control */
+#define AMD_DENSE 0            /* "dense" if degree > Control [0] * sqrt (n) */
+#define AMD_AGGRESSIVE 1    /* do aggressive absorption if Control [1] != 0 */
+
+/* default Control settings */
+#define AMD_DEFAULT_DENSE 10.0          /* default "dense" degree 10*sqrt(n) */
+#define AMD_DEFAULT_AGGRESSIVE 1    /* do aggressive absorption by default */
+
+/* contents of Info */
+#define AMD_STATUS 0           /* return value of amd_order and amd_l_order */
+#define AMD_N 1                /* A is n-by-n */
+#define AMD_NZ 2      /* number of nonzeros in A */ 
+#define AMD_SYMMETRY 3         /* symmetry of pattern (1 is sym., 0 is unsym.) */
+#define AMD_NZDIAG 4           /* # of entries on diagonal */
+#define AMD_NZ_A_PLUS_AT 5  /* nz in A+A' */
+#define AMD_NDENSE 6           /* number of "dense" rows/columns in A */
+#define AMD_MEMORY 7           /* amount of memory used by AMD */
+#define AMD_NCMPA 8            /* number of garbage collections in AMD */
+#define AMD_LNZ 9     /* approx. nz in L, excluding the diagonal */
+#define AMD_NDIV 10            /* number of fl. point divides for LU and LDL' */
+#define AMD_NMULTSUBS_LDL 11 /* number of fl. point (*,-) pairs for LDL' */
+#define AMD_NMULTSUBS_LU 12  /* number of fl. point (*,-) pairs for LU */
+#define AMD_DMAX 13             /* max nz. in any column of L, incl. diagonal */
+
+/* ------------------------------------------------------------------------- */
+/* return values of AMD */
+/* ------------------------------------------------------------------------- */
+
+#define AMD_OK 0           /* success */
+#define AMD_OUT_OF_MEMORY -1        /* malloc failed, or problem too large */
+#define AMD_INVALID -2              /* input arguments are not valid */
+#define AMD_OK_BUT_JUMBLED 1        /* input matrix is OK for amd_order, but
+    * columns were not sorted, and/or duplicate entries were present.  AMD had
+    * to do extra work before ordering the matrix.  This is a warning, not an
+    * error.  */
+
+/* ========================================================================== */
+/* === AMD version ========================================================== */
+/* ========================================================================== */
+
+/* AMD Version 1.2 and later include the following definitions.
+ * As an example, to test if the version you are using is 1.2 or later:
+ *
+ * #ifdef AMD_VERSION
+ *       if (AMD_VERSION >= AMD_VERSION_CODE (1,2)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *       #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE (1,2))
+ *           printf ("This is version 1.2 or later\n") ;
+ *       #else
+ *           printf ("This is an early version\n") ;
+ *       #endif
+ *
+ * Versions 1.1 and earlier of AMD do not include a #define'd version number.
+ */
+
+#define AMD_DATE "Jun 20, 2012"
+#define AMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define AMD_MAIN_VERSION 2
+#define AMD_SUB_VERSION 3
+#define AMD_SUBSUB_VERSION 1
+#define AMD_VERSION AMD_VERSION_CODE(AMD_MAIN_VERSION,AMD_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/AMD/Include/amd_internal.h b/src/AMD/Include/amd_internal.h
new file mode 100644
index 0000000..c5f5493
--- /dev/null
+++ b/src/AMD/Include/amd_internal.h
@@ -0,0 +1,347 @@
+/* ========================================================================= */
+/* === amd_internal.h ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,                                      */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* This file is for internal use in AMD itself, and does not normally need to
+ * be included in user code (it is included in UMFPACK, however).   All others
+ * should use amd.h instead.
+ *
+ * The following compile-time definitions affect how AMD is compiled.
+ *
+ *      -DNPRINT
+ *
+ *          Disable all printing.  stdio.h will not be included.  Printing can
+ *          be re-enabled at run-time by setting the global pointer amd_printf
+ *          to printf (or mexPrintf for a MATLAB mexFunction).
+ *
+ *      -DNMALLOC
+ *
+ *          No memory manager is defined at compile-time.  You MUST define the
+ *          function pointers amd_malloc, amd_free, amd_realloc, and
+ *          amd_calloc at run-time for AMD to work properly.
+ */
+
+/* ========================================================================= */
+/* === NDEBUG ============================================================== */
+/* ========================================================================= */
+
+/*
+ * Turning on debugging takes some work (see below).   If you do not edit this
+ * file, then debugging is always turned off, regardless of whether or not
+ * -DNDEBUG is specified in your compiler options.
+ *
+ * If AMD is being compiled as a mexFunction, then MATLAB_MEX_FILE is defined,
+ * and mxAssert is used instead of assert.  If debugging is not enabled, no
+ * MATLAB include files or functions are used.  Thus, the AMD library libamd.a
+ * can be safely used in either a stand-alone C program or in another
+ * mexFunction, without any change.
+ */
+
+/*
+    AMD will be exceedingly slow when running in debug mode.  The next three
+    lines ensure that debugging is turned off.
+*/
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/*
+    To enable debugging, uncomment the following line:
+#undef NDEBUG
+*/
+
+/* ------------------------------------------------------------------------- */
+/* ANSI include files */
+/* ------------------------------------------------------------------------- */
+
+/* from stdlib.h:  size_t, malloc, free, realloc, and calloc */
+#include <stdlib.h>
+
+#if !defined(NPRINT) || !defined(NDEBUG)
+/* from stdio.h:  printf.  Not included if NPRINT is defined at compile time.
+ * fopen and fscanf are used when debugging. */
+#include <stdio.h>
+#endif
+
+/* from limits.h:  INT_MAX and LONG_MAX */
+#include <limits.h>
+
+/* from math.h: sqrt */
+#include <math.h>
+
+/* ------------------------------------------------------------------------- */
+/* MATLAB include files (only if being used in or via MATLAB) */
+/* ------------------------------------------------------------------------- */
+
+#ifdef MATLAB_MEX_FILE
+#include "matrix.h"
+#include "mex.h"
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* basic definitions */
+/* ------------------------------------------------------------------------- */
+
+#ifdef FLIP
+#undef FLIP
+#endif
+
+#ifdef MAX
+#undef MAX
+#endif
+
+#ifdef MIN
+#undef MIN
+#endif
+
+#ifdef EMPTY
+#undef EMPTY
+#endif
+
+#ifdef GLOBAL
+#undef GLOBAL
+#endif
+
+#ifdef PRIVATE
+#undef PRIVATE
+#endif
+
+/* FLIP is a "negation about -1", and is used to mark an integer i that is
+ * normally non-negative.  FLIP (EMPTY) is EMPTY.  FLIP of a number > EMPTY
+ * is negative, and FLIP of a number < EMTPY is positive.  FLIP (FLIP (i)) = i
+ * for all integers i.  UNFLIP (i) is >= EMPTY. */
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) ((i < EMPTY) ? FLIP (i) : (i))
+
+/* for integer MAX/MIN, or for doubles when we don't care how NaN's behave: */
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+/* logical expression of p implies q: */
+#define IMPLIES(p,q) (!(p) || (q))
+
+/* Note that the IBM RS 6000 xlc predefines TRUE and FALSE in <types.h>. */
+/* The Compaq Alpha also predefines TRUE and FALSE. */
+#ifdef TRUE
+#undef TRUE
+#endif
+#ifdef FALSE
+#undef FALSE
+#endif
+
+#define TRUE (1)
+#define FALSE (0)
+#define PRIVATE static
+#define GLOBAL
+#define EMPTY (-1)
+
+/* Note that Linux's gcc 2.96 defines NULL as ((void *) 0), but other */
+/* compilers (even gcc 2.95.2 on Solaris) define NULL as 0 or (0).  We */
+/* need to use the ANSI standard value of 0. */
+#ifdef NULL
+#undef NULL
+#endif
+
+#define NULL 0
+
+/* largest value of size_t */
+#ifndef SIZE_T_MAX
+#ifdef SIZE_MAX
+/* C99 only */
+#define SIZE_T_MAX SIZE_MAX
+#else
+#define SIZE_T_MAX ((size_t) (-1))
+#endif
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* integer type for AMD: int or SuiteSparse_long */
+/* ------------------------------------------------------------------------- */
+
+#include "amd.h"
+
+#if defined (DLONG) || defined (ZLONG)
+
+#define Int SuiteSparse_long
+#define ID  SuiteSparse_long_id
+#define Int_MAX SuiteSparse_long_max
+
+#define AMD_order amd_l_order
+#define AMD_defaults amd_l_defaults
+#define AMD_control amd_l_control
+#define AMD_info amd_l_info
+#define AMD_1 amd_l1
+#define AMD_2 amd_l2
+#define AMD_valid amd_l_valid
+#define AMD_aat amd_l_aat
+#define AMD_postorder amd_l_postorder
+#define AMD_post_tree amd_l_post_tree
+#define AMD_dump amd_l_dump
+#define AMD_debug amd_l_debug
+#define AMD_debug_init amd_l_debug_init
+#define AMD_preprocess amd_l_preprocess
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define AMD_order amd_order
+#define AMD_defaults amd_defaults
+#define AMD_control amd_control
+#define AMD_info amd_info
+#define AMD_1 amd_1
+#define AMD_2 amd_2
+#define AMD_valid amd_valid
+#define AMD_aat amd_aat
+#define AMD_postorder amd_postorder
+#define AMD_post_tree amd_post_tree
+#define AMD_dump amd_dump
+#define AMD_debug amd_debug
+#define AMD_debug_init amd_debug_init
+#define AMD_preprocess amd_preprocess
+
+#endif
+
+/* ========================================================================= */
+/* === PRINTF macro ======================================================== */
+/* ========================================================================= */
+
+/* All output goes through the PRINTF macro.  */
+#define PRINTF(params) { if (amd_printf != NULL) (void) amd_printf params ; }
+
+/* ------------------------------------------------------------------------- */
+/* AMD routine definitions (not user-callable) */
+/* ------------------------------------------------------------------------- */
+
+GLOBAL size_t AMD_aat
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],
+    Int Tp [ ],
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_1
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    Int Pinv [ ],
+    Int Len [ ],
+    Int slen,
+    Int S [ ],
+    double Control [ ],
+    double Info [ ]
+) ;
+
+GLOBAL void AMD_postorder
+(
+    Int nn,
+    Int Parent [ ],
+    Int Npiv [ ],
+    Int Fsize [ ],
+    Int Order [ ],
+    Int Child [ ],
+    Int Sibling [ ],
+    Int Stack [ ]
+) ;
+
+GLOBAL Int AMD_post_tree
+(
+    Int root,
+    Int k,
+    Int Child [ ],
+    const Int Sibling [ ],
+    Int Order [ ],
+    Int Stack [ ]
+#ifndef NDEBUG
+    , Int nn
+#endif
+) ;
+
+GLOBAL void AMD_preprocess
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Rp [ ],
+    Int Ri [ ],
+    Int W [ ],
+    Int Flag [ ]
+) ;
+
+/* ------------------------------------------------------------------------- */
+/* debugging definitions */
+/* ------------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+
+/* from assert.h:  assert macro */
+#include <assert.h>
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN Int AMD_debug ;
+
+GLOBAL void AMD_debug_init ( char *s ) ;
+
+GLOBAL void AMD_dump
+(
+    Int n,
+    Int Pe [ ],
+    Int Iw [ ],
+    Int Len [ ],
+    Int iwlen,
+    Int pfree,
+    Int Nv [ ],
+    Int Next [ ],
+    Int Last [ ],
+    Int Head [ ],
+    Int Elen [ ],
+    Int Degree [ ],
+    Int W [ ],
+    Int nel
+) ;
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+/* Use mxAssert if AMD is compiled into a mexFunction */
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif
+
+#define AMD_DEBUG0(params) { PRINTF (params) ; }
+#define AMD_DEBUG1(params) { if (AMD_debug >= 1) PRINTF (params) ; }
+#define AMD_DEBUG2(params) { if (AMD_debug >= 2) PRINTF (params) ; }
+#define AMD_DEBUG3(params) { if (AMD_debug >= 3) PRINTF (params) ; }
+#define AMD_DEBUG4(params) { if (AMD_debug >= 4) PRINTF (params) ; }
+
+#else
+
+/* no debugging */
+#define ASSERT(expression)
+#define AMD_DEBUG0(params)
+#define AMD_DEBUG1(params)
+#define AMD_DEBUG2(params)
+#define AMD_DEBUG3(params)
+#define AMD_DEBUG4(params)
+
+#endif
diff --git a/src/AMD/Makefile b/src/AMD/Makefile
new file mode 100644
index 0000000..2db3476
--- /dev/null
+++ b/src/AMD/Makefile
@@ -0,0 +1,73 @@
+#------------------------------------------------------------------------------
+# AMD Makefile (for GNU Make or original make)
+#------------------------------------------------------------------------------
+
+VERSION = 2.3.1
+
+default: all
+
+include ../SuiteSparse_config/SuiteSparse_config.mk
+
+demos: all
+
+# Compile all C code.  Do not compile the FORTRAN versions.
+all:
+	( cd Lib    ; $(MAKE) )
+	( cd Demo   ; $(MAKE) )
+
+# compile just the C-callable libraries (not Demos)
+library:
+	( cd Lib    ; $(MAKE) )
+
+# compile the FORTRAN libraries and demo programs (not compiled by "make all")
+fortran:
+	( cd Lib    ; $(MAKE) fortran )
+	( cd Demo   ; $(MAKE) fortran )
+
+# compile a FORTRAN demo program that calls the C version of AMD
+# (not compiled by "make all")
+cross:
+	( cd Demo   ; $(MAKE) cross )
+
+# remove object files, but keep the compiled programs and library archives
+clean:
+	( cd Lib    ; $(MAKE) clean )
+	( cd Demo   ; $(MAKE) clean )
+	( cd MATLAB ; $(RM) $(CLEAN) )
+	( cd Doc    ; $(MAKE) clean )
+
+# clean, and then remove compiled programs and library archives
+purge:
+	( cd Lib    ; $(MAKE) purge )
+	( cd Demo   ; $(MAKE) purge )
+	( cd MATLAB ; $(RM) $(CLEAN) ; $(RM) *.mex* )
+	( cd Doc    ; $(MAKE) purge )
+
+distclean: purge
+
+# create PDF documents for the original distribution
+docs:
+	( cd Doc    ; $(MAKE) )
+
+# get ready for distribution
+dist: purge
+	( cd Demo   ; $(MAKE) dist )
+	( cd Doc    ; $(MAKE) )
+
+ccode: library
+
+lib: library
+
+# install AMD
+install:
+	$(CP) Lib/libamd.a $(INSTALL_LIB)/libamd.$(VERSION).a
+	( cd $(INSTALL_LIB) ; ln -sf libamd.$(VERSION).a libamd.a )
+	$(CP) Include/amd.h $(INSTALL_INCLUDE)
+	chmod 644 $(INSTALL_LIB)/libamd*
+	chmod 644 $(INSTALL_INCLUDE)/amd.h
+
+# uninstall AMD
+uninstall:
+	$(RM) $(INSTALL_LIB)/libamd*.a
+	$(RM) $(INSTALL_INCLUDE)/amd.h
+
diff --git a/src/AMD/README.txt b/src/AMD/README.txt
new file mode 100644
index 0000000..2f0a4ff
--- /dev/null
+++ b/src/AMD/README.txt
@@ -0,0 +1,213 @@
+AMD, Copyright (c) 2009-2012 by Timothy A. Davis (http://www.suitesparse.com),
+Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.  AMD is available
+under alternate licences; contact T. Davis for details.
+
+AMD:  a set of routines for permuting sparse matrices prior to
+    factorization.  Includes a version in C, a version in Fortran, and a MATLAB
+    mexFunction.
+
+Requires SuiteSparse_config, in the ../SuiteSparse_config directory relative to
+this directory.
+
+Quick start (Unix, or Windows with Cygwin):
+
+    To compile, test, and install AMD, you may wish to first configure the
+    installation by editting the ../SuiteSparse_config/SuiteSparse_config.mk
+    file.  Next, cd to this directory (AMD) and type "make" (or "make lib" if
+    you do not have MATLAB).  To compile and run a demo program for the Fortran
+    version, type "make fortran".  When done, type "make clean" to remove
+    unused *.o files (keeps the compiled libraries and demo programs).  See the
+    User Guide (Doc/AMD_UserGuide.pdf), or
+    ../SuiteSparse_config/SuiteSparse_config.mk for more details.
+
+Quick start (for MATLAB users);
+
+    To compile, test, and install the AMD mexFunction, cd to the
+    AMD/MATLAB directory and type amd_make at the MATLAB prompt.
+
+-------------------------------------------------------------------------------
+
+AMD License:
+
+    Your use or distribution of AMD or any modified version of
+    AMD implies that you agree to this License.
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+    USA
+
+    Permission is hereby granted to use or copy this program under the
+    terms of the GNU LGPL, provided that the Copyright, this License,
+    and the Availability of the original version is retained on all copies.
+    User documentation of any code that uses this code or any modified
+    version of this code must cite the Copyright, this License, the
+    Availability note, and "Used by permission." Permission to modify
+    the code and to distribute modified code is granted, provided the
+    Copyright, this License, and the Availability note are retained,
+    and a notice that the code was modified is included.
+
+Availability:
+
+    http://www.suitesparse.com
+
+-------------------------------------------------------------------------------
+
+This is the AMD README file.  It is a terse overview of AMD.
+Refer to the User Guide (Doc/AMD_UserGuide.pdf) for how to install
+and use AMD.
+
+Description:
+
+    AMD is a set of routines for pre-ordering sparse matrices prior to Cholesky
+    or LU factorization, using the approximate minimum degree ordering
+    algorithm.  Written in ANSI/ISO C with a MATLAB interface, and in
+    Fortran 77.
+
+Authors:
+
+    Timothy A. Davis (DrTimothyAldenDavis at gmail.com)
+    Patrick R. Amestory, ENSEEIHT, Toulouse, France.
+    Iain S. Duff, Rutherford Appleton Laboratory, UK.
+
+Acknowledgements:
+
+    This work was supported by the National Science Foundation, under
+    grants DMS-9504974, DMS-9803599, and CCR-0203270.
+
+    Portions of this work were done while on sabbatical at Stanford University
+    and Lawrence Berkeley National Laboratory (with funding from the SciDAC
+    program).  I would like to thank Gene Golub, Esmond Ng, and Horst Simon
+    for making this sabbatical possible.
+
+-------------------------------------------------------------------------------
+Files and directories in the AMD distribution:
+-------------------------------------------------------------------------------
+
+    ---------------------------------------------------------------------------
+    Subdirectories of the AMD directory:
+    ---------------------------------------------------------------------------
+
+    Doc		documentation
+    Source	primary source code
+    Include	include file for use in your code that calls AMD
+    Demo	demo programs.  also serves as test of the AMD installation.
+    MATLAB	AMD mexFunction for MATLAB, and supporting m-files
+    Lib		where the compiled C-callable and Fortran-callable
+		AMD libraries placed.
+
+    ---------------------------------------------------------------------------
+    Files in the AMD directory:
+    ---------------------------------------------------------------------------
+
+    Makefile	top-level Makefile for GNU make or original make.
+		Windows users would require Cygwin to use "make"
+
+    README.txt	this file
+
+    ---------------------------------------------------------------------------
+    Doc directory: documentation
+    ---------------------------------------------------------------------------
+
+    ChangeLog			change log
+    License			the AMD License
+    Makefile			for creating the documentation
+    AMD_UserGuide.bib		AMD User Guide (references)
+    AMD_UserGuide.tex		AMD User Guide (LaTeX)
+    AMD_UserGuide.pdf		AMD User Guide (PDF)
+    lesser.txt			the GNU LGPL license
+
+    ---------------------------------------------------------------------------
+    Source directory:
+    ---------------------------------------------------------------------------
+
+    amd_order.c			user-callable, primary AMD ordering routine
+    amd_control.c		user-callable, prints the control parameters
+    amd_defaults.c		user-callable, sets default control parameters
+    amd_info.c			user-callable, prints the statistics from AMD
+
+    amd_1.c			non-user-callable, construct A+A'
+    amd_2.c			user-callable, primary ordering kernel
+				(a C version of amd.f and amdbar.f, with
+				post-ordering added)
+    amd_aat.c			non-user-callable, computes nnz (A+A')
+    amd_dump.c			non-user-callable, debugging routines
+    amd_postorder.c		non-user-callable, postorder
+    amd_post_tree.c		non-user-callable, postorder just one tree
+    amd_valid.c			non-user-callable, verifies a matrix
+    amd_preprocess.c		non-user-callable, computes A', removes duplic
+
+    amd.f			user-callable Fortran 77 version
+    amdbar.f			user-callable Fortran 77 version
+
+    ---------------------------------------------------------------------------
+    Include directory:
+    ---------------------------------------------------------------------------
+
+    amd.h			include file for C programs that use AMD
+    amd_internal.h		non-user-callable, include file for AMD
+
+    ---------------------------------------------------------------------------
+    Demo directory:
+    ---------------------------------------------------------------------------
+
+    Makefile			for GNU make or original make
+
+    amd_demo.c			C demo program for AMD
+    amd_demo.out		output of amd_demo.c
+
+    amd_demo2.c			C demo program for AMD, jumbled matrix
+    amd_demo2.out		output of amd_demo2.c
+
+    amd_l_demo.c		C demo program for AMD (long integer version)
+    amd_l_demo.out		output of amd_l_demo.c
+
+    amd_simple.c		simple C demo program for AMD
+    amd_simple.out		output of amd_simple.c
+
+    amd_f77demo.f		Fortran 77 demo program for AMD
+    amd_f77demo.out		output of amd_f77demo.f
+
+    amd_f77simple.c		simple Fortran 77 demo program for AMD
+    amd_f77simple.out		output of amd_f77simple.f
+
+    amd_f77cross.f		Fortran 77 demo, calls the C version of AMD
+    amd_f77cross.out		output of amd_f77cross.f
+    amd_f77wrapper.c		Fortran-callable wrapper for C version of AMD
+
+    ---------------------------------------------------------------------------
+    MATLAB directory:
+    ---------------------------------------------------------------------------
+
+    GNUmakefile			a nice Makefile, for GNU make
+    Makefile			an ugly Unix Makefile (for older make's)
+
+    Contents.m			for "help amd2" listing of toolbox contents
+
+    amd2.m			MATLAB help file for AMD
+    amd_make.m			MATLAB m-file for compiling AMD mexFunction
+    amd_install.m		compile and install the AMD mexFunction
+
+    amd_mex.c			AMD mexFunction for MATLAB
+
+    amd_demo.m			MATLAB demo for AMD
+    amd_demo.m.out		diary output of amd_demo.m
+    can_24.mat			input file for AMD demo
+
+    ---------------------------------------------------------------------------
+    Lib directory:  libamd.a and libamdf77.a libraries placed here
+    ---------------------------------------------------------------------------
+
+    GNUmakefile			a nice Makefile, for GNU make
+    Makefile			an ugly Unix Makefile (for older make's)
+    libamd.def			AMD definitions for Windows
diff --git a/src/AMD/Source/amd.f b/src/AMD/Source/amd.f
new file mode 100644
index 0000000..ccfe3e8
--- /dev/null
+++ b/src/AMD/Source/amd.f
@@ -0,0 +1,1214 @@
+C-----------------------------------------------------------------------
+C AMD:  approximate minimum degree, with aggressive absorption
+C-----------------------------------------------------------------------
+
+        SUBROUTINE AMD
+     $          (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $          LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+
+        INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N),
+     $          DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N),
+     $          ELEN (N), W (N), LEN (N)
+
+C Given a representation of the nonzero pattern of a symmetric matrix,
+C       A, (excluding the diagonal) perform an approximate minimum
+C       (UMFPACK/MA38-style) degree ordering to compute a pivot order
+C       such that the introduction of nonzeros (fill-in) in the Cholesky
+C       factors A = LL^T are kept low.  At each step, the pivot
+C       selected is the one with the minimum UMFPACK/MA38-style
+C       upper-bound on the external degree.
+C
+C       Aggresive absorption is used to tighten the bound on the degree.
+
+C **********************************************************************
+C ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+C **********************************************************************
+
+C       References:
+C
+C       [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
+C           multifrontal method for sparse LU factorization", SIAM J.
+C           Matrix Analysis and Applications, vol. 18, no. 1, pp.
+C           140-158.  Discusses UMFPACK / MA38, which first introduced
+C           the approximate minimum degree used by this routine.
+C
+C       [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An
+C           approximate degree ordering algorithm," SIAM J. Matrix
+C           Analysis and Applications, vol. 17, no. 4, pp. 886-905,
+C           1996.  Discusses AMD, AMDBAR, and MC47B.
+C
+C       [3] Alan George and Joseph Liu, "The evolution of the minimum
+C           degree ordering algorithm," SIAM Review, vol. 31, no. 1,
+C           pp. 1-19, 1989.  We list below the features mentioned in
+C           that paper that this code includes:
+C
+C       mass elimination:
+C               Yes.  MA27 relied on supervariable detection for mass
+C               elimination.
+C       indistinguishable nodes:
+C               Yes (we call these "supervariables").  This was also in
+C               the MA27 code - although we modified the method of
+C               detecting them (the previous hash was the true degree,
+C               which we no longer keep track of).  A supervariable is
+C               a set of rows with identical nonzero pattern.  All
+C               variables in a supervariable are eliminated together.
+C               Each supervariable has as its numerical name that of
+C               one of its variables (its principal variable).
+C       quotient graph representation:
+C               Yes.  We use the term "element" for the cliques formed
+C               during elimination.  This was also in the MA27 code.
+C               The algorithm can operate in place, but it will work
+C               more efficiently if given some "elbow room."
+C       element absorption:
+C               Yes.  This was also in the MA27 code.
+C       external degree:
+C               Yes.  The MA27 code was based on the true degree.
+C       incomplete degree update and multiple elimination:
+C               No.  This was not in MA27, either.  Our method of
+C               degree update within MC47B/BD is element-based, not
+C               variable-based.  It is thus not well-suited for use
+C               with incomplete degree update or multiple elimination.
+
+C-----------------------------------------------------------------------
+C Authors, and Copyright (C) 1995 by:
+C       Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid.
+C
+C Acknowledgements:
+C       This work (and the UMFPACK package) was supported by the
+C       National Science Foundation (ASC-9111263 and DMS-9223088).
+C       The UMFPACK/MA38 approximate degree update algorithm, the
+C       unsymmetric analog which forms the basis of MC47B/BD, was
+C       developed while Tim Davis was supported by CERFACS (Toulouse,
+C       France) in a post-doctoral position.
+C
+C Date:  September, 1995
+C-----------------------------------------------------------------------
+
+C-----------------------------------------------------------------------
+C INPUT ARGUMENTS (unaltered):
+C-----------------------------------------------------------------------
+
+C n:    The matrix order.
+C
+C       Restriction:  1 .le. n .lt. (iovflo/2)-2, where iovflo is
+C       the largest positive integer that your computer can represent.
+
+C iwlen:        The length of iw (1..iwlen).  On input, the matrix is
+C       stored in iw (1..pfree-1).  However, iw (1..iwlen) should be
+C       slightly larger than what is required to hold the matrix, at
+C       least iwlen .ge. pfree + n is recommended.  Otherwise,
+C       excessive compressions will take place.
+C       *** We do not recommend running this algorithm with ***
+C       ***      iwlen .lt. pfree + n.                      ***
+C       *** Better performance will be obtained if          ***
+C       ***      iwlen .ge. pfree + n                       ***
+C       *** or better yet                                   ***
+C       ***      iwlen .gt. 1.2 * pfree                     ***
+C       *** (where pfree is its value on input).            ***
+C       The algorithm will not run at all if iwlen .lt. pfree-1.
+C
+C       Restriction: iwlen .ge. pfree-1
+
+C-----------------------------------------------------------------------
+C INPUT/OUPUT ARGUMENTS:
+C-----------------------------------------------------------------------
+
+C pe:   On input, pe (i) is the index in iw of the start of row i, or
+C       zero if row i has no off-diagonal non-zeros.
+C
+C       During execution, it is used for both supervariables and
+C       elements:
+C
+C       * Principal supervariable i:  index into iw of the
+C               description of supervariable i.  A supervariable
+C               represents one or more rows of the matrix
+C               with identical nonzero pattern.
+C       * Non-principal supervariable i:  if i has been absorbed
+C               into another supervariable j, then pe (i) = -j.
+C               That is, j has the same pattern as i.
+C               Note that j might later be absorbed into another
+C               supervariable j2, in which case pe (i) is still -j,
+C               and pe (j) = -j2.
+C       * Unabsorbed element e:  the index into iw of the description
+C               of element e, if e has not yet been absorbed by a
+C               subsequent element.  Element e is created when
+C               the supervariable of the same name is selected as
+C               the pivot.
+C       * Absorbed element e:  if element e is absorbed into element
+C               e2, then pe (e) = -e2.  This occurs when the pattern of
+C               e (that is, Le) is found to be a subset of the pattern
+C               of e2 (that is, Le2).  If element e is "null" (it has
+C               no nonzeros outside its pivot block), then pe (e) = 0.
+C
+C       On output, pe holds the assembly tree/forest, which implicitly
+C       represents a pivot order with identical fill-in as the actual
+C       order (via a depth-first search of the tree).
+C
+C       On output:
+C       If nv (i) .gt. 0, then i represents a node in the assembly tree,
+C       and the parent of i is -pe (i), or zero if i is a root.
+C       If nv (i) = 0, then (i,-pe (i)) represents an edge in a
+C       subtree, the root of which is a node in the assembly tree.
+
+C pfree:        On input the tail end of the array, iw (pfree..iwlen),
+C       is empty, and the matrix is stored in iw (1..pfree-1).
+C       During execution, additional data is placed in iw, and pfree
+C       is modified so that iw (pfree..iwlen) is always the unused part
+C       of iw.  On output, pfree is set equal to the size of iw that
+C       would have been needed for no compressions to occur.  If
+C       ncmpa is zero, then pfree (on output) is less than or equal to
+C       iwlen, and the space iw (pfree+1 ... iwlen) was not used.
+C       Otherwise, pfree (on output) is greater than iwlen, and all the
+C       memory in iw was used.
+
+C-----------------------------------------------------------------------
+C INPUT/MODIFIED (undefined on output):
+C-----------------------------------------------------------------------
+
+C len:  On input, len (i) holds the number of entries in row i of the
+C       matrix, excluding the diagonal.  The contents of len (1..n)
+C       are undefined on output.
+
+C iw:   On input, iw (1..pfree-1) holds the description of each row i
+C       in the matrix.  The matrix must be symmetric, and both upper
+C       and lower triangular parts must be present.  The diagonal must
+C       not be present.  Row i is held as follows:
+C
+C               len (i):  the length of the row i data structure
+C               iw (pe (i) ... pe (i) + len (i) - 1):
+C                       the list of column indices for nonzeros
+C                       in row i (simple supervariables), excluding
+C                       the diagonal.  All supervariables start with
+C                       one row/column each (supervariable i is just
+C                       row i).
+C               if len (i) is zero on input, then pe (i) is ignored
+C               on input.
+C
+C               Note that the rows need not be in any particular order,
+C               and there may be empty space between the rows.
+C
+C       During execution, the supervariable i experiences fill-in.
+C       This is represented by placing in i a list of the elements
+C       that cause fill-in in supervariable i:
+C
+C               len (i):  the length of supervariable i
+C               iw (pe (i) ... pe (i) + elen (i) - 1):
+C                       the list of elements that contain i.  This list
+C                       is kept short by removing absorbed elements.
+C               iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
+C                       the list of supervariables in i.  This list
+C                       is kept short by removing nonprincipal
+C                       variables, and any entry j that is also
+C                       contained in at least one of the elements
+C                       (j in Le) in the list for i (e in row i).
+C
+C       When supervariable i is selected as pivot, we create an
+C       element e of the same name (e=i):
+C
+C               len (e):  the length of element e
+C               iw (pe (e) ... pe (e) + len (e) - 1):
+C                       the list of supervariables in element e.
+C
+C       An element represents the fill-in that occurs when supervariable
+C       i is selected as pivot (which represents the selection of row i
+C       and all non-principal variables whose principal variable is i).
+C       We use the term Le to denote the set of all supervariables
+C       in element e.  Absorbed supervariables and elements are pruned
+C       from these lists when computationally convenient.
+C
+C       CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+C       The contents of iw are undefined on output.
+
+C-----------------------------------------------------------------------
+C OUTPUT (need not be set on input):
+C-----------------------------------------------------------------------
+
+C nv:   During execution, abs (nv (i)) is equal to the number of rows
+C       that are represented by the principal supervariable i.  If i is
+C       a nonprincipal variable, then nv (i) = 0.  Initially,
+C       nv (i) = 1 for all i.  nv (i) .lt. 0 signifies that i is a
+C       principal variable in the pattern Lme of the current pivot
+C       element me.  On output, nv (e) holds the true degree of element
+C       e at the time it was created (including the diagonal part).
+
+C ncmpa:        The number of times iw was compressed.  If this is
+C       excessive, then the execution took longer than what could have
+C       been.  To reduce ncmpa, try increasing iwlen to be 10% or 20%
+C       larger than the value of pfree on input (or at least
+C       iwlen .ge. pfree + n).  The fastest performance will be
+C       obtained when ncmpa is returned as zero.  If iwlen is set to
+C       the value returned by pfree on *output*, then no compressions
+C       will occur.
+
+C elen: See the description of iw above.  At the start of execution,
+C       elen (i) is set to zero.  During execution, elen (i) is the
+C       number of elements in the list for supervariable i.  When e
+C       becomes an element, elen (e) = -nel is set, where nel is the
+C       current step of factorization.  elen (i) = 0 is done when i
+C       becomes nonprincipal.
+C
+C       For variables, elen (i) .ge. 0 holds until just before the
+C       permutation vectors are computed.  For elements,
+C       elen (e) .lt. 0 holds.
+C
+C       On output elen (1..n) holds the inverse permutation (the same
+C       as the 'INVP' argument in Sparspak).  That is, if k = elen (i),
+C       then row i is the kth pivot row.  Row i of A appears as the
+C       (elen(i))-th row in the permuted matrix, PAP^T.
+
+C last: In a degree list, last (i) is the supervariable preceding i,
+C       or zero if i is the head of the list.  In a hash bucket,
+C       last (i) is the hash key for i.  last (head (hash)) is also
+C       used as the head of a hash bucket if head (hash) contains a
+C       degree list (see head, below).
+C
+C       On output, last (1..n) holds the permutation (the same as the
+C       'PERM' argument in Sparspak).  That is, if i = last (k), then
+C       row i is the kth pivot row.  Row last (k) of A is the k-th row
+C       in the permuted matrix, PAP^T.
+
+C-----------------------------------------------------------------------
+C LOCAL (not input or output - used only during execution):
+C-----------------------------------------------------------------------
+
+C degree:       If i is a supervariable, then degree (i) holds the
+C       current approximation of the external degree of row i (an upper
+C       bound).  The external degree is the number of nonzeros in row i,
+C       minus abs (nv (i)) (the diagonal part).  The bound is equal to
+C       the external degree if elen (i) is less than or equal to two.
+C
+C       We also use the term "external degree" for elements e to refer
+C       to |Le \ Lme|.  If e is an element, then degree (e) holds |Le|,
+C       which is the degree of the off-diagonal part of the element e
+C       (not including the diagonal part).
+
+C head: head is used for degree lists.  head (deg) is the first
+C       supervariable in a degree list (all supervariables i in a
+C       degree list deg have the same approximate degree, namely,
+C       deg = degree (i)).  If the list deg is empty then
+C       head (deg) = 0.
+C
+C       During supervariable detection head (hash) also serves as a
+C       pointer to a hash bucket.
+C       If head (hash) .gt. 0, there is a degree list of degree hash.
+C               The hash bucket head pointer is last (head (hash)).
+C       If head (hash) = 0, then the degree list and hash bucket are
+C               both empty.
+C       If head (hash) .lt. 0, then the degree list is empty, and
+C               -head (hash) is the head of the hash bucket.
+C       After supervariable detection is complete, all hash buckets
+C       are empty, and the (last (head (hash)) = 0) condition is
+C       restored for the non-empty degree lists.
+
+C next: next (i) is the supervariable following i in a link list, or
+C       zero if i is the last in the list.  Used for two kinds of
+C       lists:  degree lists and hash buckets (a supervariable can be
+C       in only one kind of list at a time).
+
+C w:    The flag array w determines the status of elements and
+C       variables, and the external degree of elements.
+C
+C       for elements:
+C          if w (e) = 0, then the element e is absorbed
+C          if w (e) .ge. wflg, then w (e) - wflg is the size of
+C               the set |Le \ Lme|, in terms of nonzeros (the
+C               sum of abs (nv (i)) for each principal variable i that
+C               is both in the pattern of element e and NOT in the
+C               pattern of the current pivot element, me).
+C          if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
+C               not yet been seen in the scan of the element lists in
+C               the computation of |Le\Lme| in loop 150 below.
+C
+C       for variables:
+C          during supervariable detection, if w (j) .ne. wflg then j is
+C          not in the pattern of variable i
+C
+C       The w array is initialized by setting w (i) = 1 for all i,
+C       and by setting wflg = 2.  It is reinitialized if wflg becomes
+C       too large (to ensure that wflg+n does not cause integer
+C       overflow).
+
+C-----------------------------------------------------------------------
+C LOCAL INTEGERS:
+C-----------------------------------------------------------------------
+
+        INTEGER DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, HASH, HMOD, I,
+     $          ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
+     $          LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM,
+     $          NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
+
+C deg:          the degree of a variable or element
+C degme:        size, |Lme|, of the current element, me (= degree (me))
+C dext:         external degree, |Le \ Lme|, of some element e
+C dmax:         largest |Le| seen so far
+C e:            an element
+C elenme:       the length, elen (me), of element list of pivotal var.
+C eln:          the length, elen (...), of an element list
+C hash:         the computed value of the hash function
+C hmod:         the hash function is computed modulo hmod = max (1,n-1)
+C i:            a supervariable
+C ilast:        the entry in a link list preceding i
+C inext:        the entry in a link list following i
+C j:            a supervariable
+C jlast:        the entry in a link list preceding j
+C jnext:        the entry in a link list, or path, following j
+C k:            the pivot order of an element or variable
+C knt1:         loop counter used during element construction
+C knt2:         loop counter used during element construction
+C knt3:         loop counter used during compression
+C lenj:         len (j)
+C ln:           length of a supervariable list
+C maxmem:       amount of memory needed for no compressions
+C me:           current supervariable being eliminated, and the
+C                       current element created by eliminating that
+C                       supervariable
+C mem:          memory in use assuming no compressions have occurred
+C mindeg:       current minimum degree
+C nel:          number of pivots selected so far
+C newmem:       amount of new memory needed for current pivot element
+C nleft:        n - nel, the number of nonpivotal rows/columns remaining
+C nvi:          the number of variables in a supervariable i (= nv (i))
+C nvj:          the number of variables in a supervariable j (= nv (j))
+C nvpiv:        number of pivots in current element
+C slenme:       number of variables in variable list of pivotal variable
+C we:           w (e)
+C wflg:         used for flagging the w array.  See description of iw.
+C wnvi:         wflg - nv (i)
+C x:            either a supervariable or an element
+
+C-----------------------------------------------------------------------
+C LOCAL POINTERS:
+C-----------------------------------------------------------------------
+
+        INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC
+
+C               Any parameter (pe (...) or pfree) or local variable
+C               starting with "p" (for Pointer) is an index into iw,
+C               and all indices into iw use variables starting with
+C               "p."  The only exception to this rule is the iwlen
+C               input argument.
+
+C p:            pointer into lots of things
+C p1:           pe (i) for some variable i (start of element list)
+C p2:           pe (i) + elen (i) -  1 for some var. i (end of el. list)
+C p3:           index of first supervariable in clean list
+C pdst:         destination pointer, for compression
+C pend:         end of memory to compress
+C pj:           pointer into an element or variable
+C pme:          pointer into the current element (pme1...pme2)
+C pme1:         the current element, me, is stored in iw (pme1...pme2)
+C pme2:         the end of the current element
+C pn:           pointer into a "clean" variable, also used to compress
+C psrc:         source pointer, for compression
+
+C-----------------------------------------------------------------------
+C  FUNCTIONS CALLED:
+C-----------------------------------------------------------------------
+
+        INTRINSIC MAX, MIN, MOD
+
+C=======================================================================
+C  INITIALIZATIONS
+C=======================================================================
+
+        WFLG = 2
+        MINDEG = 1
+        NCMPA = 0
+        NEL = 0
+        HMOD = MAX (1, N-1)
+        DMAX = 0
+        MEM = PFREE - 1
+        MAXMEM = MEM
+	ME = 0
+
+        DO 10 I = 1, N
+           LAST (I) = 0
+           HEAD (I) = 0
+           NV (I) = 1
+           W (I) = 1
+           ELEN (I) = 0
+           DEGREE (I) = LEN (I)
+10         CONTINUE
+
+C       ----------------------------------------------------------------
+C       initialize degree lists and eliminate rows with no off-diag. nz.
+C       ----------------------------------------------------------------
+
+        DO 20 I = 1, N
+
+           DEG = DEGREE (I)
+
+           IF (DEG .GT. 0) THEN
+
+C             ----------------------------------------------------------
+C             place i in the degree list corresponding to its degree
+C             ----------------------------------------------------------
+
+              INEXT = HEAD (DEG)
+              IF (INEXT .NE. 0) LAST (INEXT) = I
+              NEXT (I) = INEXT
+              HEAD (DEG) = I
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             we have a variable that can be eliminated at once because
+C             there is no off-diagonal non-zero in its row.
+C             ----------------------------------------------------------
+
+              NEL = NEL + 1
+              ELEN (I) = -NEL
+              PE (I) = 0
+              W (I) = 0
+
+              ENDIF
+
+20         CONTINUE
+
+C=======================================================================
+C  WHILE (selecting pivots) DO
+C=======================================================================
+
+30      CONTINUE
+        IF (NEL .LT. N) THEN
+
+C=======================================================================
+C  GET PIVOT OF MINIMUM DEGREE
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          find next supervariable for elimination
+C          -------------------------------------------------------------
+
+           DO 40 DEG = MINDEG, N
+              ME = HEAD (DEG)
+              IF (ME .GT. 0) GOTO 50
+40            CONTINUE
+50         CONTINUE
+           MINDEG = DEG
+
+C          -------------------------------------------------------------
+C          remove chosen variable from link list
+C          -------------------------------------------------------------
+
+           INEXT = NEXT (ME)
+           IF (INEXT .NE. 0) LAST (INEXT) = 0
+           HEAD (DEG) = INEXT
+
+C          -------------------------------------------------------------
+C          me represents the elimination of pivots nel+1 to nel+nv(me).
+C          place me itself as the first in this set.  It will be moved
+C          to the nel+nv(me) position when the permutation vectors are
+C          computed.
+C          -------------------------------------------------------------
+
+           ELENME = ELEN (ME)
+           ELEN (ME) = - (NEL + 1)
+           NVPIV = NV (ME)
+           NEL = NEL + NVPIV
+
+C=======================================================================
+C  CONSTRUCT NEW ELEMENT
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          At this point, me is the pivotal supervariable.  It will be
+C          converted into the current element.  Scan list of the
+C          pivotal supervariable, me, setting tree pointers and
+C          constructing new list of supervariables for the new element,
+C          me.  p is a pointer to the current position in the old list.
+C          -------------------------------------------------------------
+
+C          flag the variable "me" as being in Lme by negating nv (me)
+           NV (ME) = -NVPIV
+           DEGME = 0
+
+           IF (ELENME .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             construct the new element in place
+C             ----------------------------------------------------------
+
+              PME1 = PE (ME)
+              PME2 = PME1 - 1
+
+              DO 60 P = PME1, PME1 + LEN (ME) - 1
+                 I = IW (P)
+                 NVI = NV (I)
+                 IF (NVI .GT. 0) THEN
+
+C                   ----------------------------------------------------
+C                   i is a principal variable not yet placed in Lme.
+C                   store i in new list
+C                   ----------------------------------------------------
+
+                    DEGME = DEGME + NVI
+C                   flag i as being in Lme by negating nv (i)
+                    NV (I) = -NVI
+                    PME2 = PME2 + 1
+                    IW (PME2) = I
+
+C                   ----------------------------------------------------
+C                   remove variable i from degree list.
+C                   ----------------------------------------------------
+
+                    ILAST = LAST (I)
+                    INEXT = NEXT (I)
+                    IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                    IF (ILAST .NE. 0) THEN
+                       NEXT (ILAST) = INEXT
+                    ELSE
+C                      i is at the head of the degree list
+                       HEAD (DEGREE (I)) = INEXT
+                       ENDIF
+
+                    ENDIF
+60               CONTINUE
+C             this element takes no new memory in iw:
+              NEWMEM = 0
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             construct the new element in empty space, iw (pfree ...)
+C             ----------------------------------------------------------
+
+              P = PE (ME)
+              PME1 = PFREE
+              SLENME = LEN (ME) - ELENME
+
+              DO 120 KNT1 = 1, ELENME + 1
+
+                 IF (KNT1 .GT. ELENME) THEN
+C                   search the supervariables in me.
+                    E = ME
+                    PJ = P
+                    LN = SLENME
+                 ELSE
+C                   search the elements in me.
+                    E = IW (P)
+                    P = P + 1
+                    PJ = PE (E)
+                    LN = LEN (E)
+                    ENDIF
+
+C                -------------------------------------------------------
+C                search for different supervariables and add them to the
+C                new list, compressing when necessary. this loop is
+C                executed once for each element in the list and once for
+C                all the supervariables in the list.
+C                -------------------------------------------------------
+
+                 DO 110 KNT2 = 1, LN
+                    I = IW (PJ)
+                    PJ = PJ + 1
+                    NVI = NV (I)
+                    IF (NVI .GT. 0) THEN
+
+C                      -------------------------------------------------
+C                      compress iw, if necessary
+C                      -------------------------------------------------
+
+                       IF (PFREE .GT. IWLEN) THEN
+C                         prepare for compressing iw by adjusting
+C                         pointers and lengths so that the lists being
+C                         searched in the inner and outer loops contain
+C                         only the remaining entries.
+
+                          PE (ME) = P
+                          LEN (ME) = LEN (ME) - KNT1
+                          IF (LEN (ME) .EQ. 0) THEN
+C                            nothing left of supervariable me
+                             PE (ME) = 0
+                             ENDIF
+                          PE (E) = PJ
+                          LEN (E) = LN - KNT2
+                          IF (LEN (E) .EQ. 0) THEN
+C                            nothing left of element e
+                             PE (E) = 0
+                             ENDIF
+
+                          NCMPA = NCMPA + 1
+C                         store first item in pe
+C                         set first entry to -item
+                          DO 70 J = 1, N
+                             PN = PE (J)
+                             IF (PN .GT. 0) THEN
+                                PE (J) = IW (PN)
+                                IW (PN) = -J
+                                ENDIF
+70                           CONTINUE
+
+C                         psrc/pdst point to source/destination
+                          PDST = 1
+                          PSRC = 1
+                          PEND = PME1 - 1
+
+C                         while loop:
+80                        CONTINUE
+                          IF (PSRC .LE. PEND) THEN
+C                            search for next negative entry
+                             J = -IW (PSRC)
+                             PSRC = PSRC + 1
+                             IF (J .GT. 0) THEN
+                                IW (PDST) = PE (J)
+                                PE (J) = PDST
+                                PDST = PDST + 1
+C                               copy from source to destination
+                                LENJ = LEN (J)
+                                DO 90 KNT3 = 0, LENJ - 2
+                                   IW (PDST + KNT3) = IW (PSRC + KNT3)
+90                                 CONTINUE
+                                PDST = PDST + LENJ - 1
+                                PSRC = PSRC + LENJ - 1
+                                ENDIF
+                             GOTO 80
+                             ENDIF
+
+C                         move the new partially-constructed element
+                          P1 = PDST
+                          DO 100 PSRC = PME1, PFREE - 1
+                             IW (PDST) = IW (PSRC)
+                             PDST = PDST + 1
+100                          CONTINUE
+                          PME1 = P1
+                          PFREE = PDST
+                          PJ = PE (E)
+                          P = PE (ME)
+                          ENDIF
+
+C                      -------------------------------------------------
+C                      i is a principal variable not yet placed in Lme
+C                      store i in new list
+C                      -------------------------------------------------
+
+                       DEGME = DEGME + NVI
+C                      flag i as being in Lme by negating nv (i)
+                       NV (I) = -NVI
+                       IW (PFREE) = I
+                       PFREE = PFREE + 1
+
+C                      -------------------------------------------------
+C                      remove variable i from degree link list
+C                      -------------------------------------------------
+
+                       ILAST = LAST (I)
+                       INEXT = NEXT (I)
+                       IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                       IF (ILAST .NE. 0) THEN
+                          NEXT (ILAST) = INEXT
+                       ELSE
+C                         i is at the head of the degree list
+                          HEAD (DEGREE (I)) = INEXT
+                          ENDIF
+
+                       ENDIF
+110                 CONTINUE
+
+                 IF (E .NE. ME) THEN
+C                   set tree pointer and flag to indicate element e is
+C                   absorbed into new element me (the parent of e is me)
+                    PE (E) = -ME
+                    W (E) = 0
+                    ENDIF
+120              CONTINUE
+
+              PME2 = PFREE - 1
+C             this element takes newmem new memory in iw (possibly zero)
+              NEWMEM = PFREE - PME1
+              MEM = MEM + NEWMEM
+              MAXMEM = MAX (MAXMEM, MEM)
+              ENDIF
+
+C          -------------------------------------------------------------
+C          me has now been converted into an element in iw (pme1..pme2)
+C          -------------------------------------------------------------
+
+C          degme holds the external degree of new element
+           DEGREE (ME) = DEGME
+           PE (ME) = PME1
+           LEN (ME) = PME2 - PME1 + 1
+
+C          -------------------------------------------------------------
+C          make sure that wflg is not too large.  With the current
+C          value of wflg, wflg+n must not cause integer overflow
+C          -------------------------------------------------------------
+
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 130 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+130              CONTINUE
+              WFLG = 2
+              ENDIF
+
+C=======================================================================
+C  COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 1:  compute the external degrees of previous elements
+C          with respect to the current element.  That is:
+C               (w (e) - wflg) = |Le \ Lme|
+C          for each element e that appears in any supervariable in Lme.
+C          The notation Le refers to the pattern (list of
+C          supervariables) of a previous element e, where e is not yet
+C          absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
+C          The notation Lme refers to the pattern of the current element
+C          (stored in iw (pme1..pme2)).   If (w (e) - wflg) becomes
+C          zero, then the element e will be absorbed in scan 2.
+C          -------------------------------------------------------------
+
+           DO 150 PME = PME1, PME2
+              I = IW (PME)
+              ELN = ELEN (I)
+              IF (ELN .GT. 0) THEN
+C                note that nv (i) has been negated to denote i in Lme:
+                 NVI = -NV (I)
+                 WNVI = WFLG - NVI
+                 DO 140 P = PE (I), PE (I) + ELN - 1
+                    E = IW (P)
+                    WE = W (E)
+                    IF (WE .GE. WFLG) THEN
+C                      unabsorbed element e has been seen in this loop
+                       WE = WE - NVI
+                    ELSE IF (WE .NE. 0) THEN
+C                      e is an unabsorbed element
+C                      this is the first we have seen e in all of Scan 1
+                       WE = DEGREE (E) + WNVI
+                       ENDIF
+                    W (E) = WE
+140                 CONTINUE
+                 ENDIF
+150           CONTINUE
+
+C=======================================================================
+C  DEGREE UPDATE AND ELEMENT ABSORPTION
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 2:  for each i in Lme, sum up the degree of Lme (which
+C          is degme), plus the sum of the external degrees of each Le
+C          for the elements e appearing within i, plus the
+C          supervariables in i.  Place i in hash list.
+C          -------------------------------------------------------------
+
+           DO 180 PME = PME1, PME2
+              I = IW (PME)
+              P1 = PE (I)
+              P2 = P1 + ELEN (I) - 1
+              PN = P1
+              HASH = 0
+              DEG = 0
+
+C             ----------------------------------------------------------
+C             scan the element list associated with supervariable i
+C             ----------------------------------------------------------
+
+              DO 160 P = P1, P2
+                 E = IW (P)
+C                dext = | Le \ Lme |
+                 DEXT = W (E) - WFLG
+                 IF (DEXT .GT. 0) THEN
+                    DEG = DEG + DEXT
+                    IW (PN) = E
+                    PN = PN + 1
+                    HASH = HASH + E
+                 ELSE IF (DEXT .EQ. 0) THEN
+C                   aggressive absorption: e is not adjacent to me, but
+C                   the |Le \ Lme| is 0, so absorb it into me
+                    PE (E) = -ME
+                    W (E) = 0
+                 ELSE
+C                   element e has already been absorbed, due to
+C                   regular absorption, in do loop 120 above. Ignore it.
+                    CONTINUE
+                    ENDIF
+160              CONTINUE
+
+C             count the number of elements in i (including me):
+              ELEN (I) = PN - P1 + 1
+
+C             ----------------------------------------------------------
+C             scan the supervariables in the list associated with i
+C             ----------------------------------------------------------
+
+              P3 = PN
+              DO 170 P = P2 + 1, P1 + LEN (I) - 1
+                 J = IW (P)
+                 NVJ = NV (J)
+                 IF (NVJ .GT. 0) THEN
+C                   j is unabsorbed, and not in Lme.
+C                   add to degree and add to new list
+                    DEG = DEG + NVJ
+                    IW (PN) = J
+                    PN = PN + 1
+                    HASH = HASH + J
+                    ENDIF
+170              CONTINUE
+
+C             ----------------------------------------------------------
+C             update the degree and check for mass elimination
+C             ----------------------------------------------------------
+
+              IF (DEG .EQ. 0) THEN
+
+C                -------------------------------------------------------
+C                mass elimination
+C                -------------------------------------------------------
+
+C                There is nothing left of this node except for an
+C                edge to the current pivot element.  elen (i) is 1,
+C                and there are no variables adjacent to node i.
+C                Absorb i into the current pivot element, me.
+
+                 PE (I) = -ME
+                 NVI = -NV (I)
+                 DEGME = DEGME - NVI
+                 NVPIV = NVPIV + NVI
+                 NEL = NEL + NVI
+                 NV (I) = 0
+                 ELEN (I) = 0
+
+              ELSE
+
+C                -------------------------------------------------------
+C                update the upper-bound degree of i
+C                -------------------------------------------------------
+
+C                the following degree does not yet include the size
+C                of the current element, which is added later:
+                 DEGREE (I) = MIN (DEGREE (I), DEG)
+
+C                -------------------------------------------------------
+C                add me to the list for i
+C                -------------------------------------------------------
+
+C                move first supervariable to end of list
+                 IW (PN) = IW (P3)
+C                move first element to end of element part of list
+                 IW (P3) = IW (P1)
+C                add new element to front of list.
+                 IW (P1) = ME
+C                store the new length of the list in len (i)
+                 LEN (I) = PN - P1 + 1
+
+C                -------------------------------------------------------
+C                place in hash bucket.  Save hash key of i in last (i).
+C                -------------------------------------------------------
+
+                 HASH = MOD (HASH, HMOD) + 1
+                 J = HEAD (HASH)
+                 IF (J .LE. 0) THEN
+C                   the degree list is empty, hash head is -j
+                    NEXT (I) = -J
+                    HEAD (HASH) = -I
+                 ELSE
+C                   degree list is not empty
+C                   use last (head (hash)) as hash head
+                    NEXT (I) = LAST (J)
+                    LAST (J) = I
+                    ENDIF
+                 LAST (I) = HASH
+                 ENDIF
+180           CONTINUE
+
+           DEGREE (ME) = DEGME
+
+C          -------------------------------------------------------------
+C          Clear the counter array, w (...), by incrementing wflg.
+C          -------------------------------------------------------------
+
+           DMAX = MAX (DMAX, DEGME)
+           WFLG = WFLG + DMAX
+
+C          make sure that wflg+n does not cause integer overflow
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 190 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+190              CONTINUE
+              WFLG = 2
+              ENDIF
+C          at this point, w (1..n) .lt. wflg holds
+
+C=======================================================================
+C  SUPERVARIABLE DETECTION
+C=======================================================================
+
+           DO 250 PME = PME1, PME2
+              I = IW (PME)
+              IF (NV (I) .LT. 0) THEN
+C                i is a principal variable in Lme
+
+C                -------------------------------------------------------
+C                examine all hash buckets with 2 or more variables.  We
+C                do this by examing all unique hash keys for super-
+C                variables in the pattern Lme of the current element, me
+C                -------------------------------------------------------
+
+                 HASH = LAST (I)
+C                let i = head of hash bucket, and empty the hash bucket
+                 J = HEAD (HASH)
+                 IF (J .EQ. 0) GOTO 250
+                 IF (J .LT. 0) THEN
+C                   degree list is empty
+                    I = -J
+                    HEAD (HASH) = 0
+                 ELSE
+C                   degree list is not empty, restore last () of head
+                    I = LAST (J)
+                    LAST (J) = 0
+                    ENDIF
+                 IF (I .EQ. 0) GOTO 250
+
+C                while loop:
+200              CONTINUE
+                 IF (NEXT (I) .NE. 0) THEN
+
+C                   ----------------------------------------------------
+C                   this bucket has one or more variables following i.
+C                   scan all of them to see if i can absorb any entries
+C                   that follow i in hash bucket.  Scatter i into w.
+C                   ----------------------------------------------------
+
+                    LN = LEN (I)
+                    ELN = ELEN (I)
+C                   do not flag the first element in the list (me)
+                    DO 210 P = PE (I) + 1, PE (I) + LN - 1
+                       W (IW (P)) = WFLG
+210                    CONTINUE
+
+C                   ----------------------------------------------------
+C                   scan every other entry j following i in bucket
+C                   ----------------------------------------------------
+
+                    JLAST = I
+                    J = NEXT (I)
+
+C                   while loop:
+220                 CONTINUE
+                    IF (J .NE. 0) THEN
+
+C                      -------------------------------------------------
+C                      check if j and i have identical nonzero pattern
+C                      -------------------------------------------------
+
+                       IF (LEN (J) .NE. LN) THEN
+C                         i and j do not have same size data structure
+                          GOTO 240
+                          ENDIF
+                       IF (ELEN (J) .NE. ELN) THEN
+C                         i and j do not have same number of adjacent el
+                          GOTO 240
+                          ENDIF
+C                      do not flag the first element in the list (me)
+                       DO 230 P = PE (J) + 1, PE (J) + LN - 1
+                          IF (W (IW (P)) .NE. WFLG) THEN
+C                            an entry (iw(p)) is in j but not in i
+                             GOTO 240
+                             ENDIF
+230                       CONTINUE
+
+C                      -------------------------------------------------
+C                      found it!  j can be absorbed into i
+C                      -------------------------------------------------
+
+                       PE (J) = -I
+C                      both nv (i) and nv (j) are negated since they
+C                      are in Lme, and the absolute values of each
+C                      are the number of variables in i and j:
+                       NV (I) = NV (I) + NV (J)
+                       NV (J) = 0
+                       ELEN (J) = 0
+C                      delete j from hash bucket
+                       J = NEXT (J)
+                       NEXT (JLAST) = J
+                       GOTO 220
+
+C                      -------------------------------------------------
+240                    CONTINUE
+C                      j cannot be absorbed into i
+C                      -------------------------------------------------
+
+                       JLAST = J
+                       J = NEXT (J)
+                       GOTO 220
+                       ENDIF
+
+C                   ----------------------------------------------------
+C                   no more variables can be absorbed into i
+C                   go to next i in bucket and clear flag array
+C                   ----------------------------------------------------
+
+                    WFLG = WFLG + 1
+                    I = NEXT (I)
+                    IF (I .NE. 0) GOTO 200
+                    ENDIF
+                 ENDIF
+250           CONTINUE
+
+C=======================================================================
+C  RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
+C=======================================================================
+
+           P = PME1
+           NLEFT = N - NEL
+           DO 260 PME = PME1, PME2
+              I = IW (PME)
+              NVI = -NV (I)
+              IF (NVI .GT. 0) THEN
+C                i is a principal variable in Lme
+C                restore nv (i) to signify that i is principal
+                 NV (I) = NVI
+
+C                -------------------------------------------------------
+C                compute the external degree (add size of current elem)
+C                -------------------------------------------------------
+
+                 DEG = MIN (DEGREE (I) + DEGME - NVI, NLEFT - NVI)
+
+C                -------------------------------------------------------
+C                place the supervariable at the head of the degree list
+C                -------------------------------------------------------
+
+                 INEXT = HEAD (DEG)
+                 IF (INEXT .NE. 0) LAST (INEXT) = I
+                 NEXT (I) = INEXT
+                 LAST (I) = 0
+                 HEAD (DEG) = I
+
+C                -------------------------------------------------------
+C                save the new degree, and find the minimum degree
+C                -------------------------------------------------------
+
+                 MINDEG = MIN (MINDEG, DEG)
+                 DEGREE (I) = DEG
+
+C                -------------------------------------------------------
+C                place the supervariable in the element pattern
+C                -------------------------------------------------------
+
+                 IW (P) = I
+                 P = P + 1
+                 ENDIF
+260           CONTINUE
+
+C=======================================================================
+C  FINALIZE THE NEW ELEMENT
+C=======================================================================
+
+           NV (ME) = NVPIV + DEGME
+C          nv (me) is now the degree of pivot (including diagonal part)
+C          save the length of the list for the new element me
+           LEN (ME) = P - PME1
+           IF (LEN (ME) .EQ. 0) THEN
+C             there is nothing left of the current pivot element
+              PE (ME) = 0
+              W (ME) = 0
+              ENDIF
+           IF (NEWMEM .NE. 0) THEN
+C             element was not constructed in place: deallocate part
+C             of it (final size is less than or equal to newmem,
+C             since newly nonprincipal variables have been removed).
+              PFREE = P
+              MEM = MEM - NEWMEM + LEN (ME)
+              ENDIF
+
+C=======================================================================
+C          END WHILE (selecting pivots)
+           GOTO 30
+           ENDIF
+C=======================================================================
+
+C=======================================================================
+C  COMPUTE THE PERMUTATION VECTORS
+C=======================================================================
+
+C       ----------------------------------------------------------------
+C       The time taken by the following code is O(n).  At this
+C       point, elen (e) = -k has been done for all elements e,
+C       and elen (i) = 0 has been done for all nonprincipal
+C       variables i.  At this point, there are no principal
+C       supervariables left, and all elements are absorbed.
+C       ----------------------------------------------------------------
+
+C       ----------------------------------------------------------------
+C       compute the ordering of unordered nonprincipal variables
+C       ----------------------------------------------------------------
+
+        DO 290 I = 1, N
+           IF (ELEN (I) .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             i is an un-ordered row.  Traverse the tree from i until
+C             reaching an element, e.  The element, e, was the
+C             principal supervariable of i and all nodes in the path
+C             from i to when e was selected as pivot.
+C             ----------------------------------------------------------
+
+              J = -PE (I)
+C             while (j is a variable) do:
+270           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 J = -PE (J)
+                 GOTO 270
+                 ENDIF
+              E = J
+
+C             ----------------------------------------------------------
+C             get the current pivot ordering of e
+C             ----------------------------------------------------------
+
+              K = -ELEN (E)
+
+C             ----------------------------------------------------------
+C             traverse the path again from i to e, and compress the
+C             path (all nodes point to e).  Path compression allows
+C             this code to compute in O(n) time.  Order the unordered
+C             nodes in the path, and place the element e at the end.
+C             ----------------------------------------------------------
+
+              J = I
+C             while (j is a variable) do:
+280           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 JNEXT = -PE (J)
+                 PE (J) = -E
+                 IF (ELEN (J) .EQ. 0) THEN
+C                   j is an unordered row
+                    ELEN (J) = K
+                    K = K + 1
+                    ENDIF
+                 J = JNEXT
+                 GOTO 280
+                 ENDIF
+C             leave elen (e) negative, so we know it is an element
+              ELEN (E) = -K
+              ENDIF
+290        CONTINUE
+
+C       ----------------------------------------------------------------
+C       reset the inverse permutation (elen (1..n)) to be positive,
+C       and compute the permutation (last (1..n)).
+C       ----------------------------------------------------------------
+
+        DO 300 I = 1, N
+           K = ABS (ELEN (I))
+           LAST (K) = I
+           ELEN (I) = K
+300        CONTINUE
+
+C=======================================================================
+C  RETURN THE MEMORY USAGE IN IW
+C=======================================================================
+
+C       If maxmem is less than or equal to iwlen, then no compressions
+C       occurred, and iw (maxmem+1 ... iwlen) was unused.  Otherwise
+C       compressions did occur, and iwlen would have had to have been
+C       greater than or equal to maxmem for no compressions to occur.
+C       Return the value of maxmem in the pfree argument.
+
+        PFREE = MAXMEM
+
+        RETURN
+        END
+
diff --git a/src/AMD/Source/amd_1.c b/src/AMD/Source/amd_1.c
new file mode 100644
index 0000000..2be486e
--- /dev/null
+++ b/src/AMD/Source/amd_1.c
@@ -0,0 +1,180 @@
+/* ========================================================================= */
+/* === AMD_1 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_1: Construct A+A' for a sparse matrix A and perform the AMD ordering.
+ *
+ * The n-by-n sparse matrix A can be unsymmetric.  It is stored in MATLAB-style
+ * compressed-column form, with sorted row indices in each column, and no
+ * duplicate entries.  Diagonal entries may be present, but they are ignored.
+ * Row indices of column j of A are stored in Ai [Ap [j] ... Ap [j+1]-1].
+ * Ap [0] must be zero, and nz = Ap [n] is the number of entries in A.  The
+ * size of the matrix, n, must be greater than or equal to zero.
+ *
+ * This routine must be preceded by a call to AMD_aat, which computes the
+ * number of entries in each row/column in A+A', excluding the diagonal.
+ * Len [j], on input, is the number of entries in row/column j of A+A'.  This
+ * routine constructs the matrix A+A' and then calls AMD_2.  No error checking
+ * is performed (this was done in AMD_valid).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_1
+(
+    Int n,		/* n > 0 */
+    const Int Ap [ ],	/* input of size n+1, not modified */
+    const Int Ai [ ],	/* input of size nz = Ap [n], not modified */
+    Int P [ ],		/* size n output permutation */
+    Int Pinv [ ],	/* size n output inverse permutation */
+    Int Len [ ],	/* size n input, undefined on output */
+    Int slen,		/* slen >= sum (Len [0..n-1]) + 7n,
+			 * ideally slen = 1.2 * sum (Len) + 8n */
+    Int S [ ],		/* size slen workspace */
+    double Control [ ],	/* input array of size AMD_CONTROL */
+    double Info [ ]	/* output array of size AMD_INFO */
+)
+{
+    Int i, j, k, p, pfree, iwlen, pj, p1, p2, pj2, *Iw, *Pe, *Nv, *Head,
+	*Elen, *Degree, *s, *W, *Sp, *Tp ;
+
+    /* --------------------------------------------------------------------- */
+    /* construct the matrix for AMD_2 */
+    /* --------------------------------------------------------------------- */
+
+    ASSERT (n > 0) ;
+
+    iwlen = slen - 6*n ;
+    s = S ;
+    Pe = s ;	    s += n ;
+    Nv = s ;	    s += n ;
+    Head = s ;	    s += n ;
+    Elen = s ;	    s += n ;
+    Degree = s ;    s += n ;
+    W = s ;	    s += n ;
+    Iw = s ;	    s += iwlen ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+
+    /* construct the pointers for A+A' */
+    Sp = Nv ;			/* use Nv and W as workspace for Sp and Tp [ */
+    Tp = W ;
+    pfree = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Pe [j] = pfree ;
+	Sp [j] = pfree ;
+	pfree += Len [j] ;
+    }
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is strictly required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be very slow.  For better performance, at
+     * least size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+
+#ifndef NDEBUG
+    for (p = 0 ; p < iwlen ; p++) Iw [p] = EMPTY ;
+#endif
+
+    for (k = 0 ; k < n ; k++)
+    {
+	AMD_DEBUG1 (("Construct row/column k= "ID" of A+A'\n", k))  ;
+	p1 = Ap [k] ;
+	p2 = Ap [k+1] ;
+
+	/* construct A+A' */
+	for (p = p1 ; p < p2 ; )
+	{
+	    /* scan the upper triangular part of A */
+	    j = Ai [p] ;
+	    ASSERT (j >= 0 && j < n) ;
+	    if (j < k)
+	    {
+		/* entry A (j,k) in the strictly upper triangular part */
+		ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+		ASSERT (Sp [k] < (k == n-1 ? pfree : Pe [k+1])) ;
+		Iw [Sp [j]++] = k ;
+		Iw [Sp [k]++] = j ;
+		p++ ;
+	    }
+	    else if (j == k)
+	    {
+		/* skip the diagonal */
+		p++ ;
+		break ;
+	    }
+	    else /* j > k */
+	    {
+		/* first entry below the diagonal */
+		break ;
+	    }
+	    /* scan lower triangular part of A, in column j until reaching
+	     * row k.  Start where last scan left off. */
+	    ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+	    pj2 = Ap [j+1] ;
+	    for (pj = Tp [j] ; pj < pj2 ; )
+	    {
+		i = Ai [pj] ;
+		ASSERT (i >= 0 && i < n) ;
+		if (i < k)
+		{
+		    /* A (i,j) is only in the lower part, not in upper */
+		    ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+		    ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+		    Iw [Sp [i]++] = j ;
+		    Iw [Sp [j]++] = i ;
+		    pj++ ;
+		}
+		else if (i == k)
+		{
+		    /* entry A (k,j) in lower part and A (j,k) in upper */
+		    pj++ ;
+		    break ;
+		}
+		else /* i > k */
+		{
+		    /* consider this entry later, when k advances to i */
+		    break ;
+		}
+	    }
+	    Tp [j] = pj ;
+	}
+	Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+	for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+	{
+	    i = Ai [pj] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    /* A (i,j) is only in the lower part, not in upper */
+	    ASSERT (Sp [i] < (i == n-1 ? pfree : Pe [i+1])) ;
+	    ASSERT (Sp [j] < (j == n-1 ? pfree : Pe [j+1])) ;
+	    Iw [Sp [i]++] = j ;
+	    Iw [Sp [j]++] = i ;
+	}
+    }
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n-1 ; j++) ASSERT (Sp [j] == Pe [j+1]) ;
+    ASSERT (Sp [n-1] == pfree) ;
+#endif
+
+    /* Tp and Sp no longer needed ] */
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_2 (n, Pe, Iw, Len, iwlen, pfree,
+	Nv, Pinv, P, Head, Elen, Degree, W, Control, Info) ;
+}
diff --git a/src/AMD/Source/amd_2.c b/src/AMD/Source/amd_2.c
new file mode 100644
index 0000000..f144722
--- /dev/null
+++ b/src/AMD/Source/amd_2.c
@@ -0,0 +1,1842 @@
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_2:  performs the AMD ordering on a symmetric sparse matrix A, followed
+ * by a postordering (via depth-first search) of the assembly tree using the
+ * AMD_postorder routine.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === clear_flag ========================================================== */
+/* ========================================================================= */
+
+static Int clear_flag (Int wflg, Int wbig, Int W [ ], Int n)
+{
+    Int x ;
+    if (wflg < 2 || wflg >= wbig)
+    {
+	for (x = 0 ; x < n ; x++)
+	{
+	    if (W [x] != 0) W [x] = 1 ;
+	}
+	wflg = 2 ;
+    }
+    /*  at this point, W [0..n-1] < wflg holds */
+    return (wflg) ;
+}
+
+
+/* ========================================================================= */
+/* === AMD_2 =============================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_2
+(
+    Int n,		/* A is n-by-n, where n > 0 */
+    Int Pe [ ],		/* Pe [0..n-1]: index in Iw of row i on input */
+    Int Iw [ ],		/* workspace of size iwlen. Iw [0..pfree-1]
+			 * holds the matrix on input */
+    Int Len [ ],	/* Len [0..n-1]: length for row/column i on input */
+    Int iwlen,		/* length of Iw. iwlen >= pfree + n */
+    Int pfree,		/* Iw [pfree ... iwlen-1] is empty on input */
+
+    /* 7 size-n workspaces, not defined on input: */
+    Int Nv [ ],		/* the size of each supernode on output */
+    Int Next [ ],	/* the output inverse permutation */
+    Int Last [ ],	/* the output permutation */
+    Int Head [ ],
+    Int Elen [ ],	/* the size columns of L for each supernode */
+    Int Degree [ ],
+    Int W [ ],
+
+    /* control parameters and output statistics */
+    double Control [ ],	/* array of size AMD_CONTROL */
+    double Info [ ]	/* array of size AMD_INFO */
+)
+{
+
+/*
+ * Given a representation of the nonzero pattern of a symmetric matrix, A,
+ * (excluding the diagonal) perform an approximate minimum (UMFPACK/MA38-style)
+ * degree ordering to compute a pivot order such that the introduction of
+ * nonzeros (fill-in) in the Cholesky factors A = LL' is kept low.  At each
+ * step, the pivot selected is the one with the minimum UMFAPACK/MA38-style
+ * upper-bound on the external degree.  This routine can optionally perform
+ * aggresive absorption (as done by MC47B in the Harwell Subroutine
+ * Library).
+ *
+ * The approximate degree algorithm implemented here is the symmetric analog of
+ * the degree update algorithm in MA38 and UMFPACK (the Unsymmetric-pattern
+ * MultiFrontal PACKage, both by Davis and Duff).  The routine is based on the
+ * MA27 minimum degree ordering algorithm by Iain Duff and John Reid.
+ *
+ * This routine is a translation of the original AMDBAR and MC47B routines,
+ * in Fortran, with the following modifications:
+ *
+ * (1) dense rows/columns are removed prior to ordering the matrix, and placed
+ *	last in the output order.  The presence of a dense row/column can
+ *	increase the ordering time by up to O(n^2), unless they are removed
+ *	prior to ordering.
+ *
+ * (2) the minimum degree ordering is followed by a postordering (depth-first
+ *	search) of the assembly tree.  Note that mass elimination (discussed
+ *	below) combined with the approximate degree update can lead to the mass
+ *	elimination of nodes with lower exact degree than the current pivot
+ *	element.  No additional fill-in is caused in the representation of the
+ *	Schur complement.  The mass-eliminated nodes merge with the current
+ *	pivot element.  They are ordered prior to the current pivot element.
+ *	Because they can have lower exact degree than the current element, the
+ *	merger of two or more of these nodes in the current pivot element can
+ *	lead to a single element that is not a "fundamental supernode".  The
+ *	diagonal block can have zeros in it.  Thus, the assembly tree used here
+ *	is not guaranteed to be the precise supernodal elemination tree (with
+ *	"funadmental" supernodes), and the postordering performed by this
+ *	routine is not guaranteed to be a precise postordering of the
+ *	elimination tree.
+ *
+ * (3) input parameters are added, to control aggressive absorption and the
+ *	detection of "dense" rows/columns of A.
+ *
+ * (4) additional statistical information is returned, such as the number of
+ *	nonzeros in L, and the flop counts for subsequent LDL' and LU
+ *	factorizations.  These are slight upper bounds, because of the mass
+ *	elimination issue discussed above.
+ *
+ * (5) additional routines are added to interface this routine to MATLAB
+ *	to provide a simple C-callable user-interface, to check inputs for
+ *	errors, compute the symmetry of the pattern of A and the number of
+ *	nonzeros in each row/column of A+A', to compute the pattern of A+A',
+ *	to perform the assembly tree postordering, and to provide debugging
+ *	ouput.  Many of these functions are also provided by the Fortran
+ *	Harwell Subroutine Library routine MC47A.
+ *
+ * (6) both int and SuiteSparse_long versions are provided.  In the
+ *      descriptions below and integer is and int or SuiteSparse_long depending
+ *      on which version is being used.
+
+ **********************************************************************
+ ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+ **********************************************************************
+ ** If you want error checking, a more versatile input format, and a **
+ ** simpler user interface, use amd_order or amd_l_order instead.    **
+ ** This routine is not meant to be user-callable.                   **
+ **********************************************************************
+
+ * ----------------------------------------------------------------------------
+ * References:
+ * ----------------------------------------------------------------------------
+ *
+ *  [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern multifrontal
+ *	method for sparse LU factorization", SIAM J. Matrix Analysis and
+ *	Applications, vol. 18, no. 1, pp. 140-158.  Discusses UMFPACK / MA38,
+ *	which first introduced the approximate minimum degree used by this
+ *	routine.
+ *
+ *  [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An approximate
+ *	minimum degree ordering algorithm," SIAM J. Matrix Analysis and
+ *	Applications, vol. 17, no. 4, pp. 886-905, 1996.  Discusses AMDBAR and
+ *	MC47B, which are the Fortran versions of this routine.
+ *
+ *  [3] Alan George and Joseph Liu, "The evolution of the minimum degree
+ *	ordering algorithm," SIAM Review, vol. 31, no. 1, pp. 1-19, 1989.
+ *	We list below the features mentioned in that paper that this code
+ *	includes:
+ *
+ *	mass elimination:
+ *	    Yes.  MA27 relied on supervariable detection for mass elimination.
+ *
+ *	indistinguishable nodes:
+ *	    Yes (we call these "supervariables").  This was also in the MA27
+ *	    code - although we modified the method of detecting them (the
+ *	    previous hash was the true degree, which we no longer keep track
+ *	    of).  A supervariable is a set of rows with identical nonzero
+ *	    pattern.  All variables in a supervariable are eliminated together.
+ *	    Each supervariable has as its numerical name that of one of its
+ *	    variables (its principal variable).
+ *
+ *	quotient graph representation:
+ *	    Yes.  We use the term "element" for the cliques formed during
+ *	    elimination.  This was also in the MA27 code.  The algorithm can
+ *	    operate in place, but it will work more efficiently if given some
+ *	    "elbow room."
+ *
+ *	element absorption:
+ *	    Yes.  This was also in the MA27 code.
+ *
+ *	external degree:
+ *	    Yes.  The MA27 code was based on the true degree.
+ *
+ *	incomplete degree update and multiple elimination:
+ *	    No.  This was not in MA27, either.  Our method of degree update
+ *	    within MC47B is element-based, not variable-based.  It is thus
+ *	    not well-suited for use with incomplete degree update or multiple
+ *	    elimination.
+ *
+ * Authors, and Copyright (C) 2004 by:
+ * Timothy A. Davis, Patrick Amestoy, Iain S. Duff, John K. Reid.
+ *
+ * Acknowledgements: This work (and the UMFPACK package) was supported by the
+ * National Science Foundation (ASC-9111263, DMS-9223088, and CCR-0203270).
+ * The UMFPACK/MA38 approximate degree update algorithm, the unsymmetric analog
+ * which forms the basis of AMD, was developed while Tim Davis was supported by
+ * CERFACS (Toulouse, France) in a post-doctoral position.  This C version, and
+ * the etree postorder, were written while Tim Davis was on sabbatical at
+ * Stanford University and Lawrence Berkeley National Laboratory.
+
+ * ----------------------------------------------------------------------------
+ * INPUT ARGUMENTS (unaltered):
+ * ----------------------------------------------------------------------------
+
+ * n:  The matrix order.  Restriction:  n >= 1.
+ *
+ * iwlen:  The size of the Iw array.  On input, the matrix is stored in
+ *	Iw [0..pfree-1].  However, Iw [0..iwlen-1] should be slightly larger
+ *	than what is required to hold the matrix, at least iwlen >= pfree + n.
+ *	Otherwise, excessive compressions will take place.  The recommended
+ *	value of iwlen is 1.2 * pfree + n, which is the value used in the
+ *	user-callable interface to this routine (amd_order.c).  The algorithm
+ *	will not run at all if iwlen < pfree.  Restriction: iwlen >= pfree + n.
+ *	Note that this is slightly more restrictive than the actual minimum
+ *	(iwlen >= pfree), but AMD_2 will be very slow with no elbow room.
+ *	Thus, this routine enforces a bare minimum elbow room of size n.
+ *
+ * pfree: On input the tail end of the array, Iw [pfree..iwlen-1], is empty,
+ *	and the matrix is stored in Iw [0..pfree-1].  During execution,
+ *	additional data is placed in Iw, and pfree is modified so that
+ *	Iw [pfree..iwlen-1] is always the unused part of Iw.
+ *
+ * Control:  A double array of size AMD_CONTROL containing input parameters
+ *	that affect how the ordering is computed.  If NULL, then default
+ *	settings are used.
+ *
+ *	Control [AMD_DENSE] is used to determine whether or not a given input
+ *	row is "dense".  A row is "dense" if the number of entries in the row
+ *	exceeds Control [AMD_DENSE] times sqrt (n), except that rows with 16 or
+ *	fewer entries are never considered "dense".  To turn off the detection
+ *	of dense rows, set Control [AMD_DENSE] to a negative number, or to a
+ *	number larger than sqrt (n).  The default value of Control [AMD_DENSE]
+ *	is AMD_DEFAULT_DENSE, which is defined in amd.h as 10.
+ *
+ *	Control [AMD_AGGRESSIVE] is used to determine whether or not aggressive
+ *	absorption is to be performed.  If nonzero, then aggressive absorption
+ *	is performed (this is the default).
+
+ * ----------------------------------------------------------------------------
+ * INPUT/OUPUT ARGUMENTS:
+ * ----------------------------------------------------------------------------
+ *
+ * Pe:  An integer array of size n.  On input, Pe [i] is the index in Iw of
+ *	the start of row i.  Pe [i] is ignored if row i has no off-diagonal
+ *	entries.  Thus Pe [i] must be in the range 0 to pfree-1 for non-empty
+ *	rows.
+ *
+ *	During execution, it is used for both supervariables and elements:
+ *
+ *	Principal supervariable i:  index into Iw of the description of
+ *	    supervariable i.  A supervariable represents one or more rows of
+ *	    the matrix with identical nonzero pattern.  In this case,
+ *	    Pe [i] >= 0.
+ *
+ *	Non-principal supervariable i:  if i has been absorbed into another
+ *	    supervariable j, then Pe [i] = FLIP (j), where FLIP (j) is defined
+ *	    as (-(j)-2).  Row j has the same pattern as row i.  Note that j
+ *	    might later be absorbed into another supervariable j2, in which
+ *	    case Pe [i] is still FLIP (j), and Pe [j] = FLIP (j2) which is
+ *	    < EMPTY, where EMPTY is defined as (-1) in amd_internal.h.
+ *
+ *	Unabsorbed element e:  the index into Iw of the description of element
+ *	    e, if e has not yet been absorbed by a subsequent element.  Element
+ *	    e is created when the supervariable of the same name is selected as
+ *	    the pivot.  In this case, Pe [i] >= 0.
+ *
+ *	Absorbed element e:  if element e is absorbed into element e2, then
+ *	    Pe [e] = FLIP (e2).  This occurs when the pattern of e (which we
+ *	    refer to as Le) is found to be a subset of the pattern of e2 (that
+ *	    is, Le2).  In this case, Pe [i] < EMPTY.  If element e is "null"
+ *	    (it has no nonzeros outside its pivot block), then Pe [e] = EMPTY,
+ *	    and e is the root of an assembly subtree (or the whole tree if
+ *	    there is just one such root).
+ *
+ *	Dense variable i:  if i is "dense", then Pe [i] = EMPTY.
+ *
+ *	On output, Pe holds the assembly tree/forest, which implicitly
+ *	represents a pivot order with identical fill-in as the actual order
+ *	(via a depth-first search of the tree), as follows.  If Nv [i] > 0,
+ *	then i represents a node in the assembly tree, and the parent of i is
+ *	Pe [i], or EMPTY if i is a root.  If Nv [i] = 0, then (i, Pe [i])
+ *	represents an edge in a subtree, the root of which is a node in the
+ *	assembly tree.  Note that i refers to a row/column in the original
+ *	matrix, not the permuted matrix.
+ *
+ * Info:  A double array of size AMD_INFO.  If present, (that is, not NULL),
+ *	then statistics about the ordering are returned in the Info array.
+ *	See amd.h for a description.
+
+ * ----------------------------------------------------------------------------
+ * INPUT/MODIFIED (undefined on output):
+ * ----------------------------------------------------------------------------
+ *
+ * Len:  An integer array of size n.  On input, Len [i] holds the number of
+ *	entries in row i of the matrix, excluding the diagonal.  The contents
+ *	of Len are undefined on output.
+ *
+ * Iw:  An integer array of size iwlen.  On input, Iw [0..pfree-1] holds the
+ *	description of each row i in the matrix.  The matrix must be symmetric,
+ *	and both upper and lower triangular parts must be present.  The
+ *	diagonal must not be present.  Row i is held as follows:
+ *
+ *	    Len [i]:  the length of the row i data structure in the Iw array.
+ *	    Iw [Pe [i] ... Pe [i] + Len [i] - 1]:
+ *		the list of column indices for nonzeros in row i (simple
+ *		supervariables), excluding the diagonal.  All supervariables
+ *		start with one row/column each (supervariable i is just row i).
+ *		If Len [i] is zero on input, then Pe [i] is ignored on input.
+ *
+ *	    Note that the rows need not be in any particular order, and there
+ *	    may be empty space between the rows.
+ *
+ *	During execution, the supervariable i experiences fill-in.  This is
+ *	represented by placing in i a list of the elements that cause fill-in
+ *	in supervariable i:
+ *
+ *	    Len [i]:  the length of supervariable i in the Iw array.
+ *	    Iw [Pe [i] ... Pe [i] + Elen [i] - 1]:
+ *		the list of elements that contain i.  This list is kept short
+ *		by removing absorbed elements.
+ *	    Iw [Pe [i] + Elen [i] ... Pe [i] + Len [i] - 1]:
+ *		the list of supervariables in i.  This list is kept short by
+ *		removing nonprincipal variables, and any entry j that is also
+ *		contained in at least one of the elements (j in Le) in the list
+ *		for i (e in row i).
+ *
+ *	When supervariable i is selected as pivot, we create an element e of
+ *	the same name (e=i):
+ *
+ *	    Len [e]:  the length of element e in the Iw array.
+ *	    Iw [Pe [e] ... Pe [e] + Len [e] - 1]:
+ *		the list of supervariables in element e.
+ *
+ *	An element represents the fill-in that occurs when supervariable i is
+ *	selected as pivot (which represents the selection of row i and all
+ *	non-principal variables whose principal variable is i).  We use the
+ *	term Le to denote the set of all supervariables in element e.  Absorbed
+ *	supervariables and elements are pruned from these lists when
+ *	computationally convenient.
+ *
+ *  CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+ *  The contents of Iw are undefined on output.
+
+ * ----------------------------------------------------------------------------
+ * OUTPUT (need not be set on input):
+ * ----------------------------------------------------------------------------
+ *
+ * Nv:  An integer array of size n.  During execution, ABS (Nv [i]) is equal to
+ *	the number of rows that are represented by the principal supervariable
+ *	i.  If i is a nonprincipal or dense variable, then Nv [i] = 0.
+ *	Initially, Nv [i] = 1 for all i.  Nv [i] < 0 signifies that i is a
+ *	principal variable in the pattern Lme of the current pivot element me.
+ *	After element me is constructed, Nv [i] is set back to a positive
+ *	value.
+ *
+ *	On output, Nv [i] holds the number of pivots represented by super
+ *	row/column i of the original matrix, or Nv [i] = 0 for non-principal
+ *	rows/columns.  Note that i refers to a row/column in the original
+ *	matrix, not the permuted matrix.
+ *
+ * Elen:  An integer array of size n.  See the description of Iw above.  At the
+ *	start of execution, Elen [i] is set to zero for all rows i.  During
+ *	execution, Elen [i] is the number of elements in the list for
+ *	supervariable i.  When e becomes an element, Elen [e] = FLIP (esize) is
+ *	set, where esize is the size of the element (the number of pivots, plus
+ *	the number of nonpivotal entries).  Thus Elen [e] < EMPTY.
+ *	Elen (i) = EMPTY set when variable i becomes nonprincipal.
+ *
+ *	For variables, Elen (i) >= EMPTY holds until just before the
+ *	postordering and permutation vectors are computed.  For elements,
+ *	Elen [e] < EMPTY holds.
+ *
+ *	On output, Elen [i] is the degree of the row/column in the Cholesky
+ *	factorization of the permuted matrix, corresponding to the original row
+ *	i, if i is a super row/column.  It is equal to EMPTY if i is
+ *	non-principal.  Note that i refers to a row/column in the original
+ *	matrix, not the permuted matrix.
+ *
+ *	Note that the contents of Elen on output differ from the Fortran
+ *	version (Elen holds the inverse permutation in the Fortran version,
+ *	which is instead returned in the Next array in this C version,
+ *	described below).
+ *
+ * Last: In a degree list, Last [i] is the supervariable preceding i, or EMPTY
+ *	if i is the head of the list.  In a hash bucket, Last [i] is the hash
+ *	key for i.
+ *
+ *	Last [Head [hash]] is also used as the head of a hash bucket if
+ *	Head [hash] contains a degree list (see the description of Head,
+ *	below).
+ *
+ *	On output, Last [0..n-1] holds the permutation.  That is, if
+ *	i = Last [k], then row i is the kth pivot row (where k ranges from 0 to
+ *	n-1).  Row Last [k] of A is the kth row in the permuted matrix, PAP'.
+ *
+ * Next: Next [i] is the supervariable following i in a link list, or EMPTY if
+ *	i is the last in the list.  Used for two kinds of lists:  degree lists
+ *	and hash buckets (a supervariable can be in only one kind of list at a
+ *	time).
+ *
+ *	On output Next [0..n-1] holds the inverse permutation. 	That is, if
+ *	k = Next [i], then row i is the kth pivot row. Row i of A appears as
+ *	the (Next[i])-th row in the permuted matrix, PAP'.
+ *
+ *	Note that the contents of Next on output differ from the Fortran
+ *	version (Next is undefined on output in the Fortran version).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL WORKSPACE (not input or output - used only during execution):
+ * ----------------------------------------------------------------------------
+ *
+ * Degree:  An integer array of size n.  If i is a supervariable, then
+ *	Degree [i] holds the current approximation of the external degree of
+ *	row i (an upper bound).  The external degree is the number of nonzeros
+ *	in row i, minus ABS (Nv [i]), the diagonal part.  The bound is equal to
+ *	the exact external degree if Elen [i] is less than or equal to two.
+ *
+ *	We also use the term "external degree" for elements e to refer to
+ *	|Le \ Lme|.  If e is an element, then Degree [e] is |Le|, which is the
+ *	degree of the off-diagonal part of the element e (not including the
+ *	diagonal part).
+ *
+ * Head:   An integer array of size n.  Head is used for degree lists.
+ *	Head [deg] is the first supervariable in a degree list.  All
+ *	supervariables i in a degree list Head [deg] have the same approximate
+ *	degree, namely, deg = Degree [i].  If the list Head [deg] is empty then
+ *	Head [deg] = EMPTY.
+ *
+ *	During supervariable detection Head [hash] also serves as a pointer to
+ *	a hash bucket.  If Head [hash] >= 0, there is a degree list of degree
+ *	hash.  The hash bucket head pointer is Last [Head [hash]].  If
+ *	Head [hash] = EMPTY, then the degree list and hash bucket are both
+ *	empty.  If Head [hash] < EMPTY, then the degree list is empty, and
+ *	FLIP (Head [hash]) is the head of the hash bucket.  After supervariable
+ *	detection is complete, all hash buckets are empty, and the
+ *	(Last [Head [hash]] = EMPTY) condition is restored for the non-empty
+ *	degree lists.
+ *
+ * W:  An integer array of size n.  The flag array W determines the status of
+ *	elements and variables, and the external degree of elements.
+ *
+ *	for elements:
+ *	    if W [e] = 0, then the element e is absorbed.
+ *	    if W [e] >= wflg, then W [e] - wflg is the size of the set
+ *		|Le \ Lme|, in terms of nonzeros (the sum of ABS (Nv [i]) for
+ *		each principal variable i that is both in the pattern of
+ *		element e and NOT in the pattern of the current pivot element,
+ *		me).
+ *	    if wflg > W [e] > 0, then e is not absorbed and has not yet been
+ *		seen in the scan of the element lists in the computation of
+ *		|Le\Lme| in Scan 1 below.
+ *
+ *	for variables:
+ *	    during supervariable detection, if W [j] != wflg then j is
+ *	    not in the pattern of variable i.
+ *
+ *	The W array is initialized by setting W [i] = 1 for all i, and by
+ *	setting wflg = 2.  It is reinitialized if wflg becomes too large (to
+ *	ensure that wflg+n does not cause integer overflow).
+
+ * ----------------------------------------------------------------------------
+ * LOCAL INTEGERS:
+ * ----------------------------------------------------------------------------
+ */
+
+    Int deg, degme, dext, lemax, e, elenme, eln, i, ilast, inext, j,
+	jlast, jnext, k, knt1, knt2, knt3, lenj, ln, me, mindeg, nel, nleft,
+	nvi, nvj, nvpiv, slenme, wbig, we, wflg, wnvi, ok, ndense, ncmpa,
+	dense, aggressive ;
+
+    unsigned Int hash ;	    /* unsigned, so that hash % n is well defined.*/
+
+/*
+ * deg:		the degree of a variable or element
+ * degme:	size, |Lme|, of the current element, me (= Degree [me])
+ * dext:	external degree, |Le \ Lme|, of some element e
+ * lemax:	largest |Le| seen so far (called dmax in Fortran version)
+ * e:		an element
+ * elenme:	the length, Elen [me], of element list of pivotal variable
+ * eln:		the length, Elen [...], of an element list
+ * hash:	the computed value of the hash function
+ * i:		a supervariable
+ * ilast:	the entry in a link list preceding i
+ * inext:	the entry in a link list following i
+ * j:		a supervariable
+ * jlast:	the entry in a link list preceding j
+ * jnext:	the entry in a link list, or path, following j
+ * k:		the pivot order of an element or variable
+ * knt1:	loop counter used during element construction
+ * knt2:	loop counter used during element construction
+ * knt3:	loop counter used during compression
+ * lenj:	Len [j]
+ * ln:		length of a supervariable list
+ * me:		current supervariable being eliminated, and the current
+ *		    element created by eliminating that supervariable
+ * mindeg:	current minimum degree
+ * nel:		number of pivots selected so far
+ * nleft:	n - nel, the number of nonpivotal rows/columns remaining
+ * nvi:		the number of variables in a supervariable i (= Nv [i])
+ * nvj:		the number of variables in a supervariable j (= Nv [j])
+ * nvpiv:	number of pivots in current element
+ * slenme:	number of variables in variable list of pivotal variable
+ * wbig:	= (INT_MAX - n) for the int version, (SuiteSparse_long_max - n)
+ *                  for the SuiteSparse_long version.  wflg is not allowed to
+ *                  be >= wbig.
+ * we:		W [e]
+ * wflg:	used for flagging the W array.  See description of Iw.
+ * wnvi:	wflg - Nv [i]
+ * x:		either a supervariable or an element
+ *
+ * ok:		true if supervariable j can be absorbed into i
+ * ndense:	number of "dense" rows/columns
+ * dense:	rows/columns with initial degree > dense are considered "dense"
+ * aggressive:	true if aggressive absorption is being performed
+ * ncmpa:	number of garbage collections
+
+ * ----------------------------------------------------------------------------
+ * LOCAL DOUBLES, used for statistical output only (except for alpha):
+ * ----------------------------------------------------------------------------
+ */
+
+    double f, r, ndiv, s, nms_lu, nms_ldl, dmax, alpha, lnz, lnzme ;
+
+/*
+ * f:		nvpiv
+ * r:		degme + nvpiv
+ * ndiv:	number of divisions for LU or LDL' factorizations
+ * s:		number of multiply-subtract pairs for LU factorization, for the
+ *		    current element me
+ * nms_lu	number of multiply-subtract pairs for LU factorization
+ * nms_ldl	number of multiply-subtract pairs for LDL' factorization
+ * dmax:	the largest number of entries in any column of L, including the
+ *		    diagonal
+ * alpha:	"dense" degree ratio
+ * lnz:		the number of nonzeros in L (excluding the diagonal)
+ * lnzme:	the number of nonzeros in L (excl. the diagonal) for the
+ *		    current element me
+
+ * ----------------------------------------------------------------------------
+ * LOCAL "POINTERS" (indices into the Iw array)
+ * ----------------------------------------------------------------------------
+*/
+
+    Int p, p1, p2, p3, p4, pdst, pend, pj, pme, pme1, pme2, pn, psrc ;
+
+/*
+ * Any parameter (Pe [...] or pfree) or local variable starting with "p" (for
+ * Pointer) is an index into Iw, and all indices into Iw use variables starting
+ * with "p."  The only exception to this rule is the iwlen input argument.
+ *
+ * p:           pointer into lots of things
+ * p1:          Pe [i] for some variable i (start of element list)
+ * p2:          Pe [i] + Elen [i] -  1 for some variable i
+ * p3:          index of first supervariable in clean list
+ * p4:		
+ * pdst:        destination pointer, for compression
+ * pend:        end of memory to compress
+ * pj:          pointer into an element or variable
+ * pme:         pointer into the current element (pme1...pme2)
+ * pme1:        the current element, me, is stored in Iw [pme1...pme2]
+ * pme2:        the end of the current element
+ * pn:          pointer into a "clean" variable, also used to compress
+ * psrc:        source pointer, for compression
+*/
+
+/* ========================================================================= */
+/*  INITIALIZATIONS */
+/* ========================================================================= */
+
+    /* Note that this restriction on iwlen is slightly more restrictive than
+     * what is actually required in AMD_2.  AMD_2 can operate with no elbow
+     * room at all, but it will be slow.  For better performance, at least
+     * size-n elbow room is enforced. */
+    ASSERT (iwlen >= pfree + n) ;
+    ASSERT (n > 0) ;
+
+    /* initialize output statistics */
+    lnz = 0 ;
+    ndiv = 0 ;
+    nms_lu = 0 ;
+    nms_ldl = 0 ;
+    dmax = 1 ;
+    me = EMPTY ;
+
+    mindeg = 0 ;
+    ncmpa = 0 ;
+    nel = 0 ;
+    lemax = 0 ;
+
+    /* get control parameters */
+    if (Control != (double *) NULL)
+    {
+	alpha = Control [AMD_DENSE] ;
+	aggressive = (Control [AMD_AGGRESSIVE] != 0) ;
+    }
+    else
+    {
+	alpha = AMD_DEFAULT_DENSE ;
+	aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+    /* Note: if alpha is NaN, this is undefined: */
+    if (alpha < 0)
+    {
+	/* only remove completely dense rows/columns */
+	dense = n-2 ;
+    }
+    else
+    {
+	dense = alpha * sqrt ((double) n) ;
+    }
+    dense = MAX (16, dense) ;
+    dense = MIN (n,  dense) ;
+    AMD_DEBUG1 (("\n\nAMD (debug), alpha %g, aggr. "ID"\n",
+	alpha, aggressive)) ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+	Last [i] = EMPTY ;
+	Head [i] = EMPTY ;
+	Next [i] = EMPTY ;
+	/* if separate Hhead array is used for hash buckets: *
+	Hhead [i] = EMPTY ;
+	*/
+	Nv [i] = 1 ;
+	W [i] = 1 ;
+	Elen [i] = 0 ;
+	Degree [i] = Len [i] ;
+    }
+
+#ifndef NDEBUG
+    AMD_DEBUG1 (("\n======Nel "ID" initial\n", nel)) ;
+    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next, Last,
+		Head, Elen, Degree, W, -1) ;
+#endif
+
+    /* initialize wflg */
+    wbig = Int_MAX - n ;
+    wflg = clear_flag (0, wbig, W, n) ;
+
+    /* --------------------------------------------------------------------- */
+    /* initialize degree lists and eliminate dense and empty rows */
+    /* --------------------------------------------------------------------- */
+
+    ndense = 0 ;
+
+    for (i = 0 ; i < n ; i++)
+    {
+	deg = Degree [i] ;
+	ASSERT (deg >= 0 && deg < n) ;
+	if (deg == 0)
+	{
+
+	    /* -------------------------------------------------------------
+	     * we have a variable that can be eliminated at once because
+	     * there is no off-diagonal non-zero in its row.  Note that
+	     * Nv [i] = 1 for an empty variable i.  It is treated just
+	     * the same as an eliminated element i.
+	     * ------------------------------------------------------------- */
+
+	    Elen [i] = FLIP (1) ;
+	    nel++ ;
+	    Pe [i] = EMPTY ;
+	    W [i] = 0 ;
+
+	}
+	else if (deg > dense)
+	{
+
+	    /* -------------------------------------------------------------
+	     * Dense variables are not treated as elements, but as unordered,
+	     * non-principal variables that have no parent.  They do not take
+	     * part in the postorder, since Nv [i] = 0.  Note that the Fortran
+	     * version does not have this option.
+	     * ------------------------------------------------------------- */
+
+	    AMD_DEBUG1 (("Dense node "ID" degree "ID"\n", i, deg)) ;
+	    ndense++ ;
+	    Nv [i] = 0 ;		/* do not postorder this node */
+	    Elen [i] = EMPTY ;
+	    nel++ ;
+	    Pe [i] = EMPTY ;
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------
+	     * place i in the degree list corresponding to its degree
+	     * ------------------------------------------------------------- */
+
+	    inext = Head [deg] ;
+	    ASSERT (inext >= EMPTY && inext < n) ;
+	    if (inext != EMPTY) Last [inext] = i ;
+	    Next [i] = inext ;
+	    Head [deg] = i ;
+
+	}
+    }
+
+/* ========================================================================= */
+/* WHILE (selecting pivots) DO */
+/* ========================================================================= */
+
+    while (nel < n)
+    {
+
+#ifndef NDEBUG
+	AMD_DEBUG1 (("\n======Nel "ID"\n", nel)) ;
+	if (AMD_debug >= 2)
+	{
+	    AMD_dump (n, Pe, Iw, Len, iwlen, pfree, Nv, Next,
+		    Last, Head, Elen, Degree, W, nel) ;
+	}
+#endif
+
+/* ========================================================================= */
+/* GET PIVOT OF MINIMUM DEGREE */
+/* ========================================================================= */
+
+	/* ----------------------------------------------------------------- */
+	/* find next supervariable for elimination */
+	/* ----------------------------------------------------------------- */
+
+	ASSERT (mindeg >= 0 && mindeg < n) ;
+	for (deg = mindeg ; deg < n ; deg++)
+	{
+	    me = Head [deg] ;
+	    if (me != EMPTY) break ;
+	}
+	mindeg = deg ;
+	ASSERT (me >= 0 && me < n) ;
+	AMD_DEBUG1 (("=================me: "ID"\n", me)) ;
+
+	/* ----------------------------------------------------------------- */
+	/* remove chosen variable from link list */
+	/* ----------------------------------------------------------------- */
+
+	inext = Next [me] ;
+	ASSERT (inext >= EMPTY && inext < n) ;
+	if (inext != EMPTY) Last [inext] = EMPTY ;
+	Head [deg] = inext ;
+
+	/* ----------------------------------------------------------------- */
+	/* me represents the elimination of pivots nel to nel+Nv[me]-1. */
+	/* place me itself as the first in this set. */
+	/* ----------------------------------------------------------------- */
+
+	elenme = Elen [me] ;
+	nvpiv = Nv [me] ;
+	ASSERT (nvpiv > 0) ;
+	nel += nvpiv ;
+
+/* ========================================================================= */
+/* CONSTRUCT NEW ELEMENT */
+/* ========================================================================= */
+
+	/* -----------------------------------------------------------------
+	 * At this point, me is the pivotal supervariable.  It will be
+	 * converted into the current element.  Scan list of the pivotal
+	 * supervariable, me, setting tree pointers and constructing new list
+	 * of supervariables for the new element, me.  p is a pointer to the
+	 * current position in the old list.
+	 * ----------------------------------------------------------------- */
+
+	/* flag the variable "me" as being in Lme by negating Nv [me] */
+	Nv [me] = -nvpiv ;
+	degme = 0 ;
+	ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+	if (elenme == 0)
+	{
+
+	    /* ------------------------------------------------------------- */
+	    /* construct the new element in place */
+	    /* ------------------------------------------------------------- */
+
+	    pme1 = Pe [me] ;
+	    pme2 = pme1 - 1 ;
+
+	    for (p = pme1 ; p <= pme1 + Len [me] - 1 ; p++)
+	    {
+		i = Iw [p] ;
+		ASSERT (i >= 0 && i < n && Nv [i] >= 0) ;
+		nvi = Nv [i] ;
+		if (nvi > 0)
+		{
+
+		    /* ----------------------------------------------------- */
+		    /* i is a principal variable not yet placed in Lme. */
+		    /* store i in new list */
+		    /* ----------------------------------------------------- */
+
+		    /* flag i as being in Lme by negating Nv [i] */
+		    degme += nvi ;
+		    Nv [i] = -nvi ;
+		    Iw [++pme2] = i ;
+
+		    /* ----------------------------------------------------- */
+		    /* remove variable i from degree list. */
+		    /* ----------------------------------------------------- */
+
+		    ilast = Last [i] ;
+		    inext = Next [i] ;
+		    ASSERT (ilast >= EMPTY && ilast < n) ;
+		    ASSERT (inext >= EMPTY && inext < n) ;
+		    if (inext != EMPTY) Last [inext] = ilast ;
+		    if (ilast != EMPTY)
+		    {
+			Next [ilast] = inext ;
+		    }
+		    else
+		    {
+			/* i is at the head of the degree list */
+			ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+			Head [Degree [i]] = inext ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+
+	    /* ------------------------------------------------------------- */
+	    /* construct the new element in empty space, Iw [pfree ...] */
+	    /* ------------------------------------------------------------- */
+
+	    p = Pe [me] ;
+	    pme1 = pfree ;
+	    slenme = Len [me] - elenme ;
+
+	    for (knt1 = 1 ; knt1 <= elenme + 1 ; knt1++)
+	    {
+
+		if (knt1 > elenme)
+		{
+		    /* search the supervariables in me. */
+		    e = me ;
+		    pj = p ;
+		    ln = slenme ;
+		    AMD_DEBUG2 (("Search sv: "ID" "ID" "ID"\n", me,pj,ln)) ;
+		}
+		else
+		{
+		    /* search the elements in me. */
+		    e = Iw [p++] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    pj = Pe [e] ;
+		    ln = Len [e] ;
+		    AMD_DEBUG2 (("Search element e "ID" in me "ID"\n", e,me)) ;
+		    ASSERT (Elen [e] < EMPTY && W [e] > 0 && pj >= 0) ;
+		}
+		ASSERT (ln >= 0 && (ln == 0 || (pj >= 0 && pj < iwlen))) ;
+
+		/* ---------------------------------------------------------
+		 * search for different supervariables and add them to the
+		 * new list, compressing when necessary. this loop is
+		 * executed once for each element in the list and once for
+		 * all the supervariables in the list.
+		 * --------------------------------------------------------- */
+
+		for (knt2 = 1 ; knt2 <= ln ; knt2++)
+		{
+		    i = Iw [pj++] ;
+		    ASSERT (i >= 0 && i < n && (i == me || Elen [i] >= EMPTY));
+		    nvi = Nv [i] ;
+		    AMD_DEBUG2 ((": "ID" "ID" "ID" "ID"\n",
+				i, Elen [i], Nv [i], wflg)) ;
+
+		    if (nvi > 0)
+		    {
+
+			/* ------------------------------------------------- */
+			/* compress Iw, if necessary */
+			/* ------------------------------------------------- */
+
+			if (pfree >= iwlen)
+			{
+
+			    AMD_DEBUG1 (("GARBAGE COLLECTION\n")) ;
+
+			    /* prepare for compressing Iw by adjusting pointers
+			     * and lengths so that the lists being searched in
+			     * the inner and outer loops contain only the
+			     * remaining entries. */
+
+			    Pe [me] = p ;
+			    Len [me] -= knt1 ;
+			    /* check if nothing left of supervariable me */
+			    if (Len [me] == 0) Pe [me] = EMPTY ;
+			    Pe [e] = pj ;
+			    Len [e] = ln - knt2 ;
+			    /* nothing left of element e */
+			    if (Len [e] == 0) Pe [e] = EMPTY ;
+
+			    ncmpa++ ;	/* one more garbage collection */
+
+			    /* store first entry of each object in Pe */
+			    /* FLIP the first entry in each object */
+			    for (j = 0 ; j < n ; j++)
+			    {
+				pn = Pe [j] ;
+				if (pn >= 0)
+				{
+				    ASSERT (pn >= 0 && pn < iwlen) ;
+				    Pe [j] = Iw [pn] ;
+				    Iw [pn] = FLIP (j) ;
+				}
+			    }
+
+			    /* psrc/pdst point to source/destination */
+			    psrc = 0 ;
+			    pdst = 0 ;
+			    pend = pme1 - 1 ;
+
+			    while (psrc <= pend)
+			    {
+				/* search for next FLIP'd entry */
+				j = FLIP (Iw [psrc++]) ;
+				if (j >= 0)
+				{
+				    AMD_DEBUG2 (("Got object j: "ID"\n", j)) ;
+				    Iw [pdst] = Pe [j] ;
+				    Pe [j] = pdst++ ;
+				    lenj = Len [j] ;
+				    /* copy from source to destination */
+				    for (knt3 = 0 ; knt3 <= lenj - 2 ; knt3++)
+				    {
+					Iw [pdst++] = Iw [psrc++] ;
+				    }
+				}
+			    }
+
+			    /* move the new partially-constructed element */
+			    p1 = pdst ;
+			    for (psrc = pme1 ; psrc <= pfree-1 ; psrc++)
+			    {
+				Iw [pdst++] = Iw [psrc] ;
+			    }
+			    pme1 = p1 ;
+			    pfree = pdst ;
+			    pj = Pe [e] ;
+			    p = Pe [me] ;
+
+			}
+
+			/* ------------------------------------------------- */
+			/* i is a principal variable not yet placed in Lme */
+			/* store i in new list */
+			/* ------------------------------------------------- */
+
+			/* flag i as being in Lme by negating Nv [i] */
+			degme += nvi ;
+			Nv [i] = -nvi ;
+			Iw [pfree++] = i ;
+			AMD_DEBUG2 (("     s: "ID"     nv "ID"\n", i, Nv [i]));
+
+			/* ------------------------------------------------- */
+			/* remove variable i from degree link list */
+			/* ------------------------------------------------- */
+
+			ilast = Last [i] ;
+			inext = Next [i] ;
+			ASSERT (ilast >= EMPTY && ilast < n) ;
+			ASSERT (inext >= EMPTY && inext < n) ;
+			if (inext != EMPTY) Last [inext] = ilast ;
+			if (ilast != EMPTY)
+			{
+			    Next [ilast] = inext ;
+			}
+			else
+			{
+			    /* i is at the head of the degree list */
+			    ASSERT (Degree [i] >= 0 && Degree [i] < n) ;
+			    Head [Degree [i]] = inext ;
+			}
+		    }
+		}
+
+		if (e != me)
+		{
+		    /* set tree pointer and flag to indicate element e is
+		     * absorbed into new element me (the parent of e is me) */
+		    AMD_DEBUG1 ((" Element "ID" => "ID"\n", e, me)) ;
+		    Pe [e] = FLIP (me) ;
+		    W [e] = 0 ;
+		}
+	    }
+
+	    pme2 = pfree - 1 ;
+	}
+
+	/* ----------------------------------------------------------------- */
+	/* me has now been converted into an element in Iw [pme1..pme2] */
+	/* ----------------------------------------------------------------- */
+
+	/* degme holds the external degree of new element */
+	Degree [me] = degme ;
+	Pe [me] = pme1 ;
+	Len [me] = pme2 - pme1 + 1 ;
+	ASSERT (Pe [me] >= 0 && Pe [me] < iwlen) ;
+
+	Elen [me] = FLIP (nvpiv + degme) ;
+	/* FLIP (Elen (me)) is now the degree of pivot (including
+	 * diagonal part). */
+
+#ifndef NDEBUG
+	AMD_DEBUG2 (("New element structure: length= "ID"\n", pme2-pme1+1)) ;
+	for (pme = pme1 ; pme <= pme2 ; pme++) AMD_DEBUG3 ((" "ID"", Iw[pme]));
+	AMD_DEBUG3 (("\n")) ;
+#endif
+
+	/* ----------------------------------------------------------------- */
+	/* make sure that wflg is not too large. */
+	/* ----------------------------------------------------------------- */
+
+	/* With the current value of wflg, wflg+n must not cause integer
+	 * overflow */
+
+	wflg = clear_flag (wflg, wbig, W, n) ;
+
+/* ========================================================================= */
+/* COMPUTE (W [e] - wflg) = |Le\Lme| FOR ALL ELEMENTS */
+/* ========================================================================= */
+
+	/* -----------------------------------------------------------------
+	 * Scan 1:  compute the external degrees of previous elements with
+	 * respect to the current element.  That is:
+	 *       (W [e] - wflg) = |Le \ Lme|
+	 * for each element e that appears in any supervariable in Lme.  The
+	 * notation Le refers to the pattern (list of supervariables) of a
+	 * previous element e, where e is not yet absorbed, stored in
+	 * Iw [Pe [e] + 1 ... Pe [e] + Len [e]].  The notation Lme
+	 * refers to the pattern of the current element (stored in
+	 * Iw [pme1..pme2]).   If aggressive absorption is enabled, and
+	 * (W [e] - wflg) becomes zero, then the element e will be absorbed
+	 * in Scan 2.
+	 * ----------------------------------------------------------------- */
+
+	AMD_DEBUG2 (("me: ")) ;
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    eln = Elen [i] ;
+	    AMD_DEBUG3 ((""ID" Elen "ID": \n", i, eln)) ;
+	    if (eln > 0)
+	    {
+		/* note that Nv [i] has been negated to denote i in Lme: */
+		nvi = -Nv [i] ;
+		ASSERT (nvi > 0 && Pe [i] >= 0 && Pe [i] < iwlen) ;
+		wnvi = wflg - nvi ;
+		for (p = Pe [i] ; p <= Pe [i] + eln - 1 ; p++)
+		{
+		    e = Iw [p] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    we = W [e] ;
+		    AMD_DEBUG4 (("    e "ID" we "ID" ", e, we)) ;
+		    if (we >= wflg)
+		    {
+			/* unabsorbed element e has been seen in this loop */
+			AMD_DEBUG4 (("    unabsorbed, first time seen")) ;
+			we -= nvi ;
+		    }
+		    else if (we != 0)
+		    {
+			/* e is an unabsorbed element */
+			/* this is the first we have seen e in all of Scan 1 */
+			AMD_DEBUG4 (("    unabsorbed")) ;
+			we = Degree [e] + wnvi ;
+		    }
+		    AMD_DEBUG4 (("\n")) ;
+		    W [e] = we ;
+		}
+	    }
+	}
+	AMD_DEBUG2 (("\n")) ;
+
+/* ========================================================================= */
+/* DEGREE UPDATE AND ELEMENT ABSORPTION */
+/* ========================================================================= */
+
+	/* -----------------------------------------------------------------
+	 * Scan 2:  for each i in Lme, sum up the degree of Lme (which is
+	 * degme), plus the sum of the external degrees of each Le for the
+	 * elements e appearing within i, plus the supervariables in i.
+	 * Place i in hash list.
+	 * ----------------------------------------------------------------- */
+
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n && Nv [i] < 0 && Elen [i] >= 0) ;
+	    AMD_DEBUG2 (("Updating: i "ID" "ID" "ID"\n", i, Elen[i], Len [i]));
+	    p1 = Pe [i] ;
+	    p2 = p1 + Elen [i] - 1 ;
+	    pn = p1 ;
+	    hash = 0 ;
+	    deg = 0 ;
+	    ASSERT (p1 >= 0 && p1 < iwlen && p2 >= -1 && p2 < iwlen) ;
+
+	    /* ------------------------------------------------------------- */
+	    /* scan the element list associated with supervariable i */
+	    /* ------------------------------------------------------------- */
+
+	    /* UMFPACK/MA38-style approximate degree: */
+	    if (aggressive)
+	    {
+		for (p = p1 ; p <= p2 ; p++)
+		{
+		    e = Iw [p] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    we = W [e] ;
+		    if (we != 0)
+		    {
+			/* e is an unabsorbed element */
+			/* dext = | Le \ Lme | */
+			dext = we - wflg ;
+			if (dext > 0)
+			{
+			    deg += dext ;
+			    Iw [pn++] = e ;
+			    hash += e ;
+			    AMD_DEBUG4 ((" e: "ID" hash = "ID"\n",e,hash)) ;
+			}
+			else
+			{
+			    /* external degree of e is zero, absorb e into me*/
+			    AMD_DEBUG1 ((" Element "ID" =>"ID" (aggressive)\n",
+				e, me)) ;
+			    ASSERT (dext == 0) ;
+			    Pe [e] = FLIP (me) ;
+			    W [e] = 0 ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		for (p = p1 ; p <= p2 ; p++)
+		{
+		    e = Iw [p] ;
+		    ASSERT (e >= 0 && e < n) ;
+		    we = W [e] ;
+		    if (we != 0)
+		    {
+			/* e is an unabsorbed element */
+			dext = we - wflg ;
+			ASSERT (dext >= 0) ;
+			deg += dext ;
+			Iw [pn++] = e ;
+			hash += e ;
+			AMD_DEBUG4 (("	e: "ID" hash = "ID"\n",e,hash)) ;
+		    }
+		}
+	    }
+
+	    /* count the number of elements in i (including me): */
+	    Elen [i] = pn - p1 + 1 ;
+
+	    /* ------------------------------------------------------------- */
+	    /* scan the supervariables in the list associated with i */
+	    /* ------------------------------------------------------------- */
+
+	    /* The bulk of the AMD run time is typically spent in this loop,
+	     * particularly if the matrix has many dense rows that are not
+	     * removed prior to ordering. */
+	    p3 = pn ;
+	    p4 = p1 + Len [i] ;
+	    for (p = p2 + 1 ; p < p4 ; p++)
+	    {
+		j = Iw [p] ;
+		ASSERT (j >= 0 && j < n) ;
+		nvj = Nv [j] ;
+		if (nvj > 0)
+		{
+		    /* j is unabsorbed, and not in Lme. */
+		    /* add to degree and add to new list */
+		    deg += nvj ;
+		    Iw [pn++] = j ;
+		    hash += j ;
+		    AMD_DEBUG4 (("  s: "ID" hash "ID" Nv[j]= "ID"\n",
+				j, hash, nvj)) ;
+		}
+	    }
+
+	    /* ------------------------------------------------------------- */
+	    /* update the degree and check for mass elimination */
+	    /* ------------------------------------------------------------- */
+
+	    /* with aggressive absorption, deg==0 is identical to the
+	     * Elen [i] == 1 && p3 == pn test, below. */
+	    ASSERT (IMPLIES (aggressive, (deg==0) == (Elen[i]==1 && p3==pn))) ;
+
+	    if (Elen [i] == 1 && p3 == pn)
+	    {
+
+		/* --------------------------------------------------------- */
+		/* mass elimination */
+		/* --------------------------------------------------------- */
+
+		/* There is nothing left of this node except for an edge to
+		 * the current pivot element.  Elen [i] is 1, and there are
+		 * no variables adjacent to node i.  Absorb i into the
+		 * current pivot element, me.  Note that if there are two or
+		 * more mass eliminations, fillin due to mass elimination is
+		 * possible within the nvpiv-by-nvpiv pivot block.  It is this
+		 * step that causes AMD's analysis to be an upper bound.
+		 *
+		 * The reason is that the selected pivot has a lower
+		 * approximate degree than the true degree of the two mass
+		 * eliminated nodes.  There is no edge between the two mass
+		 * eliminated nodes.  They are merged with the current pivot
+		 * anyway.
+		 *
+		 * No fillin occurs in the Schur complement, in any case,
+		 * and this effect does not decrease the quality of the
+		 * ordering itself, just the quality of the nonzero and
+		 * flop count analysis.  It also means that the post-ordering
+		 * is not an exact elimination tree post-ordering. */
+
+		AMD_DEBUG1 (("  MASS i "ID" => parent e "ID"\n", i, me)) ;
+		Pe [i] = FLIP (me) ;
+		nvi = -Nv [i] ;
+		degme -= nvi ;
+		nvpiv += nvi ;
+		nel += nvi ;
+		Nv [i] = 0 ;
+		Elen [i] = EMPTY ;
+
+	    }
+	    else
+	    {
+
+		/* --------------------------------------------------------- */
+		/* update the upper-bound degree of i */
+		/* --------------------------------------------------------- */
+
+		/* the following degree does not yet include the size
+		 * of the current element, which is added later: */
+
+		Degree [i] = MIN (Degree [i], deg) ;
+
+		/* --------------------------------------------------------- */
+		/* add me to the list for i */
+		/* --------------------------------------------------------- */
+
+		/* move first supervariable to end of list */
+		Iw [pn] = Iw [p3] ;
+		/* move first element to end of element part of list */
+		Iw [p3] = Iw [p1] ;
+		/* add new element, me, to front of list. */
+		Iw [p1] = me ;
+		/* store the new length of the list in Len [i] */
+		Len [i] = pn - p1 + 1 ;
+
+		/* --------------------------------------------------------- */
+		/* place in hash bucket.  Save hash key of i in Last [i]. */
+		/* --------------------------------------------------------- */
+
+		/* NOTE: this can fail if hash is negative, because the ANSI C
+		 * standard does not define a % b when a and/or b are negative.
+		 * That's why hash is defined as an unsigned Int, to avoid this
+		 * problem. */
+		hash = hash % n ;
+		ASSERT (((Int) hash) >= 0 && ((Int) hash) < n) ;
+
+		/* if the Hhead array is not used: */
+		j = Head [hash] ;
+		if (j <= EMPTY)
+		{
+		    /* degree list is empty, hash head is FLIP (j) */
+		    Next [i] = FLIP (j) ;
+		    Head [hash] = FLIP (i) ;
+		}
+		else
+		{
+		    /* degree list is not empty, use Last [Head [hash]] as
+		     * hash head. */
+		    Next [i] = Last [j] ;
+		    Last [j] = i ;
+		}
+
+		/* if a separate Hhead array is used: *
+		Next [i] = Hhead [hash] ;
+		Hhead [hash] = i ;
+		*/
+
+		Last [i] = hash ;
+	    }
+	}
+
+	Degree [me] = degme ;
+
+	/* ----------------------------------------------------------------- */
+	/* Clear the counter array, W [...], by incrementing wflg. */
+	/* ----------------------------------------------------------------- */
+
+	/* make sure that wflg+n does not cause integer overflow */
+	lemax =  MAX (lemax, degme) ;
+	wflg += lemax ;
+	wflg = clear_flag (wflg, wbig, W, n) ;
+	/*  at this point, W [0..n-1] < wflg holds */
+
+/* ========================================================================= */
+/* SUPERVARIABLE DETECTION */
+/* ========================================================================= */
+
+	AMD_DEBUG1 (("Detecting supervariables:\n")) ;
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    AMD_DEBUG2 (("Consider i "ID" nv "ID"\n", i, Nv [i])) ;
+	    if (Nv [i] < 0)
+	    {
+		/* i is a principal variable in Lme */
+
+		/* ---------------------------------------------------------
+		 * examine all hash buckets with 2 or more variables.  We do
+		 * this by examing all unique hash keys for supervariables in
+		 * the pattern Lme of the current element, me
+		 * --------------------------------------------------------- */
+
+		/* let i = head of hash bucket, and empty the hash bucket */
+		ASSERT (Last [i] >= 0 && Last [i] < n) ;
+		hash = Last [i] ;
+
+		/* if Hhead array is not used: */
+		j = Head [hash] ;
+		if (j == EMPTY)
+		{
+		    /* hash bucket and degree list are both empty */
+		    i = EMPTY ;
+		}
+		else if (j < EMPTY)
+		{
+		    /* degree list is empty */
+		    i = FLIP (j) ;
+		    Head [hash] = EMPTY ;
+		}
+		else
+		{
+		    /* degree list is not empty, restore Last [j] of head j */
+		    i = Last [j] ;
+		    Last [j] = EMPTY ;
+		}
+
+		/* if separate Hhead array is used: *
+		i = Hhead [hash] ;
+		Hhead [hash] = EMPTY ;
+		*/
+
+		ASSERT (i >= EMPTY && i < n) ;
+		AMD_DEBUG2 (("----i "ID" hash "ID"\n", i, hash)) ;
+
+		while (i != EMPTY && Next [i] != EMPTY)
+		{
+
+		    /* -----------------------------------------------------
+		     * this bucket has one or more variables following i.
+		     * scan all of them to see if i can absorb any entries
+		     * that follow i in hash bucket.  Scatter i into w.
+		     * ----------------------------------------------------- */
+
+		    ln = Len [i] ;
+		    eln = Elen [i] ;
+		    ASSERT (ln >= 0 && eln >= 0) ;
+		    ASSERT (Pe [i] >= 0 && Pe [i] < iwlen) ;
+		    /* do not flag the first element in the list (me) */
+		    for (p = Pe [i] + 1 ; p <= Pe [i] + ln - 1 ; p++)
+		    {
+			ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+			W [Iw [p]] = wflg ;
+		    }
+
+		    /* ----------------------------------------------------- */
+		    /* scan every other entry j following i in bucket */
+		    /* ----------------------------------------------------- */
+
+		    jlast = i ;
+		    j = Next [i] ;
+		    ASSERT (j >= EMPTY && j < n) ;
+
+		    while (j != EMPTY)
+		    {
+			/* ------------------------------------------------- */
+			/* check if j and i have identical nonzero pattern */
+			/* ------------------------------------------------- */
+
+			AMD_DEBUG3 (("compare i "ID" and j "ID"\n", i,j)) ;
+
+			/* check if i and j have the same Len and Elen */
+			ASSERT (Len [j] >= 0 && Elen [j] >= 0) ;
+			ASSERT (Pe [j] >= 0 && Pe [j] < iwlen) ;
+			ok = (Len [j] == ln) && (Elen [j] == eln) ;
+			/* skip the first element in the list (me) */
+			for (p = Pe [j] + 1 ; ok && p <= Pe [j] + ln - 1 ; p++)
+			{
+			    ASSERT (Iw [p] >= 0 && Iw [p] < n) ;
+			    if (W [Iw [p]] != wflg) ok = 0 ;
+			}
+			if (ok)
+			{
+			    /* --------------------------------------------- */
+			    /* found it!  j can be absorbed into i */
+			    /* --------------------------------------------- */
+
+			    AMD_DEBUG1 (("found it! j "ID" => i "ID"\n", j,i));
+			    Pe [j] = FLIP (i) ;
+			    /* both Nv [i] and Nv [j] are negated since they */
+			    /* are in Lme, and the absolute values of each */
+			    /* are the number of variables in i and j: */
+			    Nv [i] += Nv [j] ;
+			    Nv [j] = 0 ;
+			    Elen [j] = EMPTY ;
+			    /* delete j from hash bucket */
+			    ASSERT (j != Next [j]) ;
+			    j = Next [j] ;
+			    Next [jlast] = j ;
+
+			}
+			else
+			{
+			    /* j cannot be absorbed into i */
+			    jlast = j ;
+			    ASSERT (j != Next [j]) ;
+			    j = Next [j] ;
+			}
+			ASSERT (j >= EMPTY && j < n) ;
+		    }
+
+		    /* -----------------------------------------------------
+		     * no more variables can be absorbed into i
+		     * go to next i in bucket and clear flag array
+		     * ----------------------------------------------------- */
+
+		    wflg++ ;
+		    i = Next [i] ;
+		    ASSERT (i >= EMPTY && i < n) ;
+
+		}
+	    }
+	}
+	AMD_DEBUG2 (("detect done\n")) ;
+
+/* ========================================================================= */
+/* RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVARIABLES FROM ELEMENT */
+/* ========================================================================= */
+
+	p = pme1 ;
+	nleft = n - nel ;
+	for (pme = pme1 ; pme <= pme2 ; pme++)
+	{
+	    i = Iw [pme] ;
+	    ASSERT (i >= 0 && i < n) ;
+	    nvi = -Nv [i] ;
+	    AMD_DEBUG3 (("Restore i "ID" "ID"\n", i, nvi)) ;
+	    if (nvi > 0)
+	    {
+		/* i is a principal variable in Lme */
+		/* restore Nv [i] to signify that i is principal */
+		Nv [i] = nvi ;
+
+		/* --------------------------------------------------------- */
+		/* compute the external degree (add size of current element) */
+		/* --------------------------------------------------------- */
+
+		deg = Degree [i] + degme - nvi ;
+		deg = MIN (deg, nleft - nvi) ;
+		ASSERT (IMPLIES (aggressive, deg > 0) && deg >= 0 && deg < n) ;
+
+		/* --------------------------------------------------------- */
+		/* place the supervariable at the head of the degree list */
+		/* --------------------------------------------------------- */
+
+		inext = Head [deg] ;
+		ASSERT (inext >= EMPTY && inext < n) ;
+		if (inext != EMPTY) Last [inext] = i ;
+		Next [i] = inext ;
+		Last [i] = EMPTY ;
+		Head [deg] = i ;
+
+		/* --------------------------------------------------------- */
+		/* save the new degree, and find the minimum degree */
+		/* --------------------------------------------------------- */
+
+		mindeg = MIN (mindeg, deg) ;
+		Degree [i] = deg ;
+
+		/* --------------------------------------------------------- */
+		/* place the supervariable in the element pattern */
+		/* --------------------------------------------------------- */
+
+		Iw [p++] = i ;
+
+	    }
+	}
+	AMD_DEBUG2 (("restore done\n")) ;
+
+/* ========================================================================= */
+/* FINALIZE THE NEW ELEMENT */
+/* ========================================================================= */
+
+	AMD_DEBUG2 (("ME = "ID" DONE\n", me)) ;
+	Nv [me] = nvpiv ;
+	/* save the length of the list for the new element me */
+	Len [me] = p - pme1 ;
+	if (Len [me] == 0)
+	{
+	    /* there is nothing left of the current pivot element */
+	    /* it is a root of the assembly tree */
+	    Pe [me] = EMPTY ;
+	    W [me] = 0 ;
+	}
+	if (elenme != 0)
+	{
+	    /* element was not constructed in place: deallocate part of */
+	    /* it since newly nonprincipal variables may have been removed */
+	    pfree = p ;
+	}
+
+	/* The new element has nvpiv pivots and the size of the contribution
+	 * block for a multifrontal method is degme-by-degme, not including
+	 * the "dense" rows/columns.  If the "dense" rows/columns are included,
+	 * the frontal matrix is no larger than
+	 * (degme+ndense)-by-(degme+ndense).
+	 */
+
+	if (Info != (double *) NULL)
+	{
+	    f = nvpiv ;
+	    r = degme + ndense ;
+	    dmax = MAX (dmax, f + r) ;
+
+	    /* number of nonzeros in L (excluding the diagonal) */
+	    lnzme = f*r + (f-1)*f/2 ;
+	    lnz += lnzme ;
+
+	    /* number of divide operations for LDL' and for LU */
+	    ndiv += lnzme ;
+
+	    /* number of multiply-subtract pairs for LU */
+	    s = f*r*r + r*(f-1)*f + (f-1)*f*(2*f-1)/6 ;
+	    nms_lu += s ;
+
+	    /* number of multiply-subtract pairs for LDL' */
+	    nms_ldl += (s + lnzme)/2 ;
+	}
+
+#ifndef NDEBUG
+	AMD_DEBUG2 (("finalize done nel "ID" n "ID"\n   ::::\n", nel, n)) ;
+	for (pme = Pe [me] ; pme <= Pe [me] + Len [me] - 1 ; pme++)
+	{
+	      AMD_DEBUG3 ((" "ID"", Iw [pme])) ;
+	}
+	AMD_DEBUG3 (("\n")) ;
+#endif
+
+    }
+
+/* ========================================================================= */
+/* DONE SELECTING PIVOTS */
+/* ========================================================================= */
+
+    if (Info != (double *) NULL)
+    {
+
+	/* count the work to factorize the ndense-by-ndense submatrix */
+	f = ndense ;
+	dmax = MAX (dmax, (double) ndense) ;
+
+	/* number of nonzeros in L (excluding the diagonal) */
+	lnzme = (f-1)*f/2 ;
+	lnz += lnzme ;
+
+	/* number of divide operations for LDL' and for LU */
+	ndiv += lnzme ;
+
+	/* number of multiply-subtract pairs for LU */
+	s = (f-1)*f*(2*f-1)/6 ;
+	nms_lu += s ;
+
+	/* number of multiply-subtract pairs for LDL' */
+	nms_ldl += (s + lnzme)/2 ;
+
+	/* number of nz's in L (excl. diagonal) */
+	Info [AMD_LNZ] = lnz ;
+
+	/* number of divide ops for LU and LDL' */
+	Info [AMD_NDIV] = ndiv ;
+
+	/* number of multiply-subtract pairs for LDL' */
+	Info [AMD_NMULTSUBS_LDL] = nms_ldl ;
+
+	/* number of multiply-subtract pairs for LU */
+	Info [AMD_NMULTSUBS_LU] = nms_lu ;
+
+	/* number of "dense" rows/columns */
+	Info [AMD_NDENSE] = ndense ;
+
+	/* largest front is dmax-by-dmax */
+	Info [AMD_DMAX] = dmax ;
+
+	/* number of garbage collections in AMD */
+	Info [AMD_NCMPA] = ncmpa ;
+
+	/* successful ordering */
+	Info [AMD_STATUS] = AMD_OK ;
+    }
+
+/* ========================================================================= */
+/* POST-ORDERING */
+/* ========================================================================= */
+
+/* -------------------------------------------------------------------------
+ * Variables at this point:
+ *
+ * Pe: holds the elimination tree.  The parent of j is FLIP (Pe [j]),
+ *	or EMPTY if j is a root.  The tree holds both elements and
+ *	non-principal (unordered) variables absorbed into them.
+ *	Dense variables are non-principal and unordered.
+ *
+ * Elen: holds the size of each element, including the diagonal part.
+ *	FLIP (Elen [e]) > 0 if e is an element.  For unordered
+ *	variables i, Elen [i] is EMPTY.
+ *
+ * Nv: Nv [e] > 0 is the number of pivots represented by the element e.
+ *	For unordered variables i, Nv [i] is zero.
+ *
+ * Contents no longer needed:
+ *	W, Iw, Len, Degree, Head, Next, Last.
+ *
+ * The matrix itself has been destroyed.
+ *
+ * n: the size of the matrix.
+ * No other scalars needed (pfree, iwlen, etc.)
+ * ------------------------------------------------------------------------- */
+
+    /* restore Pe */
+    for (i = 0 ; i < n ; i++)
+    {
+	Pe [i] = FLIP (Pe [i]) ;
+    }
+
+    /* restore Elen, for output information, and for postordering */
+    for (i = 0 ; i < n ; i++)
+    {
+	Elen [i] = FLIP (Elen [i]) ;
+    }
+
+/* Now the parent of j is Pe [j], or EMPTY if j is a root.  Elen [e] > 0
+ * is the size of element e.  Elen [i] is EMPTY for unordered variable i. */
+
+#ifndef NDEBUG
+    AMD_DEBUG2 (("\nTree:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	AMD_DEBUG2 ((" "ID" parent: "ID"   ", i, Pe [i])) ;
+	ASSERT (Pe [i] >= EMPTY && Pe [i] < n) ;
+	if (Nv [i] > 0)
+	{
+	    /* this is an element */
+	    e = i ;
+	    AMD_DEBUG2 ((" element, size is "ID"\n", Elen [i])) ;
+	    ASSERT (Elen [e] > 0) ;
+	}
+	AMD_DEBUG2 (("\n")) ;
+    }
+    AMD_DEBUG2 (("\nelements:\n")) ;
+    for (e = 0 ; e < n ; e++)
+    {
+	if (Nv [e] > 0)
+	{
+	    AMD_DEBUG3 (("Element e= "ID" size "ID" nv "ID" \n", e,
+		Elen [e], Nv [e])) ;
+	}
+    }
+    AMD_DEBUG2 (("\nvariables:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Int cnt ;
+	if (Nv [i] == 0)
+	{
+	    AMD_DEBUG3 (("i unordered: "ID"\n", i)) ;
+	    j = Pe [i] ;
+	    cnt = 0 ;
+	    AMD_DEBUG3 (("  j: "ID"\n", j)) ;
+	    if (j == EMPTY)
+	    {
+		AMD_DEBUG3 (("	i is a dense variable\n")) ;
+	    }
+	    else
+	    {
+		ASSERT (j >= 0 && j < n) ;
+		while (Nv [j] == 0)
+		{
+		    AMD_DEBUG3 (("	j : "ID"\n", j)) ;
+		    j = Pe [j] ;
+		    AMD_DEBUG3 (("	j:: "ID"\n", j)) ;
+		    cnt++ ;
+		    if (cnt > n) break ;
+		}
+		e = j ;
+		AMD_DEBUG3 (("	got to e: "ID"\n", e)) ;
+	    }
+	}
+    }
+#endif
+
+/* ========================================================================= */
+/* compress the paths of the variables */
+/* ========================================================================= */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	if (Nv [i] == 0)
+	{
+
+	    /* -------------------------------------------------------------
+	     * i is an un-ordered row.  Traverse the tree from i until
+	     * reaching an element, e.  The element, e, was the principal
+	     * supervariable of i and all nodes in the path from i to when e
+	     * was selected as pivot.
+	     * ------------------------------------------------------------- */
+
+	    AMD_DEBUG1 (("Path compression, i unordered: "ID"\n", i)) ;
+	    j = Pe [i] ;
+	    ASSERT (j >= EMPTY && j < n) ;
+	    AMD_DEBUG3 (("	j: "ID"\n", j)) ;
+	    if (j == EMPTY)
+	    {
+		/* Skip a dense variable.  It has no parent. */
+		AMD_DEBUG3 (("      i is a dense variable\n")) ;
+		continue ;
+	    }
+
+	    /* while (j is a variable) */
+	    while (Nv [j] == 0)
+	    {
+		AMD_DEBUG3 (("		j : "ID"\n", j)) ;
+		j = Pe [j] ;
+		AMD_DEBUG3 (("		j:: "ID"\n", j)) ;
+		ASSERT (j >= 0 && j < n) ;
+	    }
+	    /* got to an element e */
+	    e = j ;
+	    AMD_DEBUG3 (("got to e: "ID"\n", e)) ;
+
+	    /* -------------------------------------------------------------
+	     * traverse the path again from i to e, and compress the path
+	     * (all nodes point to e).  Path compression allows this code to
+	     * compute in O(n) time.
+	     * ------------------------------------------------------------- */
+
+	    j = i ;
+	    /* while (j is a variable) */
+	    while (Nv [j] == 0)
+	    {
+		jnext = Pe [j] ;
+		AMD_DEBUG3 (("j "ID" jnext "ID"\n", j, jnext)) ;
+		Pe [j] = e ;
+		j = jnext ;
+		ASSERT (j >= 0 && j < n) ;
+	    }
+	}
+    }
+
+/* ========================================================================= */
+/* postorder the assembly tree */
+/* ========================================================================= */
+
+    AMD_postorder (n, Pe, Nv, Elen,
+	W,			/* output order */
+	Head, Next, Last) ;	/* workspace */
+
+/* ========================================================================= */
+/* compute output permutation and inverse permutation */
+/* ========================================================================= */
+
+    /* W [e] = k means that element e is the kth element in the new
+     * order.  e is in the range 0 to n-1, and k is in the range 0 to
+     * the number of elements.  Use Head for inverse order. */
+
+    for (k = 0 ; k < n ; k++)
+    {
+	Head [k] = EMPTY ;
+	Next [k] = EMPTY ;
+    }
+    for (e = 0 ; e < n ; e++)
+    {
+	k = W [e] ;
+	ASSERT ((k == EMPTY) == (Nv [e] == 0)) ;
+	if (k != EMPTY)
+	{
+	    ASSERT (k >= 0 && k < n) ;
+	    Head [k] = e ;
+	}
+    }
+
+    /* construct output inverse permutation in Next,
+     * and permutation in Last */
+    nel = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+	e = Head [k] ;
+	if (e == EMPTY) break ;
+	ASSERT (e >= 0 && e < n && Nv [e] > 0) ;
+	Next [e] = nel ;
+	nel += Nv [e] ;
+    }
+    ASSERT (nel == n - ndense) ;
+
+    /* order non-principal variables (dense, & those merged into supervar's) */
+    for (i = 0 ; i < n ; i++)
+    {
+	if (Nv [i] == 0)
+	{
+	    e = Pe [i] ;
+	    ASSERT (e >= EMPTY && e < n) ;
+	    if (e != EMPTY)
+	    {
+		/* This is an unordered variable that was merged
+		 * into element e via supernode detection or mass
+		 * elimination of i when e became the pivot element.
+		 * Place i in order just before e. */
+		ASSERT (Next [i] == EMPTY && Nv [e] > 0) ;
+		Next [i] = Next [e] ;
+		Next [e]++ ;
+	    }
+	    else
+	    {
+		/* This is a dense unordered variable, with no parent.
+		 * Place it last in the output order. */
+		Next [i] = nel++ ;
+	    }
+	}
+    }
+    ASSERT (nel == n) ;
+
+    AMD_DEBUG2 (("\n\nPerm:\n")) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	k = Next [i] ;
+	ASSERT (k >= 0 && k < n) ;
+	Last [k] = i ;
+	AMD_DEBUG2 (("   perm ["ID"] = "ID"\n", k, i)) ;
+    }
+}
diff --git a/src/AMD/Source/amd_aat.c b/src/AMD/Source/amd_aat.c
new file mode 100644
index 0000000..67c03f7
--- /dev/null
+++ b/src/AMD/Source/amd_aat.c
@@ -0,0 +1,184 @@
+/* ========================================================================= */
+/* === AMD_aat ============================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* AMD_aat:  compute the symmetry of the pattern of A, and count the number of
+ * nonzeros each column of A+A' (excluding the diagonal).  Assumes the input
+ * matrix has no errors, with sorted columns and no duplicates
+ * (AMD_valid (n, n, Ap, Ai) must be AMD_OK, but this condition is not
+ * checked).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL size_t AMD_aat	/* returns nz in A+A' */
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int Len [ ],	/* Len [j]: length of column j of A+A', excl diagonal*/
+    Int Tp [ ],		/* workspace of size n */
+    double Info [ ]
+)
+{
+    Int p1, p2, p, i, j, pj, pj2, k, nzdiag, nzboth, nz ;
+    double sym ;
+    size_t nzaat ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("AMD AAT") ;
+    for (k = 0 ; k < n ; k++) Tp [k] = EMPTY ;
+    ASSERT (AMD_valid (n, n, Ap, Ai) == AMD_OK) ;
+#endif
+
+    if (Info != (double *) NULL)
+    {
+	/* clear the Info array, if it exists */
+	for (i = 0 ; i < AMD_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+	Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    for (k = 0 ; k < n ; k++)
+    {
+	Len [k] = 0 ;
+    }
+
+    nzdiag = 0 ;
+    nzboth = 0 ;
+    nz = Ap [n] ;
+
+    for (k = 0 ; k < n ; k++)
+    {
+	p1 = Ap [k] ;
+	p2 = Ap [k+1] ;
+	AMD_DEBUG2 (("\nAAT Column: "ID" p1: "ID" p2: "ID"\n", k, p1, p2)) ;
+
+	/* construct A+A' */
+	for (p = p1 ; p < p2 ; )
+	{
+	    /* scan the upper triangular part of A */
+	    j = Ai [p] ;
+	    if (j < k)
+	    {
+		/* entry A (j,k) is in the strictly upper triangular part,
+		 * add both A (j,k) and A (k,j) to the matrix A+A' */
+		Len [j]++ ;
+		Len [k]++ ;
+		AMD_DEBUG3 (("    upper ("ID","ID") ("ID","ID")\n", j,k, k,j));
+		p++ ;
+	    }
+	    else if (j == k)
+	    {
+		/* skip the diagonal */
+		p++ ;
+		nzdiag++ ;
+		break ;
+	    }
+	    else /* j > k */
+	    {
+		/* first entry below the diagonal */
+		break ;
+	    }
+	    /* scan lower triangular part of A, in column j until reaching
+	     * row k.  Start where last scan left off. */
+	    ASSERT (Tp [j] != EMPTY) ;
+	    ASSERT (Ap [j] <= Tp [j] && Tp [j] <= Ap [j+1]) ;
+	    pj2 = Ap [j+1] ;
+	    for (pj = Tp [j] ; pj < pj2 ; )
+	    {
+		i = Ai [pj] ;
+		if (i < k)
+		{
+		    /* A (i,j) is only in the lower part, not in upper.
+		     * add both A (i,j) and A (j,i) to the matrix A+A' */
+		    Len [i]++ ;
+		    Len [j]++ ;
+		    AMD_DEBUG3 (("    lower ("ID","ID") ("ID","ID")\n",
+			i,j, j,i)) ;
+		    pj++ ;
+		}
+		else if (i == k)
+		{
+		    /* entry A (k,j) in lower part and A (j,k) in upper */
+		    pj++ ;
+		    nzboth++ ;
+		    break ;
+		}
+		else /* i > k */
+		{
+		    /* consider this entry later, when k advances to i */
+		    break ;
+		}
+	    }
+	    Tp [j] = pj ;
+	}
+	/* Tp [k] points to the entry just below the diagonal in column k */
+	Tp [k] = p ;
+    }
+
+    /* clean up, for remaining mismatched entries */
+    for (j = 0 ; j < n ; j++)
+    {
+	for (pj = Tp [j] ; pj < Ap [j+1] ; pj++)
+	{
+	    i = Ai [pj] ;
+	    /* A (i,j) is only in the lower part, not in upper.
+	     * add both A (i,j) and A (j,i) to the matrix A+A' */
+	    Len [i]++ ;
+	    Len [j]++ ;
+	    AMD_DEBUG3 (("    lower cleanup ("ID","ID") ("ID","ID")\n",
+		i,j, j,i)) ;
+	}
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the symmetry of the nonzero pattern of A */
+    /* --------------------------------------------------------------------- */
+
+    /* Given a matrix A, the symmetry of A is:
+     *	B = tril (spones (A), -1) + triu (spones (A), 1) ;
+     *  sym = nnz (B & B') / nnz (B) ;
+     *  or 1 if nnz (B) is zero.
+     */
+
+    if (nz == nzdiag)
+    {
+	sym = 1 ;
+    }
+    else
+    {
+	sym = (2 * (double) nzboth) / ((double) (nz - nzdiag)) ;
+    }
+
+    nzaat = 0 ;
+    for (k = 0 ; k < n ; k++)
+    {
+	nzaat += Len [k] ;
+    }
+
+    AMD_DEBUG1 (("AMD nz in A+A', excluding diagonal (nzaat) = %g\n",
+	(double) nzaat)) ;
+    AMD_DEBUG1 (("   nzboth: "ID" nz: "ID" nzdiag: "ID" symmetry: %g\n",
+		nzboth, nz, nzdiag, sym)) ;
+
+    if (Info != (double *) NULL)
+    {
+	Info [AMD_STATUS] = AMD_OK ;
+	Info [AMD_N] = n ;
+	Info [AMD_NZ] = nz ;
+	Info [AMD_SYMMETRY] = sym ;	    /* symmetry of pattern of A */
+	Info [AMD_NZDIAG] = nzdiag ;	    /* nonzeros on diagonal of A */
+	Info [AMD_NZ_A_PLUS_AT] = nzaat ;   /* nonzeros in A+A' */
+    }
+
+    return (nzaat) ;
+}
diff --git a/src/AMD/Source/amd_control.c b/src/AMD/Source/amd_control.c
new file mode 100644
index 0000000..b3c4e01
--- /dev/null
+++ b/src/AMD/Source/amd_control.c
@@ -0,0 +1,63 @@
+/* ========================================================================= */
+/* === AMD_control ========================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the control parameters for AMD.  See amd.h
+ * for details.  If the Control array is not present, the defaults are
+ * printed instead.
+ */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_control
+(
+    double Control [ ]
+)
+{
+    double alpha ;
+    Int aggressive ;
+
+    if (Control != (double *) NULL)
+    {
+	alpha = Control [AMD_DENSE] ;
+	aggressive = Control [AMD_AGGRESSIVE] != 0 ;
+    }
+    else
+    {
+	alpha = AMD_DEFAULT_DENSE ;
+	aggressive = AMD_DEFAULT_AGGRESSIVE ;
+    }
+
+    PRINTF (("\nAMD version %d.%d.%d, %s: approximate minimum degree ordering\n"
+	"    dense row parameter: %g\n", AMD_MAIN_VERSION, AMD_SUB_VERSION,
+	AMD_SUBSUB_VERSION, AMD_DATE, alpha)) ;
+
+    if (alpha < 0)
+    {
+	PRINTF (("    no rows treated as dense\n")) ;
+    }
+    else
+    {
+	PRINTF ((
+	"    (rows with more than max (%g * sqrt (n), 16) entries are\n"
+	"    considered \"dense\", and placed last in output permutation)\n",
+	alpha)) ;
+    }
+
+    if (aggressive)
+    {
+	PRINTF (("    aggressive absorption:  yes\n")) ;
+    }
+    else
+    {
+	PRINTF (("    aggressive absorption:  no\n")) ;
+    }
+
+    PRINTF (("    size of AMD integer: %d\n\n", sizeof (Int))) ;
+}
diff --git a/src/AMD/Source/amd_defaults.c b/src/AMD/Source/amd_defaults.c
new file mode 100644
index 0000000..b9a9079
--- /dev/null
+++ b/src/AMD/Source/amd_defaults.c
@@ -0,0 +1,37 @@
+/* ========================================================================= */
+/* === AMD_defaults ======================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Sets default control parameters for AMD.  See amd.h
+ * for details.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD defaults ======================================================== */
+/* ========================================================================= */
+
+GLOBAL void AMD_defaults
+(
+    double Control [ ]
+)
+{
+    Int i ;
+
+    if (Control != (double *) NULL)
+    {
+	for (i = 0 ; i < AMD_CONTROL ; i++)
+	{
+	    Control [i] = 0 ;
+	}
+	Control [AMD_DENSE] = AMD_DEFAULT_DENSE ;
+	Control [AMD_AGGRESSIVE] = AMD_DEFAULT_AGGRESSIVE ;
+    }
+}
diff --git a/src/AMD/Source/amd_dump.c b/src/AMD/Source/amd_dump.c
new file mode 100644
index 0000000..e58aaf5
--- /dev/null
+++ b/src/AMD/Source/amd_dump.c
@@ -0,0 +1,179 @@
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* Debugging routines for AMD.  Not used if NDEBUG is not defined at compile-
+ * time (the default).  See comments in amd_internal.h on how to enable
+ * debugging.  Not user-callable.
+ */
+
+#include "amd_internal.h"
+
+#ifndef NDEBUG
+
+/* This global variable is present only when debugging */
+GLOBAL Int AMD_debug = -999 ;		/* default is no debug printing */
+
+/* ========================================================================= */
+/* === AMD_debug_init ====================================================== */
+/* ========================================================================= */
+
+/* Sets the debug print level, by reading the file debug.amd (if it exists) */
+
+GLOBAL void AMD_debug_init ( char *s )
+{
+    FILE *f ;
+    f = fopen ("debug.amd", "r") ;
+    if (f == (FILE *) NULL)
+    {
+	AMD_debug = -999 ;
+    }
+    else
+    {
+	fscanf (f, ID, &AMD_debug) ;
+	fclose (f) ;
+    }
+    if (AMD_debug >= 0)
+    {
+	printf ("%s: AMD_debug_init, D= "ID"\n", s, AMD_debug) ;
+    }
+}
+
+/* ========================================================================= */
+/* === AMD_dump ============================================================ */
+/* ========================================================================= */
+
+/* Dump AMD's data structure, except for the hash buckets.  This routine
+ * cannot be called when the hash buckets are non-empty.
+ */
+
+GLOBAL void AMD_dump (
+    Int n,	    /* A is n-by-n */
+    Int Pe [ ],	    /* pe [0..n-1]: index in iw of start of row i */
+    Int Iw [ ],	    /* workspace of size iwlen, iwlen [0..pfree-1]
+		     * holds the matrix on input */
+    Int Len [ ],    /* len [0..n-1]: length for row i */
+    Int iwlen,	    /* length of iw */
+    Int pfree,	    /* iw [pfree ... iwlen-1] is empty on input */
+    Int Nv [ ],	    /* nv [0..n-1] */
+    Int Next [ ],   /* next [0..n-1] */
+    Int Last [ ],   /* last [0..n-1] */
+    Int Head [ ],   /* head [0..n-1] */
+    Int Elen [ ],   /* size n */
+    Int Degree [ ], /* size n */
+    Int W [ ],	    /* size n */
+    Int nel
+)
+{
+    Int i, pe, elen, nv, len, e, p, k, j, deg, w, cnt, ilast ;
+
+    if (AMD_debug < 0) return ;
+    ASSERT (pfree <= iwlen) ;
+    AMD_DEBUG3 (("\nAMD dump, pfree: "ID"\n", pfree)) ;
+    for (i = 0 ; i < n ; i++)
+    {
+	pe = Pe [i] ;
+	elen = Elen [i] ;
+	nv = Nv [i] ;
+	len = Len [i] ;
+	w = W [i] ;
+
+	if (elen >= EMPTY)
+	{
+	    if (nv == 0)
+	    {
+		AMD_DEBUG3 (("\nI "ID": nonprincipal:    ", i)) ;
+		ASSERT (elen == EMPTY) ;
+		if (pe == EMPTY)
+		{
+		    AMD_DEBUG3 ((" dense node\n")) ;
+		    ASSERT (w == 1) ;
+		}
+		else
+		{
+		    ASSERT (pe < EMPTY) ;
+		    AMD_DEBUG3 ((" i "ID" -> parent "ID"\n", i, FLIP (Pe[i])));
+		}
+	    }
+	    else
+	    {
+		AMD_DEBUG3 (("\nI "ID": active principal supervariable:\n",i));
+		AMD_DEBUG3 (("   nv(i): "ID"  Flag: %d\n", nv, (nv < 0))) ;
+		ASSERT (elen >= 0) ;
+		ASSERT (nv > 0 && pe >= 0) ;
+		p = pe ;
+		AMD_DEBUG3 (("   e/s: ")) ;
+		if (elen == 0) AMD_DEBUG3 ((" : ")) ;
+		ASSERT (pe + len <= pfree) ;
+		for (k = 0 ; k < len ; k++)
+		{
+		    j = Iw [p] ;
+		    AMD_DEBUG3 (("  "ID"", j)) ;
+		    ASSERT (j >= 0 && j < n) ;
+		    if (k == elen-1) AMD_DEBUG3 ((" : ")) ;
+		    p++ ;
+		}
+		AMD_DEBUG3 (("\n")) ;
+	    }
+	}
+	else
+	{
+	    e = i ;
+	    if (w == 0)
+	    {
+		AMD_DEBUG3 (("\nE "ID": absorbed element: w "ID"\n", e, w)) ;
+		ASSERT (nv > 0 && pe < 0) ;
+		AMD_DEBUG3 ((" e "ID" -> parent "ID"\n", e, FLIP (Pe [e]))) ;
+	    }
+	    else
+	    {
+		AMD_DEBUG3 (("\nE "ID": unabsorbed element: w "ID"\n", e, w)) ;
+		ASSERT (nv > 0 && pe >= 0) ;
+		p = pe ;
+		AMD_DEBUG3 ((" : ")) ;
+		ASSERT (pe + len <= pfree) ;
+		for (k = 0 ; k < len ; k++)
+		{
+		    j = Iw [p] ;
+		    AMD_DEBUG3 (("  "ID"", j)) ;
+		    ASSERT (j >= 0 && j < n) ;
+		    p++ ;
+		}
+		AMD_DEBUG3 (("\n")) ;
+	    }
+	}
+    }
+
+    /* this routine cannot be called when the hash buckets are non-empty */
+    AMD_DEBUG3 (("\nDegree lists:\n")) ;
+    if (nel >= 0)
+    {
+	cnt = 0 ;
+	for (deg = 0 ; deg < n ; deg++)
+	{
+	    if (Head [deg] == EMPTY) continue ;
+	    ilast = EMPTY ;
+	    AMD_DEBUG3 ((ID": \n", deg)) ;
+	    for (i = Head [deg] ; i != EMPTY ; i = Next [i])
+	    {
+		AMD_DEBUG3 (("   "ID" : next "ID" last "ID" deg "ID"\n",
+		    i, Next [i], Last [i], Degree [i])) ;
+		ASSERT (i >= 0 && i < n && ilast == Last [i] &&
+		    deg == Degree [i]) ;
+		cnt += Nv [i] ;
+		ilast = i ;
+	    }
+	    AMD_DEBUG3 (("\n")) ;
+	}
+	ASSERT (cnt == n - nel) ;
+    }
+
+}
+
+#endif
diff --git a/src/AMD/Source/amd_global.c b/src/AMD/Source/amd_global.c
new file mode 100644
index 0000000..2bf5542
--- /dev/null
+++ b/src/AMD/Source/amd_global.c
@@ -0,0 +1,83 @@
+/* ========================================================================= */
+/* === amd_global ========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+#include <stdlib.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* ========================================================================= */
+/* === Default AMD memory manager ========================================== */
+/* ========================================================================= */
+
+/* The user can redefine these global pointers at run-time to change the memory
+ * manager used by AMD.  AMD only uses malloc and free; realloc and calloc are
+ * include for completeness, in case another package wants to use the same
+ * memory manager as AMD.
+ *
+ * If compiling as a MATLAB mexFunction, the default memory manager is mxMalloc.
+ * You can also compile AMD as a standard ANSI-C library and link a mexFunction
+ * against it, and then redefine these pointers at run-time, in your
+ * mexFunction.
+ *
+ * If -DNMALLOC is defined at compile-time, no memory manager is specified at
+ * compile-time.  You must then define these functions at run-time, before
+ * calling AMD, for AMD to work properly.
+ */
+
+#ifndef NMALLOC
+#ifdef MATLAB_MEX_FILE
+/* MATLAB mexFunction: */
+void *(*amd_malloc) (size_t) = mxMalloc ;
+void (*amd_free) (void *) = mxFree ;
+void *(*amd_realloc) (void *, size_t) = mxRealloc ;
+void *(*amd_calloc) (size_t, size_t) = mxCalloc ;
+#else
+/* standard ANSI-C: */
+void *(*amd_malloc) (size_t) = malloc ;
+void (*amd_free) (void *) = free ;
+void *(*amd_realloc) (void *, size_t) = realloc ;
+void *(*amd_calloc) (size_t, size_t) = calloc ;
+#endif
+#else
+/* no memory manager defined at compile-time; you MUST define one at run-time */
+void *(*amd_malloc) (size_t) = NULL ;
+void (*amd_free) (void *) = NULL ;
+void *(*amd_realloc) (void *, size_t) = NULL ;
+void *(*amd_calloc) (size_t, size_t) = NULL ;
+#endif
+
+/* ========================================================================= */
+/* === Default AMD printf routine ========================================== */
+/* ========================================================================= */
+
+/* The user can redefine this global pointer at run-time to change the printf
+ * routine used by AMD.  If NULL, no printing occurs.  
+ *
+ * If -DNPRINT is defined at compile-time, stdio.h is not included.  Printing
+ * can then be enabled at run-time by setting amd_printf to a non-NULL function.
+ */
+
+#ifndef NPRINT
+#ifdef MATLAB_MEX_FILE
+int (*amd_printf) (const char *, ...) = mexPrintf ;
+#else
+#include <stdio.h>
+int (*amd_printf) (const char *, ...) = printf ;
+#endif
+#else
+int (*amd_printf) (const char *, ...) = NULL ;
+#endif
diff --git a/src/AMD/Source/amd_info.c b/src/AMD/Source/amd_info.c
new file mode 100644
index 0000000..47e6dff
--- /dev/null
+++ b/src/AMD/Source/amd_info.c
@@ -0,0 +1,119 @@
+/* ========================================================================= */
+/* === AMD_info ============================================================ */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable.  Prints the output statistics for AMD.  See amd.h
+ * for details.  If the Info array is not present, nothing is printed.
+ */
+
+#include "amd_internal.h"
+
+#define PRI(format,x) { if (x >= 0) { PRINTF ((format, x)) ; }}
+
+GLOBAL void AMD_info
+(
+    double Info [ ]
+)
+{
+    double n, ndiv, nmultsubs_ldl, nmultsubs_lu, lnz, lnzd ;
+
+    PRINTF (("\nAMD version %d.%d.%d, %s, results:\n",
+	AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_SUBSUB_VERSION, AMD_DATE)) ;
+
+    if (!Info)
+    {
+	return ;
+    }
+
+    n = Info [AMD_N] ;
+    ndiv = Info [AMD_NDIV] ;
+    nmultsubs_ldl = Info [AMD_NMULTSUBS_LDL] ;
+    nmultsubs_lu = Info [AMD_NMULTSUBS_LU] ;
+    lnz = Info [AMD_LNZ] ;
+    lnzd = (n >= 0 && lnz >= 0) ? (n + lnz) : (-1) ;
+
+    /* AMD return status */
+    PRINTF (("    status: ")) ;
+    if (Info [AMD_STATUS] == AMD_OK)
+    {
+	PRINTF (("OK\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_OUT_OF_MEMORY)
+    {
+	PRINTF (("out of memory\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_INVALID)
+    {
+	PRINTF (("invalid matrix\n")) ;
+    }
+    else if (Info [AMD_STATUS] == AMD_OK_BUT_JUMBLED)
+    {
+	PRINTF (("OK, but jumbled\n")) ;
+    }
+    else
+    {
+	PRINTF (("unknown\n")) ;
+    }
+
+    /* statistics about the input matrix */
+    PRI ("    n, dimension of A:                                  %.20g\n", n);
+    PRI ("    nz, number of nonzeros in A:                        %.20g\n",
+	Info [AMD_NZ]) ;
+    PRI ("    symmetry of A:                                      %.4f\n",
+	Info [AMD_SYMMETRY]) ;
+    PRI ("    number of nonzeros on diagonal:                     %.20g\n",
+	Info [AMD_NZDIAG]) ;
+    PRI ("    nonzeros in pattern of A+A' (excl. diagonal):       %.20g\n",
+	Info [AMD_NZ_A_PLUS_AT]) ;
+    PRI ("    # dense rows/columns of A+A':                       %.20g\n",
+	Info [AMD_NDENSE]) ;
+
+    /* statistics about AMD's behavior  */
+    PRI ("    memory used, in bytes:                              %.20g\n",
+	Info [AMD_MEMORY]) ;
+    PRI ("    # of memory compactions:                            %.20g\n",
+	Info [AMD_NCMPA]) ;
+
+    /* statistics about the ordering quality */
+    PRINTF (("\n"
+	"    The following approximate statistics are for a subsequent\n"
+	"    factorization of A(P,P) + A(P,P)'.  They are slight upper\n"
+	"    bounds if there are no dense rows/columns in A+A', and become\n"
+	"    looser if dense rows/columns exist.\n\n")) ;
+
+    PRI ("    nonzeros in L (excluding diagonal):                 %.20g\n",
+	lnz) ;
+    PRI ("    nonzeros in L (including diagonal):                 %.20g\n",
+	lnzd) ;
+    PRI ("    # divide operations for LDL' or LU:                 %.20g\n",
+	ndiv) ;
+    PRI ("    # multiply-subtract operations for LDL':            %.20g\n",
+	nmultsubs_ldl) ;
+    PRI ("    # multiply-subtract operations for LU:              %.20g\n",
+	nmultsubs_lu) ;
+    PRI ("    max nz. in any column of L (incl. diagonal):        %.20g\n",
+	Info [AMD_DMAX]) ;
+
+    /* total flop counts for various factorizations */
+
+    if (n >= 0 && ndiv >= 0 && nmultsubs_ldl >= 0 && nmultsubs_lu >= 0)
+    {
+	PRINTF (("\n"
+	"    chol flop count for real A, sqrt counted as 1 flop: %.20g\n"
+	"    LDL' flop count for real A:                         %.20g\n"
+	"    LDL' flop count for complex A:                      %.20g\n"
+	"    LU flop count for real A (with no pivoting):        %.20g\n"
+	"    LU flop count for complex A (with no pivoting):     %.20g\n\n",
+	n + ndiv + 2*nmultsubs_ldl,
+	    ndiv + 2*nmultsubs_ldl,
+	  9*ndiv + 8*nmultsubs_ldl,
+	    ndiv + 2*nmultsubs_lu,
+	  9*ndiv + 8*nmultsubs_lu)) ;
+    }
+}
diff --git a/src/AMD/Source/amd_order.c b/src/AMD/Source/amd_order.c
new file mode 100644
index 0000000..7ab6db7
--- /dev/null
+++ b/src/AMD/Source/amd_order.c
@@ -0,0 +1,199 @@
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* User-callable AMD minimum degree ordering routine.  See amd.h for
+ * documentation.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_order =========================================================== */
+/* ========================================================================= */
+
+GLOBAL Int AMD_order
+(
+    Int n,
+    const Int Ap [ ],
+    const Int Ai [ ],
+    Int P [ ],
+    double Control [ ],
+    double Info [ ]
+)
+{
+    Int *Len, *S, nz, i, *Pinv, info, status, *Rp, *Ri, *Cp, *Ci, ok ;
+    size_t nzaat, slen ;
+    double mem = 0 ;
+
+#ifndef NDEBUG
+    AMD_debug_init ("amd") ;
+#endif
+
+    /* clear the Info array, if it exists */
+    info = Info != (double *) NULL ;
+    if (info)
+    {
+	for (i = 0 ; i < AMD_INFO ; i++)
+	{
+	    Info [i] = EMPTY ;
+	}
+	Info [AMD_N] = n ;
+	Info [AMD_STATUS] = AMD_OK ;
+    }
+
+    /* make sure inputs exist and n is >= 0 */
+    if (Ai == (Int *) NULL || Ap == (Int *) NULL || P == (Int *) NULL || n < 0)
+    {
+	if (info) Info [AMD_STATUS] = AMD_INVALID ;
+	return (AMD_INVALID) ;	    /* arguments are invalid */
+    }
+
+    if (n == 0)
+    {
+	return (AMD_OK) ;	    /* n is 0 so there's nothing to do */
+    }
+
+    nz = Ap [n] ;
+    if (info)
+    {
+	Info [AMD_NZ] = nz ;
+    }
+    if (nz < 0)
+    {
+	if (info) Info [AMD_STATUS] = AMD_INVALID ;
+	return (AMD_INVALID) ;
+    }
+
+    /* check if n or nz will cause size_t overflow */
+    if (((size_t) n) >= SIZE_T_MAX / sizeof (Int)
+     || ((size_t) nz) >= SIZE_T_MAX / sizeof (Int))
+    {
+	if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	return (AMD_OUT_OF_MEMORY) ;	    /* problem too large */
+    }
+
+    /* check the input matrix:	AMD_OK, AMD_INVALID, or AMD_OK_BUT_JUMBLED */
+    status = AMD_valid (n, n, Ap, Ai) ;
+
+    if (status == AMD_INVALID)
+    {
+	if (info) Info [AMD_STATUS] = AMD_INVALID ;
+	return (AMD_INVALID) ;	    /* matrix is invalid */
+    }
+
+    /* allocate two size-n integer workspaces */
+    Len = amd_malloc (n * sizeof (Int)) ;
+    Pinv = amd_malloc (n * sizeof (Int)) ;
+    mem += n ;
+    mem += n ;
+    if (!Len || !Pinv)
+    {
+	/* :: out of memory :: */
+	amd_free (Len) ;
+	amd_free (Pinv) ;
+	if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	return (AMD_OUT_OF_MEMORY) ;
+    }
+
+    if (status == AMD_OK_BUT_JUMBLED)
+    {
+	/* sort the input matrix and remove duplicate entries */
+	AMD_DEBUG1 (("Matrix is jumbled\n")) ;
+	Rp = amd_malloc ((n+1) * sizeof (Int)) ;
+	Ri = amd_malloc (MAX (nz,1) * sizeof (Int)) ;
+	mem += (n+1) ;
+	mem += MAX (nz,1) ;
+	if (!Rp || !Ri)
+	{
+	    /* :: out of memory :: */
+	    amd_free (Rp) ;
+	    amd_free (Ri) ;
+	    amd_free (Len) ;
+	    amd_free (Pinv) ;
+	    if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	    return (AMD_OUT_OF_MEMORY) ;
+	}
+	/* use Len and Pinv as workspace to create R = A' */
+	AMD_preprocess (n, Ap, Ai, Rp, Ri, Len, Pinv) ;
+	Cp = Rp ;
+	Ci = Ri ;
+    }
+    else
+    {
+	/* order the input matrix as-is.  No need to compute R = A' first */
+	Rp = NULL ;
+	Ri = NULL ;
+	Cp = (Int *) Ap ;
+	Ci = (Int *) Ai ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* determine the symmetry and count off-diagonal nonzeros in A+A' */
+    /* --------------------------------------------------------------------- */
+
+    nzaat = AMD_aat (n, Cp, Ci, Len, P, Info) ;
+    AMD_DEBUG1 (("nzaat: %g\n", (double) nzaat)) ;
+    ASSERT ((MAX (nz-n, 0) <= nzaat) && (nzaat <= 2 * (size_t) nz)) ;
+
+    /* --------------------------------------------------------------------- */
+    /* allocate workspace for matrix, elbow room, and 6 size-n vectors */
+    /* --------------------------------------------------------------------- */
+
+    S = NULL ;
+    slen = nzaat ;			/* space for matrix */
+    ok = ((slen + nzaat/5) >= slen) ;	/* check for size_t overflow */
+    slen += nzaat/5 ;			/* add elbow room */
+    for (i = 0 ; ok && i < 7 ; i++)
+    {
+	ok = ((slen + n) > slen) ;	/* check for size_t overflow */
+	slen += n ;			/* size-n elbow room, 6 size-n work */
+    }
+    mem += slen ;
+    ok = ok && (slen < SIZE_T_MAX / sizeof (Int)) ; /* check for overflow */
+    ok = ok && (slen < Int_MAX) ;	/* S[i] for Int i must be OK */
+    if (ok)
+    {
+	S = amd_malloc (slen * sizeof (Int)) ;
+    }
+    AMD_DEBUG1 (("slen %g\n", (double) slen)) ;
+    if (!S)
+    {
+	/* :: out of memory :: (or problem too large) */
+	amd_free (Rp) ;
+	amd_free (Ri) ;
+	amd_free (Len) ;
+	amd_free (Pinv) ;
+	if (info) Info [AMD_STATUS] = AMD_OUT_OF_MEMORY ;
+	return (AMD_OUT_OF_MEMORY) ;
+    }
+    if (info)
+    {
+	/* memory usage, in bytes. */
+	Info [AMD_MEMORY] = mem * sizeof (Int) ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* order the matrix */
+    /* --------------------------------------------------------------------- */
+
+    AMD_1 (n, Cp, Ci, P, Pinv, Len, slen, S, Control, Info) ;
+
+    /* --------------------------------------------------------------------- */
+    /* free the workspace */
+    /* --------------------------------------------------------------------- */
+
+    amd_free (Rp) ;
+    amd_free (Ri) ;
+    amd_free (Len) ;
+    amd_free (Pinv) ;
+    amd_free (S) ;
+    if (info) Info [AMD_STATUS] = status ;
+    return (status) ;	    /* successful ordering */
+}
diff --git a/src/AMD/Source/amd_post_tree.c b/src/AMD/Source/amd_post_tree.c
new file mode 100644
index 0000000..516c95c
--- /dev/null
+++ b/src/AMD/Source/amd_post_tree.c
@@ -0,0 +1,120 @@
+/* ========================================================================= */
+/* === AMD_post_tree ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* Post-ordering of a supernodal elimination tree.  */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_post_tree
+(
+    Int root,			/* root of the tree */
+    Int k,			/* start numbering at k */
+    Int Child [ ],		/* input argument of size nn, undefined on
+				 * output.  Child [i] is the head of a link
+				 * list of all nodes that are children of node
+				 * i in the tree. */
+    const Int Sibling [ ],	/* input argument of size nn, not modified.
+				 * If f is a node in the link list of the
+				 * children of node i, then Sibling [f] is the
+				 * next child of node i.
+				 */
+    Int Order [ ],		/* output order, of size nn.  Order [i] = k
+				 * if node i is the kth node of the reordered
+				 * tree. */
+    Int Stack [ ]		/* workspace of size nn */
+#ifndef NDEBUG
+    , Int nn			/* nodes are in the range 0..nn-1. */
+#endif
+)
+{
+    Int f, head, h, i ;
+
+#if 0
+    /* --------------------------------------------------------------------- */
+    /* recursive version (Stack [ ] is not used): */
+    /* --------------------------------------------------------------------- */
+
+    /* this is simple, but can caouse stack overflow if nn is large */
+    i = root ;
+    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+    {
+	k = AMD_post_tree (f, k, Child, Sibling, Order, Stack, nn) ;
+    }
+    Order [i] = k++ ;
+    return (k) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* non-recursive version, using an explicit stack */
+    /* --------------------------------------------------------------------- */
+
+    /* push root on the stack */
+    head = 0 ;
+    Stack [0] = root ;
+
+    while (head >= 0)
+    {
+	/* get head of stack */
+	ASSERT (head < nn) ;
+	i = Stack [head] ;
+	AMD_DEBUG1 (("head of stack "ID" \n", i)) ;
+	ASSERT (i >= 0 && i < nn) ;
+
+	if (Child [i] != EMPTY)
+	{
+	    /* the children of i are not yet ordered */
+	    /* push each child onto the stack in reverse order */
+	    /* so that small ones at the head of the list get popped first */
+	    /* and the biggest one at the end of the list gets popped last */
+	    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+	    {
+		head++ ;
+		ASSERT (head < nn) ;
+		ASSERT (f >= 0 && f < nn) ;
+	    }
+	    h = head ;
+	    ASSERT (head < nn) ;
+	    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+	    {
+		ASSERT (h > 0) ;
+		Stack [h--] = f ;
+		AMD_DEBUG1 (("push "ID" on stack\n", f)) ;
+		ASSERT (f >= 0 && f < nn) ;
+	    }
+	    ASSERT (Stack [h] == i) ;
+
+	    /* delete child list so that i gets ordered next time we see it */
+	    Child [i] = EMPTY ;
+	}
+	else
+	{
+	    /* the children of i (if there were any) are already ordered */
+	    /* remove i from the stack and order it.  Front i is kth front */
+	    head-- ;
+	    AMD_DEBUG1 (("pop "ID" order "ID"\n", i, k)) ;
+	    Order [i] = k++ ;
+	    ASSERT (k <= nn) ;
+	}
+
+#ifndef NDEBUG
+	AMD_DEBUG1 (("\nStack:")) ;
+	for (h = head ; h >= 0 ; h--)
+	{
+	    Int j = Stack [h] ;
+	    AMD_DEBUG1 ((" "ID, j)) ;
+	    ASSERT (j >= 0 && j < nn) ;
+	}
+	AMD_DEBUG1 (("\n\n")) ;
+	ASSERT (head < nn) ;
+#endif
+
+    }
+    return (k) ;
+}
diff --git a/src/AMD/Source/amd_postorder.c b/src/AMD/Source/amd_postorder.c
new file mode 100644
index 0000000..e5aea7b
--- /dev/null
+++ b/src/AMD/Source/amd_postorder.c
@@ -0,0 +1,206 @@
+/* ========================================================================= */
+/* === AMD_postorder ======================================================= */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* Perform a postordering (via depth-first search) of an assembly tree. */
+
+#include "amd_internal.h"
+
+GLOBAL void AMD_postorder
+(
+    /* inputs, not modified on output: */
+    Int nn,		/* nodes are in the range 0..nn-1 */
+    Int Parent [ ],	/* Parent [j] is the parent of j, or EMPTY if root */
+    Int Nv [ ],		/* Nv [j] > 0 number of pivots represented by node j,
+			 * or zero if j is not a node. */
+    Int Fsize [ ],	/* Fsize [j]: size of node j */
+
+    /* output, not defined on input: */
+    Int Order [ ],	/* output post-order */
+
+    /* workspaces of size nn: */
+    Int Child [ ],
+    Int Sibling [ ],
+    Int Stack [ ]
+)
+{
+    Int i, j, k, parent, frsize, f, fprev, maxfrsize, bigfprev, bigf, fnext ;
+
+    for (j = 0 ; j < nn ; j++)
+    {
+	Child [j] = EMPTY ;
+	Sibling [j] = EMPTY ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* place the children in link lists - bigger elements tend to be last */
+    /* --------------------------------------------------------------------- */
+
+    for (j = nn-1 ; j >= 0 ; j--)
+    {
+	if (Nv [j] > 0)
+	{
+	    /* this is an element */
+	    parent = Parent [j] ;
+	    if (parent != EMPTY)
+	    {
+		/* place the element in link list of the children its parent */
+		/* bigger elements will tend to be at the end of the list */
+		Sibling [j] = Child [parent] ;
+		Child [parent] = j ;
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    {
+	Int nels, ff, nchild ;
+	AMD_DEBUG1 (("\n\n================================ AMD_postorder:\n"));
+	nels = 0 ;
+	for (j = 0 ; j < nn ; j++)
+	{
+	    if (Nv [j] > 0)
+	    {
+		AMD_DEBUG1 (( ""ID" :  nels "ID" npiv "ID" size "ID
+		    " parent "ID" maxfr "ID"\n", j, nels,
+		    Nv [j], Fsize [j], Parent [j], Fsize [j])) ;
+		/* this is an element */
+		/* dump the link list of children */
+		nchild = 0 ;
+		AMD_DEBUG1 (("    Children: ")) ;
+		for (ff = Child [j] ; ff != EMPTY ; ff = Sibling [ff])
+		{
+		    AMD_DEBUG1 ((ID" ", ff)) ;
+		    ASSERT (Parent [ff] == j) ;
+		    nchild++ ;
+		    ASSERT (nchild < nn) ;
+		}
+		AMD_DEBUG1 (("\n")) ;
+		parent = Parent [j] ;
+		if (parent != EMPTY)
+		{
+		    ASSERT (Nv [parent] > 0) ;
+		}
+		nels++ ;
+	    }
+	}
+    }
+    AMD_DEBUG1 (("\n\nGo through the children of each node, and put\n"
+		 "the biggest child last in each list:\n")) ;
+#endif
+
+    /* --------------------------------------------------------------------- */
+    /* place the largest child last in the list of children for each node */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nn ; i++)
+    {
+	if (Nv [i] > 0 && Child [i] != EMPTY)
+	{
+
+#ifndef NDEBUG
+	    Int nchild ;
+	    AMD_DEBUG1 (("Before partial sort, element "ID"\n", i)) ;
+	    nchild = 0 ;
+	    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+	    {
+		ASSERT (f >= 0 && f < nn) ;
+		AMD_DEBUG1 (("      f: "ID"  size: "ID"\n", f, Fsize [f])) ;
+		nchild++ ;
+		ASSERT (nchild <= nn) ;
+	    }
+#endif
+
+	    /* find the biggest element in the child list */
+	    fprev = EMPTY ;
+	    maxfrsize = EMPTY ;
+	    bigfprev = EMPTY ;
+	    bigf = EMPTY ;
+	    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+	    {
+		ASSERT (f >= 0 && f < nn) ;
+		frsize = Fsize [f] ;
+		if (frsize >= maxfrsize)
+		{
+		    /* this is the biggest seen so far */
+		    maxfrsize = frsize ;
+		    bigfprev = fprev ;
+		    bigf = f ;
+		}
+		fprev = f ;
+	    }
+	    ASSERT (bigf != EMPTY) ;
+
+	    fnext = Sibling [bigf] ;
+
+	    AMD_DEBUG1 (("bigf "ID" maxfrsize "ID" bigfprev "ID" fnext "ID
+		" fprev " ID"\n", bigf, maxfrsize, bigfprev, fnext, fprev)) ;
+
+	    if (fnext != EMPTY)
+	    {
+		/* if fnext is EMPTY then bigf is already at the end of list */
+
+		if (bigfprev == EMPTY)
+		{
+		    /* delete bigf from the element of the list */
+		    Child [i] = fnext ;
+		}
+		else
+		{
+		    /* delete bigf from the middle of the list */
+		    Sibling [bigfprev] = fnext ;
+		}
+
+		/* put bigf at the end of the list */
+		Sibling [bigf] = EMPTY ;
+		ASSERT (Child [i] != EMPTY) ;
+		ASSERT (fprev != bigf) ;
+		ASSERT (fprev != EMPTY) ;
+		Sibling [fprev] = bigf ;
+	    }
+
+#ifndef NDEBUG
+	    AMD_DEBUG1 (("After partial sort, element "ID"\n", i)) ;
+	    for (f = Child [i] ; f != EMPTY ; f = Sibling [f])
+	    {
+		ASSERT (f >= 0 && f < nn) ;
+		AMD_DEBUG1 (("        "ID"  "ID"\n", f, Fsize [f])) ;
+		ASSERT (Nv [f] > 0) ;
+		nchild-- ;
+	    }
+	    ASSERT (nchild == 0) ;
+#endif
+
+	}
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* postorder the assembly tree */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nn ; i++)
+    {
+	Order [i] = EMPTY ;
+    }
+
+    k = 0 ;
+
+    for (i = 0 ; i < nn ; i++)
+    {
+	if (Parent [i] == EMPTY && Nv [i] > 0)
+	{
+	    AMD_DEBUG1 (("Root of assembly tree "ID"\n", i)) ;
+	    k = AMD_post_tree (i, k, Child, Sibling, Order, Stack
+#ifndef NDEBUG
+		, nn
+#endif
+		) ;
+	}
+    }
+}
diff --git a/src/AMD/Source/amd_preprocess.c b/src/AMD/Source/amd_preprocess.c
new file mode 100644
index 0000000..a8139c3
--- /dev/null
+++ b/src/AMD/Source/amd_preprocess.c
@@ -0,0 +1,118 @@
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* Sorts, removes duplicate entries, and transposes from the nonzero pattern of
+ * a column-form matrix A, to obtain the matrix R.  The input matrix can have
+ * duplicate entries and/or unsorted columns (AMD_valid (n,Ap,Ai) must not be
+ * AMD_INVALID).
+ *
+ * This input condition is NOT checked.  This routine is not user-callable.
+ */
+
+#include "amd_internal.h"
+
+/* ========================================================================= */
+/* === AMD_preprocess ====================================================== */
+/* ========================================================================= */
+
+/* AMD_preprocess does not check its input for errors or allocate workspace.
+ * On input, the condition (AMD_valid (n,n,Ap,Ai) != AMD_INVALID) must hold.
+ */
+
+GLOBAL void AMD_preprocess
+(
+    Int n,		/* input matrix: A is n-by-n */
+    const Int Ap [ ],	/* size n+1 */
+    const Int Ai [ ],	/* size nz = Ap [n] */
+
+    /* output matrix R: */
+    Int Rp [ ],		/* size n+1 */
+    Int Ri [ ],		/* size nz (or less, if duplicates present) */
+
+    Int W [ ],		/* workspace of size n */
+    Int Flag [ ]	/* workspace of size n */
+)
+{
+
+    /* --------------------------------------------------------------------- */
+    /* local variables */
+    /* --------------------------------------------------------------------- */
+
+    Int i, j, p, p2 ;
+
+    ASSERT (AMD_valid (n, n, Ap, Ai) != AMD_INVALID) ;
+
+    /* --------------------------------------------------------------------- */
+    /* count the entries in each row of A (excluding duplicates) */
+    /* --------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	W [i] = 0 ;		/* # of nonzeros in row i (excl duplicates) */
+	Flag [i] = EMPTY ;	/* Flag [i] = j if i appears in column j */
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	p2 = Ap [j+1] ;
+	for (p = Ap [j] ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    if (Flag [i] != j)
+	    {
+		/* row index i has not yet appeared in column j */
+		W [i]++ ;	    /* one more entry in row i */
+		Flag [i] = j ;	    /* flag row index i as appearing in col j*/
+	    }
+	}
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* compute the row pointers for R */
+    /* --------------------------------------------------------------------- */
+
+    Rp [0] = 0 ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Rp [i+1] = Rp [i] + W [i] ;
+    }
+    for (i = 0 ; i < n ; i++)
+    {
+	W [i] = Rp [i] ;
+	Flag [i] = EMPTY ;
+    }
+
+    /* --------------------------------------------------------------------- */
+    /* construct the row form matrix R */
+    /* --------------------------------------------------------------------- */
+
+    /* R = row form of pattern of A */
+    for (j = 0 ; j < n ; j++)
+    {
+	p2 = Ap [j+1] ;
+	for (p = Ap [j] ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    if (Flag [i] != j)
+	    {
+		/* row index i has not yet appeared in column j */
+		Ri [W [i]++] = j ;  /* put col j in row i */
+		Flag [i] = j ;	    /* flag row index i as appearing in col j*/
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    ASSERT (AMD_valid (n, n, Rp, Ri) == AMD_OK) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	ASSERT (W [j] == Rp [j+1]) ;
+    }
+#endif
+}
diff --git a/src/AMD/Source/amd_valid.c b/src/AMD/Source/amd_valid.c
new file mode 100644
index 0000000..609abca
--- /dev/null
+++ b/src/AMD/Source/amd_valid.c
@@ -0,0 +1,92 @@
+/* ========================================================================= */
+/* === AMD_valid =========================================================== */
+/* ========================================================================= */
+
+/* ------------------------------------------------------------------------- */
+/* AMD, Copyright (c) Timothy A. Davis,					     */
+/* Patrick R. Amestoy, and Iain S. Duff.  See ../README.txt for License.     */
+/* email: DrTimothyAldenDavis at gmail.com                                      */
+/* ------------------------------------------------------------------------- */
+
+/* Check if a column-form matrix is valid or not.  The matrix A is
+ * n_row-by-n_col.  The row indices of entries in column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1].  Required conditions are:
+ *
+ *	n_row >= 0
+ *	n_col >= 0
+ *	nz = Ap [n_col] >= 0	    number of entries in the matrix
+ *	Ap [0] == 0
+ *	Ap [j] <= Ap [j+1] for all j in the range 0 to n_col.
+ *      Ai [0 ... nz-1] must be in the range 0 to n_row-1.
+ *
+ * If any of the above conditions hold, AMD_INVALID is returned.  If the
+ * following condition holds, AMD_OK_BUT_JUMBLED is returned (a warning,
+ * not an error):
+ *
+ *	row indices in Ai [Ap [j] ... Ap [j+1]-1] are not sorted in ascending
+ *	    order, and/or duplicate entries exist.
+ *
+ * Otherwise, AMD_OK is returned.
+ *
+ * In v1.2 and earlier, this function returned TRUE if the matrix was valid
+ * (now returns AMD_OK), or FALSE otherwise (now returns AMD_INVALID or
+ * AMD_OK_BUT_JUMBLED).
+ */
+
+#include "amd_internal.h"
+
+GLOBAL Int AMD_valid
+(
+    /* inputs, not modified on output: */
+    Int n_row,		/* A is n_row-by-n_col */
+    Int n_col,
+    const Int Ap [ ],	/* column pointers of A, of size n_col+1 */
+    const Int Ai [ ]	/* row indices of A, of size nz = Ap [n_col] */
+)
+{
+    Int nz, j, p1, p2, ilast, i, p, result = AMD_OK ;
+
+    if (n_row < 0 || n_col < 0 || Ap == NULL || Ai == NULL)
+    {
+	return (AMD_INVALID) ;
+    }
+    nz = Ap [n_col] ;
+    if (Ap [0] != 0 || nz < 0)
+    {
+	/* column pointers must start at Ap [0] = 0, and Ap [n] must be >= 0 */
+	AMD_DEBUG0 (("column 0 pointer bad or nz < 0\n")) ;
+	return (AMD_INVALID) ;
+    }
+    for (j = 0 ; j < n_col ; j++)
+    {
+	p1 = Ap [j] ;
+	p2 = Ap [j+1] ;
+	AMD_DEBUG2 (("\nColumn: "ID" p1: "ID" p2: "ID"\n", j, p1, p2)) ;
+	if (p1 > p2)
+	{
+	    /* column pointers must be ascending */
+	    AMD_DEBUG0 (("column "ID" pointer bad\n", j)) ;
+	    return (AMD_INVALID) ;
+	}
+	ilast = EMPTY ;
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    i = Ai [p] ;
+	    AMD_DEBUG3 (("row: "ID"\n", i)) ;
+	    if (i < 0 || i >= n_row)
+	    {
+		/* row index out of range */
+		AMD_DEBUG0 (("index out of range, col "ID" row "ID"\n", j, i));
+		return (AMD_INVALID) ;
+	    }
+	    if (i <= ilast)
+	    {
+		/* row index unsorted, or duplicate entry present */
+		AMD_DEBUG1 (("index unsorted/dupl col "ID" row "ID"\n", j, i));
+		result = AMD_OK_BUT_JUMBLED ;
+	    }
+	    ilast = i ;
+	}
+    }
+    return (result) ;
+}
diff --git a/src/AMD/Source/amdbar.f b/src/AMD/Source/amdbar.f
new file mode 100644
index 0000000..1384392
--- /dev/null
+++ b/src/AMD/Source/amdbar.f
@@ -0,0 +1,1206 @@
+C-----------------------------------------------------------------------
+C AMDBAR:  approximate minimum degree, without aggressive absorption
+C-----------------------------------------------------------------------
+
+        SUBROUTINE AMDBAR
+     $          (N, PE, IW, LEN, IWLEN, PFREE, NV, NEXT,
+     $          LAST, HEAD, ELEN, DEGREE, NCMPA, W)
+
+        INTEGER N, IWLEN, PFREE, NCMPA, IW (IWLEN), PE (N),
+     $          DEGREE (N), NV (N), NEXT (N), LAST (N), HEAD (N),
+     $          ELEN (N), W (N), LEN (N)
+
+C Given a representation of the nonzero pattern of a symmetric matrix,
+C       A, (excluding the diagonal) perform an approximate minimum
+C       (UMFPACK/MA38-style) degree ordering to compute a pivot order
+C       such that the introduction of nonzeros (fill-in) in the Cholesky
+C       factors A = LL^T are kept low.  At each step, the pivot
+C       selected is the one with the minimum UMFPACK/MA38-style
+C       upper-bound on the external degree.
+C
+C       This routine does not do aggresive absorption (as done by AMD).
+
+C **********************************************************************
+C ***** CAUTION:  ARGUMENTS ARE NOT CHECKED FOR ERRORS ON INPUT.  ******
+C **********************************************************************
+
+C       References:
+C
+C       [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
+C           multifrontal method for sparse LU factorization", SIAM J.
+C           Matrix Analysis and Applications, vol. 18, no. 1, pp.
+C           140-158.  Discusses UMFPACK / MA38, which first introduced
+C           the approximate minimum degree used by this routine.
+C
+C       [2] Patrick Amestoy, Timothy A. Davis, and Iain S. Duff, "An
+C           approximate degree ordering algorithm," SIAM J. Matrix
+C           Analysis and Applications, vol. 17, no. 4, pp. 886-905,
+C           1996.  Discusses AMD, AMDBAR, and MC47B.
+C
+C       [3] Alan George and Joseph Liu, "The evolution of the minimum
+C           degree ordering algorithm," SIAM Review, vol. 31, no. 1,
+C           pp. 1-19, 1989.  We list below the features mentioned in
+C           that paper that this code includes:
+C
+C       mass elimination:
+C               Yes.  MA27 relied on supervariable detection for mass
+C               elimination.
+C       indistinguishable nodes:
+C               Yes (we call these "supervariables").  This was also in
+C               the MA27 code - although we modified the method of
+C               detecting them (the previous hash was the true degree,
+C               which we no longer keep track of).  A supervariable is
+C               a set of rows with identical nonzero pattern.  All
+C               variables in a supervariable are eliminated together.
+C               Each supervariable has as its numerical name that of
+C               one of its variables (its principal variable).
+C       quotient graph representation:
+C               Yes.  We use the term "element" for the cliques formed
+C               during elimination.  This was also in the MA27 code.
+C               The algorithm can operate in place, but it will work
+C               more efficiently if given some "elbow room."
+C       element absorption:
+C               Yes.  This was also in the MA27 code.
+C       external degree:
+C               Yes.  The MA27 code was based on the true degree.
+C       incomplete degree update and multiple elimination:
+C               No.  This was not in MA27, either.  Our method of
+C               degree update within MC47B/BD is element-based, not
+C               variable-based.  It is thus not well-suited for use
+C               with incomplete degree update or multiple elimination.
+
+C-----------------------------------------------------------------------
+C Authors, and Copyright (C) 1995 by:
+C       Timothy A. Davis, Patrick Amestoy, Iain S. Duff, & John K. Reid.
+C
+C Acknowledgements:
+C       This work (and the UMFPACK package) was supported by the
+C       National Science Foundation (ASC-9111263 and DMS-9223088).
+C       The UMFPACK/MA38 approximate degree update algorithm, the
+C       unsymmetric analog which forms the basis of MC47B/BD, was
+C       developed while Tim Davis was supported by CERFACS (Toulouse,
+C       France) in a post-doctoral position.
+C
+C Date:  September, 1995
+C-----------------------------------------------------------------------
+
+C-----------------------------------------------------------------------
+C INPUT ARGUMENTS (unaltered):
+C-----------------------------------------------------------------------
+
+C n:    The matrix order.
+C
+C       Restriction:  1 .le. n .lt. (iovflo/2)-2, where iovflo is
+C       the largest positive integer that your computer can represent.
+
+C iwlen:        The length of iw (1..iwlen).  On input, the matrix is
+C       stored in iw (1..pfree-1).  However, iw (1..iwlen) should be
+C       slightly larger than what is required to hold the matrix, at
+C       least iwlen .ge. pfree + n is recommended.  Otherwise,
+C       excessive compressions will take place.
+C       *** We do not recommend running this algorithm with ***
+C       ***      iwlen .lt. pfree + n.                      ***
+C       *** Better performance will be obtained if          ***
+C       ***      iwlen .ge. pfree + n                       ***
+C       *** or better yet                                   ***
+C       ***      iwlen .gt. 1.2 * pfree                     ***
+C       *** (where pfree is its value on input).            ***
+C       The algorithm will not run at all if iwlen .lt. pfree-1.
+C
+C       Restriction: iwlen .ge. pfree-1
+
+C-----------------------------------------------------------------------
+C INPUT/OUPUT ARGUMENTS:
+C-----------------------------------------------------------------------
+
+C pe:   On input, pe (i) is the index in iw of the start of row i, or
+C       zero if row i has no off-diagonal non-zeros.
+C
+C       During execution, it is used for both supervariables and
+C       elements:
+C
+C       * Principal supervariable i:  index into iw of the
+C               description of supervariable i.  A supervariable
+C               represents one or more rows of the matrix
+C               with identical nonzero pattern.
+C       * Non-principal supervariable i:  if i has been absorbed
+C               into another supervariable j, then pe (i) = -j.
+C               That is, j has the same pattern as i.
+C               Note that j might later be absorbed into another
+C               supervariable j2, in which case pe (i) is still -j,
+C               and pe (j) = -j2.
+C       * Unabsorbed element e:  the index into iw of the description
+C               of element e, if e has not yet been absorbed by a
+C               subsequent element.  Element e is created when
+C               the supervariable of the same name is selected as
+C               the pivot.
+C       * Absorbed element e:  if element e is absorbed into element
+C               e2, then pe (e) = -e2.  This occurs when the pattern of
+C               e (that is, Le) is found to be a subset of the pattern
+C               of e2 (that is, Le2).  If element e is "null" (it has
+C               no nonzeros outside its pivot block), then pe (e) = 0.
+C
+C       On output, pe holds the assembly tree/forest, which implicitly
+C       represents a pivot order with identical fill-in as the actual
+C       order (via a depth-first search of the tree).
+C
+C       On output:
+C       If nv (i) .gt. 0, then i represents a node in the assembly tree,
+C       and the parent of i is -pe (i), or zero if i is a root.
+C       If nv (i) = 0, then (i,-pe (i)) represents an edge in a
+C       subtree, the root of which is a node in the assembly tree.
+
+C pfree:        On input the tail end of the array, iw (pfree..iwlen),
+C       is empty, and the matrix is stored in iw (1..pfree-1).
+C       During execution, additional data is placed in iw, and pfree
+C       is modified so that iw (pfree..iwlen) is always the unused part
+C       of iw.  On output, pfree is set equal to the size of iw that
+C       would have been needed for no compressions to occur.  If
+C       ncmpa is zero, then pfree (on output) is less than or equal to
+C       iwlen, and the space iw (pfree+1 ... iwlen) was not used.
+C       Otherwise, pfree (on output) is greater than iwlen, and all the
+C       memory in iw was used.
+
+C-----------------------------------------------------------------------
+C INPUT/MODIFIED (undefined on output):
+C-----------------------------------------------------------------------
+
+C len:  On input, len (i) holds the number of entries in row i of the
+C       matrix, excluding the diagonal.  The contents of len (1..n)
+C       are undefined on output.
+
+C iw:   On input, iw (1..pfree-1) holds the description of each row i
+C       in the matrix.  The matrix must be symmetric, and both upper
+C       and lower triangular parts must be present.  The diagonal must
+C       not be present.  Row i is held as follows:
+C
+C               len (i):  the length of the row i data structure
+C               iw (pe (i) ... pe (i) + len (i) - 1):
+C                       the list of column indices for nonzeros
+C                       in row i (simple supervariables), excluding
+C                       the diagonal.  All supervariables start with
+C                       one row/column each (supervariable i is just
+C                       row i).
+C               if len (i) is zero on input, then pe (i) is ignored
+C               on input.
+C
+C               Note that the rows need not be in any particular order,
+C               and there may be empty space between the rows.
+C
+C       During execution, the supervariable i experiences fill-in.
+C       This is represented by placing in i a list of the elements
+C       that cause fill-in in supervariable i:
+C
+C               len (i):  the length of supervariable i
+C               iw (pe (i) ... pe (i) + elen (i) - 1):
+C                       the list of elements that contain i.  This list
+C                       is kept short by removing absorbed elements.
+C               iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
+C                       the list of supervariables in i.  This list
+C                       is kept short by removing nonprincipal
+C                       variables, and any entry j that is also
+C                       contained in at least one of the elements
+C                       (j in Le) in the list for i (e in row i).
+C
+C       When supervariable i is selected as pivot, we create an
+C       element e of the same name (e=i):
+C
+C               len (e):  the length of element e
+C               iw (pe (e) ... pe (e) + len (e) - 1):
+C                       the list of supervariables in element e.
+C
+C       An element represents the fill-in that occurs when supervariable
+C       i is selected as pivot (which represents the selection of row i
+C       and all non-principal variables whose principal variable is i).
+C       We use the term Le to denote the set of all supervariables
+C       in element e.  Absorbed supervariables and elements are pruned
+C       from these lists when computationally convenient.
+C
+C       CAUTION:  THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
+C       The contents of iw are undefined on output.
+
+C-----------------------------------------------------------------------
+C OUTPUT (need not be set on input):
+C-----------------------------------------------------------------------
+
+C nv:   During execution, abs (nv (i)) is equal to the number of rows
+C       that are represented by the principal supervariable i.  If i is
+C       a nonprincipal variable, then nv (i) = 0.  Initially,
+C       nv (i) = 1 for all i.  nv (i) .lt. 0 signifies that i is a
+C       principal variable in the pattern Lme of the current pivot
+C       element me.  On output, nv (e) holds the true degree of element
+C       e at the time it was created (including the diagonal part).
+
+C ncmpa:        The number of times iw was compressed.  If this is
+C       excessive, then the execution took longer than what could have
+C       been.  To reduce ncmpa, try increasing iwlen to be 10% or 20%
+C       larger than the value of pfree on input (or at least
+C       iwlen .ge. pfree + n).  The fastest performance will be
+C       obtained when ncmpa is returned as zero.  If iwlen is set to
+C       the value returned by pfree on *output*, then no compressions
+C       will occur.
+
+C elen: See the description of iw above.  At the start of execution,
+C       elen (i) is set to zero.  During execution, elen (i) is the
+C       number of elements in the list for supervariable i.  When e
+C       becomes an element, elen (e) = -nel is set, where nel is the
+C       current step of factorization.  elen (i) = 0 is done when i
+C       becomes nonprincipal.
+C
+C       For variables, elen (i) .ge. 0 holds until just before the
+C       permutation vectors are computed.  For elements,
+C       elen (e) .lt. 0 holds.
+C
+C       On output elen (1..n) holds the inverse permutation (the same
+C       as the 'INVP' argument in Sparspak).  That is, if k = elen (i),
+C       then row i is the kth pivot row.  Row i of A appears as the
+C       (elen(i))-th row in the permuted matrix, PAP^T.
+
+C last: In a degree list, last (i) is the supervariable preceding i,
+C       or zero if i is the head of the list.  In a hash bucket,
+C       last (i) is the hash key for i.  last (head (hash)) is also
+C       used as the head of a hash bucket if head (hash) contains a
+C       degree list (see head, below).
+C
+C       On output, last (1..n) holds the permutation (the same as the
+C       'PERM' argument in Sparspak).  That is, if i = last (k), then
+C       row i is the kth pivot row.  Row last (k) of A is the k-th row
+C       in the permuted matrix, PAP^T.
+
+C-----------------------------------------------------------------------
+C LOCAL (not input or output - used only during execution):
+C-----------------------------------------------------------------------
+
+C degree:       If i is a supervariable, then degree (i) holds the
+C       current approximation of the external degree of row i (an upper
+C       bound).  The external degree is the number of nonzeros in row i,
+C       minus abs (nv (i)) (the diagonal part).  The bound is equal to
+C       the external degree if elen (i) is less than or equal to two.
+C
+C       We also use the term "external degree" for elements e to refer
+C       to |Le \ Lme|.  If e is an element, then degree (e) holds |Le|,
+C       which is the degree of the off-diagonal part of the element e
+C       (not including the diagonal part).
+
+C head: head is used for degree lists.  head (deg) is the first
+C       supervariable in a degree list (all supervariables i in a
+C       degree list deg have the same approximate degree, namely,
+C       deg = degree (i)).  If the list deg is empty then
+C       head (deg) = 0.
+C
+C       During supervariable detection head (hash) also serves as a
+C       pointer to a hash bucket.
+C       If head (hash) .gt. 0, there is a degree list of degree hash.
+C               The hash bucket head pointer is last (head (hash)).
+C       If head (hash) = 0, then the degree list and hash bucket are
+C               both empty.
+C       If head (hash) .lt. 0, then the degree list is empty, and
+C               -head (hash) is the head of the hash bucket.
+C       After supervariable detection is complete, all hash buckets
+C       are empty, and the (last (head (hash)) = 0) condition is
+C       restored for the non-empty degree lists.
+
+C next: next (i) is the supervariable following i in a link list, or
+C       zero if i is the last in the list.  Used for two kinds of
+C       lists:  degree lists and hash buckets (a supervariable can be
+C       in only one kind of list at a time).
+
+C w:    The flag array w determines the status of elements and
+C       variables, and the external degree of elements.
+C
+C       for elements:
+C          if w (e) = 0, then the element e is absorbed
+C          if w (e) .ge. wflg, then w (e) - wflg is the size of
+C               the set |Le \ Lme|, in terms of nonzeros (the
+C               sum of abs (nv (i)) for each principal variable i that
+C               is both in the pattern of element e and NOT in the
+C               pattern of the current pivot element, me).
+C          if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
+C               not yet been seen in the scan of the element lists in
+C               the computation of |Le\Lme| in loop 150 below.
+C
+C       for variables:
+C          during supervariable detection, if w (j) .ne. wflg then j is
+C          not in the pattern of variable i
+C
+C       The w array is initialized by setting w (i) = 1 for all i,
+C       and by setting wflg = 2.  It is reinitialized if wflg becomes
+C       too large (to ensure that wflg+n does not cause integer
+C       overflow).
+
+C-----------------------------------------------------------------------
+C LOCAL INTEGERS:
+C-----------------------------------------------------------------------
+
+        INTEGER DEG, DEGME, DMAX, E, ELENME, ELN, HASH, HMOD, I,
+     $          ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
+     $          LENJ, LN, MAXMEM, ME, MEM, MINDEG, NEL, NEWMEM,
+     $          NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
+
+C deg:          the degree of a variable or element
+C degme:        size, |Lme|, of the current element, me (= degree (me))
+C dext:         external degree, |Le \ Lme|, of some element e
+C dmax:         largest |Le| seen so far
+C e:            an element
+C elenme:       the length, elen (me), of element list of pivotal var.
+C eln:          the length, elen (...), of an element list
+C hash:         the computed value of the hash function
+C hmod:         the hash function is computed modulo hmod = max (1,n-1)
+C i:            a supervariable
+C ilast:        the entry in a link list preceding i
+C inext:        the entry in a link list following i
+C j:            a supervariable
+C jlast:        the entry in a link list preceding j
+C jnext:        the entry in a link list, or path, following j
+C k:            the pivot order of an element or variable
+C knt1:         loop counter used during element construction
+C knt2:         loop counter used during element construction
+C knt3:         loop counter used during compression
+C lenj:         len (j)
+C ln:           length of a supervariable list
+C maxmem:       amount of memory needed for no compressions
+C me:           current supervariable being eliminated, and the
+C                       current element created by eliminating that
+C                       supervariable
+C mem:          memory in use assuming no compressions have occurred
+C mindeg:       current minimum degree
+C nel:          number of pivots selected so far
+C newmem:       amount of new memory needed for current pivot element
+C nleft:        n - nel, the number of nonpivotal rows/columns remaining
+C nvi:          the number of variables in a supervariable i (= nv (i))
+C nvj:          the number of variables in a supervariable j (= nv (j))
+C nvpiv:        number of pivots in current element
+C slenme:       number of variables in variable list of pivotal variable
+C we:           w (e)
+C wflg:         used for flagging the w array.  See description of iw.
+C wnvi:         wflg - nv (i)
+C x:            either a supervariable or an element
+
+C-----------------------------------------------------------------------
+C LOCAL POINTERS:
+C-----------------------------------------------------------------------
+
+        INTEGER P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2, PN, PSRC
+
+C               Any parameter (pe (...) or pfree) or local variable
+C               starting with "p" (for Pointer) is an index into iw,
+C               and all indices into iw use variables starting with
+C               "p."  The only exception to this rule is the iwlen
+C               input argument.
+
+C p:            pointer into lots of things
+C p1:           pe (i) for some variable i (start of element list)
+C p2:           pe (i) + elen (i) -  1 for some var. i (end of el. list)
+C p3:           index of first supervariable in clean list
+C pdst:         destination pointer, for compression
+C pend:         end of memory to compress
+C pj:           pointer into an element or variable
+C pme:          pointer into the current element (pme1...pme2)
+C pme1:         the current element, me, is stored in iw (pme1...pme2)
+C pme2:         the end of the current element
+C pn:           pointer into a "clean" variable, also used to compress
+C psrc:         source pointer, for compression
+
+C-----------------------------------------------------------------------
+C  FUNCTIONS CALLED:
+C-----------------------------------------------------------------------
+
+        INTRINSIC MAX, MIN, MOD
+
+C=======================================================================
+C  INITIALIZATIONS
+C=======================================================================
+
+        WFLG = 2
+        MINDEG = 1
+        NCMPA = 0
+        NEL = 0
+        HMOD = MAX (1, N-1)
+        DMAX = 0
+        MEM = PFREE - 1
+        MAXMEM = MEM
+	ME = 0
+
+        DO 10 I = 1, N
+           LAST (I) = 0
+           HEAD (I) = 0
+           NV (I) = 1
+           W (I) = 1
+           ELEN (I) = 0
+           DEGREE (I) = LEN (I)
+10         CONTINUE
+
+C       ----------------------------------------------------------------
+C       initialize degree lists and eliminate rows with no off-diag. nz.
+C       ----------------------------------------------------------------
+
+        DO 20 I = 1, N
+
+           DEG = DEGREE (I)
+
+           IF (DEG .GT. 0) THEN
+
+C             ----------------------------------------------------------
+C             place i in the degree list corresponding to its degree
+C             ----------------------------------------------------------
+
+              INEXT = HEAD (DEG)
+              IF (INEXT .NE. 0) LAST (INEXT) = I
+              NEXT (I) = INEXT
+              HEAD (DEG) = I
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             we have a variable that can be eliminated at once because
+C             there is no off-diagonal non-zero in its row.
+C             ----------------------------------------------------------
+
+              NEL = NEL + 1
+              ELEN (I) = -NEL
+              PE (I) = 0
+              W (I) = 0
+
+              ENDIF
+
+20         CONTINUE
+
+C=======================================================================
+C  WHILE (selecting pivots) DO
+C=======================================================================
+
+30      CONTINUE
+        IF (NEL .LT. N) THEN
+
+C=======================================================================
+C  GET PIVOT OF MINIMUM DEGREE
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          find next supervariable for elimination
+C          -------------------------------------------------------------
+
+           DO 40 DEG = MINDEG, N
+              ME = HEAD (DEG)
+              IF (ME .GT. 0) GOTO 50
+40            CONTINUE
+50         CONTINUE
+           MINDEG = DEG
+
+C          -------------------------------------------------------------
+C          remove chosen variable from link list
+C          -------------------------------------------------------------
+
+           INEXT = NEXT (ME)
+           IF (INEXT .NE. 0) LAST (INEXT) = 0
+           HEAD (DEG) = INEXT
+
+C          -------------------------------------------------------------
+C          me represents the elimination of pivots nel+1 to nel+nv(me).
+C          place me itself as the first in this set.  It will be moved
+C          to the nel+nv(me) position when the permutation vectors are
+C          computed.
+C          -------------------------------------------------------------
+
+           ELENME = ELEN (ME)
+           ELEN (ME) = - (NEL + 1)
+           NVPIV = NV (ME)
+           NEL = NEL + NVPIV
+
+C=======================================================================
+C  CONSTRUCT NEW ELEMENT
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          At this point, me is the pivotal supervariable.  It will be
+C          converted into the current element.  Scan list of the
+C          pivotal supervariable, me, setting tree pointers and
+C          constructing new list of supervariables for the new element,
+C          me.  p is a pointer to the current position in the old list.
+C          -------------------------------------------------------------
+
+C          flag the variable "me" as being in Lme by negating nv (me)
+           NV (ME) = -NVPIV
+           DEGME = 0
+
+           IF (ELENME .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             construct the new element in place
+C             ----------------------------------------------------------
+
+              PME1 = PE (ME)
+              PME2 = PME1 - 1
+
+              DO 60 P = PME1, PME1 + LEN (ME) - 1
+                 I = IW (P)
+                 NVI = NV (I)
+                 IF (NVI .GT. 0) THEN
+
+C                   ----------------------------------------------------
+C                   i is a principal variable not yet placed in Lme.
+C                   store i in new list
+C                   ----------------------------------------------------
+
+                    DEGME = DEGME + NVI
+C                   flag i as being in Lme by negating nv (i)
+                    NV (I) = -NVI
+                    PME2 = PME2 + 1
+                    IW (PME2) = I
+
+C                   ----------------------------------------------------
+C                   remove variable i from degree list.
+C                   ----------------------------------------------------
+
+                    ILAST = LAST (I)
+                    INEXT = NEXT (I)
+                    IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                    IF (ILAST .NE. 0) THEN
+                       NEXT (ILAST) = INEXT
+                    ELSE
+C                      i is at the head of the degree list
+                       HEAD (DEGREE (I)) = INEXT
+                       ENDIF
+
+                    ENDIF
+60               CONTINUE
+C             this element takes no new memory in iw:
+              NEWMEM = 0
+
+           ELSE
+
+C             ----------------------------------------------------------
+C             construct the new element in empty space, iw (pfree ...)
+C             ----------------------------------------------------------
+
+              P = PE (ME)
+              PME1 = PFREE
+              SLENME = LEN (ME) - ELENME
+
+              DO 120 KNT1 = 1, ELENME + 1
+
+                 IF (KNT1 .GT. ELENME) THEN
+C                   search the supervariables in me.
+                    E = ME
+                    PJ = P
+                    LN = SLENME
+                 ELSE
+C                   search the elements in me.
+                    E = IW (P)
+                    P = P + 1
+                    PJ = PE (E)
+                    LN = LEN (E)
+                    ENDIF
+
+C                -------------------------------------------------------
+C                search for different supervariables and add them to the
+C                new list, compressing when necessary. this loop is
+C                executed once for each element in the list and once for
+C                all the supervariables in the list.
+C                -------------------------------------------------------
+
+                 DO 110 KNT2 = 1, LN
+                    I = IW (PJ)
+                    PJ = PJ + 1
+                    NVI = NV (I)
+                    IF (NVI .GT. 0) THEN
+
+C                      -------------------------------------------------
+C                      compress iw, if necessary
+C                      -------------------------------------------------
+
+                       IF (PFREE .GT. IWLEN) THEN
+C                         prepare for compressing iw by adjusting
+C                         pointers and lengths so that the lists being
+C                         searched in the inner and outer loops contain
+C                         only the remaining entries.
+
+                          PE (ME) = P
+                          LEN (ME) = LEN (ME) - KNT1
+                          IF (LEN (ME) .EQ. 0) THEN
+C                            nothing left of supervariable me
+                             PE (ME) = 0
+                             ENDIF
+                          PE (E) = PJ
+                          LEN (E) = LN - KNT2
+                          IF (LEN (E) .EQ. 0) THEN
+C                            nothing left of element e
+                             PE (E) = 0
+                             ENDIF
+
+                          NCMPA = NCMPA + 1
+C                         store first item in pe
+C                         set first entry to -item
+                          DO 70 J = 1, N
+                             PN = PE (J)
+                             IF (PN .GT. 0) THEN
+                                PE (J) = IW (PN)
+                                IW (PN) = -J
+                                ENDIF
+70                           CONTINUE
+
+C                         psrc/pdst point to source/destination
+                          PDST = 1
+                          PSRC = 1
+                          PEND = PME1 - 1
+
+C                         while loop:
+80                        CONTINUE
+                          IF (PSRC .LE. PEND) THEN
+C                            search for next negative entry
+                             J = -IW (PSRC)
+                             PSRC = PSRC + 1
+                             IF (J .GT. 0) THEN
+                                IW (PDST) = PE (J)
+                                PE (J) = PDST
+                                PDST = PDST + 1
+C                               copy from source to destination
+                                LENJ = LEN (J)
+                                DO 90 KNT3 = 0, LENJ - 2
+                                   IW (PDST + KNT3) = IW (PSRC + KNT3)
+90                                 CONTINUE
+                                PDST = PDST + LENJ - 1
+                                PSRC = PSRC + LENJ - 1
+                                ENDIF
+                             GOTO 80
+                             ENDIF
+
+C                         move the new partially-constructed element
+                          P1 = PDST
+                          DO 100 PSRC = PME1, PFREE - 1
+                             IW (PDST) = IW (PSRC)
+                             PDST = PDST + 1
+100                          CONTINUE
+                          PME1 = P1
+                          PFREE = PDST
+                          PJ = PE (E)
+                          P = PE (ME)
+                          ENDIF
+
+C                      -------------------------------------------------
+C                      i is a principal variable not yet placed in Lme
+C                      store i in new list
+C                      -------------------------------------------------
+
+                       DEGME = DEGME + NVI
+C                      flag i as being in Lme by negating nv (i)
+                       NV (I) = -NVI
+                       IW (PFREE) = I
+                       PFREE = PFREE + 1
+
+C                      -------------------------------------------------
+C                      remove variable i from degree link list
+C                      -------------------------------------------------
+
+                       ILAST = LAST (I)
+                       INEXT = NEXT (I)
+                       IF (INEXT .NE. 0) LAST (INEXT) = ILAST
+                       IF (ILAST .NE. 0) THEN
+                          NEXT (ILAST) = INEXT
+                       ELSE
+C                         i is at the head of the degree list
+                          HEAD (DEGREE (I)) = INEXT
+                          ENDIF
+
+                       ENDIF
+110                 CONTINUE
+
+                 IF (E .NE. ME) THEN
+C                   set tree pointer and flag to indicate element e is
+C                   absorbed into new element me (the parent of e is me)
+                    PE (E) = -ME
+                    W (E) = 0
+                    ENDIF
+120              CONTINUE
+
+              PME2 = PFREE - 1
+C             this element takes newmem new memory in iw (possibly zero)
+              NEWMEM = PFREE - PME1
+              MEM = MEM + NEWMEM
+              MAXMEM = MAX (MAXMEM, MEM)
+              ENDIF
+
+C          -------------------------------------------------------------
+C          me has now been converted into an element in iw (pme1..pme2)
+C          -------------------------------------------------------------
+
+C          degme holds the external degree of new element
+           DEGREE (ME) = DEGME
+           PE (ME) = PME1
+           LEN (ME) = PME2 - PME1 + 1
+
+C          -------------------------------------------------------------
+C          make sure that wflg is not too large.  With the current
+C          value of wflg, wflg+n must not cause integer overflow
+C          -------------------------------------------------------------
+
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 130 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+130              CONTINUE
+              WFLG = 2
+              ENDIF
+
+C=======================================================================
+C  COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 1:  compute the external degrees of previous elements
+C          with respect to the current element.  That is:
+C               (w (e) - wflg) = |Le \ Lme|
+C          for each element e that appears in any supervariable in Lme.
+C          The notation Le refers to the pattern (list of
+C          supervariables) of a previous element e, where e is not yet
+C          absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
+C          The notation Lme refers to the pattern of the current element
+C          (stored in iw (pme1..pme2)).   If (w (e) - wflg) becomes
+C          zero, then the element e will be absorbed in scan 2.
+C          -------------------------------------------------------------
+
+           DO 150 PME = PME1, PME2
+              I = IW (PME)
+              ELN = ELEN (I)
+              IF (ELN .GT. 0) THEN
+C                note that nv (i) has been negated to denote i in Lme:
+                 NVI = -NV (I)
+                 WNVI = WFLG - NVI
+                 DO 140 P = PE (I), PE (I) + ELN - 1
+                    E = IW (P)
+                    WE = W (E)
+                    IF (WE .GE. WFLG) THEN
+C                      unabsorbed element e has been seen in this loop
+                       WE = WE - NVI
+                    ELSE IF (WE .NE. 0) THEN
+C                      e is an unabsorbed element
+C                      this is the first we have seen e in all of Scan 1
+                       WE = DEGREE (E) + WNVI
+                       ENDIF
+                    W (E) = WE
+140                 CONTINUE
+                 ENDIF
+150           CONTINUE
+
+C=======================================================================
+C  DEGREE UPDATE AND ELEMENT ABSORPTION
+C=======================================================================
+
+C          -------------------------------------------------------------
+C          Scan 2:  for each i in Lme, sum up the degree of Lme (which
+C          is degme), plus the sum of the external degrees of each Le
+C          for the elements e appearing within i, plus the
+C          supervariables in i.  Place i in hash list.
+C          -------------------------------------------------------------
+
+           DO 180 PME = PME1, PME2
+              I = IW (PME)
+              P1 = PE (I)
+              P2 = P1 + ELEN (I) - 1
+              PN = P1
+              HASH = 0
+              DEG = 0
+
+C             ----------------------------------------------------------
+C             scan the element list associated with supervariable i
+C             ----------------------------------------------------------
+
+C             UMFPACK/MA38-style approximate degree:
+              DO 160 P = P1, P2
+                 E = IW (P)
+                 WE = W (E)
+                 IF (WE .NE. 0) THEN
+C                   e is an unabsorbed element
+                    DEG = DEG + WE - WFLG
+                    IW (PN) = E
+                    PN = PN + 1
+                    HASH = HASH + E
+                    ENDIF
+160              CONTINUE
+
+C             count the number of elements in i (including me):
+              ELEN (I) = PN - P1 + 1
+
+C             ----------------------------------------------------------
+C             scan the supervariables in the list associated with i
+C             ----------------------------------------------------------
+
+              P3 = PN
+              DO 170 P = P2 + 1, P1 + LEN (I) - 1
+                 J = IW (P)
+                 NVJ = NV (J)
+                 IF (NVJ .GT. 0) THEN
+C                   j is unabsorbed, and not in Lme.
+C                   add to degree and add to new list
+                    DEG = DEG + NVJ
+                    IW (PN) = J
+                    PN = PN + 1
+                    HASH = HASH + J
+                    ENDIF
+170              CONTINUE
+
+C             ----------------------------------------------------------
+C             update the degree and check for mass elimination
+C             ----------------------------------------------------------
+
+              IF (ELEN (I) .EQ. 1 .AND. P3 .EQ. PN) THEN
+
+C                -------------------------------------------------------
+C                mass elimination
+C                -------------------------------------------------------
+
+C                There is nothing left of this node except for an
+C                edge to the current pivot element.  elen (i) is 1,
+C                and there are no variables adjacent to node i.
+C                Absorb i into the current pivot element, me.
+
+                 PE (I) = -ME
+                 NVI = -NV (I)
+                 DEGME = DEGME - NVI
+                 NVPIV = NVPIV + NVI
+                 NEL = NEL + NVI
+                 NV (I) = 0
+                 ELEN (I) = 0
+
+              ELSE
+
+C                -------------------------------------------------------
+C                update the upper-bound degree of i
+C                -------------------------------------------------------
+
+C                the following degree does not yet include the size
+C                of the current element, which is added later:
+                 DEGREE (I) = MIN (DEGREE (I), DEG)
+
+C                -------------------------------------------------------
+C                add me to the list for i
+C                -------------------------------------------------------
+
+C                move first supervariable to end of list
+                 IW (PN) = IW (P3)
+C                move first element to end of element part of list
+                 IW (P3) = IW (P1)
+C                add new element to front of list.
+                 IW (P1) = ME
+C                store the new length of the list in len (i)
+                 LEN (I) = PN - P1 + 1
+
+C                -------------------------------------------------------
+C                place in hash bucket.  Save hash key of i in last (i).
+C                -------------------------------------------------------
+
+                 HASH = MOD (HASH, HMOD) + 1
+                 J = HEAD (HASH)
+                 IF (J .LE. 0) THEN
+C                   the degree list is empty, hash head is -j
+                    NEXT (I) = -J
+                    HEAD (HASH) = -I
+                 ELSE
+C                   degree list is not empty
+C                   use last (head (hash)) as hash head
+                    NEXT (I) = LAST (J)
+                    LAST (J) = I
+                    ENDIF
+                 LAST (I) = HASH
+                 ENDIF
+180           CONTINUE
+
+           DEGREE (ME) = DEGME
+
+C          -------------------------------------------------------------
+C          Clear the counter array, w (...), by incrementing wflg.
+C          -------------------------------------------------------------
+
+           DMAX = MAX (DMAX, DEGME)
+           WFLG = WFLG + DMAX
+
+C          make sure that wflg+n does not cause integer overflow
+           IF (WFLG + N .LE. WFLG) THEN
+              DO 190 X = 1, N
+                 IF (W (X) .NE. 0) W (X) = 1
+190              CONTINUE
+              WFLG = 2
+              ENDIF
+C          at this point, w (1..n) .lt. wflg holds
+
+C=======================================================================
+C  SUPERVARIABLE DETECTION
+C=======================================================================
+
+           DO 250 PME = PME1, PME2
+              I = IW (PME)
+              IF (NV (I) .LT. 0) THEN
+C                i is a principal variable in Lme
+
+C                -------------------------------------------------------
+C                examine all hash buckets with 2 or more variables.  We
+C                do this by examing all unique hash keys for super-
+C                variables in the pattern Lme of the current element, me
+C                -------------------------------------------------------
+
+                 HASH = LAST (I)
+C                let i = head of hash bucket, and empty the hash bucket
+                 J = HEAD (HASH)
+                 IF (J .EQ. 0) GOTO 250
+                 IF (J .LT. 0) THEN
+C                   degree list is empty
+                    I = -J
+                    HEAD (HASH) = 0
+                 ELSE
+C                   degree list is not empty, restore last () of head
+                    I = LAST (J)
+                    LAST (J) = 0
+                    ENDIF
+                 IF (I .EQ. 0) GOTO 250
+
+C                while loop:
+200              CONTINUE
+                 IF (NEXT (I) .NE. 0) THEN
+
+C                   ----------------------------------------------------
+C                   this bucket has one or more variables following i.
+C                   scan all of them to see if i can absorb any entries
+C                   that follow i in hash bucket.  Scatter i into w.
+C                   ----------------------------------------------------
+
+                    LN = LEN (I)
+                    ELN = ELEN (I)
+C                   do not flag the first element in the list (me)
+                    DO 210 P = PE (I) + 1, PE (I) + LN - 1
+                       W (IW (P)) = WFLG
+210                    CONTINUE
+
+C                   ----------------------------------------------------
+C                   scan every other entry j following i in bucket
+C                   ----------------------------------------------------
+
+                    JLAST = I
+                    J = NEXT (I)
+
+C                   while loop:
+220                 CONTINUE
+                    IF (J .NE. 0) THEN
+
+C                      -------------------------------------------------
+C                      check if j and i have identical nonzero pattern
+C                      -------------------------------------------------
+
+                       IF (LEN (J) .NE. LN) THEN
+C                         i and j do not have same size data structure
+                          GOTO 240
+                          ENDIF
+                       IF (ELEN (J) .NE. ELN) THEN
+C                         i and j do not have same number of adjacent el
+                          GOTO 240
+                          ENDIF
+C                      do not flag the first element in the list (me)
+                       DO 230 P = PE (J) + 1, PE (J) + LN - 1
+                          IF (W (IW (P)) .NE. WFLG) THEN
+C                            an entry (iw(p)) is in j but not in i
+                             GOTO 240
+                             ENDIF
+230                       CONTINUE
+
+C                      -------------------------------------------------
+C                      found it!  j can be absorbed into i
+C                      -------------------------------------------------
+
+                       PE (J) = -I
+C                      both nv (i) and nv (j) are negated since they
+C                      are in Lme, and the absolute values of each
+C                      are the number of variables in i and j:
+                       NV (I) = NV (I) + NV (J)
+                       NV (J) = 0
+                       ELEN (J) = 0
+C                      delete j from hash bucket
+                       J = NEXT (J)
+                       NEXT (JLAST) = J
+                       GOTO 220
+
+C                      -------------------------------------------------
+240                    CONTINUE
+C                      j cannot be absorbed into i
+C                      -------------------------------------------------
+
+                       JLAST = J
+                       J = NEXT (J)
+                       GOTO 220
+                       ENDIF
+
+C                   ----------------------------------------------------
+C                   no more variables can be absorbed into i
+C                   go to next i in bucket and clear flag array
+C                   ----------------------------------------------------
+
+                    WFLG = WFLG + 1
+                    I = NEXT (I)
+                    IF (I .NE. 0) GOTO 200
+                    ENDIF
+                 ENDIF
+250           CONTINUE
+
+C=======================================================================
+C  RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
+C=======================================================================
+
+           P = PME1
+           NLEFT = N - NEL
+           DO 260 PME = PME1, PME2
+              I = IW (PME)
+              NVI = -NV (I)
+              IF (NVI .GT. 0) THEN
+C                i is a principal variable in Lme
+C                restore nv (i) to signify that i is principal
+                 NV (I) = NVI
+
+C                -------------------------------------------------------
+C                compute the external degree (add size of current elem)
+C                -------------------------------------------------------
+
+                 DEG = MAX (1, MIN (DEGREE (I) + DEGME-NVI, NLEFT-NVI))
+
+C                -------------------------------------------------------
+C                place the supervariable at the head of the degree list
+C                -------------------------------------------------------
+
+                 INEXT = HEAD (DEG)
+                 IF (INEXT .NE. 0) LAST (INEXT) = I
+                 NEXT (I) = INEXT
+                 LAST (I) = 0
+                 HEAD (DEG) = I
+
+C                -------------------------------------------------------
+C                save the new degree, and find the minimum degree
+C                -------------------------------------------------------
+
+                 MINDEG = MIN (MINDEG, DEG)
+                 DEGREE (I) = DEG
+
+C                -------------------------------------------------------
+C                place the supervariable in the element pattern
+C                -------------------------------------------------------
+
+                 IW (P) = I
+                 P = P + 1
+                 ENDIF
+260           CONTINUE
+
+C=======================================================================
+C  FINALIZE THE NEW ELEMENT
+C=======================================================================
+
+           NV (ME) = NVPIV + DEGME
+C          nv (me) is now the degree of pivot (including diagonal part)
+C          save the length of the list for the new element me
+           LEN (ME) = P - PME1
+           IF (LEN (ME) .EQ. 0) THEN
+C             there is nothing left of the current pivot element
+              PE (ME) = 0
+              W (ME) = 0
+              ENDIF
+           IF (NEWMEM .NE. 0) THEN
+C             element was not constructed in place: deallocate part
+C             of it (final size is less than or equal to newmem,
+C             since newly nonprincipal variables have been removed).
+              PFREE = P
+              MEM = MEM - NEWMEM + LEN (ME)
+              ENDIF
+
+C=======================================================================
+C          END WHILE (selecting pivots)
+           GOTO 30
+           ENDIF
+C=======================================================================
+
+C=======================================================================
+C  COMPUTE THE PERMUTATION VECTORS
+C=======================================================================
+
+C       ----------------------------------------------------------------
+C       The time taken by the following code is O(n).  At this
+C       point, elen (e) = -k has been done for all elements e,
+C       and elen (i) = 0 has been done for all nonprincipal
+C       variables i.  At this point, there are no principal
+C       supervariables left, and all elements are absorbed.
+C       ----------------------------------------------------------------
+
+C       ----------------------------------------------------------------
+C       compute the ordering of unordered nonprincipal variables
+C       ----------------------------------------------------------------
+
+        DO 290 I = 1, N
+           IF (ELEN (I) .EQ. 0) THEN
+
+C             ----------------------------------------------------------
+C             i is an un-ordered row.  Traverse the tree from i until
+C             reaching an element, e.  The element, e, was the
+C             principal supervariable of i and all nodes in the path
+C             from i to when e was selected as pivot.
+C             ----------------------------------------------------------
+
+              J = -PE (I)
+C             while (j is a variable) do:
+270           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 J = -PE (J)
+                 GOTO 270
+                 ENDIF
+              E = J
+
+C             ----------------------------------------------------------
+C             get the current pivot ordering of e
+C             ----------------------------------------------------------
+
+              K = -ELEN (E)
+
+C             ----------------------------------------------------------
+C             traverse the path again from i to e, and compress the
+C             path (all nodes point to e).  Path compression allows
+C             this code to compute in O(n) time.  Order the unordered
+C             nodes in the path, and place the element e at the end.
+C             ----------------------------------------------------------
+
+              J = I
+C             while (j is a variable) do:
+280           CONTINUE
+              IF (ELEN (J) .GE. 0) THEN
+                 JNEXT = -PE (J)
+                 PE (J) = -E
+                 IF (ELEN (J) .EQ. 0) THEN
+C                   j is an unordered row
+                    ELEN (J) = K
+                    K = K + 1
+                    ENDIF
+                 J = JNEXT
+                 GOTO 280
+                 ENDIF
+C             leave elen (e) negative, so we know it is an element
+              ELEN (E) = -K
+              ENDIF
+290        CONTINUE
+
+C       ----------------------------------------------------------------
+C       reset the inverse permutation (elen (1..n)) to be positive,
+C       and compute the permutation (last (1..n)).
+C       ----------------------------------------------------------------
+
+        DO 300 I = 1, N
+           K = ABS (ELEN (I))
+           LAST (K) = I
+           ELEN (I) = K
+300        CONTINUE
+
+C=======================================================================
+C  RETURN THE MEMORY USAGE IN IW
+C=======================================================================
+
+C       If maxmem is less than or equal to iwlen, then no compressions
+C       occurred, and iw (maxmem+1 ... iwlen) was unused.  Otherwise
+C       compressions did occur, and iwlen would have had to have been
+C       greater than or equal to maxmem for no compressions to occur.
+C       Return the value of maxmem in the pfree argument.
+
+        PFREE = MAXMEM
+
+        RETURN
+        END
+
diff --git a/src/CHOLMOD.diff b/src/CHOLMOD.diff
new file mode 100644
index 0000000..cb09223
--- /dev/null
+++ b/src/CHOLMOD.diff
@@ -0,0 +1,89 @@
+diff -r -x '*.o' -x '*.lo' -x .deps -x .dirstamp -x .libs CHOLMOD-orig/Include/cholmod_blas.h CHOLMOD/Include/cholmod_blas.h
+108,115c108,115
+< #define BLAS_DTRSV dtrsv
+< #define BLAS_DGEMV dgemv
+< #define BLAS_DTRSM dtrsm
+< #define BLAS_DGEMM dgemm
+< #define BLAS_DSYRK dsyrk
+< #define BLAS_DGER  dger
+< #define BLAS_DSCAL dscal
+< #define LAPACK_DPOTRF dpotrf
+---
+> #define BLAS_DTRSV igraphdtrsv
+> #define BLAS_DGEMV igraphdgemv
+> #define BLAS_DTRSM igraphdtrsm
+> #define BLAS_DGEMM igraphdgemm
+> #define BLAS_DSYRK igraphdsyrk
+> #define BLAS_DGER  igraphdger
+> #define BLAS_DSCAL igraphdscal
+> #define LAPACK_DPOTRF igraphdpotrf
+128,135c128,135
+< #define BLAS_DTRSV dtrsv_
+< #define BLAS_DGEMV dgemv_
+< #define BLAS_DTRSM dtrsm_
+< #define BLAS_DGEMM dgemm_
+< #define BLAS_DSYRK dsyrk_
+< #define BLAS_DGER  dger_
+< #define BLAS_DSCAL dscal_
+< #define LAPACK_DPOTRF dpotrf_
+---
+> #define BLAS_DTRSV igraphdtrsv_
+> #define BLAS_DGEMV igraphdgemv_
+> #define BLAS_DTRSM igraphdtrsm_
+> #define BLAS_DGEMM igraphdgemm_
+> #define BLAS_DSYRK igraphdsyrk_
+> #define BLAS_DGER  igraphdger_
+> #define BLAS_DSCAL igraphdscal_
+> #define LAPACK_DPOTRF igraphdpotrf_
+diff -r -x '*.o' -x '*.lo' -x .deps -x .dirstamp -x .libs CHOLMOD-orig/Supernodal/cholmod_super_numeric.c CHOLMOD/Supernodal/cholmod_super_numeric.c
+79,82c79,82
+< #define COMPLEX
+< #include "t_cholmod_super_numeric.c"
+< #define ZOMPLEX
+< #include "t_cholmod_super_numeric.c"
+---
+> /* #define COMPLEX */
+> /* #include "t_cholmod_super_numeric.c" */
+> /* #define ZOMPLEX */
+> /* #include "t_cholmod_super_numeric.c" */
+283,290c283,290
+< 	case CHOLMOD_COMPLEX:
+< 	    ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ;
+< 	    break ;
+< 
+< 	case CHOLMOD_ZOMPLEX:
+< 	    /* This operates on complex L, not zomplex */
+< 	    ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ;
+< 	    break ;
+---
+> 	/* case CHOLMOD_COMPLEX: */
+> 	/*     ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ; */
+> 	/*     break ; */
+> 
+> 	/* case CHOLMOD_ZOMPLEX: */
+> 	/*     /\* This operates on complex L, not zomplex *\/ */
+> 	/*     ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ; */
+> 	/*     break ; */
+diff -r -x '*.o' -x '*.lo' -x .deps -x .dirstamp -x .libs CHOLMOD-orig/Supernodal/cholmod_super_solve.c CHOLMOD/Supernodal/cholmod_super_solve.c
+29,30c29,30
+< #define COMPLEX
+< #include "t_cholmod_super_solve.c"
+---
+> /* #define COMPLEX */
+> /* #include "t_cholmod_super_solve.c" */
+112,114c112,114
+< 	case CHOLMOD_COMPLEX:
+< 	    c_cholmod_super_lsolve (L, X, E, Common) ;
+< 	    break ;
+---
+> 	/* case CHOLMOD_COMPLEX: */
+> 	/*     c_cholmod_super_lsolve (L, X, E, Common) ; */
+> 	/*     break ; */
+205,207c205,207
+< 	case CHOLMOD_COMPLEX:
+< 	    c_cholmod_super_ltsolve (L, X, E, Common) ;
+< 	    break ;
+---
+> 	/* case CHOLMOD_COMPLEX: */
+> 	/*     c_cholmod_super_ltsolve (L, X, E, Common) ; */
+> 	/*     break ; */
diff --git a/src/CHOLMOD/Check/License.txt b/src/CHOLMOD/Check/License.txt
new file mode 100644
index 0000000..ba50e66
--- /dev/null
+++ b/src/CHOLMOD/Check/License.txt
@@ -0,0 +1,24 @@
+CHOLMOD/Check Module.  Copyright (C) 2005-2006, Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/Check module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/CHOLMOD/Check/cholmod_check.c b/src/CHOLMOD/Check/cholmod_check.c
new file mode 100644
index 0000000..16f1ab9
--- /dev/null
+++ b/src/CHOLMOD/Check/cholmod_check.c
@@ -0,0 +1,2709 @@
+/* ========================================================================== */
+/* === Check/cholmod_check ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Check Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Routines to check and print the contents of the 5 CHOLMOD objects:
+ *
+ * No CHOLMOD routine calls the check or print routines.  If a user wants to
+ * check CHOLMOD's input parameters, a separate call to the appropriate check
+ * routine should be used before calling other CHOLMOD routines.
+ *
+ * cholmod_check_common		check statistics and workspace in Common
+ * cholmod_check_sparse		check sparse matrix in compressed column form
+ * cholmod_check_dense		check dense matrix
+ * cholmod_check_factor		check factorization
+ * cholmod_check_triplet	check sparse matrix in triplet form
+ *
+ * cholmod_print_common		print statistics in Common
+ * cholmod_print_sparse		print sparse matrix in compressed column form
+ * cholmod_print_dense		print dense matrix
+ * cholmod_print_factor		print factorization
+ * cholmod_print_triplet	print sparse matrix in triplet form
+ *
+ * In addition, this file contains routines to check and print three types of
+ * integer vectors:
+ * 
+ * cholmod_check_perm		check a permutation of 0:n-1 (no duplicates)
+ * cholmod_check_subset		check a subset of 0:n-1 (duplicates OK)
+ * cholmod_check_parent		check an elimination tree
+ *
+ * cholmod_print_perm		print a permutation
+ * cholmod_print_subset		print a subset
+ * cholmod_print_parent		print an elimination tree
+ *
+ * Each Common->print level prints the items at or below the given level:
+ *
+ *	0: print nothing; just check the data structures and return TRUE/FALSE
+ *	1: error messages
+ *	2: warning messages
+ *	3: one-line summary of each object printed
+ *	4: short summary of each object (first and last few entries)
+ *	5: entire contents of the object
+ *
+ * No CHOLMOD routine calls these routines, so no printing occurs unless
+ * the user specifically calls a cholmod_print_* routine.  Thus, the default
+ * print level is 3.
+ *
+ * Common->precise controls the # of digits printed for numerical entries
+ * (5 if FALSE, 15 if TRUE).
+ *
+ * If Common->print_function is NULL, then no printing occurs.  The
+ * cholmod_check_* and cholmod_print_* routines still check their inputs and
+ * return TRUE/FALSE if the object is valid or not.
+ *
+ * This file also includes debugging routines that are enabled only when
+ * NDEBUG is defined in cholmod_internal.h (cholmod_dump_*).
+ */
+
+#ifndef NCHECK
+
+#include "cholmod_internal.h"
+#include "cholmod_check.h"
+
+/* ========================================================================== */
+/* === printing definitions ================================================= */
+/* ========================================================================== */
+
+#ifdef LONG
+#define I8 "%8ld"
+#define I_8 "%-8ld"
+#else
+#define I8 "%8d"
+#define I_8 "%-8d"
+#endif
+
+#define PR(i,format,arg) \
+{ \
+    if (print >= i && Common->print_function != NULL) \
+    { \
+	(Common->print_function) (format, arg) ; \
+    } \
+}
+
+#define P1(format,arg) PR(1,format,arg)
+#define P2(format,arg) PR(2,format,arg)
+#define P3(format,arg) PR(3,format,arg)
+#define P4(format,arg) PR(4,format,arg)
+
+#define ERR(msg) \
+{ \
+    P1 ("\nCHOLMOD ERROR: %s: ", type) ; \
+    if (name != NULL) \
+    { \
+	P1 ("%s", name) ; \
+    } \
+    P1 (": %s\n", msg) ; \
+    ERROR (CHOLMOD_INVALID, "invalid") ; \
+    return (FALSE) ; \
+}
+
+/* print a numerical value */
+#define PRINTVALUE(value) \
+{ \
+    if (Common->precise) \
+    { \
+	P4 (" %23.15e", value) ; \
+    } \
+    else \
+    { \
+	P4 (" %.5g", value) ; \
+    } \
+}
+
+/* start printing */
+#define ETC_START(count,limit) \
+{ \
+    count = (init_print == 4) ? (limit) : (-1) ; \
+}
+
+/* re-enable printing if condition is met */
+#define ETC_ENABLE(condition,count,limit) \
+{ \
+    if ((condition) && init_print == 4) \
+    { \
+	count = limit ; \
+	print = 4 ; \
+    } \
+}
+
+/* turn off printing if limit is reached */
+#define ETC_DISABLE(count) \
+{ \
+    if ((count >= 0) && (count-- == 0) && print == 4) \
+    { \
+	P4 ("%s", "    ...\n")  ; \
+	print = 3 ; \
+    } \
+}
+
+/* re-enable printing, or turn if off after limit is reached */
+#define ETC(condition,count,limit) \
+{ \
+    ETC_ENABLE (condition, count, limit) ; \
+    ETC_DISABLE (count) ; \
+}
+
+#define BOOLSTR(x) ((x) ? "true " : "false")
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+static void print_value
+(
+    Int print,
+    Int xtype,
+    double *Xx,
+    double *Xz,
+    Int p,
+    cholmod_common *Common)
+{
+    if (xtype == CHOLMOD_REAL)
+    {
+	PRINTVALUE (Xx [p]) ;
+    }
+    else if (xtype == CHOLMOD_COMPLEX)
+    {
+	P4 ("%s", "(") ;
+	PRINTVALUE (Xx [2*p  ]) ;
+	P4 ("%s", " , ") ;
+	PRINTVALUE (Xx [2*p+1]) ;
+	P4 ("%s", ")") ;
+    }
+    else if (xtype == CHOLMOD_ZOMPLEX)
+    {
+	P4 ("%s", "(") ;
+	PRINTVALUE (Xx [p]) ;
+	P4 ("%s", " , ") ;
+	PRINTVALUE (Xz [p]) ;
+	P4 ("%s", ")") ;
+    }
+}
+
+/* ========================================================================== */
+/* === cholmod_check_common ================================================= */
+/* ========================================================================== */
+
+/* Print and verify the contents of Common */
+
+static int check_common
+(
+    Int print,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    double fl, lnz ;
+    double *Xwork ;
+    Int *Flag, *Head ;
+    SuiteSparse_long mark ;
+    Int i, nrow, nmethods, ordering, xworksize, amd_backup, init_print ;
+    const char *type = "common" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print control parameters and statistics */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    init_print = print ;
+
+    P2 ("%s", "\n") ;
+
+    P1 ("CHOLMOD version %d", CHOLMOD_MAIN_VERSION) ;
+    P1 (".%d", CHOLMOD_SUB_VERSION) ;
+    P1 (".%d", CHOLMOD_SUBSUB_VERSION) ;
+    P1 (", %s: ", CHOLMOD_DATE) ;
+
+    if (name != NULL)
+    {
+	P1 ("%s: ", name) ;
+    }
+    switch (Common->status)
+    {
+
+	case CHOLMOD_OK:
+	    P1 ("%s", "status: OK\n") ;
+	    break ;
+
+	case CHOLMOD_OUT_OF_MEMORY:
+	    P1 ("%s", "status: ERROR, out of memory\n") ;
+	    break ;
+
+	case CHOLMOD_INVALID:
+	    P1 ("%s", "status: ERROR, invalid parameter\n") ;
+	    break ;
+
+	case CHOLMOD_TOO_LARGE:
+	    P1 ("%s", "status: ERROR, problem too large\n") ;
+	    break ;
+
+	case CHOLMOD_NOT_INSTALLED:
+	    P1 ("%s", "status: ERROR, method not installed\n") ;
+	    break ;
+
+#if GPU_BLAS
+	case CHOLMOD_GPU_PROBLEM:
+	    P1 ("%s", "status: ERROR, GPU had a fatal error\n") ;
+	    break ;
+#endif
+
+	case CHOLMOD_NOT_POSDEF:
+	    P1 ("%s", "status: warning, matrix not positive definite\n") ;
+	    break ;
+
+	case CHOLMOD_DSMALL:
+	    P1 ("%s", "status: warning, diagonal entry has tiny abs. value\n") ;
+	    break ;
+
+	default:
+	    ERR ("unknown status") ;
+    }
+
+    P2 ("  Architecture: %s\n", CHOLMOD_ARCHITECTURE) ;
+    P3 ("    sizeof(int):      %d\n", (int) sizeof (int)) ;
+    P3 ("    sizeof(SuiteSparse_long):  %d\n", (int) sizeof (SuiteSparse_long));
+    P3 ("    sizeof(void *):   %d\n", (int) sizeof (void *)) ;
+    P3 ("    sizeof(double):   %d\n", (int) sizeof (double)) ;
+    P3 ("    sizeof(Int):      %d (CHOLMOD's basic integer)\n", (int) sizeof (Int)) ;
+    P3 ("    sizeof(BLAS_INT): %d (integer used in the BLAS)\n",
+	    (int) sizeof (BLAS_INT)) ;
+
+    if (Common->fl != EMPTY)
+    {
+	P2 ("%s", "  Results from most recent analysis:\n") ;
+	P2 ("    Cholesky flop count: %.5g\n", Common->fl) ;
+	P2 ("    Nonzeros in L:       %.5g\n", Common->lnz) ;
+    }
+    if (Common->modfl != EMPTY)
+    {
+	P2 ("    Update/downdate flop count: %.5g\n", Common->modfl) ;
+    }
+
+    P2 ("  memory blocks in use:    %8.0f\n", (double) (Common->malloc_count)) ;
+    P2 ("  memory in use (MB):      %8.1f\n", 
+	(double) (Common->memory_inuse) / 1048576.) ;
+    P2 ("  peak memory usage (MB):  %8.1f\n", 
+	(double) (Common->memory_usage) / 1048576.) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* primary control parameters and related ordering statistics */
+    /* ---------------------------------------------------------------------- */
+
+    P3 ("  maxrank:    update/downdate rank:   "ID"\n",
+	    (Int) CHOLMOD(maxrank) (0, Common)) ;
+    P3 ("  supernodal control: %d", Common->supernodal) ;
+    P3 (" %g ", Common->supernodal_switch) ;
+    if (Common->supernodal <= CHOLMOD_SIMPLICIAL)
+    {
+	P3 ("%s", "(always do simplicial)\n") ;
+    }
+    else if (Common->supernodal == CHOLMOD_AUTO)
+    {
+	P3 ("(supernodal if flops/lnz >= %g)\n", Common->supernodal_switch) ;
+    }
+    else
+    {
+	P3 ("%s", "(always do supernodal)\n") ;
+    }
+
+    nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ;
+    nmethods = MAX (0, nmethods) ;
+
+    if (nmethods > 0)
+    {
+	P3 ("%s", "  nmethods:   number of ordering methods to try: ") ;
+	P3 (""ID"\n", nmethods) ;
+        amd_backup = (nmethods > 1) || (nmethods == 1 &&
+            (Common->method [0].ordering == CHOLMOD_METIS ||
+             Common->method [0].ordering == CHOLMOD_NESDIS)) ;
+    }
+    else
+    {
+	P3 ("%s", "  nmethods=0: default strategy:  Try user permutation if "
+		"given.  Try AMD.\n") ;
+#ifndef NPARTITION
+	if (Common->default_nesdis)
+	{
+	    P3 ("%s", "    Try NESDIS if AMD reports flops/nnz(L) >= 500 and "
+		"nnz(L)/nnz(A) >= 5.\n") ;
+	}
+	else
+	{
+	    P3 ("%s", "    Try METIS if AMD reports flops/nnz(L) >= 500 and "
+		"nnz(L)/nnz(A) >= 5.\n") ;
+	}
+#endif
+	P3 ("%s", "    Select best ordering tried.\n") ;
+	Common->method [0].ordering = CHOLMOD_GIVEN ;
+	Common->method [1].ordering = CHOLMOD_AMD ;
+	Common->method [2].ordering = 
+            (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ;
+        amd_backup = FALSE ;
+#ifndef NPARTITION
+	nmethods = 3 ;
+#else
+	nmethods = 2 ;
+#endif
+    }
+
+    for (i = 0 ; i < nmethods ; i++)
+    {
+	P3 ("    method "ID": ", i) ;
+	ordering = Common->method [i].ordering ;
+	fl = Common->method [i].fl ;
+	lnz = Common->method [i].lnz ;
+	switch (ordering)
+	{
+
+	    case CHOLMOD_NATURAL:
+		P3 ("%s", "natural\n") ;
+		break ;
+
+	    case CHOLMOD_GIVEN:
+		P3 ("%s", "user permutation (if given)\n") ;
+		break ;
+
+	    case CHOLMOD_AMD:
+		P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ;
+		amd_backup = FALSE ;
+		break ;
+
+	    case CHOLMOD_COLAMD:
+		P3 ("%s", "AMD if factorizing A, COLAMD if factorizing AA')\n");
+		amd_backup = FALSE ;
+		break ;
+
+	    case CHOLMOD_METIS:
+		P3 ("%s", "METIS_NodeND nested dissection\n") ;
+		break ;
+
+	    case CHOLMOD_NESDIS:
+		P3 ("%s", "CHOLMOD nested dissection\n") ;
+
+		P3 ("        nd_small: # nodes in uncut subgraph: "ID"\n",
+			(Int) (Common->method [i].nd_small)) ;
+		P3 ("        nd_compress: compress the graph:     %s\n",
+			BOOLSTR (Common->method [i].nd_compress)) ;
+		P3 ("        nd_camd: use constrained min degree: %s\n",
+			BOOLSTR (Common->method [i].nd_camd)) ;
+		break ;
+
+	    default:
+		P3 (ID, ordering) ;
+		ERR ("unknown ordering method") ;
+		break ;
+
+	}
+
+	if (!(ordering == CHOLMOD_NATURAL || ordering == CHOLMOD_GIVEN))
+	{
+	    if (Common->method [i].prune_dense < 0)
+	    {
+		P3 ("        prune_dense: for pruning dense nodes:   %s\n",
+			" none pruned") ;
+	    }
+	    else
+	    {
+		P3 ("        prune_dense: for pruning dense nodes:   "
+		    "%.5g\n",
+		    Common->method [i].prune_dense) ;
+		P3 ("        a dense node has degree "
+			">= max(16,(%.5g)*sqrt(n))\n",
+		    Common->method [i].prune_dense) ;
+	    }
+	}
+
+	if (ordering == CHOLMOD_COLAMD || ordering == CHOLMOD_NESDIS)
+	{
+	    if (Common->method [i].prune_dense2 < 0)
+	    {
+		P3 ("        prune_dense2: for pruning dense rows for AA':"
+			"  %s\n", " none pruned") ;
+	    }
+	    else
+	    {
+		P3 ("        prune_dense2: for pruning dense rows for AA':"
+		    " %.5g\n", Common->method [i].prune_dense2) ;
+		P3 ("        a dense row has degree "
+			">= max(16,(%.5g)*sqrt(ncol))\n",
+		    Common->method [i].prune_dense2) ;
+	    }
+	}
+
+	if (fl  != EMPTY) P3 ("        flop count: %.5g\n", fl) ;
+	if (lnz != EMPTY) P3 ("        nnz(L):     %.5g\n", lnz) ;
+    }
+
+    /* backup AMD results, if any */
+    if (amd_backup)
+    {
+	P3 ("%s", "    backup method: ") ;
+	P3 ("%s", "AMD (or COLAMD if factorizing AA')\n") ;
+	fl = Common->method [nmethods].fl ;
+	lnz = Common->method [nmethods].lnz ;
+	if (fl  != EMPTY) P3 ("        AMD flop count: %.5g\n", fl) ;
+	if (lnz != EMPTY) P3 ("        AMD nnz(L):     %.5g\n", lnz) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* arcane control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->final_asis)
+    {
+	P4 ("%s", "  final_asis: TRUE, leave as is\n") ;
+    }
+    else
+    {
+	P4 ("%s", "  final_asis: FALSE, convert when done\n") ;
+	if (Common->final_super)
+	{
+	    P4 ("%s", "  final_super: TRUE, leave in supernodal form\n") ;
+	}
+	else
+	{
+	    P4 ("%s", "  final_super: FALSE, convert to simplicial form\n") ;
+	}
+	if (Common->final_ll)
+	{
+	    P4 ("%s", "  final_ll: TRUE, convert to LL' form\n") ;
+	}
+	else
+	{
+	    P4 ("%s", "  final_ll: FALSE, convert to LDL' form\n") ;
+	}
+	if (Common->final_pack)
+	{
+	    P4 ("%s", "  final_pack: TRUE, pack when done\n") ;
+	}
+	else
+	{
+	    P4 ("%s", "  final_pack: FALSE, do not pack when done\n") ;
+	}
+	if (Common->final_monotonic)
+	{
+	    P4 ("%s", "  final_monotonic: TRUE, ensure L is monotonic\n") ;
+	}
+	else
+	{
+	    P4 ("%s",
+		"  final_monotonic: FALSE, do not ensure L is monotonic\n") ;
+	}
+	P4 ("  final_resymbol: remove zeros from amalgamation: %s\n",
+		BOOLSTR (Common->final_resymbol)) ;
+    }
+
+    P4 ("  dbound:  LDL' diagonal threshold: % .5g\n    Entries with abs. value"
+	    " less than dbound are replaced with +/- dbound.\n",
+	    Common->dbound) ;
+
+    P4 ("  grow0: memory reallocation: % .5g\n", Common->grow0) ;
+    P4 ("  grow1: memory reallocation: % .5g\n", Common->grow1) ;
+    P4 ("  grow2: memory reallocation: %g\n", (double) (Common->grow2)) ;
+
+    P4 ("%s", "  nrelax, zrelax:  supernodal amalgamation rule:\n") ;
+    P4 ("%s", "    s = # columns in two adjacent supernodes\n") ;
+    P4 ("%s", "    z = % of zeros in new supernode if they are merged.\n") ;
+    P4 ("%s", "    Two supernodes are merged if") ;
+    P4 (" (s <= %g) or (no new zero entries) or\n",
+	    (double) (Common->nrelax [0])) ;
+    P4 ("    (s <= %g and ",  (double) (Common->nrelax [1])) ;
+    P4 ("z < %.5g%%) or",      Common->zrelax [0] * 100) ;
+    P4 (" (s <= %g and ",     (double) (Common->nrelax [2])) ;
+    P4 ("z < %.5g%%) or",      Common->zrelax [1] * 100) ;
+    P4 (" (z < %.5g%%)\n",     Common->zrelax [2] * 100) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check workspace */
+    /* ---------------------------------------------------------------------- */
+
+    mark = Common->mark ;
+    nrow = Common->nrow ;
+    Flag = Common->Flag ;
+    Head = Common->Head ;
+    if (nrow > 0)
+    {
+	if (mark < 0 || Flag == NULL || Head == NULL)
+	{
+	    ERR ("workspace corrupted (Flag and/or Head missing)") ;
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    if (Flag [i] >= mark)
+	    {
+		PRINT0 (("Flag ["ID"]="ID", mark = %ld\n", i, Flag [i], mark)) ;
+		ERR ("workspace corrupted (Flag)") ;
+	    }
+	}
+	for (i = 0 ; i <= nrow ; i++)
+	{
+	    if (Head [i] != EMPTY)
+	    {
+		PRINT0 (("Head ["ID"] = "ID",\n", i, Head [i])) ;
+		ERR ("workspace corrupted (Head)") ;
+	    }
+	}
+    }
+    xworksize = Common->xworksize ;
+    Xwork = Common->Xwork ;
+    if (xworksize > 0)
+    {
+	if (Xwork == NULL)
+	{
+	    ERR ("workspace corrupted (Xwork missing)") ;
+	}
+	for (i = 0 ; i < xworksize ; i++)
+	{
+	    if (Xwork [i] != 0.)
+	    {
+		PRINT0 (("Xwork ["ID"] = %g\n", i, Xwork [i])) ;
+		ERR ("workspace corrupted (Xwork)") ;
+	    }
+	}
+    }
+
+    /* workspace and parameters are valid */
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_common)
+(
+    cholmod_common *Common
+)
+{
+    return (check_common (0, NULL, Common)) ;
+}
+
+
+int CHOLMOD(print_common)
+(
+    /* ---- input ---- */
+    const char *name,		/* printed name of Common object */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int print = (Common == NULL) ? 3 : (Common->print) ;
+    return (check_common (print, name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_gpu_stats ==================================================== */
+/* ========================================================================== */
+
+/* Print CPU / GPU statistics.  If the timer is not installed, the times are
+   reported as zero, but this function still works.  Likewise, the function
+   still works if the GPU BLAS is not installed. */
+
+int CHOLMOD(gpu_stats)
+(
+    cholmod_common *Common      /* input */
+)
+{
+    double cpu_time, gpu_time ;
+    int print ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    print = Common->print ;
+
+    P2 ("%s", "\nCHOLMOD GPU/CPU statistics:\n") ;
+    P2 ("SYRK  CPU calls %12.0f", (double) Common->CHOLMOD_CPU_SYRK_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_CPU_SYRK_TIME) ;
+    P2 ("      GPU calls %12.0f", (double) Common->CHOLMOD_GPU_SYRK_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_GPU_SYRK_TIME) ;
+    P2 ("GEMM  CPU calls %12.0f", (double) Common->CHOLMOD_CPU_GEMM_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_CPU_GEMM_TIME) ;
+    P2 ("      GPU calls %12.0f", (double) Common->CHOLMOD_GPU_GEMM_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_GPU_GEMM_TIME) ;
+    P2 ("POTRF CPU calls %12.0f", (double) Common->CHOLMOD_CPU_POTRF_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_CPU_POTRF_TIME) ;
+    P2 ("      GPU calls %12.0f", (double) Common->CHOLMOD_GPU_POTRF_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_GPU_POTRF_TIME) ;
+    P2 ("TRSM  CPU calls %12.0f", (double) Common->CHOLMOD_CPU_TRSM_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_CPU_TRSM_TIME) ;
+    P2 ("      GPU calls %12.0f", (double) Common->CHOLMOD_GPU_TRSM_CALLS) ;
+    P2 (" time %12.4e\n", Common->CHOLMOD_GPU_TRSM_TIME) ;
+
+    cpu_time = Common->CHOLMOD_CPU_SYRK_TIME + Common->CHOLMOD_CPU_TRSM_TIME +
+               Common->CHOLMOD_CPU_GEMM_TIME + Common->CHOLMOD_CPU_POTRF_TIME ;
+
+    gpu_time = Common->CHOLMOD_GPU_SYRK_TIME + Common->CHOLMOD_GPU_TRSM_TIME +
+               Common->CHOLMOD_GPU_GEMM_TIME + Common->CHOLMOD_GPU_POTRF_TIME ;
+
+    P2 ("time in the BLAS: CPU %12.4e", cpu_time) ;
+    P2 (" GPU %12.4e", gpu_time) ;
+    P2 (" total: %12.4e\n", cpu_time + gpu_time) ;
+
+    P2 ("assembly time %12.4e", Common->CHOLMOD_ASSEMBLE_TIME) ;
+    P2 ("  %12.4e\n", Common->CHOLMOD_ASSEMBLE_TIME2) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_sparse ================================================= */
+/* ========================================================================== */
+
+/* Ensure that a sparse matrix in column-oriented form is valid, and optionally
+ * print it.  Returns the number of entries on the diagonal or -1 if error.
+ *
+ * workspace: Iwork (nrow)
+ */
+
+static SuiteSparse_long check_sparse
+(
+    Int *Wi,
+    Int print,
+    const char *name,
+    cholmod_sparse *A,
+    SuiteSparse_long *nnzdiag,
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az ;
+    Int *Ap, *Ai, *Anz ;
+    Int nrow, ncol, nzmax, sorted, packed, j, p, pend, i, nz, ilast,
+	space, init_print, dnz, count, xtype ;
+    const char *type = "sparse" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD sparse:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (A == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    nzmax = A->nzmax ;
+    sorted = A->sorted ;
+    packed = A->packed ;
+    xtype = A->xtype ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    nz = CHOLMOD(nnz) (A, Common) ;
+
+    P3 (" "ID"", nrow) ;
+    P3 ("-by-"ID", ", ncol) ;
+    P3 ("nz "ID",", nz) ;
+    if (A->stype > 0)
+    {
+	P3 ("%s", " upper.") ;
+    }
+    else if (A->stype < 0)
+    {
+	P3 ("%s", " lower.") ;
+    }
+    else
+    {
+	P3 ("%s", " up/lo.") ;
+    }
+
+    P4 ("\n  nzmax "ID", ", nzmax) ;
+    if (nz > nzmax)
+    {
+	ERR ("nzmax too small") ;
+    }
+    if (!sorted)
+    {
+	P4 ("%s", "un") ;
+    }
+    P4 ("%s", "sorted, ") ;
+    if (!packed)
+    {
+	P4 ("%s", "un") ;
+    }
+    P4 ("%s", "packed, ") ;
+
+    switch (A->itype)
+    {
+	case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
+	case CHOLMOD_INTLONG: ERR ("mixed int/long type unsupported") ;
+	case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: SuiteSparse_long, ");
+        break ;
+	default:	      ERR ("unknown itype") ;
+    }
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;	break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (A->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("float unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    if (A->itype != ITYPE || A->dtype != DTYPE)
+    {
+	ERR ("integer and real type must match routine") ;
+    }
+
+    if (A->stype && nrow != ncol)
+    {
+	ERR ("symmetric but not square") ;
+    }
+
+    /* check for existence of Ap, Ai, Anz, Ax, and Az arrays */
+    if (Ap == NULL)
+    {
+	ERR ("p array not present") ;
+    }
+    if (Ai == NULL)
+    {
+	ERR ("i array not present") ;
+    }
+    if (!packed && Anz == NULL)
+    {
+	ERR ("nz array not present") ;
+    }
+    if (xtype != CHOLMOD_PATTERN && Ax == NULL)
+    {
+	ERR ("x array not present") ;
+    }
+    if (xtype == CHOLMOD_ZOMPLEX && Az == NULL)
+    {
+	ERR ("z array not present") ;
+    }
+
+    /* packed matrices must start at Ap [0] = 0 */
+    if (packed && Ap [0] != 0)
+    {
+	ERR ("p [0] must be zero") ;
+    }
+    if (packed && (Ap [ncol] < Ap [0] || Ap [ncol] > nzmax))
+    {
+	ERR ("p [ncol] invalid") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace if needed */
+    /* ---------------------------------------------------------------------- */
+
+    if (!sorted)
+    {
+	if (Wi == NULL)
+	{
+	    CHOLMOD(allocate_work) (0, nrow, 0, Common) ;
+	    Wi = Common->Iwork ;	/* size nrow, (i/i/l) */
+	}
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return (FALSE) ;	    /* out of memory */
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [i] = EMPTY ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check and print each column */
+    /* ---------------------------------------------------------------------- */
+
+    init_print = print ;
+    dnz = 0 ;
+    ETC_START (count, 8) ;
+
+    for (j = 0 ; j < ncol ; j++)
+    {
+	ETC (j == ncol-1, count, 4) ;
+	p = Ap [j] ;
+	if (packed)
+	{
+	    pend = Ap [j+1] ;
+	    nz = pend - p ;
+	}
+	else
+	{
+	    /* Note that Anz [j] < 0 is treated as zero */
+	    nz = MAX (0, Anz [j]) ;
+	    pend = p + nz ;
+	}
+	/* Note that space can be negative if the matrix is non-monotonic */
+	space = Ap [j+1] - p ;
+	P4 ("  col "ID":", j) ;
+	P4 (" nz "ID"", nz) ;
+	P4 (" start "ID"", p) ;
+	P4 (" end "ID"", pend) ;
+	if (!packed)
+	{
+	    P4 (" space "ID"", space) ;
+	}
+	P4 ("%s", ":\n") ;
+	if (p < 0 || pend > nzmax)
+	{
+	    ERR ("pointer invalid") ;
+	}
+	if (nz < 0 || nz > nrow)
+	{
+	    ERR ("nz invalid") ;
+	}
+	ilast = EMPTY ;
+
+	for ( ; p < pend ; p++)
+	{
+	    ETC (j == ncol-1 && p >= pend-4, count, -1) ;
+	    i = Ai [p] ;
+	    P4 ("  "I8":", i) ;
+
+	    print_value (print, xtype, Ax, Az, p, Common) ;
+
+	    if (i == j)
+	    {
+		dnz++ ;
+	    }
+	    if (i < 0 || i >= nrow)
+	    {
+		ERR ("row index out of range") ;
+	    }
+	    if (sorted && i <= ilast)
+	    {
+		ERR ("row indices out of order") ;
+	    }
+	    if (!sorted && Wi [i] == j)
+	    {
+		ERR ("duplicate row index") ;
+	    }
+	    P4 ("%s", "\n") ;
+	    ilast = i ;
+	    if (!sorted)
+	    {
+		Wi [i] = j ;
+	    }
+	}
+    }
+
+    /* matrix is valid */
+    P4 ("  nnz on diagonal: "ID"\n", dnz) ;
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    *nnzdiag = dnz ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    SuiteSparse_long nnzdiag ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_sparse (NULL, 0, NULL, A, &nnzdiag, Common)) ;
+}
+
+
+int CHOLMOD(print_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to print */
+    const char *name,	/* printed name of sparse matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    SuiteSparse_long nnzdiag ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_sparse (NULL, Common->print, name, A, &nnzdiag, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_dense ================================================== */
+/* ========================================================================== */
+
+/* Ensure a dense matrix is valid, and optionally print it. */
+
+static int check_dense
+(
+    Int print,
+    const char *name,
+    cholmod_dense *X,
+    cholmod_common *Common
+)
+{
+    double *Xx, *Xz ;
+    Int i, j, d, nrow, ncol, nzmax, nz, init_print, count, xtype ;
+    const char *type = "dense" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD dense:   ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (X == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+    nzmax = X->nzmax ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    xtype = X->xtype ;
+
+    P3 (" "ID"", nrow) ;
+    P3 ("-by-"ID", ", ncol) ;
+    P4 ("\n  leading dimension "ID", ", d) ;
+    P4 ("nzmax "ID", ", nzmax) ;
+    if (d * ncol > nzmax)
+    {
+	ERR ("nzmax too small") ;
+    }
+    if (d < nrow)
+    {
+	ERR ("leading dimension must be >= # of rows") ;
+    }
+    if (Xx == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_PATTERN: ERR ("pattern unsupported") ;  break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (X->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check and print each entry */
+    /* ---------------------------------------------------------------------- */
+
+    if (print >= 4)
+    {
+	init_print = print ;
+	ETC_START (count, 9) ;
+	nz = nrow * ncol ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    ETC (j == ncol-1, count, 5) ;
+	    P4 ("  col "ID":\n", j) ;
+	    for (i = 0 ; i < nrow ; i++)
+	    {
+		ETC (j == ncol-1 && i >= nrow-4, count, -1) ;
+		P4 ("  "I8":", i) ;
+
+		print_value (print, xtype, Xx, Xz, i+j*d, Common) ;
+
+		P4 ("%s", "\n") ;
+	    }
+	}
+    }
+
+    /* dense  is valid */
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_dense (0, NULL, X, Common)) ;
+}
+
+
+int CHOLMOD(print_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to print */
+    const char *name,	/* printed name of dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_dense (Common->print, name, X, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_subset ================================================= */
+/* ========================================================================== */
+
+/* Ensure S (0:len-1) is a subset of 0:n-1.  Duplicates are allowed.  S may be
+ * NULL.  A negative len denotes the set 0:n-1.
+ *
+ * To check the rset and cset for A(rset,cset), where nc and nr are the length
+ * of cset and rset respectively:
+ *
+ *	cholmod_check_subset (cset, nc, A->ncol, Common) ;
+ *	cholmod_check_subset (rset, nr, A->nrow, Common) ;
+ *
+ * workspace: none
+ */
+
+static int check_subset
+(
+    Int *S,
+    SuiteSparse_long len,
+    size_t n,
+    Int print,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    Int i, k, init_print, count ;
+    const char *type = "subset" ;
+
+    init_print = print ;
+
+    if (S == NULL)
+    {
+	/* zero len denotes S = [ ], negative len denotes S = 0:n-1 */
+	len = (len < 0) ? (-1) : 0 ;
+    }
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD subset:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    P3 (" len: %ld ", len) ;
+    if (len < 0)
+    {
+	P3 ("%s", "(denotes 0:n-1) ") ;
+    }
+    P3 ("n: "ID"", (Int) n) ;
+    P4 ("%s", "\n") ;
+
+    if (len <= 0 || S == NULL)
+    {
+	P3 ("%s", "  OK\n") ;
+	P4 ("%s", "\n") ;
+	return (TRUE) ;
+    }
+
+    if (print >= 4)
+    {
+	ETC_START (count, 8) ;
+	for (k = 0 ; k < ((Int) len) ; k++)
+	{
+	    ETC (k == ((Int) len) - 4, count, -1) ;
+	    i = S [k] ;
+	    P4 ("  "I8":", k) ;
+	    P4 (" "ID"\n", i) ;
+	    if (i < 0 || i >= ((Int) n))
+	    {
+		ERR ("entry out range") ;
+	    }
+	}
+    }
+    else
+    {
+	for (k = 0 ; k < ((Int) len) ; k++)
+	{
+	    i = S [k] ;
+	    if (i < 0 || i >= ((Int) n))
+	    {
+		ERR ("entry out range") ;
+	    }
+	}
+    }
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_subset)
+(
+    /* ---- input ---- */
+    Int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    SuiteSparse_long len, /* size of Set (an integer array), or < 0 if 0:n-1 */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_subset (Set, len, n, 0, NULL, Common)) ;
+}
+
+
+int CHOLMOD(print_subset)
+(
+    /* ---- input ---- */
+    Int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    SuiteSparse_long len, /* size of Set (an integer array), or < 0 if 0:n-1 */
+    size_t n,		/* 0:n-1 is valid range */
+    const char *name,	/* printed name of Set */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_subset (Set, len, n, Common->print, name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_perm =================================================== */
+/* ========================================================================== */
+
+/* Ensure that Perm [0..len-1] is a permutation of a subset of 0:n-1.  Perm
+ * may be NULL, which is interpreted as the identity permutation.  There can
+ * be no duplicate entries (len must be <= n).
+ *
+ * If n <= Common->nrow, then this routine takes O(len) time and does not
+ * allocate any memory, by using Common->Flag.  Otherwise, it takes O(n) time
+ * and ensures that Common->Iwork is at least n*sizeof(Int) in size.
+ *
+ * To check the fset:	    cholmod_check_perm (fset, fsize, ncol, Common) ;
+ * To check a permutation:  cholmod_check_perm (Perm, n, n, Common) ;
+ *
+ * workspace:  Flag (n) if n <= Common->nrow, Iwork (n) otherwise.
+ */
+
+static int check_perm
+(
+    Int *Wi,
+    Int print,
+    const char *name,
+    Int *Perm,
+    size_t len,
+    size_t n,
+    cholmod_common *Common
+)
+{
+    Int *Flag ;
+    Int i, k, mark, init_print, count ;
+    const char *type = "perm" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* checks that take O(1) time */
+    /* ---------------------------------------------------------------------- */
+
+    if (Perm == NULL || n == 0)
+    {
+	/* Perm is valid implicit identity, or empty */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* checks that take O(n) time or require memory allocation */
+    /* ---------------------------------------------------------------------- */
+
+    init_print = print ;
+    ETC_START (count, 8) ;
+
+    if (Wi == NULL && n <= Common->nrow)
+    {
+	/* use the Common->Flag array if it's big enough */
+	mark = CHOLMOD(clear_flag) (Common) ;
+	Flag = Common->Flag ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
+	if (print >= 4)
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		ETC (k >= ((Int) len) - 4, count, -1) ;
+		i = Perm [k] ;
+		P4 ("  "I8":", k) ;
+		P4 (""ID"\n", i) ;
+		if (i < 0 || i >= ((Int) n) || Flag [i] == mark)
+		{
+		    CHOLMOD(clear_flag) (Common) ;
+		    ERR ("invalid permutation") ;
+		}
+		Flag [i] = mark ;
+	    }
+	}
+	else
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		i = Perm [k] ;
+		if (i < 0 || i >= ((Int) n) || Flag [i] == mark)
+		{
+		    CHOLMOD(clear_flag) (Common) ;
+		    ERR ("invalid permutation") ;
+		}
+		Flag [i] = mark ;
+	    }
+	}
+	CHOLMOD(clear_flag) (Common) ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
+    }
+    else
+    {
+	if (Wi == NULL)
+	{
+	    /* use Common->Iwork instead, but initialize it first */
+	    CHOLMOD(allocate_work) (0, n, 0, Common) ;
+	    Wi = Common->Iwork ;		    /* size n, (i/i/i) is OK */
+	}
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return (FALSE) ;	    /* out of memory */
+	}
+	for (i = 0 ; i < ((Int) n) ; i++)
+	{
+	    Wi [i] = FALSE ;
+	}
+	if (print >= 4)
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		ETC (k >= ((Int) len) - 4, count, -1) ;
+		i = Perm [k] ;
+		P4 ("  "I8":", k) ;
+		P4 (""ID"\n", i) ;
+		if (i < 0 || i >= ((Int) n) || Wi [i])
+		{
+		    ERR ("invalid permutation") ;
+		}
+		Wi [i] = TRUE ;
+	    }
+	}
+	else
+	{
+	    for (k = 0 ; k < ((Int) len) ; k++)
+	    {
+		i = Perm [k] ;
+		if (i < 0 || i >= ((Int) n) || Wi [i])
+		{
+		    ERR ("invalid permutation") ;
+		}
+		Wi [i] = TRUE ;
+	    }
+	}
+    }
+
+    /* perm is valid */
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_perm)
+(
+    /* ---- input ---- */
+    Int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_perm (NULL, 0, NULL, Perm, len, n, Common)) ;
+}
+
+
+int CHOLMOD(print_perm)
+(
+    /* ---- input ---- */
+    Int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    const char *name,	/* printed name of Perm */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok, print ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    print = Common->print ;
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD perm:    ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+    P3 (" len: "ID"", (Int) len) ;
+    P3 (" n: "ID"", (Int) n) ;
+    P4 ("%s", "\n") ;
+    ok = check_perm (NULL, print, name, Perm, len, n, Common) ;
+    if (ok)
+    {
+	P3 ("%s", "  OK\n") ;
+	P4 ("%s", "\n") ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_parent ================================================= */
+/* ========================================================================== */
+
+/* Ensure that Parent is a valid elimination tree of nodes 0 to n-1.
+ * If j is a root of the tree then Parent [j] is EMPTY (-1).
+ *
+ * NOTE: this check will fail if applied to the component tree (CParent) in
+ * cholmod_nested_dissection, unless it has been postordered and renumbered.
+ *
+ * workspace: none
+ */
+
+static int check_parent
+(
+    Int *Parent,
+    size_t n,
+    Int print,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    Int j, p, init_print, count ;
+    const char *type = "parent" ;
+
+    init_print = print ;
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD parent:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    P3 (" n: "ID"", (Int) n) ;
+    P4 ("%s", "\n") ;
+
+    if (Parent == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* checks that take O(n) time */
+    /* ---------------------------------------------------------------------- */
+
+    ETC_START (count, 8) ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	ETC (j == ((Int) n) - 4, count, -1) ;
+	p = Parent [j] ;
+	P4 ("  "I8":", j) ;
+	P4 (" "ID"\n", p) ;
+	if (!(p == EMPTY || p > j))
+	{
+	    ERR ("invalid") ;
+	}
+    }
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_parent)
+(
+    /* ---- input ---- */
+    Int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_parent (Parent, n, 0, NULL, Common)) ;
+}
+
+
+int CHOLMOD(print_parent)
+(
+    /* ---- input ---- */
+    Int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    const char *name,	/* printed name of Parent */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_parent (Parent, n, Common->print, name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_factor ================================================= */
+/* ========================================================================== */
+
+static int check_factor
+(
+    Int *Wi,
+    Int print,
+    const char *name,
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz, *Lnext, *Lprev, *Perm, *ColCount, *Lpi, *Lpx, *Super,
+	*Ls ;
+    Int n, nzmax, j, p, pend, i, nz, ordering, space, is_monotonic, minor,
+	count, precise, init_print, ilast, lnz, head, tail, jprev, plast,
+	jnext, examine_super, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol,
+	ps2, psxend, ssize, xsize, maxcsize, maxesize, nsrow2, jj, ii, xtype ;
+    Int for_cholesky ;
+    const char *type = "factor" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD factor:  ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (L == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    n = L->n ;
+    minor = L->minor ;
+    ordering = L->ordering ;
+    xtype = L->xtype ;
+
+    Perm = L->Perm ;
+    ColCount = L->ColCount ;
+    lnz = 0 ;
+
+    precise = Common->precise ;
+
+    P3 (" "ID"", n) ;
+    P3 ("-by-"ID"", n) ;
+
+    if (minor < n)
+    {
+	P3 (" not positive definite (column "ID")", minor) ;
+    }
+
+    switch (L->itype)
+    {
+	case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
+	case CHOLMOD_INTLONG: ERR ("mixed int/long type unsupported") ;
+	case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: SuiteSparse_long, ");
+        break ;
+	default:	      ERR ("unknown itype") ;
+    }
+
+    switch (L->xtype)
+    {
+	case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;	break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (L->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    if (L->itype != ITYPE || L->dtype != DTYPE)
+    {
+	ERR ("integer and real type must match routine") ;
+    }
+
+    if (L->is_super)
+    {
+	P3 ("%s", "  supernodal") ;
+    }
+    else
+    {
+	P3 ("%s", "  simplicial") ;
+    }
+
+    if (L->is_ll)
+    {
+	P3 ("%s", ", LL'.") ;
+    }
+    else
+    {
+	P3 ("%s", ", LDL'.") ;
+    }
+
+    P4 ("%s", "\n  ordering method used: ") ;
+    switch (L->ordering)
+    {
+	case CHOLMOD_POSTORDERED:P4 ("%s", "natural (postordered)") ;	 break ;
+	case CHOLMOD_NATURAL:	P4 ("%s", "natural") ;			 break ;
+	case CHOLMOD_GIVEN:	P4 ("%s", "user-provided") ;		 break ;
+	case CHOLMOD_AMD:	P4 ("%s", "AMD") ;			 break ;
+	case CHOLMOD_COLAMD:	P4 ("%s", "AMD for A, COLAMD for A*A'") ;break ;
+#ifndef NPARTITION
+	case CHOLMOD_METIS:	P4 ("%s", "METIS NodeND") ;		 break ;
+	case CHOLMOD_NESDIS:	P4 ("%s", "CHOLMOD nested dissection") ; break ;
+#endif
+	default:		ERR ("unknown ordering") ;
+    }
+
+    P4 ("%s", "\n") ;
+
+    init_print = print ;
+
+    if (L->is_super && L->xtype == CHOLMOD_ZOMPLEX)
+    {
+	ERR ("Supernodal zomplex L not supported") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check L->Perm */
+    /* ---------------------------------------------------------------------- */
+
+    if (!check_perm (Wi, print, name, Perm, n, n, Common))
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check L->ColCount */
+    /* ---------------------------------------------------------------------- */
+
+    if (ColCount == NULL)
+    {
+	ERR ("ColCount vector invalid") ;
+    }
+
+    ETC_START (count, 8) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	ETC (j >= n-4, count, -1) ;
+	P4 ("  col: "ID" ", j) ;
+	nz = ColCount [j] ;
+	P4 ("colcount: "ID"\n", nz) ;
+	if (nz < 0 || nz > n-j)
+	{
+	    ERR ("ColCount out of range") ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check factor */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* check simplicial symbolic factor */
+	/* ------------------------------------------------------------------ */
+
+	/* nothing else to do */ ;
+
+    }
+    else if (L->xtype != CHOLMOD_PATTERN && !(L->is_super))
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* check simplicial numerical factor */
+	/* ------------------------------------------------------------------ */
+
+	P4 ("monotonic: %d\n", L->is_monotonic) ;
+	nzmax = L->nzmax ;
+	P3 (" nzmax "ID".", nzmax) ;
+	P4 ("%s", "\n") ;
+	Lp = L->p ;
+	Li = L->i ;
+	Lx = L->x ;
+	Lz = L->z ;
+	Lnz = L->nz ;
+	Lnext = L->next ;
+	Lprev = L->prev ;
+
+	/* check for existence of Lp, Li, Lnz, Lnext, Lprev, and Lx arrays */
+	if (Lp == NULL)
+	{
+	    ERR ("p array not present") ;
+	}
+	if (Li == NULL)
+	{
+	    ERR ("i array not present") ;
+	}
+	if (Lnz == NULL)
+	{
+	    ERR ("nz array not present") ;
+	}
+	if (Lx == NULL)
+	{
+	    ERR ("x array not present") ;
+	}
+	if (xtype == CHOLMOD_ZOMPLEX && Lz == NULL)
+	{
+	    ERR ("z array not present") ;
+	}
+	if (Lnext == NULL)
+	{
+	    ERR ("next array not present") ;
+	}
+	if (Lprev == NULL)
+	{
+	    ERR ("prev array not present") ;
+	}
+
+	ETC_START (count, 8) ;
+
+	/* check each column of L */
+	plast = 0 ;
+	is_monotonic = TRUE ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    ETC (j >= n-3, count, -1) ;
+	    p = Lp [j] ;
+	    nz = Lnz [j] ;
+	    pend = p + nz ;
+	    lnz += nz ;
+
+	    P4 ("  col "ID":", j) ;
+	    P4 (" nz "ID"", nz) ;
+	    P4 (" start "ID"", p) ;
+	    P4 (" end "ID"", pend) ;
+
+	    if (Lnext [j] < 0 || Lnext [j] > n)
+	    {
+		ERR ("invalid link list")  ;
+	    }
+	    space = Lp [Lnext [j]] - p ;
+
+	    P4 (" space "ID"", space) ;
+	    P4 (" free "ID":\n", space - nz) ;
+
+	    if (p < 0 || pend > nzmax || space < 1)
+	    {
+		ERR ("pointer invalid") ;
+	    }
+	    if (nz < 1 || nz > (n-j) || nz > space)
+	    {
+		ERR ("nz invalid") ;
+	    }
+	    ilast = j-1 ;
+
+	    if (p < plast)
+	    {
+		is_monotonic = FALSE ;
+	    }
+	    plast = p ;
+
+	    i = Li [p] ;
+	    P4 ("  "I8":", i) ;
+	    if (i != j)
+	    {
+		ERR ("diagonal missing") ;
+	    }
+
+	    print_value (print, xtype, Lx, Lz, p, Common) ;
+
+	    P4 ("%s", "\n") ;
+	    ilast = j ;
+	    for (p++ ; p < pend ; p++)
+	    {
+		ETC_DISABLE (count) ;
+		i = Li [p] ;
+		P4 ("  "I8":", i) ;
+		if (i < j || i >= n)
+		{
+		    ERR ("row index out of range") ;
+		}
+		if (i <= ilast)
+		{
+		    ERR ("row indices out of order") ;
+		}
+
+		print_value (print, xtype, Lx, Lz, p, Common) ;
+
+		P4 ("%s", "\n") ;
+		ilast = i ;
+	    }
+	}
+
+	if (L->is_monotonic && !is_monotonic)
+	{
+	    ERR ("columns not monotonic") ;
+	}
+
+	/* check the link list */
+	head = n+1 ;
+	tail = n ;
+	j = head ;
+	jprev = EMPTY ;
+	count = 0 ;
+	for ( ; ; )
+	{
+	    if (j < 0 || j > n+1 || count > n+2)
+	    {
+		ERR ("invalid link list") ;
+	    }
+	    jnext = Lnext [j] ;
+	    if (j >= 0 && j < n)
+	    {
+		if (jprev != Lprev [j])
+		{
+		    ERR ("invalid link list") ;
+		}
+	    }
+	    count++ ;
+	    if (j == tail)
+	    {
+		break ;
+	    }
+	    jprev = j ;
+	    j = jnext ;
+	}
+	if (Lnext [tail] != EMPTY || count != n+2)
+	{
+	    ERR ("invalid link list") ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* check supernodal numeric or symbolic factor */
+	/* ------------------------------------------------------------------ */
+
+	nsuper = L->nsuper ;
+	ssize = L->ssize ;
+	xsize = L->xsize ;
+	maxcsize = L->maxcsize ;
+	maxesize = L->maxesize ;
+	Ls = L->s ;
+	Lpi = L->pi ;
+	Lpx = L->px ;
+	Super = L->super ;
+	Lx = L->x ;
+	ETC_START (count, 8) ;
+
+	P4 ("  ssize "ID" ", ssize) ;
+	P4 ("xsize "ID" ", xsize) ;
+	P4 ("maxcsize "ID" ", maxcsize) ;
+	P4 ("maxesize "ID"\n", maxesize) ;
+
+	if (Ls == NULL)
+	{
+	    ERR ("invalid: L->s missing") ;
+	}
+	if (Lpi == NULL)
+	{
+	    ERR ("invalid: L->pi missing") ;
+	}
+	if (Lpx == NULL)
+	{
+	    ERR ("invalid: L->px missing") ;
+	}
+	if (Super == NULL)
+	{
+	    ERR ("invalid: L->super missing") ;
+	}
+
+	if (L->xtype != CHOLMOD_PATTERN)
+	{
+	    /* numerical supernodal factor */
+	    if (Lx == NULL)
+	    {
+		ERR ("invalid: L->x missing") ;
+	    }
+	    if (Ls [0] == EMPTY)
+	    {
+		ERR ("invalid: L->s not defined") ;
+	    }
+	    examine_super = TRUE ;
+	}
+	else
+	{
+	    /* symbolic supernodal factor, but only if it has been computed */
+	    examine_super = (Ls [0] != EMPTY) ;
+	}
+
+	if (examine_super)
+	{
+	    if (Lpi [0] != 0 || MAX (1, Lpi [nsuper]) != ssize)
+	    {
+		PRINT0 (("Lpi [0] "ID", Lpi [nsuper = "ID"] = "ID"\n",
+			Lpi [0], nsuper, Lpi [nsuper])) ;
+		ERR ("invalid: L->pi invalid") ;
+	    }
+
+            for_cholesky = (Lpx [0] != 123456) ;
+	    if (for_cholesky && (Lpx [0] != 0 || MAX (1, Lpx[nsuper]) != xsize))
+	    {
+		ERR ("invalid: L->px invalid") ;
+	    }
+
+	    /* check and print each supernode */
+	    for (s = 0 ; s < nsuper ; s++)
+	    {
+		k1 = Super [s] ;
+		k2 = Super [s+1] ;
+		psi = Lpi [s] ;
+		psend = Lpi [s+1] ;
+		nsrow = psend - psi ;
+		nscol = k2 - k1 ;
+		nsrow2 = nsrow - nscol ;
+		ps2 = psi + nscol ;
+
+                if (for_cholesky)
+                {
+                    psx = Lpx [s] ;
+                    psxend = Lpx [s+1] ;
+                }
+
+		ETC (s == nsuper-1, count, 4) ;
+
+		P4 ("  supernode "ID", ", s) ;
+		P4 ("col "ID" ", k1) ;
+		P4 ("to "ID". ", k2-1) ;
+		P4 ("nz in first col: "ID".\n", nsrow) ;
+
+                if (for_cholesky)
+                {
+                    P4 ("  values start "ID", ", psx) ;
+                    P4 ("end "ID"\n", psxend) ;
+                }
+
+		if (k1 > k2 || k1 < 0 || k2 > n || nsrow < nscol || nsrow2 < 0
+                    || (for_cholesky && psxend - psx != nsrow * nscol))
+		{
+		    ERR ("invalid supernode") ;
+		}
+
+		lnz += nscol * nsrow - (nscol*nscol - nscol)/2 ;
+
+		if (L->xtype != CHOLMOD_PATTERN)
+		{
+		    /* print each column of the supernode */
+		    for (jj = 0 ; jj < nscol ; jj++)
+		    {
+			ETC_ENABLE (s == nsuper-1 && jj >= nscol-3, count, -1) ;
+			j = k1 + jj ;
+			P4 ("  col "ID"\n", j) ;
+			ilast = j ;
+			i = Ls [psi + jj] ;
+			P4 ("  "I8":", i) ;
+			if (i != j)
+			{
+			    ERR ("row index invalid") ;
+			}
+
+			/* PRINTVALUE (Lx [psx + jj + jj*nsrow]) ; */
+			print_value (print, xtype, Lx, NULL,
+				psx + jj + jj*nsrow, Common) ;
+
+			P4 ("%s", "\n") ;
+			for (ii = jj + 1 ; ii < nsrow ; ii++)
+			{
+			    ETC_DISABLE (count) ;
+			    i = Ls [psi + ii] ;
+			    P4 ("  "I8":", i) ;
+			    if (i <= ilast || i > n)
+			    {
+				ERR ("row index out of range") ;
+			    }
+
+			    /* PRINTVALUE (Lx [psx + ii + jj*nsrow]) ; */
+			    print_value (print, xtype, Lx, NULL,
+				    psx + ii + jj*nsrow, Common) ;
+
+			    P4 ("%s", "\n") ;
+			    ilast = i ;
+			}
+		    }
+		}
+		else
+		{
+		    /* just print the leading column of the supernode */
+		    P4 ("  col "ID"\n", k1) ;
+		    for (jj = 0 ; jj < nscol ; jj++)
+		    {
+			ETC (s == nsuper-1 && jj >= nscol-3, count, -1) ;
+			j = k1 + jj ;
+			i = Ls [psi + jj] ;
+			P4 ("  "I8"", i) ;
+			if (i != j)
+			{
+			    ERR ("row index invalid") ;
+			}
+			P4 ("%s", "\n") ;
+		    }
+		    ilast = j ;
+		    for (ii = nscol ; ii < nsrow ; ii++)
+		    {
+			ETC_DISABLE (count) ;
+			i = Ls [psi + ii] ;
+			P4 ("  "I8"", i) ;
+			if (i <= ilast || i > n)
+			{
+			    ERR ("row index out of range") ;
+			}
+			P4 ("%s", "\n") ;
+			ilast = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    /* factor is valid */
+    P3 ("  nz "ID"", lnz) ;
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    return (TRUE) ;
+}
+
+
+int CHOLMOD(check_factor)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_factor (NULL, 0, NULL, L, Common)) ;
+}
+
+
+int CHOLMOD(print_factor)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to print */
+    const char *name,	/* printed name of factor */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_factor (NULL, Common->print, name, L, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_check_triplet ================================================ */
+/* ========================================================================== */
+
+/* Ensure a triplet matrix is valid, and optionally print it. */
+
+static int check_triplet
+(
+    Int print,
+    const char *name,
+    cholmod_triplet *T,
+    cholmod_common *Common
+)
+{
+    double *Tx, *Tz ;
+    Int *Ti, *Tj ;
+    Int i, j, p, nrow, ncol, nzmax, nz, xtype, init_print, count ;
+    const char *type = "triplet" ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print header information */
+    /* ---------------------------------------------------------------------- */
+
+    P4 ("%s", "\n") ;
+    P3 ("%s", "CHOLMOD triplet: ") ;
+    if (name != NULL)
+    {
+	P3 ("%s: ", name) ;
+    }
+
+    if (T == NULL)
+    {
+	ERR ("null") ;
+    }
+
+    nrow = T->nrow ;
+    ncol = T->ncol ;
+    nzmax = T->nzmax ;
+    nz = T->nnz ;
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    xtype = T->xtype ;
+
+
+    P3 (" "ID"", nrow) ;
+    P3 ("-by-"ID", ", ncol) ;
+    P3 ("nz "ID",", nz) ;
+    if (T->stype > 0)
+    {
+	P3 ("%s", " upper.") ;
+    }
+    else if (T->stype < 0)
+    {
+	P3 ("%s", " lower.") ;
+    }
+    else
+    {
+	P3 ("%s", " up/lo.") ;
+    }
+
+    P4 ("\n  nzmax "ID", ", nzmax) ;
+    if (nz > nzmax)
+    {
+	ERR ("nzmax too small") ;
+    }
+
+    switch (T->itype)
+    {
+	case CHOLMOD_INT:     P4 ("%s", "\n  scalar types: int, ") ; break ;
+	case CHOLMOD_INTLONG: ERR ("mixed int/long type unsupported") ;
+	case CHOLMOD_LONG:    P4 ("%s", "\n  scalar types: SuiteSparse_long, ");
+        break ;
+	default:	      ERR ("unknown itype") ;
+    }
+
+    switch (T->xtype)
+    {
+	case CHOLMOD_PATTERN: P4 ("%s", "pattern") ;	break ;
+	case CHOLMOD_REAL:    P4 ("%s", "real") ;	break ;
+	case CHOLMOD_COMPLEX: P4 ("%s", "complex") ;	break ;
+	case CHOLMOD_ZOMPLEX: P4 ("%s", "zomplex") ;	break ;
+	default:	      ERR ("unknown xtype") ;
+    }
+
+    switch (T->dtype)
+    {
+	case CHOLMOD_DOUBLE:  P4 ("%s", ", double\n") ;	       break ;
+	case CHOLMOD_SINGLE:  ERR ("single unsupported") ;
+	default:	      ERR ("unknown dtype") ;
+    }
+
+    if (T->itype != ITYPE || T->dtype != DTYPE)
+    {
+	ERR ("integer and real type must match routine") ;
+    }
+
+    if (T->stype && nrow != ncol)
+    {
+	ERR ("symmetric but not square") ;
+    }
+
+    /* check for existence of Ti, Tj, Tx arrays */
+    if (Tj == NULL)
+    {
+	ERR ("j array not present") ;
+    }
+    if (Ti == NULL)
+    {
+	ERR ("i array not present") ;
+    }
+
+    if (xtype != CHOLMOD_PATTERN && Tx == NULL)
+    {
+	ERR ("x array not present") ;
+    }
+    if (xtype == CHOLMOD_ZOMPLEX && Tz == NULL)
+    {
+	ERR ("z array not present") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* check and print each entry */
+    /* ---------------------------------------------------------------------- */
+
+    init_print = print ;
+    ETC_START (count, 8) ;
+
+    for (p = 0 ; p < nz ; p++)
+    {
+	ETC (p >= nz-4, count, -1) ;
+	i = Ti [p] ;
+	P4 ("  "I8":", p) ;
+	P4 (" "I_8"", i) ;
+	if (i < 0 || i >= nrow)
+	{
+	    ERR ("row index out of range") ;
+	}
+	j = Tj [p] ;
+	P4 (" "I_8"", j) ;
+	if (j < 0 || j >= ncol)
+	{
+	    ERR ("column index out of range") ;
+	}
+
+	print_value (print, xtype, Tx, Tz, p, Common) ;
+
+	P4 ("%s", "\n") ;
+    }
+
+    /* triplet matrix is valid */
+    P3 ("%s", "  OK\n") ;
+    P4 ("%s", "\n") ;
+    return (TRUE) ;
+}
+
+
+
+int CHOLMOD(check_triplet)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_triplet (0, NULL, T, Common)) ;
+}
+
+
+int CHOLMOD(print_triplet)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to print */
+    const char *name,	/* printed name of triplet matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    return (check_triplet (Common->print, name, T, Common)) ;
+}
+
+
+
+/* ========================================================================== */
+/* === CHOLMOD debugging routines =========================================== */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+/* The global variables present only when debugging enabled. */
+int CHOLMOD(dump) = 0 ;
+int CHOLMOD(dump_malloc) = -1 ;
+
+/* workspace: no debug routines use workspace in Common */
+
+/* ========================================================================== */
+/* === cholmod_dump_init ==================================================== */
+/* ========================================================================== */
+
+void CHOLMOD(dump_init) (const char *s, cholmod_common *Common)
+{
+    int i = 0 ;
+    FILE *f ;
+    f = fopen ("debug", "r") ;
+    CHOLMOD(dump) = 0 ;
+    if (f != NULL)
+    {
+	i = fscanf (f, "%d", &CHOLMOD(dump)) ;
+	fclose (f) ;
+    }
+    PRINT1 (("%s: cholmod_dump_init, D = %d\n", s, CHOLMOD(dump))) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_sparse ================================================== */
+/* ========================================================================== */
+
+/* returns nnz (diag (A)) or EMPTY if error */
+
+SuiteSparse_long CHOLMOD(dump_sparse)
+(
+    cholmod_sparse *A,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    Int *Wi ;
+    SuiteSparse_long nnzdiag ;
+    Int ok ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (0) ;
+    }
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    Wi = malloc (MAX (1, A->nrow) * sizeof (Int)) ;
+    ok = check_sparse (Wi, CHOLMOD(dump), name, A, &nnzdiag, Common) ;
+    if (Wi != NULL) free (Wi) ;
+    return (ok ? nnzdiag : EMPTY) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_factor ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_factor)
+(
+    cholmod_factor *L,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    Int *Wi ;
+    int ok ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    Wi = malloc (MAX (1, L->n) * sizeof (Int)) ;
+    ok = check_factor (Wi, CHOLMOD(dump), name, L, Common) ;
+    if (Wi != NULL) free (Wi) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_perm ==================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_perm)
+(
+    Int *Perm,
+    size_t len,
+    size_t n,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    Int *Wi ;
+    int ok ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Wi = malloc (MAX (1, n) * sizeof (Int)) ;
+    ok = check_perm (Wi, CHOLMOD(dump), name, Perm, len, n,Common) ;
+    if (Wi != NULL) free (Wi) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_dense =================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_dense)
+(
+    cholmod_dense *X,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_dense (CHOLMOD(dump), name, X, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_triplet ================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(dump_triplet)
+(
+    cholmod_triplet *T,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_triplet (CHOLMOD(dump), name, T, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_subset ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_subset)
+(
+    Int *S,
+    size_t len,
+    size_t n,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_subset (S, len, n, CHOLMOD(dump), name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_parent ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_parent)
+(
+    Int *Parent,
+    size_t n,
+    const char *name,
+    cholmod_common *Common
+)
+{
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    return (check_parent (Parent, n, CHOLMOD(dump), name, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_real ==================================================== */
+/* ========================================================================== */
+
+void CHOLMOD(dump_real)
+(
+    const char *name,
+    Real *X, SuiteSparse_long nrow, SuiteSparse_long ncol, int lower,
+    int xentry, cholmod_common *Common
+)
+{
+    /* dump an nrow-by-ncol real dense matrix */
+    SuiteSparse_long i, j ;
+    double x, z ;
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return ;
+    }
+    PRINT1 (("%s: dump_real, nrow: %ld ncol: %ld lower: %d\n",
+		name, nrow, ncol, lower)) ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	PRINT2 (("    col %ld\n", j)) ;
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    /* X is stored in column-major form */
+	    if (lower && i < j)
+	    {
+		PRINT2 (("        %5ld: -", i)) ;
+	    }
+	    else
+	    {
+		x = *X ;
+		PRINT2 (("        %5ld: %e", i, x)) ;
+		if (xentry == 2)
+		{
+		    z = *(X+1) ;
+		    PRINT2 ((", %e", z)) ;
+		}
+	    }
+	    PRINT2 (("\n")) ;
+	    X += xentry ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_super =================================================== */
+/* ========================================================================== */
+
+void CHOLMOD(dump_super)
+(
+    SuiteSparse_long s,
+    Int *Super, Int *Lpi, Int *Ls, Int *Lpx, double *Lx,
+    int xentry,
+    cholmod_common *Common
+)
+{
+    Int k1, k2, do_values, psi, psx, nsrow, nscol, psend, ilast, p, i ;
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return ;
+    }
+    k1 = Super [s] ;
+    k2 = Super [s+1] ;
+    nscol = k2 - k1 ;
+    do_values = (Lpx != NULL) && (Lx != NULL) ;
+    psi = Lpi [s] ;
+    psend = Lpi [s+1] ;
+    nsrow = psend - psi ;
+    PRINT1 (("\nSuper %ld, columns "ID" to "ID", "ID" rows "ID" cols\n",
+		s, k1, k2-1, nsrow, nscol)) ;
+    ilast = -1 ;
+    for (p = psi ; p < psend ; p++)
+    {
+	i = Ls [p] ;
+	PRINT2 (("  "ID" : p-psi "ID"\n", i, p-psi)) ;
+	ASSERT (IMPLIES (p-psi < nscol, i == k1 + (p-psi))) ;
+	if (p-psi == nscol-1) PRINT2 (("------\n")) ;
+	ASSERT (i > ilast) ;
+	ilast = i ;
+    }
+    if (do_values)
+    {
+	psx = Lpx [s] ;
+	CHOLMOD(dump_real) ("Supernode", Lx + xentry*psx, nsrow, nscol, TRUE, 
+		xentry, Common) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_mem ===================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_mem)
+(
+    const char *where,
+    SuiteSparse_long should,
+    cholmod_common *Common
+)
+{
+    SuiteSparse_long diff = should - Common->memory_inuse ;
+    if (diff != 0)
+    {
+	PRINT0 (("mem: %-15s peak %10g inuse %10g should %10g\n",
+	    where, (double) Common->memory_usage, (double) Common->memory_inuse,
+	    (double) should)) ;
+	PRINT0 (("mem: %s diff %ld !\n", where, diff)) ;
+    }
+    return (diff == 0) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_partition =============================================== */
+/* ========================================================================== */
+
+/* make sure we have a proper separator (for debugging only)
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(dump_partition)
+(
+    SuiteSparse_long n,
+    Int *Cp,
+    Int *Ci,
+    Int *Cnw,
+    Int *Part,
+    SuiteSparse_long sepsize,
+    cholmod_common *Common
+)
+{
+    Int chek [3], which, ok, i, j, p ;
+    PRINT1 (("bisect sepsize %ld\n", sepsize)) ;
+    ok = TRUE ;
+    chek [0] = 0 ;
+    chek [1] = 0 ;
+    chek [2] = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT2 (("--------j "ID" in part "ID" nw "ID"\n", j, Part [j], Cnw[j]));
+	which = Part [j] ;
+	for (p = Cp [j] ; p < Cp [j+1] ; p++)
+	{
+	    i = Ci [p] ;
+	    PRINT3 (("i "ID", part "ID"\n", i, Part [i])) ;
+	    if (which == 0)
+	    {
+		if (Part [i] == 1)
+		{
+		    PRINT0 (("Error! "ID" "ID"\n", i, j)) ;
+		    ok = FALSE ;
+		}
+	    }
+	    else if (which == 1)
+	    {
+		if (Part [i] == 0)
+		{
+		    PRINT0 (("Error! "ID" "ID"\n", i, j)) ;
+		    ok = FALSE ;
+		}
+	    }
+	}
+	if (which < 0 || which > 2)
+	{
+	    PRINT0 (("Part out of range\n")) ;
+	    ok = FALSE ;
+	}
+	chek [which] += Cnw [j] ;
+    }
+    PRINT1 (("sepsize %ld check "ID" "ID" "ID"\n",
+		sepsize, chek[0], chek[1],chek[2]));
+    if (sepsize != chek[2])
+    {
+	PRINT0 (("mismatch!\n")) ;
+	ok = FALSE ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dump_work ==================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(dump_work) (int flag, int head, SuiteSparse_long wsize,
+    cholmod_common *Common)
+{
+    double *W ;
+    Int *Flag, *Head ;
+    Int k, nrow, mark ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return (TRUE) ;
+    }
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    nrow = Common->nrow ;
+    Flag = Common->Flag ;
+    Head = Common->Head ;
+    W = Common->Xwork ;
+    mark = Common->mark ;
+
+    if (wsize < 0)
+    {
+	/* check all of Xwork */
+	wsize = Common->xworksize ;
+    }
+    else
+    {
+	/* check on the first wsize doubles in Xwork */
+	wsize = MIN (wsize, (Int) (Common->xworksize)) ;
+    }
+
+    if (flag)
+    {
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    if (Flag [k] >= mark)
+	    {
+		PRINT0 (("Flag invalid, Flag ["ID"] = "ID", mark = "ID"\n",
+			    k, Flag [k], mark)) ;
+		ASSERT (0) ;
+		return (FALSE) ;
+	    }
+	}
+    }
+
+    if (head)
+    {
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    if (Head [k] != EMPTY)
+	    {
+		PRINT0 (("Head invalid, Head ["ID"] = "ID"\n", k, Head [k])) ;
+		ASSERT (0) ;
+		return (FALSE) ;
+	    }
+	}
+    }
+
+    for (k = 0 ; k < wsize ; k++)
+    {
+	if (W [k] != 0.)
+	{
+	    PRINT0 (("W invalid, W ["ID"] = %g\n", k, W [k])) ;
+	    ASSERT (0) ;
+	    return (FALSE) ;
+	}
+    }
+
+    return (TRUE) ;
+}
+#endif
+#endif
diff --git a/src/CHOLMOD/Check/cholmod_read.c b/src/CHOLMOD/Check/cholmod_read.c
new file mode 100644
index 0000000..144fd60
--- /dev/null
+++ b/src/CHOLMOD/Check/cholmod_read.c
@@ -0,0 +1,1319 @@
+/* ========================================================================== */
+/* === Check/cholmod_read =================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Check Module.  Copyright (C) 2005-2006, Timothy A. Davis.
+ * The CHOLMOD/Check Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Read a sparse matrix in triplet or dense form.  A triplet matrix can be
+ * returned as compressed-column sparse matrix.  The file format is compatible
+ * with all variations of the Matrix Market "coordinate" and "array" format
+ * (http://www.nist.gov/MatrixMarket).  The format supported by these routines
+ * also allow other formats, where the Matrix Market header is optional.
+ *
+ * Although the Matrix Market header is optional, I recommend that users stick
+ * with the strict Matrix Market format.  The optional format appears here to
+ * support the reading of symmetric matrices stored with just their upper
+ * triangular parts present, for testing and development of the A->stype > 0
+ * format in CHOLMOD.  That format is not included in the Matrix Market format.
+ *
+ * If the first line of the file starts with %%MatrixMarket, then it is
+ * interpretted as a file in Matrix Market format.  This line must have
+ * the following format:
+ *
+ *	%%MatrixMarket matrix <fmt> <type> <storage>
+ *
+ *	<fmt> is one of: coordinate or array.  The former is a sparse matrix in
+ *	triplet form.  The latter is a dense matrix in column-major form.
+ *
+ *	<type> is one of: real, complex, pattern, or integer.
+ *	The functions here convert the  "integer" and "pattern" types to real.  
+ *
+ *	<storage> is one of: general, hermitian, symmetric, or skew-symmetric
+ *
+ *	The strings are case-insensitive.  Only the first character is
+ *	significant (or the first two for skew-symmetric).
+ *
+ *	<type> is ignored for all matrices; the actual type (real, complex,
+ *	or pattern) is inferred from the number of tokens in each line of the
+ *	file.  For a "coordinate" matrix: 2: pattern, 3: real, 4: complex; for
+ *	a dense "array" matrix: 1: real, 2: complex.  This is compatible with
+ *	the Matrix Market format, since pattern matrices must have two tokens
+ *	per line, real matrices must have 3, and complex matrices must have 4.
+ *	A storage of "general" implies an stype of zero (see below). 
+ *	"symmetric" and "hermitian" imply an stype of -1. Skew-symmetric and
+ *	complex symmetric matrices are always returned with both upper and lower
+ *	triangular parts present, with an stype of zero, since CHOLMOD does not
+ *	have a method for representing skew-symmetric and complex symmetric
+ *	matrices.  Real symmetric and complex Hermitian matrices may optionally
+ *	be returned with both parts present.
+ *
+ * Any other lines starting with "%" are treated as comments, and are ignored.
+ * Blank lines are ignored.  The Matrix Market header is optional in this
+ * routine (it is not optional in the Matrix Market format).
+ *
+ * Note that complex matrices are always returned in CHOLMOD_COMPLEX format,
+ * not CHOLMOD_ZOMPLEX.
+ *
+ * -----------------------------------------------------------------------------
+ * Triplet matrices:
+ * -----------------------------------------------------------------------------
+ *
+ * The first data line of a triplet matrix contains 3 or 4 integers:
+ *
+ *	nrow ncol nnz stype
+ *
+ * where stype is optional (stype does not appear in the Matrix Market format).
+ * The matrix is nrow-by-ncol.  The following nnz lines (excluding comments
+ * and blank lines) each contain a single entry.  Duplicates are permitted,
+ * and are summed in the output matrix.
+ *
+ * The stype is first derived from the Matrix Market header.  If the stype
+ * appears as the fourth integer in the first data line, it is determined from
+ * that line.
+ * 
+ * If stype is present, it denotes the storage format for the matrix.
+ * stype = 0 denotes an unsymmetric matrix (same as Matrix Market "general").
+ * stype = -1 denotes a real symmetric or complex Hermitian matrix whose lower
+ *	triangular entries are stored.  Entries may be present in the upper
+ *	triangular part, but these are ignored (same as Matrix Market
+ *	"real symmetric" and "complex Hermitian").
+ * stype = 1 denotes a real symmetric or complex Hermitian matrix whose upper
+ *	triangular entries are stored.  Entries may be present in the lower
+ *	triangular part, but these are ignored.  This option is not present
+ *	in the Matrix Market format.
+ *
+ * If stype is not present (no Matrix Market header and not in the first data
+ * line) it is inferred from the rest of the data.  If the matrix is
+ * rectangular, or has entries in both the upper and lower triangular parts,
+ * then it is assumed to be unsymmetric (stype=0).  If only entries in the
+ * lower triangular part are present, the matrix is assumed to have stype = -1.
+ * If only entries in the upper triangular part are present, the matrix is
+ * assumed to have stype = 1.
+ *
+ * After the first data line (with nrow, ncol, nnz, and optionally stype),
+ * each nonzero consists of one line with 2, 3, or 4 entries.  All lines must
+ * have the same number of entries.  The first two entries are the row and
+ * column indices of the nonzero.  If 3 entries are present, the 3rd entry is
+ * the numerical value, and the matrix is real.  If 4 entries are present,
+ * the 3rd and 4th entries in the line are the real and imaginary parts of
+ * a complex value.
+ *
+ * The matrix can be either 0-based or 1-based.  It is first assumed to be
+ * one-based (all matrices in the Matrix Market are one-based), with row indices
+ * in the range 1 to ncol and column indices in the range 1 to nrow.  If a row
+ * or column index of zero is found, the matrix is assumed to be zero-based
+ * (with row indices in the range 0 to ncol-1 and column indices in the range 0
+ * to nrow-1).
+ *
+ * If Common->prefer_binary is set to its default value of FALSE, then
+ * for symmetric pattern-only matrices, the kth diagonal (if present) is set to
+ * one plus the degree of the row/column k, and the off-diagonal entries are set
+ * to -1.  A symmetric pattern-only matrix with a zero-free diagonal is thus
+ * converted into a symmetric positive definite matrix.  All entries are set to
+ * one for an unsymmetric pattern-only matrix.  This differs from the
+ * Matrix Market format (A = mmread ('file') returns a binary pattern for A for
+ * symmetric pattern-only matrices).  If Common->prefer_binary is TRUE, then
+ * this function returns a binary matrix (just like mmread('file')).
+ *
+ * -----------------------------------------------------------------------------
+ * Dense matrices:
+ * -----------------------------------------------------------------------------
+ *
+ * A dense matrix is specified by the Matrix Market "array" format.  The
+ * Matrix Market header is optional; if not present, the matrix is assumed to
+ * be in the Matrix Market "general" format.  The first data line contains just
+ * two integers:
+ *
+ *	nrow ncol
+ *
+ * The <type> can be real, integer, or complex (not pattern).  These functions
+ * convert an integer type to real.  The entries in the matrix are stored in
+ * column-major format, with one line per entry.  Two entries are present in
+ * each line for complex matrices, one for real and integer matrices.  In
+ * rectangular and unsymmetric matrices, all entries are present.  For real
+ * symmetric or complex Hermitian matrices, only entries in the lower triangular
+ * part appear.  For skew-symmetric matrices, only entries in the strictly
+ * lower triangular part appear.
+ *
+ * Since CHOLMOD does not have a data structure for presenting dense symmetric/
+ * Hermitian matrices, these functions always return a dense matrix in its
+ * general form, with both upper and lower parts present.
+ */
+
+#ifndef NCHECK
+
+#include "cholmod_internal.h"
+#include "cholmod_check.h"
+#include <string.h>
+#include <ctype.h>
+
+/* The MatrixMarket format specificies a maximum line length of 1024 */
+#define MAXLINE 1030
+
+/* ========================================================================== */
+/* === get_line ============================================================= */
+/* ========================================================================== */
+
+/* Read one line of the file, return TRUE if successful, FALSE if EOF. */
+
+static int get_line (FILE *f, char *buf)
+{
+    buf [0] = '\0' ;
+    buf [1] = '\0' ;
+    buf [MAXLINE] = '\0' ;
+    return (fgets (buf, MAXLINE, f) != NULL) ;
+}
+
+/* ========================================================================== */
+/* === fix_inf ============================================================== */
+/* ========================================================================== */
+
+/* Replace huge values with +/- Inf's, since scanf and printf don't deal
+ * with Inf's properly.
+ */
+
+static double fix_inf (double x)
+{
+    if ((x >= HUGE_DOUBLE) || (x <= -HUGE_DOUBLE))
+    {
+	/* treat this as +/- Inf (assume 2*x leads to overflow) */
+	x = 2*x ;
+    }
+    return (x) ;
+}
+
+/* ========================================================================== */
+/* === is_blank_line ======================================================== */
+/* ========================================================================== */
+
+/* TRUE if s is a blank line or comment, FALSE otherwise */
+
+static int is_blank_line
+(
+    char *s
+)
+{
+    int c, k ;
+    if (s [0] == '%')
+    {
+	/* a comment line */
+	return (TRUE) ;
+    }
+    for (k = 0 ; k <= MAXLINE ; k++)
+    {
+	c = s [k] ;
+	if (c == '\0')
+	{
+	    /* end of line */
+	    break ;
+	}
+	if (!isspace (c))
+	{
+	    /* non-space character */
+	    return (FALSE) ;
+	}
+    }
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === read_header ========================================================== */
+/* ========================================================================== */
+
+/* Read the header.  This consists of zero or more comment lines (blank, or
+ * starting with a "%" in the first column), followed by a single data line
+ * containing up to four numerical values.
+ *
+ * The first line may optionally be a Matrix Market header line, of the form
+ *
+ *	%%MatrixMarket matrix <fmt> <type> <storage>
+ *
+ * The first data line of a sparse matrix in triplet form consists of 3 or 4
+ * numerical values:
+ *
+ *	nrow ncol nnz stype
+ *
+ * where stype is optional (it does not appear in the Matrix Market file
+ * format).  The first line of a dense matrix in column-major form consists of
+ * two numerical values:
+ *
+ *	nrow ncol
+ *
+ * The stype of the matrix is determine either from the Matrix Market header,
+ * or (optionally) from the first data line.  stypes of 0 to -3 directly
+ * correlate with the Matrix Market format; stype = 1 is an extension to that
+ * format.
+ *
+ *	999: unknown (will be inferred from the data)
+ *	1: real symmetric or complex Hermitian with upper part stored
+ *		(not in the Matrix Market format)
+ *	0: unsymmetric (same as Matrix Market "general")
+ *	-1: real symmetric or complex Hermitian, with lower part stored
+ *		(Matrix Market "real symmetric" or "complex hermitian")
+ *	-2: real or complex skew symmetric (lower part stored, can only be
+ *		specified by Matrix Market header)
+ *	-3: complex symmetric (lower part stored)
+ *		specified by Matrix Market header)
+ *
+ * The Matrix Market header is optional.  If stype appears in the first data
+ * line, it is determine by that data line.  Otherwise, if the Matrix Market
+ * header appears, stype is determined from that header.  If stype does not
+ * appear, it is set to "unknown" (999).
+ */
+
+#define STYPE_UNKNOWN 999
+#define STYPE_SYMMETRIC_UPPER 1
+#define STYPE_UNSYMMETRIC 0
+#define STYPE_SYMMETRIC_LOWER -1
+#define STYPE_SKEW_SYMMETRIC -2
+#define STYPE_COMPLEX_SYMMETRIC_LOWER -3
+
+static int read_header	/* returns TRUE if successful, FALSE on error */
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from */
+    /* ---- output --- */
+    char *buf,		/* a character array of size MAXLINE+1 */
+    int *mtype,		/* CHOLMOD_TRIPLET or CHOLMOD_DENSE */
+    size_t *nrow,	/* number of rows in the matrix */
+    size_t *ncol,	/* number of columns in the matrix */
+    size_t *nnz,	/* number of entries in a triplet matrix (0 for dense)*/
+    int *stype		/* stype (see above) */
+)
+{
+    char *p ;
+    int first = TRUE, got_mm_header = FALSE, c, c2, is_complex, nitems ;
+    double l1, l2, l3, l4 ;
+
+    *mtype = CHOLMOD_TRIPLET ;
+    *nrow = 0 ;
+    *ncol = 0 ;
+    *nnz = 0 ;
+    *stype = STYPE_UNKNOWN ;
+
+    for ( ; ; )
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the next line */
+	/* ------------------------------------------------------------------ */
+
+	if (!get_line (f, buf))
+	{
+	    /* premature end of file */
+	    return (FALSE) ;
+	}
+
+	if (first && (strncmp (buf, "%%MatrixMarket", 14) == 0))
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* read a Matrix Market header */
+	    /* -------------------------------------------------------------- */
+
+	    got_mm_header = TRUE ;
+	    p = buf ;
+
+	    /* -------------------------------------------------------------- */
+	    /* get "matrix" token */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    if (c != 'm')
+	    {
+		/* bad format */
+		return (FALSE) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* get the fmt token ("coord" or "array") */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    if (c == 'c')
+	    {
+		*mtype = CHOLMOD_TRIPLET  ;
+	    }
+	    else if (c == 'a')
+	    {
+		*mtype = CHOLMOD_DENSE  ;
+	    }
+	    else
+	    {
+		/* bad format, neither "coordinate" nor "array" */
+		return (FALSE) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* get type token (real, pattern, complex, integer) */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    if (!(c == 'r' || c == 'p' || c == 'c' || c == 'i'))
+	    {
+		/* bad format */
+		return (FALSE) ;
+	    }
+	    is_complex = (c == 'c') ;
+
+	    /* -------------------------------------------------------------- */
+	    /* get storage token (general, hermitian, symmetric, skew) */
+	    /* -------------------------------------------------------------- */
+
+	    while (*p && !isspace (*p)) p++ ;
+	    while (*p &&  isspace (*p)) p++ ;
+	    c = tolower (*p) ;
+	    c2 = tolower (*(p+1)) ;
+	    if (c == 'g')
+	    {
+		/* "general" storage (unsymmetric matrix), both parts present */
+		*stype = STYPE_UNSYMMETRIC ;
+	    }
+	    else if (c == 's' && c2 == 'y')
+	    {
+		/* "symmetric" */
+		if (is_complex)
+		{
+		    /* complex symmetric, lower triangular part present */
+		    *stype = STYPE_COMPLEX_SYMMETRIC_LOWER ;
+		}
+		else
+		{
+		    /* real symmetric, lower triangular part present */
+		    *stype = STYPE_SYMMETRIC_LOWER ;
+		}
+	    }
+	    else if (c == 'h')
+	    {
+		/* "hermitian" matrix, lower triangular part present */
+		*stype = STYPE_SYMMETRIC_LOWER ;
+	    }
+	    else if (c == 's' && c2 == 'k')
+	    {
+		/* "skew-symmetric" (real or complex), lower part present */
+		*stype = STYPE_SKEW_SYMMETRIC ;
+	    }
+	    else
+	    {
+		/* bad format */
+		return (FALSE) ;
+	    }
+
+	}
+	else if (is_blank_line (buf))
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* blank line or comment line */
+	    /* -------------------------------------------------------------- */
+
+	    continue ;
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* read the first data line and return */
+	    /* -------------------------------------------------------------- */
+
+	    /* format: nrow ncol nnz stype */
+	    l1 = EMPTY ;
+	    l2 = EMPTY ;
+	    l3 = 0 ;
+	    l4 = 0 ;
+	    nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &l3, &l4) ;
+	    if (nitems < 2 || nitems > 4 || l1 > Int_max || l2 > Int_max)
+	    {
+		/* invalid matrix */
+		return (FALSE) ;
+	    }
+	    *nrow = l1 ;
+	    *ncol = l2 ;
+	    if (nitems == 2)
+	    {
+		/* a dense matrix */
+		if (!got_mm_header)
+		{
+		    *mtype = CHOLMOD_DENSE ;
+		    *stype = STYPE_UNSYMMETRIC ;
+		}
+	    }
+	    if (nitems == 3 || nitems == 4)
+	    {
+		/* a sparse triplet matrix */
+		*nnz = l3 ;
+		if (!got_mm_header)
+		{
+		    *mtype = CHOLMOD_TRIPLET ;
+		}
+	    }
+	    if (nitems == 4)
+	    {
+		/* an stype specified here can only be 1, 0, or -1 */
+		if (l4 < 0)
+		{
+		    *stype = STYPE_SYMMETRIC_LOWER ;
+		}
+		else if (l4 > 0)
+		{
+		    *stype = STYPE_SYMMETRIC_UPPER ;
+		}
+		else
+		{
+		    *stype = STYPE_UNSYMMETRIC ;
+		}
+	    }
+	    if (*nrow != *ncol)
+	    {
+		/* a rectangular matrix must be unsymmetric */
+		*stype = STYPE_UNSYMMETRIC ;
+	    }
+	    return (TRUE) ;
+	}
+
+	first = FALSE ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === read_triplet ========================================================= */
+/* ========================================================================== */
+
+/* Header has already been read in, including first line (nrow ncol nnz stype).
+ * Read the triplets. */
+
+static cholmod_triplet *read_triplet
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to read from, must already be open */
+    size_t nrow,	    /* number of rows */
+    size_t ncol,	    /* number of columns */
+    size_t nnz,		    /* number of triplets in file to read */
+    int stype,		    /* stype from header, or "unknown" */
+    int prefer_unsym,	    /* if TRUE, always return T->stype of zero */
+    /* ---- workspace */
+    char *buf,		    /* of size MAXLINE+1 */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    double *Tx ;
+    Int *Ti, *Tj, *Rdeg, *Cdeg ;
+    cholmod_triplet *T ;
+    double l1, l2 ;
+    Int nitems, xtype, unknown, k, nshould, is_lower, is_upper, one_based, i, j,
+	imax, jmax, skew_symmetric, p, complex_symmetric ;
+    size_t s, nnz2, extra ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return for empty matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow == 0 || ncol == 0 || nnz == 0)
+    {
+	/* return an empty matrix */
+	return (CHOLMOD(allocate_triplet) (nrow, ncol, 0, 0, CHOLMOD_REAL,
+		    Common)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* special stype cases: unknown, skew symmetric, and complex symmetric  */
+    /* ---------------------------------------------------------------------- */
+
+    unknown = (stype == STYPE_UNKNOWN) ;
+    skew_symmetric = (stype == STYPE_SKEW_SYMMETRIC) ;
+    complex_symmetric = (stype == STYPE_COMPLEX_SYMMETRIC_LOWER) ;
+
+    extra = 0 ;
+    if (stype < STYPE_SYMMETRIC_LOWER
+	|| (prefer_unsym && stype != STYPE_UNSYMMETRIC))
+    {
+	/* 999: unknown might be converted to unsymmetric */
+	/*  1:  symmetric upper converted to unsym. if prefer_unsym is TRUE */
+	/* -1:  symmetric lower converted to unsym. if prefer_unsym is TRUE */
+	/* -2:  real or complex skew symmetric converted to unsymmetric */
+	/* -3:  complex symmetric converted to unsymmetric */
+	stype = STYPE_UNSYMMETRIC ;
+	extra = nnz ;
+    }
+    nnz2 = CHOLMOD(add_size_t) (nnz, extra, &ok) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = nrow + ncol */
+    s = CHOLMOD(add_size_t) (nrow, ncol, &ok) ;
+    if (!ok || nrow > Int_max || ncol > Int_max || nnz > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    Rdeg = Common->Iwork ;	/* size nrow */
+    Cdeg = Rdeg + nrow ;	/* size ncol */
+
+    /* ---------------------------------------------------------------------- */
+    /* read the triplets */
+    /* ---------------------------------------------------------------------- */
+
+    is_lower = TRUE ;
+    is_upper = TRUE ;
+    one_based = TRUE ;
+    imax = 0 ;
+    jmax = 0 ;
+
+    Tx = NULL ;
+    Ti = NULL ;
+    Tj = NULL ;
+    xtype = 999 ;
+    nshould = 0 ;
+
+    for (k = 0 ; k < (Int) nnz ; k++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the next triplet, skipping blank lines and comment lines */
+	/* ------------------------------------------------------------------ */
+
+	l1 = EMPTY ;
+	l2 = EMPTY ;
+	x = 0 ;
+	z = 0 ;
+
+	for ( ; ; )
+	{
+	    if (!get_line (f, buf))
+	    {
+		/* premature end of file - not enough triplets read in */
+		ERROR (CHOLMOD_INVALID, "premature EOF") ;
+		return (NULL) ;
+	    }
+	    if (is_blank_line (buf))
+	    {
+		/* blank line or comment */
+		continue ;
+	    }
+	    nitems = sscanf (buf, "%lg %lg %lg %lg\n", &l1, &l2, &x, &z) ;
+	    x = fix_inf (x) ;
+	    z = fix_inf (z) ;
+	    break ;
+	}
+
+	nitems = (nitems == EOF) ? 0 : nitems ;
+	i = l1 ;
+	j = l2 ;
+
+	/* ------------------------------------------------------------------ */
+	/* for first triplet: determine type and allocate triplet matrix */
+	/* ------------------------------------------------------------------ */
+
+	if (k == 0)
+	{
+	    if (nitems < 2 || nitems > 4)
+	    {
+		/* invalid matrix */
+		ERROR (CHOLMOD_INVALID, "invalid format") ;
+		return (NULL) ;
+	    }
+	    else if (nitems == 2)
+	    {
+		/* this will be converted into a real matrix later */
+		xtype = CHOLMOD_PATTERN ;
+	    }
+	    else if (nitems == 3)
+	    {
+		xtype = CHOLMOD_REAL ;
+	    }
+	    else if (nitems == 4)
+	    {
+		xtype = CHOLMOD_COMPLEX ;
+	    }
+
+	    /* the rest of the lines should have the same number of entries */
+	    nshould = nitems ;
+
+	    /* allocate triplet matrix */
+	    T = CHOLMOD(allocate_triplet) (nrow, ncol, nnz2, stype,
+		    (xtype == CHOLMOD_PATTERN ? CHOLMOD_REAL : xtype), Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		/* out of memory */
+		return (NULL) ;
+	    }
+	    Ti = T->i ;
+	    Tj = T->j ;
+	    Tx = T->x ;
+	    T->nnz = nnz ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* save the entry in the triplet matrix */
+	/* ------------------------------------------------------------------ */
+
+	if (nitems != nshould || i < 0 || j < 0)
+	{
+	    /* wrong format, premature end-of-file, or negative indices */
+	    CHOLMOD(free_triplet) (&T, Common) ;
+	    ERROR (CHOLMOD_INVALID, "invalid matrix file") ;
+	    return (NULL) ;
+	}
+
+	Ti [k] = i ;
+	Tj [k] = j ;
+
+	if (i < j)
+	{
+	    /* this entry is in the upper triangular part */
+	    is_lower = FALSE ;
+	}
+	if (i > j)
+	{
+	    /* this entry is in the lower triangular part */
+	    is_upper = FALSE ;
+	}
+
+	if (xtype == CHOLMOD_REAL)
+	{
+	    Tx [k] = x ;
+	}
+	else if (xtype == CHOLMOD_COMPLEX)
+	{
+	    Tx [2*k  ] = x ;	/* real part */
+	    Tx [2*k+1] = z ;	/* imaginary part */
+	}
+
+	if (i == 0 || j == 0)
+	{
+	    one_based = FALSE ;
+	}
+
+	imax = MAX (i, imax) ;
+	jmax = MAX (j, jmax) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to zero-based */
+    /* ---------------------------------------------------------------------- */
+
+    if (one_based)
+    {
+	/* input matrix is one-based; convert matrix to zero-based */
+	for (k = 0 ; k < (Int) nnz ; k++)
+	{
+	    Ti [k]-- ;
+	    Tj [k]-- ;
+	}
+    }
+
+    if (one_based ?
+	(imax >  (Int) nrow || jmax >  (Int) ncol) :
+	(imax >= (Int) nrow || jmax >= (Int) ncol))
+    {
+	/* indices out of range */
+	CHOLMOD(free_triplet) (&T, Common) ;
+	ERROR (CHOLMOD_INVALID, "indices out of range") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the stype, if not yet known */
+    /* ---------------------------------------------------------------------- */
+
+    if (unknown)
+    {
+	if (is_lower && is_upper)
+	{
+	    /* diagonal matrix, symmetric with upper part present */
+	    stype = STYPE_SYMMETRIC_UPPER ;
+	}
+	else if (is_lower && !is_upper)
+	{
+	    /* symmetric, lower triangular part present */
+	    stype = STYPE_SYMMETRIC_LOWER ;
+	}
+	else if (!is_lower && is_upper)
+	{
+	    /* symmetric, upper triangular part present */
+	    stype = STYPE_SYMMETRIC_UPPER ;
+	}
+	else
+	{
+	    /* unsymmetric */
+	    stype = STYPE_UNSYMMETRIC ;
+	    extra = 0 ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* add the remainder of symmetric, skew-symmetric or Hermitian matrices */
+    /* ---------------------------------------------------------------------- */
+
+    /* note that this step is not done for real symmetric or complex Hermitian
+     * matrices, unless prefer_unsym is TRUE */
+    if (extra > 0)
+    {
+	p = nnz ;
+	for (k = 0 ; k < (Int) nnz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i != j)
+	    {
+		Ti [p] = j ;
+		Tj [p] = i ;
+		if (xtype == CHOLMOD_REAL)
+		{
+		    if (skew_symmetric)
+		    {
+			Tx [p] = -Tx [k] ;
+		    }
+		    else
+		    {
+			Tx [p] =  Tx [k] ;
+		    }
+		}
+		else if (xtype == CHOLMOD_COMPLEX)
+		{
+		    if (skew_symmetric)
+		    {
+			Tx [2*p  ] = -Tx [2*k ] ;
+			Tx [2*p+1] = -Tx [2*k+1] ;
+		    }
+		    else if (complex_symmetric)
+		    {
+			Tx [2*p  ] =  Tx [2*k ] ;
+			Tx [2*p+1] =  Tx [2*k+1] ;
+		    }
+		    else /* Hermitian */
+		    {
+			Tx [2*p  ] =  Tx [2*k ] ;
+			Tx [2*p+1] = -Tx [2*k+1] ;
+		    }
+		}
+		p++ ;
+	    }
+	}
+	T->nnz = p ;
+	nnz = p ;
+    }
+
+    T->stype = stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* create values for a pattern-only matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (xtype == CHOLMOD_PATTERN)
+    {
+	if (stype == STYPE_UNSYMMETRIC || Common->prefer_binary)
+	{
+	    /* unsymmetric case, or binary case */
+	    for (k = 0 ; k < (Int) nnz ; k++)
+	    {
+		Tx [k] = 1 ;
+	    }
+	}
+	else
+	{
+	    /* compute the row and columm degrees (excluding the diagonal) */
+	    for (i = 0 ; i < (Int) nrow ; i++)
+	    {
+		Rdeg [i] = 0 ;
+	    }
+	    for (j = 0 ; j < (Int) ncol ; j++)
+	    {
+		Cdeg [j] = 0 ;
+	    }
+	    for (k = 0 ; k < (Int) nnz ; k++)
+	    {
+		i = Ti [k] ;
+		j = Tj [k] ;
+		if ((stype < 0 && i > j) || (stype > 0 && i < j))
+		{
+		    /* both a(i,j) and a(j,i) appear in the matrix */
+		    Rdeg [i]++ ;
+		    Cdeg [j]++ ;
+		    Rdeg [j]++ ;
+		    Cdeg [i]++ ;
+		}
+	    }
+	    /* assign the numerical values */
+	    for (k = 0 ; k < (Int) nnz ; k++)
+	    {
+		i = Ti [k] ;
+		j = Tj [k] ;
+		Tx [k] = (i == j) ? (1 + MAX (Rdeg [i], Cdeg [j])) : (-1) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the new triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (T) ;
+}
+
+
+/* ========================================================================== */
+/* === read_dense =========================================================== */
+/* ========================================================================== */
+
+/* Header has already been read in, including first line (nrow ncol).
+ * Read a dense matrix. */
+
+static cholmod_dense *read_dense
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to read from, must already be open */
+    size_t nrow,	    /* number of rows */
+    size_t ncol,	    /* number of columns */
+    int stype,		    /* stype from header */
+    /* ---- workspace */
+    char *buf,		    /* of size MAXLINE+1 */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    double *Xx = NULL ;
+    cholmod_dense *X ;
+    Int nitems, xtype = -1, nshould = 0, i, j, k, kup, first ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return for empty matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow == 0 || ncol == 0)
+    {
+	/* return an empty dense matrix */
+	return (CHOLMOD(zeros) (nrow, ncol, CHOLMOD_REAL, Common)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the entries */
+    /* ---------------------------------------------------------------------- */
+
+    first = TRUE ;
+
+    for (j = 0 ; j < (Int) ncol ; j++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the row index of the first entry in the file for column j */
+	/* ------------------------------------------------------------------ */
+
+	if (stype == STYPE_UNSYMMETRIC)
+	{
+	    i = 0 ;
+	}
+	else if (stype == STYPE_SKEW_SYMMETRIC)
+	{
+	    i = j+1 ;
+	}
+	else /* real symmetric or complex Hermitian lower */
+	{
+	    i = j ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* get column j */
+	/* ------------------------------------------------------------------ */
+
+	for ( ; i < (Int) nrow ; i++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* get the next entry, skipping blank lines and comment lines */
+	    /* -------------------------------------------------------------- */
+
+	    x = 0 ;
+	    z = 0 ;
+	    for ( ; ; )
+	    {
+
+		if (!get_line (f, buf))
+		{
+		    /* premature end of file - not enough entries read in */
+		    ERROR (CHOLMOD_INVALID, "premature EOF") ;
+		    return (NULL) ;
+		}
+
+		if (is_blank_line (buf))
+		{
+		    /* blank line or comment */
+		    continue ;
+		}
+		nitems = sscanf (buf, "%lg %lg\n", &x, &z) ;
+		x = fix_inf (x) ;
+		z = fix_inf (z) ;
+		break ;
+	    }
+
+	    nitems = (nitems == EOF) ? 0 : nitems ;
+
+	    /* -------------------------------------------------------------- */
+	    /* for first entry: determine type and allocate dense matrix */
+	    /* -------------------------------------------------------------- */
+
+	    if (first)
+	    {
+		first = FALSE ;
+
+		if (nitems < 1 || nitems > 2)
+		{
+		    /* invalid matrix */
+		    ERROR (CHOLMOD_INVALID, "invalid format") ;
+		    return (NULL) ;
+		}
+		else if (nitems == 1)
+		{
+		    /* a real matrix */
+		    xtype = CHOLMOD_REAL ;
+		}
+		else if (nitems == 2)
+		{
+		    /* a complex matrix */
+		    xtype = CHOLMOD_COMPLEX ;
+		}
+
+		/* the rest of the lines should have same number of entries */
+		nshould = nitems ;
+
+		/* allocate the result */
+		X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ;
+		if (Common->status < CHOLMOD_OK)
+		{
+		    /* out of memory */
+		    return (NULL) ;
+		}
+		Xx = X->x ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* save the entry in the dense matrix */
+	    /* -------------------------------------------------------------- */
+
+	    if (nitems != nshould)
+	    {
+		/* wrong format or premature end-of-file */
+		CHOLMOD(free_dense) (&X, Common) ;
+		ERROR (CHOLMOD_INVALID, "invalid matrix file") ;
+		return (NULL) ;
+	    }
+
+	    k = i + j*nrow ;
+	    kup = j + i*nrow ;
+
+	    if (xtype == CHOLMOD_REAL)
+	    {
+		/* real matrix */
+		Xx [k] = x ;
+		if (k != kup)
+		{
+		    if (stype == STYPE_SYMMETRIC_LOWER)
+		    {
+			/* real symmetric matrix */
+			Xx [kup] = x ;
+		    }
+		    else if (stype == STYPE_SKEW_SYMMETRIC)
+		    {
+			/* real skew symmetric matrix */
+			Xx [kup] = -x ;
+		    }
+		}
+	    }
+	    else if (xtype == CHOLMOD_COMPLEX)
+	    {
+		Xx [2*k  ] = x ;	    /* real part */
+		Xx [2*k+1] = z ;	    /* imaginary part */
+		if (k != kup)
+		{
+		    if (stype == STYPE_SYMMETRIC_LOWER)
+		    {
+			/* complex Hermitian */
+			Xx [2*kup  ] = x ;	    /* real part */
+			Xx [2*kup+1] = -z ;	    /* imaginary part */
+		    }
+		    else if (stype == STYPE_SKEW_SYMMETRIC)
+		    {
+			/* complex skew symmetric */
+			Xx [2*kup  ] = -x ;	    /* real part */
+			Xx [2*kup+1] = -z ;	    /* imaginary part */
+		    }
+		    if (stype == STYPE_COMPLEX_SYMMETRIC_LOWER)
+		    {
+			/* complex symmetric */
+			Xx [2*kup  ] = x ;	    /* real part */
+			Xx [2*kup+1] = z ;	    /* imaginary part */
+		    }
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the new dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_triplet ================================================= */
+/* ========================================================================== */
+
+/* Read in a triplet matrix from a file. */
+
+cholmod_triplet *CHOLMOD(read_triplet)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    char buf [MAXLINE+1] ;
+    size_t nrow, ncol, nnz ;
+    int stype, mtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* read the header and first data line */
+    /* ---------------------------------------------------------------------- */
+
+    if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) ||
+	mtype != CHOLMOD_TRIPLET)
+    {
+	/* invalid matrix - this function can only read in a triplet matrix */
+	ERROR (CHOLMOD_INVALID, "invalid format") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (read_triplet (f, nrow, ncol, nnz, stype, FALSE, buf, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_sparse ================================================== */
+/* ========================================================================== */
+
+/* Read a sparse matrix from a file.  See cholmod_read_triplet for a discussion
+ * of the file format.
+ *
+ * If Common->prefer_upper is TRUE (the default case), a symmetric matrix is
+ * returned stored in upper-triangular form (A->stype == 1).
+ */
+
+cholmod_sparse *CHOLMOD(read_sparse)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A, *A2 ;
+    cholmod_triplet *T ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to a sparse matrix in compressed-column form */
+    /* ---------------------------------------------------------------------- */
+
+    T = CHOLMOD(read_triplet) (f, Common) ;
+    A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ;
+    CHOLMOD(free_triplet) (&T, Common) ;
+
+    if (Common->prefer_upper && A != NULL && A->stype == -1)
+    {
+	/* A=A' */
+	A2 = CHOLMOD(transpose) (A, 2, Common) ;
+	CHOLMOD(free_sparse) (&A, Common) ;
+	A = A2 ;
+    }
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_dense =================================================== */
+/* ========================================================================== */
+
+/* Read a dense matrix from a file. */
+
+cholmod_dense *CHOLMOD(read_dense)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    char buf [MAXLINE+1] ;
+    size_t nrow, ncol, nnz ;
+    int stype, mtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* read the header and first data line */
+    /* ---------------------------------------------------------------------- */
+
+    if (!read_header (f, buf, &mtype, &nrow, &ncol, &nnz, &stype) ||
+	mtype != CHOLMOD_DENSE)
+    {
+	/* invalid matrix - this function can only read in a dense matrix */
+	ERROR (CHOLMOD_INVALID, "invalid format") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read the dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (read_dense (f, nrow, ncol, stype, buf, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_read_matrix ================================================== */
+/* ========================================================================== */
+
+/* Read a triplet matrix, sparse matrix or a dense matrix from a file.  Returns
+ * a void pointer to either a cholmod_triplet, cholmod_sparse, or cholmod_dense
+ * object.  The type of object is passed back to the caller as the mtype
+ * argument. */
+
+void *CHOLMOD(read_matrix)
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    int prefer,		/* If 0, a sparse matrix is always return as a
+			 *	cholmod_triplet form.  It can have any stype
+			 *	(symmetric-lower, unsymmetric, or
+			 *	symmetric-upper).
+			 * If 1, a sparse matrix is returned as an unsymmetric
+			 *	cholmod_sparse form (A->stype == 0), with both
+			 *	upper and lower triangular parts present.
+			 *	This is what the MATLAB mread mexFunction does,
+			 *	since MATLAB does not have an stype.
+			 * If 2, a sparse matrix is returned with an stype of 0
+			 *	or 1 (unsymmetric, or symmetric with upper part
+			 *	stored).
+			 * This argument has no effect for dense matrices.
+			 */
+    /* ---- output---- */
+    int *mtype,		/* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    void *G = NULL ;
+    cholmod_sparse *A, *A2 ;
+    cholmod_triplet *T ;
+    char buf [MAXLINE+1] ;
+    size_t nrow, ncol, nnz ;
+    int stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (f, NULL) ;
+    RETURN_IF_NULL (mtype, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* read the header to determine the mtype */
+    /* ---------------------------------------------------------------------- */
+
+    if (!read_header (f, buf, mtype, &nrow, &ncol, &nnz, &stype))
+    {
+	/* invalid matrix */
+	ERROR (CHOLMOD_INVALID, "invalid format") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* read a matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (*mtype == CHOLMOD_TRIPLET)
+    {
+	/* read in the triplet matrix, converting to unsymmetric format if
+	 * prefer == 1 */
+	T = read_triplet (f, nrow, ncol, nnz, stype, prefer == 1, buf, Common) ;
+	if (prefer == 0)
+	{
+	    /* return matrix in its original triplet form */
+	    G = T ;
+	}
+	else
+	{
+	    /* return matrix in a compressed-column form */
+	    A = CHOLMOD(triplet_to_sparse) (T, 0, Common) ;
+	    CHOLMOD(free_triplet) (&T, Common) ;
+	    if (A != NULL && prefer == 2 && A->stype == -1)
+	    {
+		/* convert A from symmetric-lower to symmetric-upper */
+		A2 = CHOLMOD(transpose) (A, 2, Common) ;
+		CHOLMOD(free_sparse) (&A, Common) ;
+		A = A2 ;
+	    }
+	    *mtype = CHOLMOD_SPARSE ;
+	    G = A ;
+	}
+    }
+    else if (*mtype == CHOLMOD_DENSE)
+    {
+	/* return a dense matrix */
+	G = read_dense (f, nrow, ncol, stype, buf, Common) ;
+    }
+    return (G) ;
+}
+#endif
diff --git a/src/CHOLMOD/Check/cholmod_write.c b/src/CHOLMOD/Check/cholmod_write.c
new file mode 100644
index 0000000..eb578f9
--- /dev/null
+++ b/src/CHOLMOD/Check/cholmod_write.c
@@ -0,0 +1,744 @@
+/* ========================================================================== */
+/* === Check/cholmod_write ================================================== */
+/* ========================================================================== */
+
+/* Write a matrix to a file in Matrix Market form.
+ *
+ * A can be sparse or full.
+ *
+ * If present and non-empty, A and Z must have the same dimension.  Z contains
+ * the explicit zero entries in the matrix (which MATLAB drops).  The entries
+ * of Z appear as explicit zeros in the output file.  Z is optional.  If it is
+ * an empty matrix it is ignored.  Z must be sparse or empty, if present.
+ * It is ignored if A is full.
+ *
+ * filename is the name of the output file.  comments is file whose
+ * contents are include after the Matrix Market header and before the first
+ * data line.  Ignored if an empty string or not present.
+ *
+ * Except for the workspace used by cholmod_symmetry (ncol integers) for
+ * the sparse case, these routines use no workspace at all.
+ */
+
+#ifndef NCHECK
+
+#include "cholmod_internal.h"
+#include "cholmod_check.h"
+#include "cholmod_matrixops.h"
+#include <string.h>
+#include <ctype.h>
+
+#define MMLEN 1024
+#define MAXLINE MMLEN+6
+
+/* ========================================================================== */
+/* === include_comments ===================================================== */
+/* ========================================================================== */
+
+/* Read in the comments file, if it exists, and copy it to the Matrix Market
+ * file.  A "%" is prepended to each line.  Returns TRUE if successful, FALSE
+ * otherwise.
+ */
+
+static int include_comments (FILE *f, const char *comments)
+{
+    FILE *cf = NULL ;
+    char buffer [MAXLINE] ;
+    int ok = TRUE ;
+    if (comments != NULL && comments [0] != '\0')
+    {
+	cf = fopen (comments, "r") ;
+	if (cf == NULL)
+	{
+	    return (FALSE) ;
+	}
+	while (ok && fgets (buffer, MAXLINE, cf) != NULL)
+	{
+	    /* ensure the line is not too long */
+	    buffer [MMLEN-1] = '\0' ;
+	    buffer [MMLEN-2] = '\n' ;
+	    ok = ok && (fprintf (f, "%%%s", buffer) > 0) ;
+	}
+	fclose (cf) ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === get_value ============================================================ */
+/* ========================================================================== */
+
+/* Get the pth value in the matrix. */
+
+static void get_value
+(
+    double *Ax,	    /* real values, or real/imag. for CHOLMOD_COMPLEX type */
+    double *Az,	    /* imaginary values for CHOLMOD_ZOMPLEX type */
+    Int p,	    /* get the pth entry */
+    Int xtype,	    /* A->xtype: pattern, real, complex, or zomplex */
+    double *x,	    /* the real part */
+    double *z	    /* the imaginary part */
+)
+{
+    switch (xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    *x = 1 ;
+	    *z = 0 ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    *x = Ax [p] ;
+	    *z = 0 ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    *x = Ax [2*p] ;
+	    *z = Ax [2*p+1] ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    *x = Ax [p] ;
+	    *z = Az [p] ;
+	    break ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === print_value ========================================================== */
+/* ========================================================================== */
+
+/* Print a numeric value to the file, using the shortest format that ensures
+ * the value is written precisely.  Returns TRUE if successful, FALSE otherwise.
+ */ 
+
+static int print_value
+(
+    FILE *f,	    /* file to print to */
+    double x,	    /* value to print */
+    Int is_integer  /* TRUE if printing as an integer */
+)
+{
+    double y ;
+    char s [MAXLINE], *p ;
+    Int i, dest = 0, src = 0 ;
+    int width, ok ;
+
+    if (is_integer)
+    {
+	i = (Int) x ;
+	ok = (fprintf (f, ID, i) > 0) ;
+	return (ok) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* handle Inf and NaN */
+    /* ---------------------------------------------------------------------- */
+
+    /* change -inf to -HUGE_DOUBLE, and change +inf and nan to +HUGE_DOUBLE */
+    if (CHOLMOD_IS_NAN (x) || x >= HUGE_DOUBLE)
+    {
+	x = HUGE_DOUBLE ;
+    }
+    else if (x <= -HUGE_DOUBLE)
+    {
+	x = -HUGE_DOUBLE ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the smallest acceptable precision */
+    /* ---------------------------------------------------------------------- */
+
+    for (width = 6 ; width < 20 ; width++)
+    {
+	sprintf (s, "%.*g", width, x) ;
+	sscanf (s, "%lg", &y) ;
+	if (x == y) break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* shorten the string */
+    /* ---------------------------------------------------------------------- */
+
+    /* change "e+0" to "e", change "e+" to "e", and change "e-0" to "e-" */
+    for (i = 0 ; i < MAXLINE && s [i] != '\0' ; i++)
+    {
+	if (s [i] == 'e')
+	{
+	    if (s [i+1] == '+')
+	    {
+		dest = i+1 ;
+		if (s [i+2] == '0')
+		{
+		    /* delete characters s[i+1] and s[i+2] */
+		    src = i+3 ;
+		}
+		else
+		{
+		    /* delete characters s[i+1] */
+		    src = i+2 ;
+		}
+	    }
+	    else if (s [i+1] == '-')
+	    {
+		dest = i+2 ;
+		if (s [i+2] == '0')
+		{
+		    /* delete character s[i+2] */
+		    src = i+3 ;
+		}
+		else
+		{
+		    /* no change */
+		    break ;
+		}
+	    }
+	    while (s [src] != '\0')
+	    {
+		s [dest++] = s [src++] ;
+	    }
+	    s [dest] = '\0' ;
+	    break ;
+	}
+    }
+
+    /* delete the leading "0" if present and not necessary */
+    p = s ;
+    s [MAXLINE-1] = '\0' ;
+    i = strlen (s) ;
+    if (i > 2 && s [0] == '0' && s [1] == '.')
+    {
+	/* change "0.x" to ".x" */
+	p = s + 1 ;
+    }
+    else if (i > 3 && s [0] == '-' && s [1] == '0' && s [2] == '.')
+    {
+	/* change "-0.x" to "-.x" */
+	s [1] = '-' ;
+	p = s + 1 ;
+    }
+
+#if 0
+    /* double-check */
+    i = sscanf (p, "%lg", &z) ;
+    if (i != 1 || y != z)
+    {
+	/* oops! something went wrong in the "e+0" edit, above. */
+	/* this "cannot" happen */
+	sprintf (s, "%.*g", width, x) ;
+	p = s ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* print the value to the file */
+    /* ---------------------------------------------------------------------- */
+
+    ok = (fprintf (f, "%s", p) > 0) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === print_triplet ======================================================== */
+/* ========================================================================== */
+
+/* Print a triplet, converting it to one-based.  Returns TRUE if successful,
+ * FALSE otherwise.
+ */
+
+static int print_triplet
+(
+    FILE *f,		/* file to print to */
+    Int is_binary,	/* TRUE if file is "pattern" */
+    Int is_complex,	/* TRUE if file is "complex" */
+    Int is_integer,	/* TRUE if file is "integer" */
+    Int i,		/* row index (zero-based) */
+    Int j,		/* column index (zero-based) */
+    double x,		/* real part */
+    double z		/* imaginary part */
+)
+{
+    int ok ; 
+    ok = (fprintf (f, ID " " ID, 1+i, 1+j) > 0) ;
+    if (!is_binary)
+    {
+	fprintf (f, " ") ;
+	ok = ok && print_value (f, x, is_integer) ;
+	if (is_complex)
+	{
+	    fprintf (f, " ") ;
+	    ok = ok && print_value (f, z, is_integer) ;
+	}
+    }
+    ok = ok && (fprintf (f, "\n") > 0) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === ntriplets ============================================================ */
+/* ========================================================================== */
+
+/* Compute the number of triplets that will be printed to the file
+ * from the matrix A. */
+
+static Int ntriplets
+(
+    cholmod_sparse *A,	    /* matrix that will be printed */
+    Int is_sym		    /* TRUE if the file is symmetric (lower part only)*/
+)
+{
+    Int *Ap, *Ai, *Anz, packed, i, j, p, pend, ncol, stype, nz = 0 ;
+    if (A == NULL)
+    {
+	/* the Z matrix is NULL */
+	return (0) ;
+    }
+    stype = A->stype ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    ncol = A->ncol ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	p = Ap [j] ;
+	pend = (packed) ? Ap [j+1] : p + Anz [j] ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Ai [p] ;
+	    if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym)))
+	    {
+		/* CHOLMOD matrix is symmetric-lower (and so is the file);
+		 * or CHOLMOD matrix is unsymmetric and either A(i,j) is in
+		 * the lower part or the file is unsymmetric. */
+		nz++ ;
+	    }
+	    else if (stype > 0 && i <= j)
+	    {
+		/* CHOLMOD matrix is symmetric-upper, but the file is
+		 * symmetric-lower.  Need to transpose the entry. */
+		nz++ ;
+	    }
+	}
+    }
+    return (nz) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_write_sparse ================================================= */
+/* ========================================================================== */
+
+/* Write a sparse matrix to a file in Matrix Market format.   Optionally include
+ * comments, and print explicit zero entries given by the pattern of the Z
+ * matrix.  If not NULL, the Z matrix must have the same dimensions and stype
+ * as A.
+ *
+ * Returns the symmetry in which the matrix was printed (1 to 7, see the
+ * CHOLMOD_MM_* codes in CHOLMOD/Include/cholmod_core.h), or -1 on failure.
+ *
+ * If A and Z are sorted on input, and either unsymmetric (stype = 0) or
+ * symmetric-lower (stype < 0), and if A and Z do not overlap, then the triplets
+ * are sorted, first by column and then by row index within each column, with
+ * no duplicate entries.  If all the above holds except stype > 0, then the
+ * triplets are sorted by row first and then column.
+ */
+
+int CHOLMOD(write_sparse)
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_sparse *A,	    /* matrix to print */
+    cholmod_sparse *Z,	    /* optional matrix with pattern of explicit zeros */
+    const char *comments,    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x = 0, z = 0 ;
+    double *Ax, *Az ;
+    Int *Ap, *Ai, *Anz, *Zp, *Zi, *Znz ;
+    Int nrow, ncol, is_complex, symmetry, i, j, q, iz, p, nz, is_binary, stype,
+	is_integer, asym, is_sym, xtype, apacked, zpacked, pend, qend, zsym ;
+    int ok ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (f, EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    if (Z != NULL && (Z->nrow == 0 || Z->ncol == 0))
+    {
+	/* Z is non-NULL but empty, so treat it as a NULL matrix */
+	Z = NULL ;
+    }
+    if (Z != NULL)
+    {
+	RETURN_IF_XTYPE_INVALID (Z, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+	if (Z->nrow != A->nrow || Z->ncol != A->ncol || Z->stype != A->stype)
+	{
+	    ERROR (CHOLMOD_INVALID, "dimension or type of A and Z mismatch") ;
+	    return (EMPTY) ;
+	}
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the A matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    xtype = A->xtype ;
+    apacked = A->packed ;
+
+    if (xtype == CHOLMOD_PATTERN)
+    {
+	/* a CHOLMOD pattern matrix is printed as "pattern" in the file */
+	is_binary = TRUE ;
+	is_integer = FALSE ;
+	is_complex = FALSE ;
+    }
+    else if (xtype == CHOLMOD_REAL)
+    {
+	/* determine if a real matrix is in fact binary or integer */
+	is_binary = TRUE ;
+	is_integer = TRUE ;
+	is_complex = FALSE ;
+	for (j = 0 ; (is_binary || is_integer) && j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (apacked) ? Ap [j+1] : p + Anz [j] ;
+	    for ( ; (is_binary || is_integer) && p < pend ; p++)
+	    {
+		x = Ax [p] ;
+		if (x != 1)
+		{
+		    is_binary = FALSE ;
+		}
+		/* convert to Int and then back to double */
+		i = (Int) x ;
+		z = (double) i ;
+		if (z != x)
+		{
+		    is_integer = FALSE ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* a CHOLMOD complex matrix is printed as "complex" in the file */
+	is_binary = FALSE ;
+	is_integer = FALSE ;
+	is_complex = TRUE ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get the Z matrix (only consider the pattern) */
+    /* ---------------------------------------------------------------------- */
+
+    Zp = NULL ;
+    Zi = NULL ;
+    Znz = NULL ;
+    zpacked = TRUE ;
+    if (Z != NULL)
+    {
+	Zp = Z->p ;
+	Zi = Z->i ;
+	Znz = Z->nz ;
+	zpacked = Z->packed ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the symmetry of A and Z */
+    /* ---------------------------------------------------------------------- */
+
+    stype = A->stype ;
+    if (A->nrow != A->ncol)
+    {
+	asym = CHOLMOD_MM_RECTANGULAR ;
+    }
+    else if (stype != 0)
+    {
+	/* CHOLMOD's A and Z matrices have a symmetric (and matching) stype.
+	 * Note that the diagonal is not checked. */
+	asym = is_complex ? CHOLMOD_MM_HERMITIAN : CHOLMOD_MM_SYMMETRIC ;
+    }
+    else if (!A->sorted)
+    {
+	/* A is in unsymmetric storage, but unsorted */
+	asym = CHOLMOD_MM_UNSYMMETRIC ;
+    }
+    else
+    {
+	/* CHOLMOD's stype is zero (stored in unsymmetric form) */
+	asym = EMPTY ;
+	zsym = EMPTY ;
+
+#ifndef NMATRIXOPS
+	/* determine if the matrices are in fact symmetric or Hermitian */
+	asym = CHOLMOD(symmetry) (A, 1, NULL, NULL, NULL, NULL, Common) ;
+	zsym = (Z == NULL) ? 999 :
+	       CHOLMOD(symmetry) (Z, 1, NULL, NULL, NULL, NULL, Common) ;
+#endif
+
+	if (asym == EMPTY || zsym <= CHOLMOD_MM_UNSYMMETRIC)
+	{
+	    /* not computed, out of memory, or Z is unsymmetric */
+	    asym = CHOLMOD_MM_UNSYMMETRIC ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* write the Matrix Market header */
+    /* ---------------------------------------------------------------------- */
+
+    ok = fprintf (f, "%%%%MatrixMarket matrix coordinate") > 0 ;
+
+    if (is_complex)
+    {
+	ok = ok && (fprintf (f, " complex") > 0) ;
+    }
+    else if (is_binary)
+    {
+	ok = ok && (fprintf (f, " pattern") > 0) ;
+    }
+    else if (is_integer)
+    {
+	ok = ok && (fprintf (f, " integer") > 0) ;
+    }
+    else
+    {
+	ok = ok && (fprintf (f, " real") > 0) ;
+    }
+
+    is_sym = FALSE ;
+
+    switch (asym)
+    {
+	case CHOLMOD_MM_RECTANGULAR:
+	case CHOLMOD_MM_UNSYMMETRIC:
+	    /* A is rectangular or unsymmetric */
+	    ok = ok && (fprintf (f, " general\n") > 0) ;
+	    is_sym = FALSE ;
+	    symmetry = CHOLMOD_MM_UNSYMMETRIC ;
+	    break ;
+
+	case CHOLMOD_MM_SYMMETRIC:
+	case CHOLMOD_MM_SYMMETRIC_POSDIAG:
+	    /* A is symmetric */
+	    ok = ok && (fprintf (f, " symmetric\n") > 0) ;
+	    is_sym = TRUE ;
+	    symmetry = CHOLMOD_MM_SYMMETRIC ;
+	    break ;
+
+	case CHOLMOD_MM_HERMITIAN:
+	case CHOLMOD_MM_HERMITIAN_POSDIAG:
+	    /* A is Hermitian */
+	    ok = ok && (fprintf (f, " Hermitian\n") > 0) ;
+	    is_sym = TRUE ;
+	    symmetry = CHOLMOD_MM_HERMITIAN ;
+	    break ;
+
+	case CHOLMOD_MM_SKEW_SYMMETRIC:
+	    /* A is skew symmetric */
+	    ok = ok && (fprintf (f, " skew-symmetric\n") > 0) ;
+	    is_sym = TRUE ;
+	    symmetry = CHOLMOD_MM_SKEW_SYMMETRIC ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* include the comments if present */
+    /* ---------------------------------------------------------------------- */
+
+    ok = ok && include_comments (f, comments) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* write a sparse matrix (A and Z) */
+    /* ---------------------------------------------------------------------- */
+
+    nz = ntriplets (A, is_sym) + ntriplets (Z, is_sym) ;
+
+    /* write the first data line, with nrow, ncol, and # of triplets */
+    ok = ok && (fprintf (f, ID " " ID " " ID "\n", nrow, ncol, nz) > 0) ;
+
+    for (j = 0 ; ok && j < ncol ; j++)
+    {
+	/* merge column of A and Z */
+	p = Ap [j] ;
+	pend = (apacked) ? Ap [j+1] : p + Anz [j] ;
+	q = (Z == NULL) ? 0 : Zp [j] ;
+	qend = (Z == NULL) ? 0 : ((zpacked) ? Zp [j+1] : q + Znz [j]) ;
+	while (ok)
+	{
+	    /* get the next row index from A and Z */
+	    i  = (p < pend) ? Ai [p] : (nrow+1) ;
+	    iz = (q < qend) ? Zi [q] : (nrow+2) ;
+	    if (i <= iz)
+	    {
+		/* get A(i,j), or quit if both A and Z are exhausted */
+		if (i == nrow+1) break ;
+		get_value (Ax, Az, p, xtype, &x, &z) ;
+		p++ ;
+	    }
+	    else
+	    {
+		/* get Z(i,j) */
+		i = iz ;
+		x = 0 ;
+		z = 0 ;
+		q++ ;
+	    }
+	    if ((stype < 0 && i >= j) || (stype == 0 && (i >= j || !is_sym)))
+	    {
+		/* CHOLMOD matrix is symmetric-lower (and so is the file);
+		 * or CHOLMOD matrix is unsymmetric and either A(i,j) is in
+		 * the lower part or the file is unsymmetric. */
+		ok = ok && print_triplet (f, is_binary, is_complex, is_integer,
+		    i,j, x,z) ;
+	    }
+	    else if (stype > 0 && i <= j)
+	    {
+		/* CHOLMOD matrix is symmetric-upper, but the file is
+		 * symmetric-lower.  Need to transpose the entry.   If the
+		 * matrix is real, the complex part is ignored.  If the matrix
+		 * is complex, it Hermitian.
+		 */
+		ASSERT (IMPLIES (is_complex, asym == CHOLMOD_MM_HERMITIAN)) ;
+		if (z != 0)
+		{
+		    z = -z ;
+		}
+		ok = ok && print_triplet (f, is_binary, is_complex, is_integer,
+		    j,i, x,z) ;
+	    }
+	}
+    }
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_INVALID, "error reading/writing file") ;
+	return (EMPTY) ;
+    }
+
+    return (asym) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_write_dense ================================================== */
+/* ========================================================================== */
+
+/* Write a dense matrix to a file in Matrix Market format.   Optionally include
+ * comments.  Returns > 0 if successful, -1 otherwise (1 if rectangular, 2 if
+ * square).  Future versions may return 1 to 7 on success (a CHOLMOD_MM_* code,
+ * just as cholmod_write_sparse does).
+ *
+ * A dense matrix is written in "general" format; symmetric formats in the
+ * Matrix Market standard are not exploited.
+ */
+
+int CHOLMOD(write_dense)
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_dense *X,	    /* matrix to print */
+    const char *comments,    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x = 0, z = 0 ;
+    double *Xx, *Xz ;
+    Int nrow, ncol, is_complex, i, j, xtype, p ;
+    int ok ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (f, EMPTY) ;
+    RETURN_IF_NULL (X, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the X matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Xx = X->x ;
+    Xz = X->z ;
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+    xtype = X->xtype ;
+    is_complex = (xtype == CHOLMOD_COMPLEX) || (xtype == CHOLMOD_ZOMPLEX) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* write the Matrix Market header */
+    /* ---------------------------------------------------------------------- */
+
+    ok = (fprintf (f, "%%%%MatrixMarket matrix array") > 0) ;
+    if (is_complex)
+    {
+	ok = ok && (fprintf (f, " complex general\n") > 0) ;
+    }
+    else
+    {
+	ok = ok && (fprintf (f, " real general\n") > 0) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* include the comments if present */
+    /* ---------------------------------------------------------------------- */
+
+    ok = ok && include_comments (f, comments) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* write a dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    /* write the first data line, with nrow and ncol */
+    ok = ok && (fprintf (f, ID " " ID "\n", nrow, ncol) > 0) ;
+
+    Xx = X->x ;
+    Xz = X->z ;
+    for (j = 0 ; ok && j < ncol ; j++)
+    {
+	for (i = 0 ; ok && i < nrow ; i++)
+	{
+	    p = i + j*nrow ;
+	    get_value (Xx, Xz, p, xtype, &x, &z) ;
+	    ok = ok && print_value (f, x, FALSE) ;
+	    if (is_complex)
+	    {
+		ok = ok && (fprintf (f, " ") > 0) ;
+		ok = ok && print_value (f, z, FALSE) ;
+	    }
+	    ok = ok && (fprintf (f, "\n") > 0) ;
+	}
+    }
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_INVALID, "error reading/writing file") ;
+	return (EMPTY) ;
+    }
+
+    return ((nrow == ncol) ? CHOLMOD_MM_UNSYMMETRIC : CHOLMOD_MM_RECTANGULAR) ;
+}
+#endif
diff --git a/src/CHOLMOD/Check/lesser.txt b/src/CHOLMOD/Check/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/CHOLMOD/Check/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/CHOLMOD/Cholesky/License.txt b/src/CHOLMOD/Cholesky/License.txt
new file mode 100644
index 0000000..800ac5e
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/License.txt
@@ -0,0 +1,24 @@
+CHOLMOD/Cholesky module, Copyright (C) 2005-2006, Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/Cholesky module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/CHOLMOD/Cholesky/cholmod_amd.c b/src/CHOLMOD/Cholesky/cholmod_amd.c
new file mode 100644
index 0000000..9d04532
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_amd.c
@@ -0,0 +1,211 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_amd ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the AMD ordering routine.  Orders A if the matrix is
+ * symmetric.  On output, Perm [k] = i if row/column i of A is the kth
+ * row/column of P*A*P'.  This corresponds to A(p,p) in MATLAB notation.
+ *
+ * If A is unsymmetric, cholmod_amd orders A*A'.  On output, Perm [k] = i if
+ * row/column i of A*A' is the kth row/column of P*A*A'*P'.  This corresponds to
+ * A(p,:)*A(p,:)' in MATLAB notation.  If f is present, A(p,f)*A(p,f)' is
+ * ordered.
+ *
+ * Computes the flop count for a subsequent LL' factorization, the number
+ * of nonzeros in L, and the number of nonzeros in the matrix ordered (A,
+ * A*A' or A(:,f)*A(:,f)').
+ *
+ * workspace: Iwork (6*nrow). Head (nrow).
+ *
+ * Allocates a temporary copy of A+A' or A*A' (with
+ * both upper and lower triangular parts) as input to AMD.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "amd.h"
+#include "cholmod_cholesky.h"
+
+#if (!defined (AMD_VERSION) || (AMD_VERSION < AMD_VERSION_CODE (2,0)))
+#error "AMD v2.0 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === cholmod_amd ========================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(amd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double Info [AMD_INFO], Control2 [AMD_CONTROL], *Control ;
+    Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Iwork, *Next ;
+    cholmod_sparse *C ;
+    Int j, n, cnz ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    n = A->nrow ;
+
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    if (n == 0)
+    {
+	/* nothing to do */
+	Common->fl = 0 ;
+	Common->lnz = 0 ;
+	Common->anz = 0 ;
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: this is less than the space used in cholmod_analyze, so if
+     * cholmod_amd is being called by that routine, no space will be
+     * allocated.
+     */
+
+    /* s = MAX (6*n, A->ncol) */
+    s = CHOLMOD(mult_size_t) (n, 6, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+    s = MAX (s, A->ncol) ;
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    Iwork  = Common->Iwork ;
+    Degree = Iwork ;			/* size n */
+    Wi     = Iwork + n ;		/* size n */
+    Len    = Iwork + 2*((size_t) n) ;	/* size n */
+    Nv     = Iwork + 3*((size_t) n) ;   /* size n */
+    Next   = Iwork + 4*((size_t) n) ;   /* size n */
+    Elen   = Iwork + 5*((size_t) n) ;   /* size n */
+
+    Head = Common->Head ;   /* size n+1, but only n is used */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the input matrix for AMD */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->stype == 0)
+    {
+	/* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */
+	C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ;
+    }
+    else
+    {
+	/* C = A+A', but use only the upper triangular part of A if A->stype = 1
+	 * and only the lower part of A if A->stype = -1.  Add extra space of
+	 * nnz(C)/2+n to C. */
+	C = CHOLMOD(copy) (A, 0, -2, Common) ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory, fset invalid, or other error */
+	return (FALSE) ;
+    }
+
+    Cp = C->p ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Len [j] = Cp [j+1] - Cp [j] ;
+    }
+
+    /* C does not include the diagonal, and both upper and lower parts.
+     * Common->anz includes the diagonal, and just the lower part of C */
+    cnz = Cp [n] ;
+    Common->anz = cnz / 2 + n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order C using AMD */
+    /* ---------------------------------------------------------------------- */
+
+    /* get parameters */
+    if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
+    {
+	/* use AMD defaults */
+	Control = NULL ;
+    }
+    else
+    {
+	Control = Control2 ;
+	Control [AMD_DENSE] = Common->method [Common->current].prune_dense ;
+	Control [AMD_AGGRESSIVE] = Common->method [Common->current].aggressive ;
+    }
+
+    /* AMD_2 does not use amd_malloc and amd_free, but set these pointers just
+     * be safe. */
+    amd_malloc = Common->malloc_memory ;
+    amd_free = Common->free_memory ;
+    amd_calloc = Common->calloc_memory ;
+    amd_realloc = Common->realloc_memory ;
+
+    /* AMD_2 doesn't print anything either, but future versions might,
+     * so set the amd_printf pointer too. */
+    amd_printf = Common->print_function ;
+
+#ifdef LONG
+    amd_l2 (n, C->p,  C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
+	    Degree, Wi, Control, Info) ;
+#else
+    amd_2 (n, C->p,  C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
+	    Degree, Wi, Control, Info) ;
+#endif
+
+    /* LL' flop count.  Need to subtract n for LL' flop count.  Note that this
+     * is a slight upper bound which is often exact (see AMD/Source/amd_2.c for
+     * details).  cholmod_analyze computes an exact flop count and fill-in. */
+    Common->fl = Info [AMD_NDIV] + 2 * Info [AMD_NMULTSUBS_LDL] + n ;
+
+    /* Info [AMD_LNZ] excludes the diagonal */
+    Common->lnz = n + Info [AMD_LNZ] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the AMD workspace and clear the persistent workspace in Common */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (IMPLIES (Common->status == CHOLMOD_OK,
+		CHOLMOD(dump_perm) (Perm, n, n, "AMD2 perm", Common))) ;
+    CHOLMOD(free_sparse) (&C, Common) ;
+    for (j = 0 ; j <= n ; j++)
+    {
+	Head [j] = EMPTY ;
+    }
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_analyze.c b/src/CHOLMOD/Cholesky/cholmod_analyze.c
new file mode 100644
index 0000000..433fd95
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_analyze.c
@@ -0,0 +1,942 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_analyze ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Order and analyze a matrix (either simplicial or supernodal), in prepartion
+ * for numerical factorization via cholmod_factorize or via the "expert"
+ * routines cholmod_rowfac and cholmod_super_numeric.
+ *
+ * symmetric case:    A or A(p,p)
+ * unsymmetric case:  AA', A(p,:)*A(p,:)', A(:,f)*A(:,f)', or A(p,f)*A(p,f)'
+ *
+ * For the symmetric case, only the upper or lower triangular part of A is
+ * accessed (depending on the type of A).  LL'=A (or permuted A) is analzed.
+ * For the unsymmetric case (LL'=AA' or permuted A).
+ *
+ * There can be no duplicate entries in p or f.  p is of length m if A is
+ * m-by-n.  f can be length 0 to n.
+ *
+ * In both cases, the columns of A need not be sorted.  A can be in packed
+ * or unpacked form.
+ *
+ * Ordering options include:
+ *
+ *	natural:    A is not permuted to reduce fill-in
+ *	given:	    a permutation can be provided to this routine (UserPerm)
+ *	AMD:	    approximate minumum degree (AMD for the symmetric case,
+ *		    COLAMD for the AA' case).
+ *	METIS:	    nested dissection with METIS_NodeND
+ *	NESDIS:	    nested dissection using METIS_NodeComputeSeparator,
+ *		    typically followed by a constrained minimum degree
+ *		    (CAMD for the symmetric case, CCOLAMD for the AA' case).
+ *
+ * Multiple ordering options can be tried (up to 9 of them), and the best one
+ * is selected (the one that gives the smallest number of nonzeros in the
+ * simplicial factor L).  If one method fails, cholmod_analyze keeps going, and
+ * picks the best among the methods that succeeded.  This routine fails (and
+ * returns NULL) if either initial memory allocation fails, all ordering methods
+ * fail, or the supernodal analysis (if requested) fails.  By default, the 9
+ * methods available are:
+ *
+ *	1) given permutation (skipped if UserPerm is NULL)
+ *	2) AMD (symmetric case) or COLAMD (unsymmetric case)
+ *	3) METIS with default parameters
+ *	4) NESDIS with default parameters (stopping the partitioning when
+ *	    the graph is of size nd_small = 200 or less, remove nodes with
+ *	    more than max (16, prune_dense * sqrt (n)) nodes where
+ *	    prune_dense = 10, and follow partitioning with CCOLAMD, a
+ *	    constrained minimum degree ordering).
+ *	5) natural
+ *	6) NESDIS, nd_small = 20000, prune_dense = 10
+ *	7) NESDIS, nd_small =     4, prune_dense = 10, no min degree
+ *	8) NESDIS, nd_small =   200, prune_dense = 0
+ *	9) COLAMD for A*A' or AMD for A
+ *
+ * By default, the first two are tried, and METIS is tried if AMD reports a high
+ * flop count and fill-in.  Let fl denote the flop count for the AMD, ordering,
+ * nnz(L) the # of nonzeros in L, and nnz(tril(A)) (or A*A').  If
+ * fl/nnz(L) >= 500 and nnz(L)/nnz(tril(A)) >= 5, then METIS is attempted.  The
+ * best ordering is used (UserPerm if given, AMD, and METIS if attempted).  If
+ * you do not have METIS, only the first two will be tried (user permutation,
+ * if provided, and AMD/COLAMD).  This default behavior is obtained when
+ * Common->nmethods is zero.  In this case, methods 0, 1, and 2 in
+ * Common->method [..] are reset to User-provided, AMD, and METIS (or NESDIS
+ * if Common->default_nesdis is set to the non-default value of TRUE),
+ * respectively.
+ *
+ * You can modify these 9 methods and the number of methods tried by changing
+ * parameters in the Common argument.  If you know the best ordering for your
+ * matrix, set Common->nmethods to 1 and set Common->method[0].ordering to the
+ * requested ordering method.  Parameters for each method can also be modified
+ * (refer to cholmod.h for details).
+ *
+ * Note that it is possible for METIS to terminate your program if it runs out
+ * of memory.  This is not the case for any CHOLMOD or minimum degree ordering
+ * routine (AMD, COLAMD, CAMD, CCOLAMD, or CSYMAMD).  Since NESDIS relies on
+ * METIS, it too can terminate your program.
+ *
+ * The factor L is returned as simplicial symbolic (L->is_super FALSE) if
+ * Common->supernodal <= CHOLMOD_SIMPLICIAL (0) or as supernodal symbolic if
+ * Common->supernodal >= CHOLMOD_SUPERNODAL (2).  If Common->supernodal is
+ * equal to CHOLMOD_AUTO (1), then L is simplicial if the flop count per
+ * nonzero in L is less than Common->supernodal_switch (default: 40), and
+ * is returned as a supernodal factor otherwise.
+ *
+ * In both cases, L->xtype is CHOLMOD_PATTERN.
+ * A subsequent call to cholmod_factorize will perform a
+ * simplicial or supernodal factorization, depending on the type of L.
+ *
+ * For the simplicial case, L contains the fill-reducing permutation (L->Perm)
+ * and the counts of nonzeros in each column of L (L->ColCount).  For the
+ * supernodal case, L also contains the nonzero pattern of each supernode.
+ *
+ * workspace: Flag (nrow), Head (nrow+1)
+ *	if symmetric:   Iwork (6*nrow)
+ *	if unsymmetric: Iwork (6*nrow+ncol).
+ *	calls various ordering routines, which typically allocate O(nnz(A))
+ *	temporary workspace ((2 to 3)*nnz(A) * sizeof (Int) is typical, but it
+ *	can be much higher if A*A' must be explicitly formed for METIS).  Also
+ *	allocates up to 2 temporary (permuted/transpose) copies of the nonzero
+ *	pattern of A, and up to 3*n*sizeof(Int) additional workspace.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+#ifndef NPARTITION
+#include "cholmod_partition.h"
+#endif
+
+
+/* ========================================================================== */
+/* === cholmod_analyze ====================================================== */
+/* ========================================================================== */
+
+/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor
+ * that can later be passed to cholmod_factorize. */
+
+cholmod_factor *CHOLMOD(analyze)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(analyze_p2) (TRUE, A, NULL, NULL, 0, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_analyze_p ==================================================== */
+/* ========================================================================== */
+
+/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a
+ * symbolic factor that can later be passed to cholmod_factorize, where
+ * F = A(:,fset) if fset is not NULL and A->stype is zero.
+ * UserPerm is tried if non-NULL.  */
+
+cholmod_factor *CHOLMOD(analyze_p)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    Int *UserPerm,	/* user-provided permutation, size A->nrow */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(analyze_p2) (TRUE, A, UserPerm, fset, fsize, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === permute_matrices ===================================================== */
+/* ========================================================================== */
+
+/* Permute and transpose a matrix.  Allocates the A1 and A2 matrices, if needed,
+ * or returns them as NULL if not needed.
+ */
+
+static int permute_matrices
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to permute */
+    Int ordering,	/* ordering method used */
+    Int *Perm,		/* fill-reducing permutation */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    Int do_rowcolcounts,/* if TRUE, compute both S and F.  If FALSE, only
+			 * S is needed for the symmetric case, and only F for
+			 * the unsymmetric case */
+    /* ---- output --- */
+    cholmod_sparse **A1_handle,	    /* see comments below for A1, A2, S, F */
+    cholmod_sparse **A2_handle,
+    cholmod_sparse **S_handle,
+    cholmod_sparse **F_handle,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A1, *A2, *S, *F ;
+
+    *A1_handle = NULL ;
+    *A2_handle = NULL ;
+    *S_handle = NULL ;
+    *F_handle = NULL ;
+    A1 = NULL ;
+    A2 = NULL ;
+
+    if (ordering == CHOLMOD_NATURAL)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* natural ordering of A */
+	/* ------------------------------------------------------------------ */
+
+	if (A->stype < 0)
+	{
+	    /* symmetric lower case: A already in lower form, so S=A' */
+	    /* workspace: Iwork (nrow) */
+	    A2 = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ;
+	    F = A ;
+	    S = A2 ;
+	}
+	else if (A->stype > 0)
+	{
+	    /* symmetric upper case: F = pattern of triu (A)', S = A */
+	    /* workspace: Iwork (nrow) */
+	    if (do_rowcolcounts)
+	    {
+		/* F not needed for symmetric case if do_rowcolcounts FALSE */
+		A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ;
+	    }
+	    F = A1 ;
+	    S = A ;
+	}
+	else
+	{
+	    /* unsymmetric case: F = pattern of A (:,f)',  S = A */
+	    /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */
+	    A1 = CHOLMOD(ptranspose) (A, 0, NULL, fset, fsize, Common) ;
+	    F = A1 ;
+	    S = A ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A is permuted */
+	/* ------------------------------------------------------------------ */
+
+	if (A->stype < 0)
+	{
+	    /* symmetric lower case: S = tril (A (p,p))' and F = S' */
+	    /* workspace: Iwork (2*nrow) */
+	    A2 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ;
+	    S = A2 ;
+	    /* workspace: Iwork (nrow) */
+	    if (do_rowcolcounts)
+	    {
+		/* F not needed for symmetric case if do_rowcolcounts FALSE */
+		A1 = CHOLMOD(ptranspose) (A2, 0, NULL, NULL, 0, Common) ;
+	    }
+	    F = A1 ;
+	}
+	else if (A->stype > 0)
+	{
+	    /* symmetric upper case: F = triu (A (p,p))' and S = F' */
+	    /* workspace: Iwork (2*nrow) */
+	    A1 = CHOLMOD(ptranspose) (A, 0, Perm, NULL, 0, Common) ;
+	    F = A1 ;
+	    /* workspace: Iwork (nrow) */
+	    A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ;
+	    S = A2 ;
+	}
+	else
+	{
+	    /* unsymmetric case:     F = A (p,f)'         and S = F' */
+	    /* workspace: Iwork (nrow if no fset, MAX(nrow,ncol) if fset) */
+	    A1 = CHOLMOD(ptranspose) (A, 0, Perm, fset, fsize, Common) ;
+	    F = A1 ;
+	    if (do_rowcolcounts)
+	    {
+		/* S not needed for unsymmetric case if do_rowcolcounts FALSE */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (A1, 0, NULL, NULL, 0, Common) ;
+	    }
+	    S = A2 ;
+	}
+    }
+
+    /* If any cholmod_*transpose fails, one or more matrices will be NULL */
+    *A1_handle = A1 ;
+    *A2_handle = A2 ;
+    *S_handle = S ;
+    *F_handle = F ;
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_analyze_ordering ============================================= */
+/* ========================================================================== */
+
+/* Given a matrix A and its fill-reducing permutation, compute the elimination
+ * tree, its (non-weighted) postordering, and the number of nonzeros in each
+ * column of L.  Also computes the flop count, the total nonzeros in L, and
+ * the nonzeros in A (Common->fl, Common->lnz, and Common->anz).
+ *
+ * The column counts of L, flop count, and other statistics from
+ * cholmod_rowcolcounts are not computed if ColCount is NULL.
+ *
+ * workspace: Iwork (2*nrow if symmetric, 2*nrow+ncol if unsymmetric),
+ *	Flag (nrow), Head (nrow+1)
+ */
+
+int CHOLMOD(analyze_ordering)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int ordering,	/* ordering method used */
+    Int *Perm,		/* size n, fill-reducing permutation to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    Int *Parent,	/* size n, elimination tree */
+    Int *Post,		/* size n, postordering of elimination tree */
+    Int *ColCount,	/* size n, nnz in each column of L */
+    /* ---- workspace  */
+    Int *First,		/* size n workspace for cholmod_postorder */
+    Int *Level,		/* size n workspace for cholmod_postorder */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A1, *A2, *S, *F ;
+    Int n, ok, do_rowcolcounts ;
+
+    /* check inputs */
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+
+    n = A->nrow ;
+
+    do_rowcolcounts = (ColCount != NULL) ;
+
+    /* permute A according to Perm and fset */
+    ok = permute_matrices (A, ordering, Perm, fset, fsize, do_rowcolcounts,
+	    &A1, &A2, &S, &F, Common) ;
+
+    /* find etree of S (symmetric upper/lower case) or F (unsym case) */
+    /* workspace: symmmetric: Iwork (nrow), unsym: Iwork (nrow+ncol) */
+    ok = ok && CHOLMOD(etree) (A->stype ? S:F, Parent, Common) ;
+
+    /* postorder the etree (required by cholmod_rowcolcounts) */
+    /* workspace: Iwork (2*nrow) */
+    ok = ok && (CHOLMOD(postorder) (Parent, n, NULL, Post, Common) == n) ;
+
+    /* cholmod_postorder doesn't set Common->status if it returns < n */
+    Common->status = (!ok && Common->status == CHOLMOD_OK) ?
+	CHOLMOD_INVALID : Common->status ;
+
+    /* analyze LL'=S or SS' or S(:,f)*S(:,f)' */
+    /* workspace:
+     *	if symmetric:   Flag (nrow), Iwork (2*nrow)
+     *	if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1)
+     */
+    if (do_rowcolcounts)
+    {
+	ok = ok && CHOLMOD(rowcolcounts) (A->stype ? F:S, fset, fsize, Parent,
+	    Post, NULL, ColCount, First, Level, Common) ;
+    }
+
+    /* free temporary matrices and return result */
+    CHOLMOD(free_sparse) (&A1, Common) ;
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === Free workspace and return L ========================================== */
+/* ========================================================================== */
+
+#define FREE_WORKSPACE_AND_RETURN \
+{ \
+    Common->no_workspace_reallocate = FALSE ; \
+    CHOLMOD(free) (n, sizeof (Int), Lparent,  Common) ; \
+    CHOLMOD(free) (n, sizeof (Int), Perm,     Common) ; \
+    CHOLMOD(free) (n, sizeof (Int), ColCount, Common) ; \
+    if (Common->status < CHOLMOD_OK) \
+    { \
+	CHOLMOD(free_factor) (&L, Common) ; \
+    } \
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \
+    return (L) ; \
+}
+
+
+/* ========================================================================== */
+/* === cholmod_analyze_p2 =================================================== */
+/* ========================================================================== */
+
+/* Ordering and analysis for sparse Cholesky or sparse QR.  CHOLMOD itself
+ * always uses for_cholesky = TRUE.  The for_cholesky = FALSE option is
+ * for SuiteSparseQR only. */
+
+cholmod_factor *CHOLMOD(analyze_p2)
+(
+    /* ---- input ---- */
+    int for_cholesky,   /* if TRUE, then analyze for Cholesky; else for QR */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    Int *UserPerm,	/* user-provided permutation, size A->nrow */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double lnz_best ;
+    Int *First, *Level, *Work4n, *Cmember, *CParent, *ColCount, *Lperm, *Parent,
+	*Post, *Perm, *Lparent, *Lcolcount ;
+    cholmod_factor *L ;
+    Int k, n, ordering, method, nmethods, status, default_strategy, ncol, uncol,
+	skip_analysis, skip_best ;
+    Int amd_backup ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    status = CHOLMOD_OK ;
+    Common->selected = EMPTY ;
+    Common->called_nd = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+    ncol = A->ncol ;
+    uncol = (A->stype == 0) ? (A->ncol) : 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* set the default strategy */
+    /* ---------------------------------------------------------------------- */
+
+    lnz_best = (double) EMPTY ;
+    skip_best = FALSE ;
+    nmethods = MIN (Common->nmethods, CHOLMOD_MAXMETHODS) ;
+    nmethods = MAX (0, nmethods) ;
+
+#ifndef NDEBUG
+    PRINT1 (("cholmod_analyze_p2 :: nmethods "ID"\n", nmethods)) ;
+    for (method = 0 ; method < nmethods ; method++)
+    {
+        PRINT1 (("  "ID": ordering "ID"\n",     
+            method, Common->method [method].ordering)) ;
+    }
+#endif
+
+    default_strategy = (nmethods == 0) ;
+    if (default_strategy)
+    {
+	/* default strategy: try UserPerm, if given.  Try AMD for A, or AMD
+	 * to order A*A'.  Try METIS for the symmetric case only if AMD reports
+         * a high degree of fill-in and flop count.  METIS is not tried if the
+         * Partition Module isn't installed.   If Common->default_nesdis is
+         * TRUE, then NESDIS is used as the 3rd ordering instead. */
+	Common->method [0].ordering = CHOLMOD_GIVEN ;/* skip if UserPerm NULL */
+	Common->method [1].ordering = CHOLMOD_AMD ;
+	Common->method [2].ordering = 
+	    (Common->default_nesdis ? CHOLMOD_NESDIS : CHOLMOD_METIS) ;
+        amd_backup = FALSE ;
+#ifndef NPARTITION
+	nmethods = 3 ;
+#else
+	nmethods = 2 ;
+#endif
+    }
+    else
+    {
+        /* If only METIS and NESDIS are selected, or if 2 or more methods are
+         * being tried, then enable AMD backup */
+        amd_backup = (nmethods > 1) || (nmethods == 1 &&
+            (Common->method [0].ordering == CHOLMOD_METIS ||
+             Common->method [0].ordering == CHOLMOD_NESDIS)) ;
+    }
+
+#ifdef NSUPERNODAL
+    /* CHOLMOD Supernodal module not installed, just do simplicial analysis */
+    Common->supernodal = CHOLMOD_SIMPLICIAL ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: enough space needs to be allocated here so that routines called by
+     * cholmod_analyze do not reallocate the space.
+     */
+
+    /* s = 6*n + uncol */
+    s = CHOLMOD(mult_size_t) (n, 6, &ok) ;
+    s = CHOLMOD(add_size_t) (s, uncol, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ensure that subsequent routines, called by cholmod_analyze, do not
+     * reallocate any workspace.  This is set back to FALSE in the
+     * FREE_WORKSPACE_AND_RETURN macro, which is the only way this function
+     * returns to its caller. */
+    Common->no_workspace_reallocate = TRUE ;
+
+    /* Use the last 4*n Int's in Iwork for Parent, First, Level, and Post, since
+     * other CHOLMOD routines will use the first 2n+uncol space.  The ordering
+     * routines (cholmod_amd, cholmod_colamd, cholmod_ccolamd, cholmod_metis)
+     * are an exception.  They can use all 6n + ncol space, since the contents
+     * of Parent, First, Level, and Post are not needed across calls to those
+     * routines. */
+    Work4n = Common->Iwork ;
+    Work4n += 2*((size_t) n) + uncol ;
+    Parent = Work4n ;
+    First  = Work4n + n ;
+    Level  = Work4n + 2*((size_t) n) ;
+    Post   = Work4n + 3*((size_t) n) ;
+
+    /* note that this assignment means that cholmod_nested_dissection,
+     * cholmod_ccolamd, and cholmod_camd can use only the first 4n+uncol
+     * space in Common->Iwork */
+    Cmember = Post ;
+    CParent = Level ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate more workspace, and an empty simplicial symbolic factor */
+    /* ---------------------------------------------------------------------- */
+
+    L = CHOLMOD(allocate_factor) (n, Common) ;
+    Lparent  = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    Perm     = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	FREE_WORKSPACE_AND_RETURN ;
+    }
+    Lperm = L->Perm ;
+    Lcolcount = L->ColCount ;
+    Common->anz = EMPTY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* try all the requested ordering options and backup to AMD if needed */
+    /* ---------------------------------------------------------------------- */
+
+    /* turn off error handling [ */
+    Common->try_catch = TRUE ;
+
+    for (method = 0 ; method <= nmethods ; method++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* determine the method to try */
+	/* ------------------------------------------------------------------ */
+
+	Common->fl = EMPTY ;
+	Common->lnz = EMPTY ;
+	skip_analysis = FALSE ;
+
+	if (method == nmethods)
+	{
+	    /* All methods failed: backup to AMD */
+	    if (Common->selected == EMPTY && amd_backup)
+	    {
+		PRINT1 (("All methods requested failed: backup to AMD\n")) ;
+		ordering = CHOLMOD_AMD ;
+	    }
+	    else
+	    {
+		break ;
+	    }
+	}
+	else
+	{
+	    ordering = Common->method [method].ordering ;
+	}
+	Common->current = method ;
+	PRINT1 (("method "ID": Try method: "ID"\n", method, ordering)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* find the fill-reducing permutation */
+	/* ------------------------------------------------------------------ */
+
+	if (ordering == CHOLMOD_NATURAL)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* natural ordering */
+	    /* -------------------------------------------------------------- */
+
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Perm [k] = k ;
+	    }
+
+	}
+	else if (ordering == CHOLMOD_GIVEN)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use given ordering of A, if provided */
+	    /* -------------------------------------------------------------- */
+
+	    if (UserPerm == NULL)
+	    {
+		/* this is not an error condition */
+		PRINT1 (("skip, no user perm given\n")) ;
+		continue ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		/* UserPerm is checked in cholmod_ptranspose */
+		Perm [k] = UserPerm [k] ;
+	    }
+
+	}
+	else if (ordering == CHOLMOD_AMD)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* AMD ordering of A, A*A', or A(:,f)*A(:,f)' */
+	    /* -------------------------------------------------------------- */
+
+            amd_backup = FALSE ;    /* no need to try AMD twice ... */
+	    CHOLMOD(amd) (A, fset, fsize, Perm, Common) ;
+	    skip_analysis = TRUE ;
+
+	}
+	else if (ordering == CHOLMOD_COLAMD)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* AMD for symmetric case, COLAMD for A*A' or A(:,f)*A(:,f)' */
+	    /* -------------------------------------------------------------- */
+
+	    if (A->stype)
+	    {
+		CHOLMOD(amd) (A, fset, fsize, Perm, Common) ;
+		skip_analysis = TRUE ;
+	    }
+	    else
+	    {
+		/* Alternative:
+		CHOLMOD(ccolamd) (A, fset, fsize, NULL, Perm, Common) ;
+		*/
+		/* do not postorder, it is done later, below */
+		/* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1)*/
+		CHOLMOD(colamd) (A, fset, fsize, FALSE, Perm, Common) ;
+	    }
+
+	}
+	else if (ordering == CHOLMOD_METIS)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use METIS_NodeND directly (via a CHOLMOD wrapper) */
+	    /* -------------------------------------------------------------- */
+
+#ifndef NPARTITION
+	    /* postorder parameter is false, because it will be later, below */
+	    /* workspace: Iwork (4*nrow+uncol), Flag (nrow), Head (nrow+1) */
+	    Common->called_nd = TRUE ;
+	    CHOLMOD(metis) (A, fset, fsize, FALSE, Perm, Common) ;
+#else
+	    Common->status = CHOLMOD_NOT_INSTALLED ;
+#endif
+
+	}
+	else if (ordering == CHOLMOD_NESDIS)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* use CHOLMOD's nested dissection */
+	    /* -------------------------------------------------------------- */
+
+	    /* this method is based on METIS' node bissection routine
+	     * (METIS_NodeComputeSeparator).  In contrast to METIS_NodeND,
+	     * it calls CAMD or CCOLAMD on the whole graph, instead of MMD
+	     * on just the leaves. */
+#ifndef NPARTITION
+	    /* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow) */
+	    Common->called_nd = TRUE ;
+	    CHOLMOD(nested_dissection) (A, fset, fsize, Perm, CParent, Cmember,
+		    Common) ;
+#else
+	    Common->status = CHOLMOD_NOT_INSTALLED ;
+#endif
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* invalid ordering method */
+	    /* -------------------------------------------------------------- */
+
+	    Common->status = CHOLMOD_INVALID ;
+	    PRINT1 (("No such ordering: "ID"\n", ordering)) ;
+	}
+
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory, or method failed */
+	    status = MIN (status, Common->status) ;
+	    Common->status = CHOLMOD_OK ;
+	    continue ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* analyze the ordering */
+	/* ------------------------------------------------------------------ */
+
+	if (!skip_analysis)
+	{
+	    if (!CHOLMOD(analyze_ordering) (A, ordering, Perm, fset, fsize,
+		    Parent, Post, ColCount, First, Level, Common))
+	    {
+		/* ordering method failed; clear status and try next method */
+		status = MIN (status, Common->status) ;
+		Common->status = CHOLMOD_OK ;
+		continue ;
+	    }
+	}
+
+	ASSERT (Common->fl >= 0 && Common->lnz >= 0) ;
+	Common->method [method].fl  = Common->fl ;
+	Common->method [method].lnz = Common->lnz ;
+	PRINT1 (("lnz %g fl %g\n", Common->lnz, Common->fl)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* pick the best method */
+	/* ------------------------------------------------------------------ */
+
+	/* fl.pt. compare, but lnz can never be NaN */
+	if (Common->selected == EMPTY || Common->lnz < lnz_best)
+	{
+	    Common->selected = method ;
+	    PRINT1 (("this is best so far, method "ID"\n", method)) ;
+	    L->ordering = ordering ;
+	    lnz_best = Common->lnz ;
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lperm [k] = Perm [k] ;
+	    }
+	    /* save the results of cholmod_analyze_ordering, if it was called */
+	    skip_best = skip_analysis ;
+	    if (!skip_analysis)
+	    {
+		/* save the column count; becomes permanent part of L */
+		for (k = 0 ; k < n ; k++)
+		{
+		    Lcolcount [k] = ColCount [k] ;
+		}
+		/* Parent is needed for weighted postordering and for supernodal
+		 * analysis.  Does not become a permanent part of L */
+		for (k = 0 ; k < n ; k++)
+		{
+		    Lparent [k] = Parent [k] ;
+		}
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* determine if METIS is to be skipped */
+	/* ------------------------------------------------------------------ */
+
+	if (default_strategy && ordering == CHOLMOD_AMD)
+	{
+	    if ((Common->fl < 500 * Common->lnz) ||
+		(Common->lnz < 5 * Common->anz))
+	    {
+		/* AMD found an ordering with less than 500 flops per nonzero in
+		 * L, or one with a fill-in ratio (nnz(L)/nnz(A)) of less than
+		 * 5.  This is pretty good, and it's unlikely that METIS will do
+		 * better (this heuristic is based on tests on all symmetric
+		 * positive definite matrices in the UF sparse matrix
+		 * collection, and it works well across a wide range of
+		 * problems).  METIS can take much more time than AMD. */
+		break ;
+	    }
+	}
+    }
+
+    /* turn error printing back on ] */
+    Common->try_catch = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return if no ordering method succeeded */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->selected == EMPTY)
+    {
+	/* All methods failed.  
+	 * If two or more methods failed, they may have failed for different
+	 * reasons.  Both would clear Common->status and skip to the next
+	 * method.  Common->status needs to be restored here to the worst error
+	 * obtained in any of the methods.  CHOLMOD_INVALID is worse
+	 * than CHOLMOD_OUT_OF_MEMORY, since the former implies something may
+	 * be wrong with the user's input.  CHOLMOD_OUT_OF_MEMORY is simply an
+	 * indication of lack of resources. */
+        if (status >= CHOLMOD_OK)
+        {
+            /* this can occur if nmethods = 1, ordering = CHOLMOD_GIVEN,
+               but UserPerm is NULL */
+            status = CHOLMOD_INVALID ;
+        }
+	ERROR (status, "all methods failed") ;
+	FREE_WORKSPACE_AND_RETURN ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* do the analysis for AMD, if skipped */
+    /* ---------------------------------------------------------------------- */
+
+    Common->fl  = Common->method [Common->selected].fl  ;
+    Common->lnz = Common->method [Common->selected].lnz ;
+    ASSERT (Common->lnz >= 0) ;
+
+    if (skip_best)
+    {
+	if (!CHOLMOD(analyze_ordering) (A, L->ordering, Lperm, fset, fsize,
+		Lparent, Post, Lcolcount, First, Level, Common))
+	{
+	    /* out of memory, or method failed */
+	    FREE_WORKSPACE_AND_RETURN ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* postorder the etree, weighted by the column counts */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->postorder)
+    {
+	/* combine the fill-reducing ordering with the weighted postorder */
+	/* workspace: Iwork (2*nrow) */
+	if (CHOLMOD(postorder) (Lparent, n, Lcolcount, Post, Common) == n)
+	{
+	    /* use First and Level as workspace [ */
+	    Int *Wi = First, *InvPost = Level ;
+	    Int newchild, oldchild, newparent, oldparent ;
+
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Wi [k] = Lperm [Post [k]] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lperm [k] = Wi [k] ;
+	    }
+
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Wi [k] = Lcolcount [Post [k]] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lcolcount [k] = Wi [k] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		InvPost [Post [k]] = k ;
+	    }
+
+	    /* updated Lparent needed only for supernodal case */
+	    for (newchild = 0 ; newchild < n ; newchild++)
+	    {
+		oldchild = Post [newchild] ;
+		oldparent = Lparent [oldchild] ;
+		newparent = (oldparent == EMPTY) ? EMPTY : InvPost [oldparent] ;
+		Wi [newchild] = newparent ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Lparent [k] = Wi [k] ;
+	    }
+	    /* done using Iwork as workspace ] */
+
+	    /* L is now postordered, no longer in natural ordering */
+	    if (L->ordering == CHOLMOD_NATURAL)
+	    {
+		L->ordering = CHOLMOD_POSTORDERED ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal analysis, if requested or if selected automatically */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NSUPERNODAL
+    if (Common->supernodal > CHOLMOD_AUTO
+    || (Common->supernodal == CHOLMOD_AUTO &&
+	Common->lnz > 0 &&
+	(Common->fl / Common->lnz) >= Common->supernodal_switch))
+    {
+	cholmod_sparse *S, *F, *A2, *A1 ;
+
+	permute_matrices (A, L->ordering, Lperm, fset, fsize, TRUE,
+		&A1, &A2, &S, &F, Common) ;
+
+	/* workspace: Flag (nrow), Head (nrow), Iwork (5*nrow) */
+	CHOLMOD(super_symbolic2) (for_cholesky, S, F, Lparent, L, Common) ;
+	PRINT1 (("status %d\n", Common->status)) ;
+
+	CHOLMOD(free_sparse) (&A1, Common) ;
+	CHOLMOD(free_sparse) (&A2, Common) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* free temporary matrices and workspace, and return result L */
+    /* ---------------------------------------------------------------------- */
+
+    FREE_WORKSPACE_AND_RETURN ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_colamd.c b/src/CHOLMOD/Cholesky/cholmod_colamd.c
new file mode 100644
index 0000000..b2d06b0
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_colamd.c
@@ -0,0 +1,209 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_colamd ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the COLAMD ordering routine (version 2.4 or later).
+ * Finds a permutation p such that the Cholesky factorization of PAA'P' is
+ * sparser than AA' using colamd.  If the postorder input parameter is TRUE,
+ * the column etree is found and postordered, and the colamd ordering is then
+ * combined with its postordering.  A must be unsymmetric.
+ *
+ * There can be no duplicate entries in f.
+ * f can be length 0 to n if A is m-by-n.
+ *
+ * workspace: Iwork (4*nrow+ncol), Head (nrow+1), Flag (nrow)
+ *	Allocates a copy of its input matrix, which
+ *	is then used as CCOLAMD's workspace.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "colamd.h"
+#include "cholmod_cholesky.h"
+
+#if (!defined (COLAMD_VERSION) || (COLAMD_VERSION < COLAMD_VERSION_CODE (2,5)))
+#error "COLAMD v2.5 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === cholmod_colamd ======================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(colamd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with a coletree postorder */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double knobs [COLAMD_KNOBS] ;
+    cholmod_sparse *C ;
+    Int *NewPerm, *Parent, *Post, *Work2n ;
+    Int k, nrow, ncol ;
+    size_t s, alen ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->stype != 0)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: this is less than the space used in cholmod_analyze, so if
+     * cholmod_colamd is being called by that routine, no space will be
+     * allocated.
+     */
+
+    /* s = 4*nrow + ncol */
+    s = CHOLMOD(mult_size_t) (nrow, 4, &ok) ;
+    s = CHOLMOD(add_size_t) (s, ncol, &ok) ;
+
+#ifdef LONG
+    alen = colamd_l_recommended (A->nzmax, ncol, nrow) ;
+    colamd_l_set_defaults (knobs) ;
+#else
+    alen = colamd_recommended (A->nzmax, ncol, nrow) ;
+    colamd_set_defaults (knobs) ;
+#endif
+
+    if (!ok || alen == 0)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate COLAMD workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* colamd_printf is only available in colamd v2.4 or later */
+    colamd_printf = Common->print_function ;
+
+    C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0,
+	    CHOLMOD_PATTERN, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy (and transpose) the input matrix A into the colamd workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* C = A (:,f)', which also packs A if needed. */
+    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset) */
+    ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order the matrix (destroys the contents of C->i and C->p) */
+    /* ---------------------------------------------------------------------- */
+
+    /* get parameters */
+    if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
+    {
+	/* this is the CHOLMOD default, not the COLAMD default */
+	knobs [COLAMD_DENSE_ROW] = -1 ;
+    }
+    else
+    {
+	/* get the knobs from the Common parameters */
+	knobs [COLAMD_DENSE_COL] = Common->method[Common->current].prune_dense ;
+	knobs [COLAMD_DENSE_ROW] = Common->method[Common->current].prune_dense2;
+	knobs [COLAMD_AGGRESSIVE] = Common->method[Common->current].aggressive ;
+    }
+
+    if (ok)
+    {
+	Int *Cp ;
+	Int stats [COLAMD_STATS] ;
+	Cp = C->p ;
+
+#ifdef LONG
+	colamd_l (ncol, nrow, alen, C->i, Cp, knobs, stats) ;
+#else
+	colamd (ncol, nrow, alen, C->i, Cp, knobs, stats) ;
+#endif
+
+	ok = stats [COLAMD_STATUS] ;
+	ok = (ok == COLAMD_OK || ok == COLAMD_OK_BUT_JUMBLED) ;
+	/* permutation returned in C->p, if the ordering succeeded */
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    Perm [k] = Cp [k] ;
+	}
+    }
+
+    CHOLMOD(free_sparse) (&C, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* column etree postordering */
+    /* ---------------------------------------------------------------------- */
+
+    if (postorder)
+    {
+	/* use the last 2*n space in Iwork for Parent and Post */
+	Work2n = Common->Iwork ;
+	Work2n += 2*((size_t) nrow) + ncol ;
+	Parent = Work2n ;		/* size nrow (i/i/l) */
+	Post   = Work2n + nrow ;	/* size nrow (i/i/l) */
+
+	/* workspace: Iwork (2*nrow+ncol), Flag (nrow), Head (nrow+1) */
+	ok = ok && CHOLMOD(analyze_ordering) (A, CHOLMOD_COLAMD, Perm, fset,
+		fsize, Parent, Post, NULL, NULL, NULL, Common) ;
+
+	/* combine the colamd permutation with its postordering */
+	if (ok)
+	{
+	    NewPerm = Common->Iwork ;		/* size nrow (i/i/l) */
+	    for (k = 0 ; k < nrow ; k++)
+	    {
+		NewPerm [k] = Perm [Post [k]] ;
+	    }
+	    for (k = 0 ; k < nrow ; k++)
+	    {
+		Perm [k] = NewPerm [k] ;
+	    }
+	}
+    }
+
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_etree.c b/src/CHOLMOD/Cholesky/cholmod_etree.c
new file mode 100644
index 0000000..0dcb85f
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_etree.c
@@ -0,0 +1,226 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_etree =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Compute the elimination tree of A or A'*A
+ *
+ * In the symmetric case, the upper triangular part of A is used.  Entries not
+ * in this part of the matrix are ignored.  Computing the etree of a symmetric
+ * matrix from just its lower triangular entries is not supported.
+ *
+ * In the unsymmetric case, all of A is used, and the etree of A'*A is computed.
+ *
+ * References:
+ *
+ * J. Liu, "A compact row storage scheme for Cholesky factors", ACM Trans.
+ * Math. Software, vol 12, 1986, pp. 127-148.
+ *
+ * J. Liu, "The role of elimination trees in sparse factorization", SIAM J.
+ * Matrix Analysis & Applic., vol 11, 1990, pp. 134-172.
+ *
+ * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for
+ * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710.
+ *
+ * workspace: symmetric: Iwork (nrow), unsymmetric: Iwork (nrow+ncol)
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === update_etree ========================================================= */
+/* ========================================================================== */
+
+static void update_etree
+(
+    /* inputs, not modified */
+    Int k,		/* process the edge (k,i) in the input graph */
+    Int i,
+    /* inputs, modified on output */
+    Int Parent [ ],	/* Parent [t] = p if p is the parent of t */
+    Int Ancestor [ ]	/* Ancestor [t] is the ancestor of node t in the
+			   partially-constructed etree */
+)
+{
+    Int a ;
+    for ( ; ; )		/* traverse the path from k to the root of the tree */
+    {
+	a = Ancestor [k] ;
+	if (a == i)
+	{
+	    /* final ancestor reached; no change to tree */
+	    return ;
+	}
+	/* perform path compression */
+	Ancestor [k] = i ;
+	if (a == EMPTY)
+	{
+	    /* final ancestor undefined; this is a new edge in the tree */
+	    Parent [k] = i ;
+	    return ;
+	}
+	/* traverse up to the ancestor of k */
+	k = a ;
+    }
+}
+
+/* ========================================================================== */
+/* === cholmod_etree ======================================================== */
+/* ========================================================================== */
+
+/* Find the elimination tree of A or A'*A */
+
+int CHOLMOD(etree)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* ---- output --- */
+    Int *Parent,	/* size ncol.  Parent [j] = p if p is the parent of j */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Ai, *Anz, *Ancestor, *Prev, *Iwork ;
+    Int i, j, jprev, p, pend, nrow, ncol, packed, stype ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    stype = A->stype ;
+
+    /* s = A->nrow + (stype ? 0 : A->ncol) */
+    s = CHOLMOD(add_size_t) (A->nrow, (stype ? 0 : A->ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "etree", Common) >= 0) ;
+    Iwork = Common->Iwork ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;	/* the number of columns of A */
+    nrow = A->nrow ;	/* the number of rows of A */
+    Ap = A->p ;		/* size ncol+1, column pointers for A */
+    Ai = A->i ;		/* the row indices of A */
+    Anz = A->nz ;	/* number of nonzeros in each column of A */
+    packed = A->packed ;
+    Ancestor = Iwork ;	/* size ncol (i/i/l) */
+
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Parent [j] = EMPTY ;
+	Ancestor [j] = EMPTY ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the etree */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype > 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetric (upper) case: compute etree (A) */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    /* for each row i in column j of triu(A), excluding the diagonal */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i < j)
+		{
+		    update_etree (i, j, Parent, Ancestor) ;
+		}
+	    }
+	}
+
+    }
+    else if (stype == 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* unsymmetric case: compute etree (A'*A) */
+	/* ------------------------------------------------------------------ */
+
+	Prev = Iwork + ncol ;	/* size nrow (i/i/l) */
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Prev [i] = EMPTY ;
+	}
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    /* for each row i in column j of A */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		/* a graph is constructed dynamically with one path per row
+		 * of A.  If the ith row of A contains column indices
+		 * (j1,j2,j3,j4) then the new graph has edges (j1,j2), (j2,j3),
+		 * and (j3,j4).  When at node i of this path-graph, all edges
+		 * (jprev,j) are considered, where jprev<j */
+		i = Ai [p] ;
+		jprev = Prev [i] ;
+		if (jprev != EMPTY)
+		{
+		    update_etree (jprev, j, Parent, Ancestor) ;
+		}
+		Prev [i] = j ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetric case with lower triangular part not supported */
+	/* ------------------------------------------------------------------ */
+
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+
+    ASSERT (CHOLMOD(dump_parent) (Parent, ncol, "Parent", Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_factorize.c b/src/CHOLMOD/Cholesky/cholmod_factorize.c
new file mode 100644
index 0000000..884fdc7
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_factorize.c
@@ -0,0 +1,428 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_factorize =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Computes the numerical factorization of a symmetric matrix.  The primary
+ * inputs to this routine are a sparse matrix A and the symbolic factor L from
+ * cholmod_analyze or a prior numerical factor L.  If A is symmetric, this
+ * routine factorizes A(p,p)+beta*I (beta can be zero), where p is the
+ * fill-reducing permutation (L->Perm).  If A is unsymmetric, either
+ * A(p,:)*A(p,:)'+beta*I or A(p,f)*A(p,f)'+beta*I is factorized.  The set f and
+ * the nonzero pattern of the matrix A must be the same as the matrix passed to
+ * cholmod_analyze for the supernodal case.  For the simplicial case, it can
+ * be different, but it should be the same for best performance.  beta is real.
+ *
+ * A simplicial factorization or supernodal factorization is chosen, based on
+ * the type of the factor L.  If L->is_super is TRUE, a supernodal LL'
+ * factorization is computed.  Otherwise, a simplicial numeric factorization
+ * is computed, either LL' or LDL', depending on Common->final_ll.
+ *
+ * Once the factorization is complete, it can be left as is or optionally
+ * converted into any simplicial numeric type, depending on the
+ * Common->final_* parameters.  If converted from a supernodal to simplicial
+ * type, and the Common->final_resymbol parameter is true, then numerically
+ * zero entries in L due to relaxed supernodal amalgamation are removed from
+ * the simplicial factor (they are always left in the supernodal form of L).
+ * Entries that are numerically zero but present in the simplicial symbolic
+ * pattern of L are left in place (that is, the graph of L remains chordal).
+ * This is required for the update/downdate/rowadd/rowdel routines to work
+ * properly.
+ *
+ * workspace: Flag (nrow), Head (nrow+1),
+ *	if symmetric:   Iwork (2*nrow+2*nsuper)
+ *	if unsymmetric: Iwork (2*nrow+MAX(2*nsuper,ncol))
+ *	    where nsuper is 0 if simplicial, or the # of relaxed supernodes in
+ *	    L otherwise (nsuper <= nrow).
+ *	if simplicial: W (nrow).
+ *	Allocates up to two temporary copies of its input matrix (including
+ *	both pattern and numerical values).
+ *
+ * If the matrix is not positive definite the routine returns TRUE, but
+ * sets Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the
+ * column at which the failure occurred.  Columns L->minor to L->n-1 are
+ * set to zero.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex), except that the
+ * input matrix A cannot be pattern-only.  If L is simplicial, its numeric
+ * xtype matches A on output.  If L is supernodal, its xtype is real if A is
+ * real, or complex if A is complex or zomplex.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+
+/* ========================================================================== */
+/* === cholmod_factorize ==================================================== */
+/* ========================================================================== */
+
+/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained
+ * from cholmod_analyze.  The analysis can be re-used simply by calling this
+ * routine a second time with another matrix.  A must have the same nonzero
+ * pattern as that passed to cholmod_analyze. */
+
+int CHOLMOD(factorize)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double zero [2] ;
+    zero [0] = 0 ;
+    zero [1] = 0 ;
+    return (CHOLMOD(factorize_p) (A, zero, NULL, 0, L, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_factorize_p ================================================== */
+/* ========================================================================== */
+
+/* Same as cholmod_factorize, but with more options. */
+
+int CHOLMOD(factorize_p)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *S, *F, *A1, *A2 ;
+    Int nrow, ncol, stype, convert, n, nsuper, grow2, status ;
+    size_t s, t, uncol ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    n = L->n ;
+    stype = A->stype ;
+    if (L->n != A->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+    if (stype != 0 && nrow != ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (FALSE) ;
+    }
+    DEBUG (CHOLMOD(dump_sparse) (A, "A for cholmod_factorize", Common)) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = (L->is_super ? L->nsuper : 0) ;
+    uncol = ((stype != 0) ? 0 : ncol) ;
+
+    /* s = 2*nrow + MAX (uncol, 2*nsuper) */
+    s = CHOLMOD(mult_size_t) (nsuper, 2, &ok) ;
+    s = MAX (uncol, s) ;
+    t = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    s = CHOLMOD(add_size_t) (s, t, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    S  = NULL ;
+    F  = NULL ;
+    A1 = NULL ;
+    A2 = NULL ;
+
+    /* convert to another form when done, if requested */
+    convert = !(Common->final_asis) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* perform supernodal LL' or simplicial LDL' factorization */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->is_super)
+    {
+
+#ifndef NSUPERNODAL
+
+	/* ------------------------------------------------------------------ */
+	/* supernodal factorization */
+	/* ------------------------------------------------------------------ */
+
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* natural ordering */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* S = tril (A'), F not needed */
+		/* workspace: Iwork (nrow) */
+		A1 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ;
+		S = A1 ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* This is the fastest option for the natural ordering */
+		/* S = A; F not needed */
+		S = A ;
+	    }
+	    else
+	    {
+		/* F = A(:,f)' */
+		/* workspace: Iwork (nrow) */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ;
+		F = A1 ;
+		/* S = A */
+		S = A ;
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* permute the input matrix before factorization */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* This is the fastest option for factoring a permuted matrix */
+		/* S = tril (PAP'); F not needed */
+		/* workspace: Iwork (2*nrow) */
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+		S = A1 ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* A2 = triu (PAP') */
+		/* workspace: Iwork (2*nrow) */
+		A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+		/* S = tril (A2'); F not needed */
+		/* workspace: Iwork (nrow) */
+		A1 = CHOLMOD(ptranspose) (A2, 2, NULL, NULL, 0, Common) ;
+		S = A1 ;
+		CHOLMOD(free_sparse) (&A2, Common) ;
+		ASSERT (A2 == NULL) ;
+	    }
+	    else
+	    {
+		/* F = A(p,f)' */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ;
+		F = A1 ;
+		/* S = F' */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ;
+		S = A2 ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* supernodal factorization */
+	/* ------------------------------------------------------------------ */
+
+	/* workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow+2*nsuper) */
+	if (Common->status == CHOLMOD_OK)
+	{
+	    CHOLMOD(super_numeric) (S, F, beta, L, Common) ;
+	}
+	status = Common->status ;
+	ASSERT (IMPLIES (status >= CHOLMOD_OK, L->xtype != CHOLMOD_PATTERN)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* convert to final form, if requested */
+	/* ------------------------------------------------------------------ */
+
+	if (Common->status >= CHOLMOD_OK && convert)
+	{
+	    /* workspace: none */
+	    ok = CHOLMOD(change_factor) (L->xtype, Common->final_ll,
+		    Common->final_super, Common->final_pack,
+		    Common->final_monotonic, L, Common) ;
+	    if (ok && Common->final_resymbol && !(L->is_super))
+	    {
+		/* workspace: Flag (nrow), Head (nrow+1),
+		 *	if symmetric:   Iwork (2*nrow)
+		 *	if unsymmetric: Iwork (2*nrow+ncol) */
+		CHOLMOD(resymbol_noperm) (S, fset, fsize, Common->final_pack,
+		    L, Common) ;
+	    }
+	}
+
+#else
+
+	/* ------------------------------------------------------------------ */
+	/* CHOLMOD Supernodal module not installed */
+	/* ------------------------------------------------------------------ */
+
+	status = CHOLMOD_NOT_INSTALLED ;
+	ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ;
+
+#endif
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* simplicial LDL' factorization */
+	/* ------------------------------------------------------------------ */
+
+	/* Permute the input matrix A if necessary.  cholmod_rowfac requires
+	 * triu(A) in column form for the symmetric case, and A in column form
+	 * for the unsymmetric case (the matrix S).  The unsymmetric case
+	 * requires A in row form, or equivalently A' in column form (the
+	 * matrix F).
+	 */
+
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* natural ordering */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* F is not needed, S = A */
+		S = A ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* F is not needed, S = A' */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (A, 2, NULL, NULL, 0, Common) ;
+		S = A2 ;
+	    }
+	    else
+	    {
+		/* F = A (:,f)' */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, NULL, fset, fsize, Common) ;
+		F = A1 ;
+		S = A ;
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* permute the input matrix before factorization */
+	    /* -------------------------------------------------------------- */
+
+	    if (stype > 0)
+	    {
+		/* F = tril (A (p,p)') */
+		/* workspace: Iwork (2*nrow) */
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+		/* A2 = triu (F') */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (A1, 2, NULL, NULL, 0, Common) ;
+		/* the symmetric case does not need F, free it and set to NULL*/
+		CHOLMOD(free_sparse) (&A1, Common) ;
+	    }
+	    else if (stype < 0)
+	    {
+		/* A2 = triu (A (p,p)'), F not needed.  This is the fastest
+		 * way to factorize a matrix using the simplicial routine
+		 * (cholmod_rowfac). */
+		/* workspace: Iwork (2*nrow) */
+		A2 = CHOLMOD(ptranspose) (A, 2, L->Perm, NULL, 0, Common) ;
+	    }
+	    else
+	    {
+		/* F = A (p,f)' */
+		/* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+		A1 = CHOLMOD(ptranspose) (A, 2, L->Perm, fset, fsize, Common) ;
+		F = A1 ;
+		/* A2 = F' */
+		/* workspace: Iwork (nrow) */
+		A2 = CHOLMOD(ptranspose) (F, 2, NULL, NULL, 0, Common) ;
+	    }
+	    S = A2 ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* simplicial LDL' or LL' factorization */
+	/* ------------------------------------------------------------------ */
+
+	/* factorize beta*I+S (symmetric) or beta*I+F*F' (unsymmetric) */
+	/* workspace: Flag (nrow), W (nrow), Iwork (2*nrow) */
+	if (Common->status == CHOLMOD_OK)
+	{
+	    grow2 = Common->grow2 ;
+	    L->is_ll = BOOLEAN (Common->final_ll) ;
+	    if (L->xtype == CHOLMOD_PATTERN && Common->final_pack)
+	    {
+		/* allocate a factor with exactly the space required */
+		Common->grow2 = 0 ;
+	    }
+	    CHOLMOD(rowfac) (S, F, beta, 0, nrow, L, Common) ;
+	    Common->grow2 = grow2 ;
+	}
+	status = Common->status ;
+
+	/* ------------------------------------------------------------------ */
+	/* convert to final form, if requested */
+	/* ------------------------------------------------------------------ */
+
+	if (Common->status >= CHOLMOD_OK && convert)
+	{
+	    /* workspace: none */
+	    CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE,
+		    Common->final_pack, Common->final_monotonic, L, Common) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free A1 and A2 if they exist */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&A1, Common) ;
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    Common->status = MAX (Common->status, status) ;
+    return (Common->status >= CHOLMOD_OK) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_postorder.c b/src/CHOLMOD/Cholesky/cholmod_postorder.c
new file mode 100644
index 0000000..f66b1df
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_postorder.c
@@ -0,0 +1,291 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_postorder =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Compute the postorder of a tree. */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+
+/* ========================================================================== */
+/* === dfs ================================================================== */
+/* ========================================================================== */
+
+/* The code below includes both a recursive and non-recursive depth-first-search
+ * of a tree.  The recursive code is simpler, but can lead to stack overflow.
+ * It is left here for reference, to understand what the non-recursive code
+ * is computing.  To try the recursive version, uncomment the following
+ * #define, or compile the code with -DRECURSIVE.  Be aware that stack
+ * overflow may occur.
+#define RECURSIVE
+ */
+
+#ifdef RECURSIVE
+
+/* recursive version: a working code for reference only, not actual use */
+
+static Int dfs			/* return the new value of k */
+(
+    Int p,		/* start a DFS at node p */
+    Int k,		/* start the node numbering at k */
+    Int Post [ ],	/* Post ordering, modified on output */
+    Int Head [ ],	/* Head [p] = youngest child of p; EMPTY on output */
+    Int Next [ ],	/* Next [j] = sibling of j; unmodified */
+    Int Pstack [ ]	/* unused */
+)
+{
+    Int j ;
+    /* start a DFS at each child of node p */
+    for (j = Head [p] ; j != EMPTY ; j = Next [j])
+    {
+	/* start a DFS at child node j */
+	k = dfs (j, k, Post, Head, Next, Pstack) ;
+    }
+    Post [k++] = p ;	/* order node p as the kth node */
+    Head [p] = EMPTY ;	/* link list p no longer needed */
+    return (k) ;	/* the next node will be numbered k */
+}
+
+#else
+
+/* non-recursive version for actual use */
+
+static Int dfs		/* return the new value of k */
+(
+    Int p,		/* start the DFS at a root node p */
+    Int k,		/* start the node numbering at k */
+    Int Post [ ],	/* Post ordering, modified on output */
+    Int Head [ ],	/* Head [p] = youngest child of p; EMPTY on output */
+    Int Next [ ],	/* Next [j] = sibling of j; unmodified */
+    Int Pstack [ ]	/* workspace of size n, undefined on input or output */
+)
+{
+    Int j, phead ;
+
+    /* put the root node on the stack */
+    Pstack [0] = p ;
+    phead = 0 ;
+
+    /* while the stack is not empty, do: */
+    while (phead >= 0)
+    {
+	/* grab the node p from top of the stack and get its youngest child j */
+	p = Pstack [phead] ;
+	j = Head [p] ;
+	if (j == EMPTY)
+	{
+	    /* all children of p ordered.  remove p from stack and order it */
+	    phead-- ;
+	    Post [k++] = p ;	/* order node p as the kth node */
+	}
+	else
+	{
+	    /* leave p on the stack.  Start a DFS at child node j by putting
+	     * j on the stack and removing j from the list of children of p. */
+	    Head [p] = Next [j] ;
+	    Pstack [++phead] = j ;
+	}
+    }
+    return (k) ;	/* the next node will be numbered k */
+}
+
+#endif
+
+/* ========================================================================== */
+/* === cholmod_postorder ==================================================== */
+/* ========================================================================== */
+
+/* Postorder a tree.  The tree is either an elimination tree (the output from
+ * from cholmod_etree) or a component tree (from cholmod_nested_dissection).
+ *
+ * An elimination tree is a complete tree of n nodes with Parent [j] > j or
+ * Parent [j] = EMPTY if j is a root.  On output Post [0..n-1] is a complete
+ * permutation vector.
+ *
+ * A component tree is a subset of 0..n-1.  Parent [j] = -2 if node j is not
+ * in the component tree.  Parent [j] = EMPTY if j is a root of the component
+ * tree, and Parent [j] is in the range 0 to n-1 if j is in the component
+ * tree but not a root.  On output, Post [k] is defined only for nodes in
+ * the component tree.  Post [k] = j if node j is the kth node in the
+ * postordered component tree, where k is in the range 0 to the number of
+ * components minus 1.
+ *
+ * Node j is ignored and not included in the postorder if Parent [j] < EMPTY.
+ *
+ * As a result, check_parent (Parent, n,...) may fail on input, since
+ * cholmod_check_parent assumes Parent is an elimination tree.  Similarly,
+ * cholmod_check_perm (Post, ...) may fail on output, since Post is a partial
+ * permutation if Parent is a component tree.
+ *
+ * An optional node weight can be given.  When starting a postorder at node j,
+ * the children of j are ordered in increasing order of their weight.
+ * If no weights are given (Weight is NULL) then children are ordered in
+ * increasing order of their node number.  The weight of a node must be in the
+ * range 0 to n-1.  Weights outside that range are silently converted to that
+ * range (weights < 0 are treated as zero, and weights >= n are treated as n-1).
+ *
+ *
+ * workspace: Head (n), Iwork (2*n)
+ */
+
+SuiteSparse_long CHOLMOD(postorder)	/* return # of nodes postordered */
+(
+    /* ---- input ---- */
+    Int *Parent,	/* size n. Parent [j] = p if p is the parent of j */
+    size_t n,
+    Int *Weight,	/* size n, optional. Weight [j] is weight of node j */
+    /* ---- output --- */
+    Int *Post,		/* size n. Post [k] = j is kth in postordered tree */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Head, *Next, *Pstack, *Iwork ;
+    Int j, p, k, w, nextj ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (Parent, EMPTY) ;
+    RETURN_IF_NULL (Post, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 2*n */
+    s = CHOLMOD(mult_size_t) (n, 2, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (EMPTY) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Head  = Common->Head ;	/* size n+1, initially all EMPTY */
+    Iwork = Common->Iwork ;
+    Next  = Iwork ;		/* size n (i/i/l) */
+    Pstack = Iwork + n ;	/* size n (i/i/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct a link list of children for each node */
+    /* ---------------------------------------------------------------------- */
+
+    if (Weight == NULL)
+    {
+
+	/* in reverse order so children are in ascending order in each list */
+	for (j = n-1 ; j >= 0 ; j--)
+	{
+	    p = Parent [j] ;
+	    if (p >= 0 && p < ((Int) n))
+	    {
+		/* add j to the list of children for node p */
+		Next [j] = Head [p] ;
+		Head [p] = j ;
+	    }
+	}
+
+	/* Head [p] = j if j is the youngest (least-numbered) child of p */
+	/* Next [j1] = j2 if j2 is the next-oldest sibling of j1 */
+
+    }
+    else
+    {
+
+	/* First, construct a set of link lists according to Weight.
+	 *
+	 * Whead [w] = j if node j is the first node in bucket w.
+	 * Next [j1] = j2 if node j2 follows j1 in a link list.
+	 */
+
+	Int *Whead = Pstack ;	    /* use Pstack as workspace for Whead [ */
+
+	for (w = 0 ; w < ((Int) n) ; w++)
+	{
+	    Whead [w] = EMPTY ;
+	}
+	/* do in forward order, so nodes that ties are ordered by node index */
+	for (j = 0 ; j < ((Int) n) ; j++)
+	{
+	    p = Parent [j] ;
+	    if (p >= 0 && p < ((Int) n))
+	    {
+		w = Weight [j] ;
+		w = MAX (0, w) ;
+		w = MIN (w, ((Int) n) - 1) ;
+		/* place node j at the head of link list for weight w */
+		Next [j] = Whead [w] ;
+		Whead [w] = j ;
+	    }
+	}
+
+	/* traverse weight buckets, placing each node in its parent's list */
+	for (w = n-1 ; w >= 0 ; w--)
+	{
+	    for (j = Whead [w] ; j != EMPTY ; j = nextj)
+	    {
+		nextj = Next [j] ;
+		/* put node j in the link list of its parent */
+		p = Parent [j] ;
+		ASSERT (p >= 0 && p < ((Int) n)) ;
+		Next [j] = Head [p] ;
+		Head [p] = j ;
+	    }
+	}
+
+	/* Whead no longer needed ] */
+	/* Head [p] = j if j is the lightest child of p */
+	/* Next [j1] = j2 if j2 is the next-heaviest sibling of j1 */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* start a DFS at each root node of the etree */
+    /* ---------------------------------------------------------------------- */
+
+    k = 0 ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	if (Parent [j] == EMPTY)
+	{
+	    /* j is the root of a tree; start a DFS here */
+	    k = dfs (j, k, Post, Head, Next, Pstack) ;
+	}
+    }
+
+    /* this would normally be EMPTY already, unless Parent is invalid */
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	Head [j] = EMPTY ;
+    }
+
+    PRINT1 (("postordered "ID" nodes\n", k)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (k) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_rcond.c b/src/CHOLMOD/Cholesky/cholmod_rcond.c
new file mode 100644
index 0000000..f261e31
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_rcond.c
@@ -0,0 +1,160 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_rcond =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Return a rough estimate of the reciprocal of the condition number:
+ * the minimum entry on the diagonal of L (or absolute entry of D for an LDL'
+ * factorization) divided by the maximum entry (squared for LL').  L can be
+ * real, complex, or zomplex.  Returns -1 on error, 0 if the matrix is singular
+ * or has a zero entry on the diagonal of L, 1 if the matrix is 0-by-0, or
+ * min(diag(L))/max(diag(L)) otherwise.  Never returns NaN; if L has a NaN on
+ * the diagonal it returns zero instead.
+ *
+ * For an LL' factorization,  (min(diag(L))/max(diag(L)))^2 is returned.
+ * For an LDL' factorization, (min(diag(D))/max(diag(D))) is returned.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === LMINMAX ============================================================== */
+/* ========================================================================== */
+
+/* Update lmin and lmax for one entry L(j,j) */
+
+#define FIRST_LMINMAX(Ljj,lmin,lmax) \
+{ \
+    double ljj = Ljj ; \
+    if (IS_NAN (ljj)) \
+    { \
+	return (0) ; \
+    } \
+    lmin = ljj ; \
+    lmax = ljj ; \
+}
+
+#define LMINMAX(Ljj,lmin,lmax) \
+{ \
+    double ljj = Ljj ; \
+    if (IS_NAN (ljj)) \
+    { \
+	return (0) ; \
+    } \
+    if (ljj < lmin) \
+    { \
+	lmin = ljj ; \
+    } \
+    else if (ljj > lmax) \
+    { \
+	lmax = ljj ; \
+    } \
+}
+
+/* ========================================================================== */
+/* === cholmod_rcond ======================================================== */
+/* ========================================================================== */
+
+double CHOLMOD(rcond)	    /* return min(diag(L)) / max(diag(L)) */
+(
+    /* ---- input ---- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double lmin, lmax, rcond ;
+    double *Lx ;
+    Int *Lpi, *Lpx, *Super, *Lp ;
+    Int n, e, nsuper, s, k1, k2, psi, psend, psx, nsrow, nscol, jj, j ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (L, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    n = L->n ;
+    if (n == 0)
+    {
+	return (1) ;
+    }
+    if (L->minor < L->n)
+    {
+	return (0) ;
+    }
+
+    e = (L->xtype == CHOLMOD_COMPLEX) ? 2 : 1 ;
+
+    if (L->is_super)
+    {
+	/* L is supernodal */
+	nsuper = L->nsuper ;	/* number of supernodes in L */
+	Lpi = L->pi ;		/* column pointers for integer pattern */
+	Lpx = L->px ;		/* column pointers for numeric values */
+	Super = L->super ;	/* supernode sizes */
+	Lx = L->x ;		/* numeric values */
+	FIRST_LMINMAX (Lx [0], lmin, lmax) ;	/* first diagonal entry of L */
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;		/* first column in supernode s */
+	    k2 = Super [s+1] ;		/* last column in supernode is k2-1 */
+	    psi = Lpi [s] ;		/* first row index is L->s [psi] */
+	    psend = Lpi [s+1] ;		/* last row index is L->s [psend-1] */
+	    psx = Lpx [s] ;		/* first numeric entry is Lx [psx] */
+	    nsrow = psend - psi ;	/* supernode is nsrow-by-nscol */
+	    nscol = k2 - k1 ;
+	    for (jj = 0 ; jj < nscol ; jj++)
+	    {
+		LMINMAX (Lx [e * (psx + jj + jj*nsrow)], lmin, lmax) ;
+	    }
+	}
+    }
+    else
+    {
+	/* L is simplicial */
+	Lp = L->p ;
+	Lx = L->x ;
+	if (L->is_ll)
+	{
+	    /* LL' factorization */
+	    FIRST_LMINMAX (Lx [Lp [0]], lmin, lmax) ;
+	    for (j = 1 ; j < n ; j++)
+	    {
+		LMINMAX (Lx [e * Lp [j]], lmin, lmax) ;
+	    }
+	}
+	else
+	{
+	    /* LDL' factorization, the diagonal might be negative */
+	    FIRST_LMINMAX (fabs (Lx [Lp [0]]), lmin, lmax) ;
+	    for (j = 1 ; j < n ; j++)
+	    {
+		LMINMAX (fabs (Lx [e * Lp [j]]), lmin, lmax) ;
+	    }
+	}
+    }
+    rcond = lmin / lmax ;
+    if (L->is_ll)
+    {
+	rcond = rcond*rcond ;
+    }
+    return (rcond) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_resymbol.c b/src/CHOLMOD/Cholesky/cholmod_resymbol.c
new file mode 100644
index 0000000..5b39cd9
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_resymbol.c
@@ -0,0 +1,608 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_resymbol ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Recompute the symbolic pattern of L.  Entries not in the symbolic pattern
+ * are dropped.  L->Perm can be used (or not) to permute the input matrix A.
+ *
+ * These routines are used after a supernodal factorization is converted into
+ * a simplicial one, to remove zero entries that were added due to relaxed
+ * supernode amalgamation.  They can also be used after a series of downdates
+ * to remove entries that would no longer be present if the matrix were
+ * factorized from scratch.  A downdate (cholmod_updown) does not remove any
+ * entries from L.
+ *
+ * workspace: Flag (nrow), Head (nrow+1),
+ *	if symmetric:   Iwork (2*nrow)
+ *	if unsymmetric: Iwork (2*nrow+ncol).
+ *	Allocates up to 2 copies of its input matrix A (pattern only).
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === cholmod_resymbol ===================================================== */
+/* ========================================================================== */
+
+/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P',
+ * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not).
+ *
+ * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it
+ * first permutes A according to L->Perm.  A can be upper/lower/unsymmetric,
+ * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */
+
+int CHOLMOD(resymbol)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *H, *F, *G ;
+    Int stype, nrow, ncol ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    if (L->is_super)
+    {
+	/* cannot operate on a supernodal factorization */
+	ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ;
+	return (FALSE) ;
+    }
+    if (L->n != A->nrow)
+    {
+	/* dimensions must agree */
+	ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    stype = A->stype ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    /* s = 2*nrow + (stype ? 0 : ncol) */
+    s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    s = CHOLMOD(add_size_t) (s, (stype ? 0 : ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* permute the input matrix if necessary */
+    /* ---------------------------------------------------------------------- */
+
+    H = NULL ;
+    G = NULL ;
+
+    if (stype > 0)
+    {
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+	    /* F = triu(A)' */
+	    /* workspace: Iwork (nrow) */
+	    G = CHOLMOD(ptranspose) (A, 0, NULL, NULL, 0, Common) ;
+	}
+	else
+	{
+	    /* F = triu(A(p,p))' */
+	    /* workspace: Iwork (2*nrow) */
+	    G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ;
+	}
+	F = G ;
+    }
+    else if (stype < 0)
+    {
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+	    F = A ;
+	}
+	else
+	{
+	    /* G = triu(A(p,p))' */
+	    /* workspace: Iwork (2*nrow) */
+	    G = CHOLMOD(ptranspose) (A, 0, L->Perm, NULL, 0, Common) ;
+	    /* H = G' */
+	    /* workspace: Iwork (nrow) */
+	    H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ;
+	    F = H ;
+	}
+    }
+    else
+    {
+	if (L->ordering == CHOLMOD_NATURAL)
+	{
+	    F = A ;
+	}
+	else
+	{
+	    /* G = A(p,f)' */
+	    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+	    G = CHOLMOD(ptranspose) (A, 0, L->Perm, fset, fsize, Common) ;
+	    /* H = G' */
+	    /* workspace: Iwork (ncol) */
+	    H = CHOLMOD(ptranspose) (G, 0, NULL, NULL, 0, Common) ;
+	    F = H ;
+	}
+    }
+
+    /* No need to check for failure here.  cholmod_resymbol_noperm will return
+     * FALSE if F is NULL. */
+
+    /* ---------------------------------------------------------------------- */
+    /* resymbol */
+    /* ---------------------------------------------------------------------- */
+
+    ok = CHOLMOD(resymbol_noperm) (F, fset, fsize, pack, L, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the temporary matrices, if they exist */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&H, Common) ;
+    CHOLMOD(free_sparse) (&G, Common) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_resymbol_noperm ============================================== */
+/* ========================================================================== */
+
+/* Redo symbolic LDL' or LL' factorization of I + F*F' or I+A, where F=A(:,f).
+ *
+ * L already exists, but is a superset of the true dynamic pattern (simple
+ * column downdates and row deletions haven't pruned anything).  Just redo the
+ * symbolic factorization and drop entries that are no longer there.  The
+ * diagonal is not modified.  The number of nonzeros in column j of L
+ * (L->nz[j]) can decrease.  The column pointers (L->p[j]) remain unchanged if
+ * pack is FALSE or if L is not monotonic.  Otherwise, the columns of L are
+ * packed in place.
+ *
+ * For the symmetric case, the columns of the lower triangular part of A
+ * are accessed by column.  NOTE that this the transpose of the general case.
+ *
+ * For the unsymmetric case, F=A(:,f) is accessed by column.
+ *
+ * A need not be sorted, and can be packed or unpacked.  If L->Perm is not
+ * identity, then A must already be permuted according to the permutation used
+ * to factorize L.  The advantage of using this routine is that it does not
+ * need to create permuted copies of A first.
+ *
+ * This routine can be called if L is only partially factored via cholmod_rowfac
+ * since all it does is prune.  If an entry is in F*F' or A, but not in L, it
+ * isn't added to L.
+ *
+ * L must be simplicial LDL' or LL'; it cannot be supernodal or symbolic.
+ *
+ * The set f is held in fset and fsize.
+ *	fset = NULL means ":" in MATLAB. fset is ignored.
+ *	fset != NULL means f = fset [0..fset-1].
+ *	fset != NULL and fsize = 0 means f is the empty set.
+ *	There can be no duplicates in fset.
+ *	Common->status is set to CHOLMOD_INVALID if fset is invalid.
+ *
+ * workspace: Flag (nrow), Head (nrow+1),
+ *	if symmetric:   Iwork (2*nrow)
+ *	if unsymmetric: Iwork (2*nrow+ncol).
+ *	Unlike cholmod_resymbol, this routine does not allocate any temporary
+ *	copies of its input matrix.
+ */
+
+int CHOLMOD(resymbol_noperm)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Lz ;
+    Int i, j, k, row, parent, p, pend, pdest, ncol, apacked, sorted, nrow, nf,
+	use_fset, mark, jj, stype, xtype ;
+    Int *Ap, *Ai, *Anz, *Li, *Lp, *Lnz, *Flag, *Head, *Link, *Anext, *Iwork ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+    stype = A->stype ;
+    ASSERT (IMPLIES (stype != 0, nrow == ncol)) ;
+    if (stype > 0)
+    {
+	/* symmetric, with upper triangular part, not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric upper not supported ") ;
+	return (FALSE) ;
+    }
+    if (L->is_super)
+    {
+	/* cannot operate on a supernodal or symbolic factorization */
+	ERROR (CHOLMOD_INVALID, "cannot operate on supernodal L") ;
+	return (FALSE) ;
+    }
+    if (L->n != A->nrow)
+    {
+	/* dimensions must agree */
+	ERROR (CHOLMOD_INVALID, "A and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 2*nrow + (stype ? 0 : ncol) */
+    s = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    if (stype != 0)
+    {
+	s = CHOLMOD(add_size_t) (s, ncol, &ok) ;
+    }
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ai = A->i ;
+    Ap = A->p ;
+    Anz = A->nz ;
+    apacked = A->packed ;
+    sorted = A->sorted ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+    xtype = L->xtype ;
+
+    /* If L is monotonic on input, then it can be packed or
+     * unpacked on output, depending on the pack input parameter. */
+
+    /* cannot pack a non-monotonic matrix */
+    if (!(L->is_monotonic))
+    {
+	pack = FALSE ;
+    }
+
+    ASSERT (L->nzmax >= (size_t) (Lp [L->n])) ;
+
+    pdest = 0 ;
+
+    PRINT1 (("\n\n===================== Resymbol pack %d Apacked %d\n",
+	pack, A->packed)) ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "ReSymbol A:", Common) >= 0) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol initial L (i, x):", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag  = Common->Flag ;	/* size nrow */
+    Head  = Common->Head ;	/* size nrow+1 */
+    Iwork = Common->Iwork ;
+    Link  = Iwork ;		/* size nrow (i/i/l) [ */
+    Lnz   = Iwork + nrow ;	/* size nrow (i/i/l), if L not packed */
+    Anext = Iwork + 2*((size_t) nrow) ;	/* size ncol (i/i/l), unsym. only */
+    for (j = 0 ; j < nrow ; j++)
+    {
+	Link [j] = EMPTY ;
+    }
+
+    /* use Lnz in L itself */
+    Lnz = L->nz ;
+    ASSERT (Lnz != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* for the unsymmetric case, queue each column of A (:,f) */
+    /* ---------------------------------------------------------------------- */
+
+    /* place each column of the basis set on the link list corresponding to */
+    /* the smallest row index in that column */
+
+    if (stype == 0)
+    {
+	use_fset = (fset != NULL) ;
+	if (use_fset)
+	{
+	    nf = fsize ;
+	    /* This is the only O(ncol) loop in cholmod_resymbol.
+	     * It is required only to check the fset. */
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		Anext [j] = -2 ;
+	    }
+	    for (jj = 0 ; jj < nf ; jj++)
+	    {
+		j = fset [jj] ;
+		if (j < 0 || j > ncol || Anext [j] != -2)
+		{
+		    /* out-of-range or duplicate entry in fset */
+		    ERROR (CHOLMOD_INVALID, "fset invalid") ;
+		    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+		    return (FALSE) ;
+		}
+		/* flag column j as having been seen */
+		Anext [j] = EMPTY ;
+	    }
+	    /* the fset is now valid */
+	    ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ;
+	}
+	else
+	{
+	    nf = ncol ;
+	}
+	for (jj = 0 ; jj < nf ; jj++)
+	{
+	    j = (use_fset) ? (fset [jj]) : jj ;
+	    /* column j is the fset; find the smallest row (if any) */
+	    p = Ap [j] ;
+	    pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    if (pend > p)
+	    {
+		k = Ai [p] ;
+		if (!sorted)
+		{
+		    for ( ; p < pend ; p++)
+		    {
+			k = MIN (k, Ai [p]) ;
+		    }
+		}
+		/* place column j on link list k */
+		ASSERT (k >= 0 && k < nrow) ;
+		Anext [j] = Head [k] ;
+		Head [k] = j ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* recompute symbolic LDL' factorization */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < nrow ; k++)
+    {
+
+#ifndef NDEBUG
+	PRINT1 (("\n\n================== Initial column k = "ID"\n", k)) ;
+	for (p = Lp [k] ; p < Lp [k] + Lnz [k] ; p++)
+	{
+	    PRINT1 ((" row: "ID"  value: ", Li [p])) ;
+	    PRINT1 (("\n")) ;
+	}
+	PRINT1 (("Recomputing LDL, column k = "ID"\n", k)) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* compute column k of I+F*F' or I+A */
+	/* ------------------------------------------------------------------ */
+
+	/* flag the diagonal entry */
+	/* mark = CHOLMOD(clear_flag) (Common) ; */
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	mark = Common->mark ;
+
+	Flag [k] = mark ;
+	PRINT1 (("	row: "ID" (diagonal)\n", k)) ;
+
+	if (stype != 0)
+	{
+	    /* merge column k of A into Flag (lower triangular part only) */
+	    p = Ap [k] ;
+	    pend = (apacked) ? (Ap [k+1]) : (p + Anz [k]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i > k)
+		{
+		    Flag [i] = mark ;
+		}
+	    }
+	}
+	else
+	{
+	    /* for each column j whos first row index is in row k */
+	    for (j = Head [k] ; j != EMPTY ; j = Anext [j])
+	    {
+		/* merge column j of A into Flag */
+		PRINT1 (("	---- A column "ID"\n", j)) ;
+		p = Ap [j] ;
+		pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+		PRINT1 (("  length "ID"  adding\n", pend-p)) ;
+		for ( ; p < pend ; p++)
+		{
+#ifndef NDEBUG
+		    ASSERT (Ai [p] >= k && Ai [p] < nrow) ;
+		    if (Flag [Ai [p]] < mark) PRINT1 ((" row "ID"\n", Ai [p])) ;
+#endif
+		    Flag [Ai [p]] = mark ;
+		}
+	    }
+	    /* clear the kth link list */
+	    Head [k] = EMPTY ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* compute pruned pattern of kth column of L = union of children */
+	/* ------------------------------------------------------------------ */
+
+	/* for each column j of L whose parent is k */
+	for (j = Link [k] ; j != EMPTY ; j = Link [j])
+	{
+	    /* merge column j of L into Flag */
+	    PRINT1 (("	---- L column "ID"\n", k)) ;
+	    ASSERT (j < k) ;
+	    ASSERT (Lnz [j] > 0) ;
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+	    ASSERT (Li [p] == j && Li [p+1] == k) ;
+	    p++ ;	    /* skip past the diagonal entry */
+	    for ( ; p < pend ; p++)
+	    {
+		/* add to pattern */
+		ASSERT (Li [p] >= k && Li [p] < nrow) ;
+		Flag [Li [p]] = mark ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* prune the kth column of L */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("Final column of L:\n")) ;
+	p = Lp [k] ;
+	pend = p + Lnz [k] ;
+
+	if (pack)
+	{
+	    /* shift column k upwards */
+	    Lp [k] = pdest ;
+	}
+	else
+	{
+	    /* leave column k in place, just reduce Lnz [k] */
+	    pdest = p ;
+	}
+
+	for ( ; p < pend ; p++)
+	{
+	    ASSERT (pdest < pend) ;
+	    ASSERT (pdest <= p) ;
+	    row = Li [p] ;
+	    ASSERT (row >= k && row < nrow) ;
+	    if (Flag [row] == mark)
+	    {
+		/* keep this entry */
+		Li [pdest] = row ;
+		if (xtype == CHOLMOD_REAL)
+		{
+		    Lx [pdest] = Lx [p] ;
+		}
+		else if (xtype == CHOLMOD_COMPLEX)
+		{
+		    Lx [2*pdest  ] = Lx [2*p  ] ;
+		    Lx [2*pdest+1] = Lx [2*p+1] ;
+		}
+		else if (xtype == CHOLMOD_ZOMPLEX)
+		{
+		    Lx [pdest] = Lx [p] ;
+		    Lz [pdest] = Lz [p] ;
+		}
+		pdest++ ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* prepare this column for its parent */
+	/* ------------------------------------------------------------------ */
+
+	Lnz [k] = pdest - Lp [k] ;
+
+	PRINT1 ((" L("ID") length "ID"\n", k, Lnz [k])) ;
+	ASSERT (Lnz [k] > 0) ;
+
+	/* parent is the first entry in the column after the diagonal */
+	parent = (Lnz [k] > 1) ? (Li [Lp [k] + 1]) : EMPTY ;
+
+	PRINT1 (("parent ("ID") = "ID"\n", k, parent)) ;
+	ASSERT ((parent > k && parent < nrow) || (parent == EMPTY)) ;
+
+	if (parent != EMPTY)
+	{
+	    Link [k] = Link [parent] ;
+	    Link [parent] = k ;
+	}
+    }
+
+    /* done using Iwork for Link, Lnz (if needed), and Anext ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert L to packed, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    if (pack)
+    {
+	/* finalize Lp */
+	Lp [nrow] = pdest ;
+	/* Shrink L to be just large enough.  It cannot fail. */
+	/* workspace: none */
+	ASSERT ((size_t) (Lp [nrow]) <= L->nzmax) ;
+	CHOLMOD(reallocate_factor) (Lp [nrow], L, Common) ;
+	ASSERT (Common->status >= CHOLMOD_OK) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "ReSymbol final L (i, x):", Common)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_rowcolcounts.c b/src/CHOLMOD/Cholesky/cholmod_rowcolcounts.c
new file mode 100644
index 0000000..5b0290d
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_rowcolcounts.c
@@ -0,0 +1,536 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_rowcolcounts ======================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Compute the row and column counts of the Cholesky factor L of the matrix
+ * A or A*A'.  The etree and its postordering must already be computed (see
+ * cholmod_etree and cholmod_postorder) and given as inputs to this routine.
+ *
+ * For the symmetric case (LL'=A), A is accessed by column.  Only the lower
+ * triangular part of A is used.  Entries not in this part of the matrix are
+ * ignored.  This is the same as storing the upper triangular part of A by
+ * rows, with entries in the lower triangular part being ignored.  NOTE: this
+ * representation is the TRANSPOSE of the input to cholmod_etree.
+ *
+ * For the unsymmetric case (LL'=AA'), A is accessed by column.  Equivalently,
+ * if A is viewed as a matrix in compressed-row form, this routine computes
+ * the row and column counts for L where LL'=A'A.  If the input vector f is
+ * present, then F*F' is analyzed instead, where F = A(:,f).
+ *
+ * The set f is held in fset and fsize.
+ *	fset = NULL means ":" in MATLAB. fset is ignored.
+ *	fset != NULL means f = fset [0..fset-1].
+ *	fset != NULL and fsize = 0 means f is the empty set.
+ *	Common->status is set to CHOLMOD_INVALID if fset is invalid.
+ *
+ * In both cases, the columns of A need not be sorted.
+ * A can be packed or unpacked.
+ *
+ * References:
+ * J. Gilbert, E. Ng, B. Peyton, "An efficient algorithm to compute row and
+ * column counts for sparse Cholesky factorization", SIAM J. Matrix Analysis &
+ * Applic., vol 15, 1994, pp. 1075-1091.
+ *
+ * J. Gilbert, X. Li, E. Ng, B. Peyton, "Computing row and column counts for
+ * sparse QR and LU factorization", BIT, vol 41, 2001, pp. 693-710.
+ *
+ * workspace:
+ *	if symmetric:   Flag (nrow), Iwork (2*nrow)
+ *	if unsymmetric: Flag (nrow), Iwork (2*nrow+ncol), Head (nrow+1)
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === initialize_node ====================================================== */
+/* ========================================================================== */
+
+static int initialize_node  /* initial work for kth node in postordered etree */
+(
+    Int k,		/* at the kth step of the algorithm (and kth node) */
+    Int Post [ ],	/* Post [k] = i, the kth node in postordered etree */
+    Int Parent [ ],	/* Parent [i] is the parent of i in the etree */
+    Int ColCount [ ],	/* ColCount [c] is the current weight of node c */
+    Int PrevNbr [ ]	/* PrevNbr [u] = k if u was last considered at step k */
+)
+{
+    Int p, parent ;
+    /* determine p, the kth node in the postordered etree */
+    p = Post [k] ;
+    /* adjust the weight if p is not a root of the etree */
+    parent = Parent [p] ;
+    if (parent != EMPTY)
+    {
+	ColCount [parent]-- ;
+    }
+    /* flag node p to exclude self edges (p,p) */
+    PrevNbr [p] = k ;
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === process_edge ========================================================= */
+/* ========================================================================== */
+
+/* edge (p,u) is being processed.  p < u is a descendant of its ancestor u in
+ * the etree.  node p is the kth node in the postordered etree.  */
+
+static void process_edge
+(
+    Int p,		/* process edge (p,u) of the matrix */
+    Int u,
+    Int k,		/* we are at the kth node in the postordered etree */
+    Int First [ ],	/* First [i] = k if the postordering of first
+			 * descendent of node i is k */
+    Int PrevNbr [ ],	/* u was last considered at step k = PrevNbr [u] */
+    Int ColCount [ ],	/* ColCount [c] is the current weight of node c */
+    Int PrevLeaf [ ],	/* s = PrevLeaf [u] means that s was the last leaf
+			 * seen in the subtree rooted at u.  */
+    Int RowCount [ ],	/* RowCount [i] is # of nonzeros in row i of L,
+			 * including the diagonal.  Not computed if NULL. */
+    Int SetParent [ ],	/* the FIND/UNION data structure, which forms a set
+			 * of trees.  A root i has i = SetParent [i].  Following
+			 * a path from i to the root q of the subtree containing
+			 * i means that q is the SetParent representative of i.
+			 * All nodes in the tree could have their SetParent
+			 * equal to the root q; the tree representation is used
+			 * to save time.  When a path is traced from i to its
+			 * root q, the path is re-traversed to set the SetParent
+			 * of the whole path to be the root q. */
+    Int Level [ ]	 /* Level [i] = length of path from node i to root */
+)
+{
+    Int prevleaf, q, s, sparent ;
+    if (First [p] > PrevNbr [u])
+    {
+	/* p is a leaf of the subtree of u */
+	ColCount [p]++ ;
+	prevleaf = PrevLeaf [u] ;
+	if (prevleaf == EMPTY)
+	{
+	    /* p is the first leaf of subtree of u; RowCount will be incremented
+	     * by the length of the path in the etree from p up to u. */
+	    q = u ;
+	}
+	else
+	{
+	    /* q = FIND (prevleaf): find the root q of the
+	     * SetParent tree containing prevleaf */
+	    for (q = prevleaf ; q != SetParent [q] ; q = SetParent [q])
+	    {
+		;
+	    }
+	    /* the root q has been found; re-traverse the path and
+	     * perform path compression */
+	    s = prevleaf ;
+	    for (s = prevleaf ; s != q ; s = sparent)
+	    {
+		sparent = SetParent [s] ;
+		SetParent [s] = q ;
+	    }
+	    /* adjust the RowCount and ColCount; RowCount will be incremented by
+	     * the length of the path from p to the SetParent root q, and
+	     * decrement the ColCount of q by one. */
+	    ColCount [q]-- ;
+	}
+	if (RowCount != NULL)
+	{
+	    /* if RowCount is being computed, increment it by the length of
+	     * the path from p to q */
+	    RowCount [u] += (Level [p] - Level [q]) ;
+	}
+	/* p is a leaf of the subtree of u, so mark PrevLeaf [u] to be p */
+	PrevLeaf [u] = p ;
+    }
+    /* flag u has having been processed at step k */
+    PrevNbr [u] = k ;
+}
+
+
+/* ========================================================================== */
+/* === finalize_node ======================================================== */
+/* ========================================================================== */
+
+static void finalize_node    /* compute UNION (p, Parent [p]) */
+(
+    Int p,
+    Int Parent [ ],	/* Parent [p] is the parent of p in the etree */
+    Int SetParent [ ]	/* see process_edge, above */
+)
+{
+    /* all nodes in the SetParent tree rooted at p now have as their final
+     * root the node Parent [p].  This computes UNION (p, Parent [p]) */
+    if (Parent [p] != EMPTY)
+    {
+	SetParent [p] = Parent [p] ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowcolcounts ================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(rowcolcounts)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    Int *Parent,	/* size nrow.  Parent [i] = p if p is the parent of i */
+    Int *Post,		/* size nrow.  Post [k] = i if i is the kth node in
+			 * the postordered etree. */
+    /* ---- output --- */
+    Int *RowCount,	/* size nrow. RowCount [i] = # entries in the ith row of
+			 * L, including the diagonal. */
+    Int *ColCount,	/* size nrow. ColCount [i] = # entries in the ith
+			 * column of L, including the diagonal. */
+    Int *First,		/* size nrow.  First [i] = k is the least postordering
+			 * of any descendant of i. */
+    Int *Level,		/* size nrow.  Level [i] is the length of the path from
+			 * i to the root, with Level [root] = 0. */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double fl, ff ;
+    Int *Ap, *Ai, *Anz, *PrevNbr, *SetParent, *Head, *PrevLeaf, *Anext, *Ipost,
+	*Iwork ;
+    Int i, j, r, k, len, s, p, pend, inew, stype, nf, anz, inode, parent,
+	nrow, ncol, packed, use_fset, jj ;
+    size_t w ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_NULL (Post, FALSE) ;
+    RETURN_IF_NULL (ColCount, FALSE) ;
+    RETURN_IF_NULL (First, FALSE) ;
+    RETURN_IF_NULL (Level, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype > 0)
+    {
+	/* symmetric with upper triangular part not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric upper not supported") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;	/* the number of rows of A */
+    ncol = A->ncol ;	/* the number of columns of A */
+
+    /* w = 2*nrow + (stype ? 0 : ncol) */
+    w = CHOLMOD(mult_size_t) (nrow, 2, &ok) ;
+    w = CHOLMOD(add_size_t) (w, (stype ? 0 : ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (nrow, w, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    ASSERT (CHOLMOD(dump_perm) (Post, nrow, nrow, "Post", Common)) ;
+    ASSERT (CHOLMOD(dump_parent) (Parent, nrow, "Parent", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;	/* size ncol+1, column pointers for A */
+    Ai = A->i ;	/* the row indices of A, of size nz=Ap[ncol+1] */
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    SetParent = Iwork ;		    /* size nrow (i/i/l) */
+    PrevNbr   = Iwork + nrow ;	    /* size nrow (i/i/l) */
+    Anext     = Iwork + 2*((size_t) nrow) ;    /* size ncol (i/i/l) (unsym only) */
+    PrevLeaf  = Common->Flag ;	    /* size nrow */
+    Head      = Common->Head ;	    /* size nrow+1 (unsym only)*/
+
+    /* ---------------------------------------------------------------------- */
+    /* find the first descendant and level of each node in the tree */
+    /* ---------------------------------------------------------------------- */
+
+    /* First [i] = k if the postordering of first descendent of node i is k */
+    /* Level [i] = length of path from node i to the root (Level [root] = 0) */
+
+    for (i = 0 ; i < nrow ; i++)
+    {
+	First [i] = EMPTY ;
+    }
+
+    /* postorder traversal of the etree */
+    for (k = 0 ; k < nrow ; k++)
+    {
+	/* node i of the etree is the kth node in the postordered etree */
+	i = Post [k] ;
+
+	/* i is a leaf if First [i] is still EMPTY */
+	/* ColCount [i] starts at 1 if i is a leaf, zero otherwise */
+	ColCount [i] = (First [i] == EMPTY) ? 1 : 0 ;
+
+	/* traverse the path from node i to the root, stopping if we find a
+	 * node r whose First [r] is already defined. */
+	len = 0 ;
+	for (r = i ; (r != EMPTY) && (First [r] == EMPTY) ; r = Parent [r])
+	{
+	    First [r] = k ;
+	    len++ ;
+	}
+	if (r == EMPTY)
+	{
+	    /* we hit a root node, the level of which is zero */
+	    len-- ;
+	}
+	else
+	{
+	    /* we stopped at node r, where Level [r] is already defined */
+	    len += Level [r] ;
+	}
+	/* re-traverse the path from node i to r; set the level of each node */
+	for (s = i ; s != r ; s = Parent [s])
+	{
+	    Level [s] = len-- ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* AA' case: sort columns of A according to first postordered row index */
+    /* ---------------------------------------------------------------------- */
+
+    fl = 0.0 ;
+    if (stype == 0)
+    {
+	/* [ use PrevNbr [0..nrow-1] as workspace for Ipost */
+	Ipost = PrevNbr ;
+	/* Ipost [i] = k if i is the kth node in the postordered etree. */
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    Ipost [Post [k]] = k ;
+	}
+	use_fset = (fset != NULL) ;
+	if (use_fset)
+	{
+	    nf = fsize ;
+	    /* clear Anext to check fset */
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		Anext [j] = -2 ;
+	    }
+	    /* find the first postordered row in each column of A (post,f)
+	     * and place the column in the corresponding link list */
+	    for (jj = 0 ; jj < nf ; jj++)
+	    {
+		j = fset [jj] ;
+		if (j < 0 || j > ncol || Anext [j] != -2)
+		{
+		    /* out-of-range or duplicate entry in fset */
+		    ERROR (CHOLMOD_INVALID, "fset invalid") ;
+		    return (FALSE) ;
+		}
+		/* flag column j as having been seen */
+		Anext [j] = EMPTY ;
+	    }
+	    /* fset is now valid */
+	    ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ;
+	}
+	else
+	{
+	    nf = ncol ;
+	}
+	for (jj = 0 ; jj < nf ; jj++)
+	{
+	    j = (use_fset) ? (fset [jj]) : jj ;
+	    /* column j is in the fset; find the smallest row (if any) */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    ff = (double) MAX (0, pend - p) ;
+	    fl += ff*ff + ff ;
+	    if (pend > p)
+	    {
+		k = Ipost [Ai [p]] ;
+		for ( ; p < pend ; p++)
+		{
+		    inew = Ipost [Ai [p]] ;
+		    k = MIN (k, inew) ;
+		}
+		/* place column j in link list k */
+		ASSERT (k >= 0 && k < nrow) ;
+		Anext [j] = Head [k] ;
+		Head [k] = j ;
+	    }
+	}
+	/* Ipost no longer needed for inverse postordering ]
+	 * Head [k] contains a link list of all columns whose first
+	 * postordered row index is equal to k, for k = 0 to nrow-1. */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row counts and node weights */
+    /* ---------------------------------------------------------------------- */
+
+    if (RowCount != NULL)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    RowCount [i] = 1 ;
+	}
+    }
+    for (i = 0 ; i < nrow ; i++)
+    {
+	PrevLeaf [i] = EMPTY ;
+	PrevNbr [i] = EMPTY ;
+	SetParent [i] = i ;	/* every node is in its own set, by itself */
+    }
+
+    if (stype != 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetric case: LL' = A */
+	/* ------------------------------------------------------------------ */
+
+	/* also determine the number of entries in triu(A) */
+	anz = nrow ;
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    /* j is the kth node in the postordered etree */
+	    j = initialize_node (k, Post, Parent, ColCount, PrevNbr) ;
+
+	    /* for all nonzeros A(i,j) below the diagonal, in column j of A */
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i > j)
+		{
+		    /* j is a descendant of i in etree(A) */
+		    anz++ ;
+		    process_edge (j, i, k, First, PrevNbr, ColCount,
+			    PrevLeaf, RowCount, SetParent, Level) ;
+		}
+	    }
+	    /* update SetParent: UNION (j, Parent [j]) */
+	    finalize_node (j, Parent, SetParent) ;
+	}
+	Common->anz = anz ;
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* unsymmetric case: LL' = AA' */
+	/* ------------------------------------------------------------------ */
+
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    /* inode is the kth node in the postordered etree */
+	    inode = initialize_node (k, Post, Parent, ColCount, PrevNbr) ;
+
+	    /* for all cols j whose first postordered row is k: */
+	    for (j = Head [k] ; j != EMPTY ; j = Anext [j])
+	    {
+		/* k is the first postordered row in column j of A */
+		/* for all rows i in column j: */
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    /* has i already been considered at this step k */
+		    if (PrevNbr [i] < k)
+		    {
+			/* inode is a descendant of i in etree(AA') */
+			/* process edge (inode,i) and set PrevNbr[i] to k */
+			process_edge (inode, i, k, First, PrevNbr, ColCount,
+				PrevLeaf, RowCount, SetParent, Level) ;
+		    }
+		}
+	    }
+	    /* clear link list k */
+	    Head [k] = EMPTY ;
+	    /* update SetParent: UNION (inode, Parent [inode]) */
+	    finalize_node (inode, Parent, SetParent) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finish computing the column counts */
+    /* ---------------------------------------------------------------------- */
+
+    for (j = 0 ; j < nrow ; j++)
+    {
+	parent = Parent [j] ;
+	if (parent != EMPTY)
+	{
+	    /* add the ColCount of j to its parent */
+	    ColCount [parent] += ColCount [j] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Common->mark = EMPTY ;
+    /* CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* flop count and nnz(L) for subsequent LL' numerical factorization */
+    /* ---------------------------------------------------------------------- */
+
+    /* use double to avoid integer overflow.  lnz cannot be NaN. */
+    Common->aatfl = fl ;
+    Common->lnz = 0. ;
+    fl = 0 ;
+    for (j = 0 ; j < nrow ; j++)
+    {
+	ff = (double) (ColCount [j]) ;
+	Common->lnz += ff ;
+	fl += ff*ff ;
+    }
+
+    Common->fl = fl ;
+    PRINT1 (("rowcol fl %g lnz %g\n", Common->fl, Common->lnz)) ;
+
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_rowfac.c b/src/CHOLMOD/Cholesky/cholmod_rowfac.c
new file mode 100644
index 0000000..10e6ba1
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_rowfac.c
@@ -0,0 +1,735 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_rowfac ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Full or incremental numerical LDL' or LL' factorization (simplicial, not
+ * supernodal) cholmod_factorize is the "easy" wrapper for this code, but it
+ * does not provide access to incremental factorization.
+ *
+ * cholmod_rowfac computes the full or incremental LDL' or LL' factorization of
+ * A+beta*I (where A is symmetric) or A*F+beta*I (where A and F are unsymmetric
+ * and only the upper triangular part of A*F+beta*I is used).  It computes
+ * L (and D, for LDL') one row at a time.  beta is real.
+ *
+ * A is nrow-by-ncol or nrow-by-nrow.  In "packed" form it is a conventional
+ * column-oriented sparse matrix.  Row indices of column j are in
+ * Ai [Ap [j] ... Ap [j+1]-1] and values in the same locations of Ax.
+ * will be faster if A has sorted columns.  In "unpacked" form the column
+ * of A ends at Ap [j] + Anz [j] - 1 instead of Ap [j+1] - 1.
+ *
+ * Row indices in each column of A can be sorted or unsorted, but the routine
+ * routine works fastest if A is sorted, or if only triu(A) is provided
+ * for the symmetric case.
+ *
+ * The unit-diagonal nrow-by-nrow output matrix L is returned in "unpacked"
+ * column form, with row indices of column j in Li [Lp [j] ...
+ * Lp [j] + Lnz [j] - 1] and values in the same location in Lx.  The row
+ * indices in each column of L are in sorted order.  The unit diagonal of L
+ * is not stored.
+ *
+ * L can be a simplicial symbolic or numeric (L->is_super must be FALSE).
+ * A symbolic factor is converted immediately into a numeric factor containing
+ * the identity matrix.
+ *
+ * For a full factorization, kstart = 0 and kend = nrow.  The existing nonzero
+ * entries (numerical values in L->x and L->z for the zomplex case, and indices
+ * in L->i), if any, are overwritten.
+ *
+ * To compute an incremental factorization, select kstart and kend as the range
+ * of rows of L you wish to compute.  A correct factorization will be computed
+ * only if all descendants of all nodes k = kstart to kend-1 in the etree have
+ * been factorized by a prior call to this routine, and if rows kstart to kend-1
+ * have not been factorized.  This condition is NOT checked on input.
+ *
+ * ---------------
+ * Symmetric case:
+ * ---------------
+ *
+ *	The factorization (in MATLAB notation) is:
+ *
+ *	S = beta*I + A
+ *	S = triu (S) + triu (S,1)'
+ *	L*D*L' = S, or L*L' = S
+ *
+ *	A is a conventional sparse matrix in compressed column form.  Only the
+ *	diagonal and upper triangular part of A is accessed; the lower
+ *	triangular part is ignored and assumed to be equal to the upper
+ *	triangular part.  For an incremental factorization, only columns kstart
+ *	to kend-1 of A are accessed.  F is not used.
+ *
+ * ---------------
+ * Unsymmetric case:
+ * ---------------
+ *
+ *	The factorization (in MATLAB notation) is:
+ *
+ *	S = beta*I + A*F
+ *	S = triu (S) + triu (S,1)'
+ *	L*D*L' = S, or L*L' = S
+ *
+ *	The typical case is F=A'.  Alternatively, if F=A(:,f)', then this
+ *	routine factorizes S = beta*I + A(:,f)*A(:,f)'.
+ *
+ *	All of A and F are accessed, but only the upper triangular part of A*F
+ *	is used.  F must be of size A->ncol by A->nrow.  F is used for the
+ *	unsymmetric case only.  F can be packed or unpacked and it need not be
+ *	sorted.
+ *
+ *	For a complete factorization of beta*I + A*A',
+ *	this routine performs a number of flops exactly equal to:
+ *
+ *	sum (for each column j of A) of (Anz (j)^2 + Anz (j)), to form S
+ *	+
+ *	sum (for each column j of L) of (Lnz (j)^2 + 3*Lnz (j)), to factorize S
+ *
+ *	where Anz (j) is the number of nonzeros in column j of A, and Lnz (j)
+ *	is the number of nonzero in column j of L below the diagonal.
+ *
+ *
+ * workspace: Flag (nrow), W (nrow if real, 2*nrow if complex/zomplex),
+ * Iwork (nrow)
+ *
+ * Supports any xtype, except a pattern-only input matrix A cannot be
+ * factorized.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === subtree ============================================================== */
+/* ========================================================================== */
+
+/* Compute the nonzero pattern of the sparse triangular solve Lx=b, where L in
+ * this case is L(0:k-1,0:k-1), and b is a column of A.  This is done by
+ * traversing the kth row-subtree of the elimination tree of L, starting from
+ * each nonzero entry in b.  The pattern is returned postordered, and is valid
+ * for a subsequent numerical triangular solve of Lx=b.  The elimination tree
+ * can be provided in a Parent array, or extracted from the pattern of L itself.
+ *
+ * The pattern of x = inv(L)*b is returned in Stack [top...].
+ * Also scatters b, or a multiple of b, into the work vector W.
+ *
+ * The SCATTER macro is defines how the numerical values of A or A*A' are to be
+ * scattered.
+ *
+ * PARENT(i) is a macro the defines how the etree is accessed.  It is either:
+ *	#define PARENT(i) Parent [i]
+ *	#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
+ */
+
+#define SUBTREE \
+    for ( ; p < pend ; p++) \
+    { \
+	i = Ai [p] ; \
+	if (i <= k) \
+	{ \
+	    /* scatter the column of A, or A*A' into Wx and Wz */ \
+	    SCATTER ; \
+	    /* start at node i and traverse up the subtree, stop at node k */ \
+	    for (len = 0 ; i < k && i != EMPTY && Flag [i] < mark ; i = parent) \
+	    { \
+		/* L(k,i) is nonzero, and seen for the first time */ \
+		Stack [len++] = i ;	    /* place i on the stack */ \
+		Flag [i] = mark ;	    /* mark i as visited */ \
+		parent = PARENT (i) ;   /* traverse up the etree to the parent */ \
+	    } \
+	    /* move the path down to the bottom of the stack */ \
+	    while (len > 0) \
+	    { \
+		Stack [--top] = Stack [--len] ; \
+	    } \
+	} \
+	else if (sorted) \
+	{ \
+	    break ; \
+	} \
+    }
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_rowfac.c"
+#define COMPLEX
+#include "t_cholmod_rowfac.c"
+#define ZOMPLEX
+#include "t_cholmod_rowfac.c"
+
+#define MASK
+#define REAL
+#include "t_cholmod_rowfac.c"
+#define COMPLEX
+#include "t_cholmod_rowfac.c"
+#define ZOMPLEX
+#include "t_cholmod_rowfac.c"
+#undef MASK
+
+
+/* ========================================================================== */
+/* === cholmod_row_subtree ================================================== */
+/* ========================================================================== */
+
+/* Compute the nonzero pattern of the solution to the lower triangular system
+ * L(0:k-1,0:k-1) * x = A (0:k-1,k) if A is symmetric, or
+ * L(0:k-1,0:k-1) * x = A (0:k-1,:) * A (:,k)' if A is unsymmetric.
+ * This gives the nonzero pattern of row k of L (excluding the diagonal).
+ * The pattern is returned postordered.
+ *
+ * The symmetric case requires A to be in symmetric-upper form.
+ *
+ * The result is returned in R, a pre-allocated sparse matrix of size nrow-by-1,
+ * with R->nzmax >= nrow.  R is assumed to be packed (Rnz [0] is not updated);
+ * the number of entries in R is given by Rp [0].
+ *
+ * FUTURE WORK:  a very minor change to this routine could allow it to compute
+ * the nonzero pattern of x for any system Lx=b.  The SUBTREE macro would need
+ * to change, to eliminate its dependence on k.
+ *
+ * workspace: Flag (nrow)
+ */
+
+int CHOLMOD(row_subtree)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    size_t krow,	/* row k of L */
+    Int *Parent,	/* elimination tree */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), 1-by-n with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Fp, *Fi, *Fnz ;
+    Int p, pend, parent, t, stype, nrow, k, pf, pfend, Fpacked, packed,
+	sorted, top, len, i, mark ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (R, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype == 0)
+    {
+	RETURN_IF_NULL (F, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    }
+    if (krow >= A->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "subtree: k invalid") ;
+	return (FALSE) ;
+    }
+    if (R->ncol != 1 || A->nrow != R->nrow || A->nrow > R->nzmax)
+    {
+	ERROR (CHOLMOD_INVALID, "subtree: R invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    CHOLMOD(allocate_work) (nrow, 0, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype > 0)
+    {
+	/* symmetric upper case: F is not needed.  It may be NULL */
+	Fp = NULL ;
+	Fi = NULL ;
+	Fnz = NULL ;
+	Fpacked = TRUE ;
+    }
+    else if (stype == 0)
+    {
+	/* unsymmetric case: F is required. */
+	Fp = F->p ;
+	Fi = F->i ;
+	Fnz = F->nz ;
+	Fpacked = F->packed ;
+    }
+    else
+    {
+	/* symmetric lower triangular form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    sorted = A->sorted ;
+
+    k = krow ;
+    Stack = R->i ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;	/* size nrow, Flag [i] < mark must hold */
+    /* mark = CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    mark = Common->mark ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the pattern of L(k,:) */
+    /* ---------------------------------------------------------------------- */
+
+    top = nrow ;		/* Stack is empty */
+    Flag [k] = mark ;		/* do not include diagonal entry in Stack */
+
+#define SCATTER			/* do not scatter numerical values */
+#define PARENT(i) Parent [i]	/* use Parent for etree */
+
+    if (stype != 0)
+    {
+	/* scatter kth col of triu (A), get pattern L(k,:) */
+	p = Ap [k] ;
+	pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ;
+	SUBTREE ;
+    }
+    else
+    {
+	/* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	pf = Fp [k] ;
+	pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ;
+	for ( ; pf < pfend ; pf++)
+	{
+	    /* get nonzero entry F (t,k) */
+	    t = Fi [pf] ;
+	    p = Ap [t] ;
+	    pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
+	    SUBTREE ;
+	}
+    }
+
+#undef SCATTER
+#undef PARENT
+
+    /* shift the stack upwards, to the first part of R */
+    len = nrow - top ;
+    for (i = 0 ; i < len ; i++)
+    {
+	Stack [i] = Stack [top + i] ;
+    }
+
+    Rp = R->p ;
+    Rp [0] = 0 ;
+    Rp [1] = len ;
+    R->sorted = FALSE ;
+
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_lsolve_pattern =============================================== */
+/* ========================================================================== */
+
+/* Compute the nonzero pattern of Y=L\B.  L must be simplicial, and B
+ * must be a single sparse column vector with B->stype = 0.  The values of
+ * B are not used; it just specifies a nonzero pattern.  The pattern of
+ * Y is not sorted, but is in topological order instead (suitable for a
+ * sparse forward/backsolve).
+ */
+
+int CHOLMOD(lsolve_pattern)
+(
+    /* ---- input ---- */
+    cholmod_sparse *B,	/* sparse right-hand-side (a single sparse column) */
+    cholmod_factor *L,	/* the factor L from which parent(i) is derived */
+    /* ---- output --- */
+    cholmod_sparse *Yset,   /* pattern of Y=L\B, n-by-1 with Y->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    size_t krow ;
+    RETURN_IF_NULL (B, FALSE) ;
+    krow = B->nrow ;
+    return (CHOLMOD(row_lsubtree) (B, NULL, 0, krow, L, Yset, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_row_lsubtree ================================================= */
+/* ========================================================================== */
+
+/* Identical to cholmod_row_subtree, except that the elimination tree is
+ * obtained from L itself, as the first off-diagonal entry in each column.
+ * L must be simplicial, not supernodal.
+ *
+ * If krow = A->nrow, then A must be a single sparse column vector, (A->stype
+ * must be zero), and the nonzero pattern of x=L\b is computed, where b=A(:,0)
+ * is the single sparse right-hand-side.  The inputs Fi and fnz are ignored.
+ * See CHOLMOD(lsolve_pattern) above for a simpler interface for this case.
+ */
+
+int CHOLMOD(row_lsubtree)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    Int *Fi, size_t fnz,    /* nonzero pattern of kth row of A', not required
+			     * for the symmetric case.  Need not be sorted. */
+    size_t krow,	/* row k of L */
+    cholmod_factor *L,	/* the factor L from which parent(i) is derived */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), n-by-1 with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Rp, *Stack, *Flag, *Ap, *Ai, *Anz, *Lp, *Li, *Lnz ;
+    Int p, pend, parent, t, stype, nrow, k, pf, packed, sorted, top, len, i,
+	mark, ka ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (R, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+
+    nrow = A->nrow ;
+    stype = A->stype ;
+    if (stype < 0)
+    {
+	/* symmetric lower triangular form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+
+    if (krow > nrow)
+    {
+        ERROR (CHOLMOD_INVALID, "lsubtree: krow invalid") ;
+        return (FALSE) ;
+    }
+    else if (krow == nrow)
+    {
+        /* find pattern of x=L\b where b=A(:,0) */
+        k = nrow ;      /* compute all of the result; don't stop in SUBTREE */
+        ka = 0 ;        /* use column A(:,0) */
+        if (stype != 0 || A->ncol != 1)
+        {
+            /* A must be unsymmetric (it's a single sparse column vector) */
+            ERROR (CHOLMOD_INVALID, "lsubtree: A invalid") ;
+            return (FALSE) ;
+        }
+    }
+    else
+    {
+        /* find pattern of L(k,:) using A(:,k) and Fi if A unsymmetric */
+        k = krow ;      /* which row of L to compute */
+        ka = k ;        /* which column of A to use */
+        if (stype == 0)
+        {
+            RETURN_IF_NULL (Fi, FALSE) ;
+        }
+    }
+
+    if (R->ncol != 1 || nrow != R->nrow || nrow > R->nzmax || ka >= A->ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "lsubtree: R invalid") ;
+	return (FALSE) ;
+    }
+    if (L->is_super)
+    {
+	ERROR (CHOLMOD_INVALID, "lsubtree: L invalid (cannot be supernodal)") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(allocate_work) (nrow, 0, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    sorted = A->sorted ;
+
+    Stack = R->i ;
+
+    Lp = L->p ;
+    Li = L->i ;
+    Lnz = L->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;	/* size nrow, Flag [i] < mark must hold */
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the pattern of L(k,:) */
+    /* ---------------------------------------------------------------------- */
+
+    top = nrow ;		/* Stack is empty */
+    if (k < nrow)
+    {
+        Flag [k] = mark ;       /* do not include diagonal entry in Stack */
+    }
+
+#define SCATTER			/* do not scatter numerical values */
+#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
+
+    if (krow == nrow || stype != 0)
+    {
+	/* scatter kth col of triu (A), get pattern L(k,:) */
+	p = Ap [ka] ;
+	pend = (packed) ? (Ap [ka+1]) : (p + Anz [ka]) ;
+	SUBTREE ;
+    }
+    else
+    {
+	/* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	for (pf = 0 ; pf < (Int) fnz ; pf++)
+	{
+	    /* get nonzero entry F (t,k) */
+	    t = Fi [pf] ;
+	    p = Ap [t] ;
+	    pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
+	    SUBTREE ;
+	}
+    }
+
+#undef SCATTER
+#undef PARENT
+
+    /* shift the stack upwards, to the first part of R */
+    len = nrow - top ;
+    for (i = 0 ; i < len ; i++)
+    {
+	Stack [i] = Stack [top + i] ;
+    }
+
+    Rp = R->p ;
+    Rp [0] = 0 ;
+    Rp [1] = len ;
+    R->sorted = FALSE ;
+
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowfac ======================================================= */
+/* ========================================================================== */
+
+/* This is the incremental factorization for general purpose usage. */
+
+int CHOLMOD(rowfac)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+AA' */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(rowfac_mask) (A, F, beta, kstart, kend, NULL, NULL, L,
+	Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowfac_mask ================================================== */
+/* ========================================================================== */
+
+/* This is meant for use in LPDASA only. */
+
+int CHOLMOD(rowfac_mask)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+AA' */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    Int *mask,		/* size A->nrow. if mask[i] >= 0 row i is set to zero */
+    Int *RLinkUp,	/* size A->nrow. link list of rows to compute */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int n ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (L->xtype != CHOLMOD_PATTERN && A->xtype != L->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype of A and L do not match") ;
+	return (FALSE) ;
+    }
+    if (L->is_super)
+    {
+	ERROR (CHOLMOD_INVALID, "can only do simplicial factorization");
+	return (FALSE) ;
+    }
+    if (A->stype == 0)
+    {
+	RETURN_IF_NULL (F, FALSE) ;
+	if (A->xtype != F->xtype)
+	{
+	    ERROR (CHOLMOD_INVALID, "xtype of A and F do not match") ;
+	    return (FALSE) ;
+	}
+    }
+    if (A->stype < 0)
+    {
+	/* symmetric lower triangular form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+    if (kend > L->n)
+    {
+	ERROR (CHOLMOD_INVALID, "kend invalid") ;
+	return (FALSE) ;
+    }
+    if (A->nrow != L->n)
+    {
+	ERROR (CHOLMOD_INVALID, "dimensions of A and L do not match") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    Common->rowfacfl = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Xwork is of size n for the real case, 2*n for complex/zomplex */
+    n = L->n  ;
+
+    /* s = ((A->xtype != CHOLMOD_REAL) ? 2:1)*n */
+    s = CHOLMOD(mult_size_t) (n, ((A->xtype != CHOLMOD_REAL) ? 2:1), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, n, s, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, A->nrow, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* factorize the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    if (RLinkUp == NULL)
+    {
+
+	switch (A->xtype)
+	{
+	    case CHOLMOD_REAL:
+		ok = r_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		ok = c_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		ok = z_cholmod_rowfac (A, F, beta, kstart, kend, L, Common) ;
+		break ;
+	}
+
+    }
+    else
+    {
+
+	switch (A->xtype)
+	{
+	    case CHOLMOD_REAL:
+		ok = r_cholmod_rowfac_mask (A, F, beta, kstart, kend,
+		    mask, RLinkUp, L, Common) ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		ok = c_cholmod_rowfac_mask (A, F, beta, kstart, kend,
+		    mask, RLinkUp, L, Common) ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		ok = z_cholmod_rowfac_mask (A, F, beta, kstart, kend,
+		    mask, RLinkUp, L, Common) ;
+		break ;
+	}
+    }
+
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_solve.c b/src/CHOLMOD/Cholesky/cholmod_solve.c
new file mode 100644
index 0000000..2c5728e
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_solve.c
@@ -0,0 +1,1684 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_solve =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Solve one of the following systems.  D is identity for an LL' factorization,
+ * in which the D operation is skipped:
+ *
+ *      Ax=b        0: CHOLMOD_A     x = P' * (L' \ (D \ (L \ (P * b))))
+ *      LDL'x=b     1: CHOLMOD_LDLt  x =      (L' \ (D \ (L \ (    b))))
+ *      LDx=b       2: CHOLMOD_LD    x =      (     (D \ (L \ (    b))))
+ *      DL'x=b      3: CHOLMOD_DLt   x =      (L' \ (D \ (    (    b))))
+ *      Lx=b        4: CHOLMOD_L     x =      (     (    (L \ (    b))))
+ *      L'x=b       5: CHOLMOD_Lt    x =      (L' \ (    (    (    b))))
+ *      Dx=b        6: CHOLMOD_D     x =      (     (D \ (    (    b))))
+ *      x=Pb        7: CHOLMOD_P     x =      (     (    (    (P * b))))
+ *      x=P'b       8: CHOLMOD_Pt    x = P' * (     (    (    (    b))))
+ *
+ * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'.
+ * For an LL' factorization, D is the identity matrix.  Thus CHOLMOD_LD and
+ * CHOLMOD_L solve the same system if an LL' factorization was performed,
+ * for example.
+ *
+ * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm,
+ * or their complex counterparts ztrsv, zgemv, ztrsm, and zgemm.
+ *
+ * If both L and B are real, then X is returned real.  If either is complex
+ * or zomplex, X is returned as either complex or zomplex, depending on the
+ * Common->prefer_zomplex parameter.
+ *
+ * Supports any numeric xtype (pattern-only matrices not supported).
+ *
+ * This routine does not check to see if the diagonal of L or D is zero,
+ * because sometimes a partial solve can be done with indefinite or singular
+ * matrix.  If you wish to check in your own code, test L->minor.  If
+ * L->minor == L->n, then the matrix has no zero diagonal entries.
+ * If k = L->minor < L->n, then L(k,k) is zero for an LL' factorization, or
+ * D(k,k) is zero for an LDL' factorization.
+ *
+ * This routine returns X as NULL only if it runs out of memory.  If L is
+ * indefinite or singular, then X may contain Inf's or NaN's, but it will
+ * exist on output.
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_solve.c"
+
+#define COMPLEX
+#include "t_cholmod_solve.c"
+
+#define ZOMPLEX
+#include "t_cholmod_solve.c"
+
+/* ========================================================================== */
+/* === Permutation macro ==================================================== */
+/* ========================================================================== */
+
+/* If Perm is NULL, it is interpretted as the identity permutation */
+
+#define P(k) ((Perm == NULL) ? (k) : Perm [k])
+
+
+/* ========================================================================== */
+/* === perm ================================================================= */
+/* ========================================================================== */
+
+/* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1) where B is nrow-by-ncol.
+ *
+ * Creates a permuted copy of a contiguous set of columns of B.
+ * Y is already allocated on input.  Y must be of sufficient size.  Let nk be
+ * the number of columns accessed in B.  Y->xtype determines the complexity of
+ * the result.
+ *
+ * If B is real and Y is complex (or zomplex), only the real part of B is
+ * copied into Y.  The imaginary part of Y is set to zero.
+ *
+ * If B is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of B are returned in Y.  Y is returned as nrow-by-2*nk. The even
+ * columns of Y contain the real part of B and the odd columns contain the
+ * imaginary part of B.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * returned as nrow-by-nk with leading dimension nrow.  Y->nzmax must be >=
+ * nrow*nk.
+ *
+ * The case where the input (B) is real and the output (Y) is zomplex is
+ * not used.
+ */
+
+static void perm
+(
+    /* ---- input ---- */
+    cholmod_dense *B,	/* input matrix B */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of B to copy */
+    Int ncols,		/* last column to copy is min(k1+ncols,B->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *Y	/* output matrix Y, already allocated */
+)
+{
+    double *Yx, *Yz, *Bx, *Bz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dual, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = B->ncol ;
+    nrow = B->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ;
+    d = B->d ;
+    Bx = B->x ;
+    Bz = B->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    Y->nrow = nrow ;
+    Y->ncol = dual*nk ;
+    Y->d = nrow ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = B (P (1:nrow), k1:k2-1) */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, B real */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2] = Bx [p] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, B complex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2       ] = Bx [2*p  ] ;	/* real */
+			    Yx [k + j2 + nrow] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, B zomplex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2       ] = Bx [p] ;	/* real */
+			    Yx [k + j2 + nrow] = Bz [p] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y complex, B real */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [2*k   + j2] = Bx [p] ;		/* real */
+			    Yx [2*k+1 + j2] = 0 ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, B complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [2*k   + j2] = Bx [2*p  ] ;	/* real */
+			    Yx [2*k+1 + j2] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, B zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [2*k   + j2] = Bx [p] ;		/* real */
+			    Yx [2*k+1 + j2] = Bz [p] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, B complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2] = Bx [2*p  ] ;		/* real */
+			    Yz [k + j2] = Bx [2*p+1] ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, B zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [k + j2] = Bx [p] ;		/* real */
+			    Yz [k + j2] = Bz [p] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === iperm ================================================================ */
+/* ========================================================================== */
+
+/* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y where X is nrow-by-ncol.
+ *
+ * Copies and permutes Y into a contiguous set of columns of X.  X is already
+ * allocated on input.  Y must be of sufficient size.  Let nk be the number
+ * of columns accessed in X.  X->xtype determines the complexity of the result.
+ *
+ * If X is real and Y is complex (or zomplex), only the real part of B is
+ * copied into X.  The imaginary part of Y is ignored.
+ *
+ * If X is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of Y are returned in X.  Y is nrow-by-2*nk. The even
+ * columns of Y contain the real part of B and the odd columns contain the
+ * imaginary part of B.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * nrow-by-nk with leading dimension nrow.  Y->nzmax must be >= nrow*nk.
+ *
+ * The case where the input (Y) is complex and the output (X) is real,
+ * and the case where the input (Y) is zomplex and the output (X) is real,
+ * are not used.
+ */
+
+static void iperm
+(
+    /* ---- input ---- */
+    cholmod_dense *Y,	/* input matrix Y */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of B to copy */
+    Int ncols,		/* last column to copy is min(k1+ncols,B->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *X	/* output matrix X, already allocated */
+)
+{
+    double *Yx, *Yz, *Xx, *Xz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = X->ncol ;
+    nrow = X->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*
+	    ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* X (P (1:nrow), k1:k2-1) = Y */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (X->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, X real */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [k + j2] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, X complex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [k + j2       ] ;	/* real */
+			    Xx [2*p+1] = Yx [k + j2 + nrow] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, X zomplex. Y is nrow-by-2*nk */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [k + j2       ] ;	/* real */
+			    Xz [p] = Yx [k + j2 + nrow] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, X complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [2*k   + j2] ;	/* real */
+			    Xx [2*p+1] = Yx [2*k+1 + j2] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, X zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * 2 * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [2*k   + j2] ;		/* real */
+			    Xz [p] = Yx [2*k+1 + j2] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, X complex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [k + j2] ;		/* real */
+			    Xx [2*p+1] = Yz [k + j2] ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, X zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = nrow * (j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [k + j2] ;		/* real */
+			    Xz [p] = Yz [k + j2] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === ptrans =============================================================== */
+/* ========================================================================== */
+
+/* Y = B (P (1:nrow), k1 : min (k1+ncols,ncol)-1)' where B is nrow-by-ncol.
+ *
+ * Creates a permuted and transposed copy of a contiguous set of columns of B.
+ * Y is already allocated on input.  Y must be of sufficient size.  Let nk be
+ * the number of columns accessed in B.  Y->xtype determines the complexity of
+ * the result.
+ *
+ * If B is real and Y is complex (or zomplex), only the real part of B is
+ * copied into Y.  The imaginary part of Y is set to zero.
+ *
+ * If B is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of B are returned in Y.  Y is returned as 2*nk-by-nrow. The even
+ * rows of Y contain the real part of B and the odd rows contain the
+ * imaginary part of B.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * returned as nk-by-nrow with leading dimension nk.  Y->nzmax must be >=
+ * nrow*nk.
+ *
+ * The array transpose is performed, not the complex conjugate transpose.
+ */
+
+static void ptrans
+(
+    /* ---- input ---- */
+    cholmod_dense *B,	/* input matrix B */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of B to copy */
+    Int ncols,		/* last column to copy is min(k1+ncols,B->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *Y	/* output matrix Y, already allocated */
+)
+{
+    double *Yx, *Yz, *Bx, *Bz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dual, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = B->ncol ;
+    nrow = B->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    dual = (Y->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ;
+    d = B->d ;
+    Bx = B->x ;
+    Bz = B->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    Y->nrow = dual*nk ;
+    Y->ncol = nrow ;
+    Y->d = dual*nk ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*dual) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = B (P (1:nrow), k1:k2-1)' */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, B real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [p] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, B complex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [2*p  ] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, B zomplex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [p] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bz [p] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y complex, B real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [p] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = 0 ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, B complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [2*p  ] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, B zomplex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2   + k*2*nk] = Bx [p] ;	/* real */
+			    Yx [j2+1 + k*2*nk] = Bz [p] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y zomplex, B real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [p] ;		/* real */
+			    Yz [j2 + k*nk] = 0 ;		/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, B complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [2*p  ] ;	/* real */
+			    Yz [j2 + k*nk] = Bx [2*p+1] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, B zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Yx [j2 + k*nk] = Bx [p] ;		/* real */
+			    Yz [j2 + k*nk] = Bz [p] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === iptrans ============================================================== */
+/* ========================================================================== */
+
+/* X (P (1:nrow), k1 : min (k1+ncols,ncol)-1) = Y' where X is nrow-by-ncol.
+ *
+ * Copies into a permuted and transposed contiguous set of columns of X.
+ * X is already allocated on input.  Y must be of sufficient size.  Let nk be
+ * the number of columns accessed in X.  X->xtype determines the complexity of
+ * the result.
+ *
+ * If X is real and Y is complex (or zomplex), only the real part of Y is
+ * copied into X.  The imaginary part of Y is ignored.
+ *
+ * If X is complex (or zomplex) and Y is real, both the real and imaginary and
+ * parts of X are returned in Y.  Y is 2*nk-by-nrow. The even
+ * rows of Y contain the real part of X and the odd rows contain the
+ * imaginary part of X.  Y->nzmax must be >= 2*nrow*nk.  Otherise, Y is
+ * nk-by-nrow with leading dimension nk.  Y->nzmax must be >= nrow*nk.
+ *
+ * The case where Y is complex or zomplex, and X is real, is not used.
+ *
+ * The array transpose is performed, not the complex conjugate transpose.
+ */
+
+static void iptrans
+(
+    /* ---- input ---- */
+    cholmod_dense *Y,	/* input matrix Y */
+    Int *Perm,		/* optional input permutation (can be NULL) */
+    Int k1,		/* first column of X to copy into */
+    Int ncols,		/* last column to copy is min(k1+ncols,X->ncol)-1 */
+    /* ---- in/out --- */
+    cholmod_dense *X	/* output matrix X, already allocated */
+)
+{
+    double *Yx, *Yz, *Xx, *Xz ;
+    Int k2, nk, p, k, j, nrow, ncol, d, dj, j2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = X->ncol ;
+    nrow = X->nrow ;
+    k2 = MIN (k1+ncols, ncol) ;
+    nk = MAX (k2 - k1, 0) ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    ASSERT (((Int) Y->nzmax) >= nrow*nk*
+	    ((X->xtype != CHOLMOD_REAL && Y->xtype == CHOLMOD_REAL) ? 2:1)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* X (P (1:nrow), k1:k2-1) = Y' */
+    /* ---------------------------------------------------------------------- */
+
+    switch (Y->xtype)
+    {
+
+	case CHOLMOD_REAL:
+
+	    switch (X->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    /* Y real, X real  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2 + k*nk] ;		/* real */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    /* Y real, X complex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xx [2*p+1] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y real, X zomplex. Y is 2*nk-by-nrow */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xz [p] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y complex, X complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xx [2*p+1] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y complex, X zomplex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = 2*(j-k1) ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2   + k*2*nk] ;	/* real */
+			    Xz [p] = Yx [j2+1 + k*2*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (X->xtype)
+	    {
+
+#if 0
+		case CHOLMOD_REAL:
+		    /* this case is not used */
+		    break ;
+#endif
+
+		case CHOLMOD_COMPLEX:
+		    /* Y zomplex, X complex  */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [2*p  ] = Yx [j2 + k*nk] ;	/* real */
+			    Xx [2*p+1] = Yz [j2 + k*nk] ;	/* imag */
+			}
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    /* Y zomplex, X zomplex */
+		    for (j = k1 ; j < k2 ; j++)
+		    {
+			dj = d*j ;
+			j2 = j-k1 ;
+			for (k = 0 ; k < nrow ; k++)
+			{
+			    p = P(k) + dj ;
+			    Xx [p] = Yx [j2 + k*nk] ;		/* real */
+			    Xz [p] = Yz [j2 + k*nk] ;		/* imag */
+			}
+		    }
+		    break ;
+
+	    }
+	    break ;
+
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_solve ======================================================== */
+/* ========================================================================== */
+
+/* Solve a linear system.
+ *
+ * The factorization can be simplicial LDL', simplicial LL', or supernodal LL'.
+ * The Dx=b solve returns silently for the LL' factorizations (it is implicitly
+ * identity).
+ */
+
+cholmod_dense *CHOLMOD(solve)
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_dense *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *Y = NULL, *X = NULL ;
+    cholmod_dense *E = NULL ;
+    int ok ;
+
+    /* do the solve, allocating workspaces as needed  */
+    ok = CHOLMOD (solve2) (sys, L, B, NULL, &X, NULL, &Y, &E, Common) ;
+
+    /* free workspaces if allocated, and free result if an error occured */
+    CHOLMOD(free_dense) (&Y, Common) ;
+    CHOLMOD(free_dense) (&E, Common) ;
+    if (!ok)
+    {
+        CHOLMOD(free_dense) (&X, Common) ;
+    }
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_solve2 ======================================================= */
+/* ========================================================================== */
+
+/* This function acts just like cholmod_solve, except that the solution X and
+ * the internal workspace (Y and E) can be passed in preallocated.  If the
+ * solution X or any required workspaces are not allocated on input, or if they
+ * are the wrong size or type, then this function frees them and reallocates
+ * them as the proper size and type.  Thus, if you have a sequence of solves to
+ * do, you can let this function allocate X, Y, and E on the first call.
+ * Subsequent calls to cholmod_solve2 can then reuse this space.  You must
+ * then free the workspaces Y and E (and X if desired) when you are finished.
+ * For example, the first call to cholmod_l_solve2, below, will solve the
+ * requested system.  The next 2 calls (with different right-hand-sides but
+ * the same value of "sys") will resuse the workspace and solution X from the
+ * first call.  Finally, when all solves are done, you must free the workspaces
+ * Y and E (otherwise you will have a memory leak), and you should also free X
+ * when you are done with it.  Note that on input, X, Y, and E must be either
+ * valid cholmod_dense matrices, or initialized to NULL.  You cannot pass in an
+ * uninitialized X, Y, or E.
+ *
+ *      cholmod_dense *X = NULL, *Y = NULL, *E = NULL ;
+ *      ...
+ *      cholmod_l_solve2 (sys, L, B1, NULL, &X, NULL, &Y, &E, Common) ;
+ *      cholmod_l_solve2 (sys, L, B2, NULL, &X, NULL, &Y, &E, Common) ;
+ *      cholmod_l_solve2 (sys, L, B3, NULL, &X, NULL, &Y, &E, Common) ;
+ *      cholmod_l_free_dense (&X, Common) ;
+ *      cholmod_l_free_dense (&Y, Common) ;
+ *      cholmod_l_free_dense (&E, Common) ;
+ *
+ * The equivalent when using cholmod_l_solve is:
+ *
+ *      cholmod_dense *X = NULL, *Y = NULL, *E = NULL ;
+ *      ...
+ *      X = cholmod_l_solve (sys, L, B1, Common) ;
+ *      cholmod_l_free_dense (&X, Common) ;
+ *      X = cholmod_l_solve (sys, L, B2, Common) ;
+ *      cholmod_l_free_dense (&X, Common) ;
+ *      X = cholmod_l_solve (sys, L, B3, Common) ;
+ *      cholmod_l_free_dense (&X, Common) ;
+ *
+ * Both methods work fine, but in the 2nd method with cholmod_solve, the
+ * internal workspaces (Y and E) are allocated and freed on each call.
+ *
+ * Bset is an optional sparse column (pattern only) that specifies a set
+ * of row indices.  It is ignored if NULL, or if sys is CHOLMOD_P or
+ * CHOLMOD_Pt.  If it is present and not ignored, B must be a dense column
+ * vector, and only entries B(i) where i is in the pattern of Bset are
+ * considered.  All others are treated as if they were zero (they are not
+ * accessed).  L must be a simplicial factorization, not supernodal.  L is
+ * converted from supernodal to simplicial if necessary.  The solution X is
+ * defined only for entries in the output sparse pattern of Xset.
+ * The xtype (real/complex/zomplex) of L and B must match.
+ *
+ * NOTE: If Bset is present and L is supernodal, it is converted to simplicial
+ * on output.
+ */
+
+int CHOLMOD(solve2)         /* returns TRUE on success, FALSE on failure */
+(
+    /* ---- input ---- */
+    int sys,		            /* system to solve */
+    cholmod_factor *L,	            /* factorization to use */
+    cholmod_dense *B,               /* right-hand-side */
+    cholmod_sparse *Bset,
+    /* ---- output --- */
+    cholmod_dense **X_Handle,       /* solution, allocated if need be */
+    cholmod_sparse **Xset_Handle,
+    /* ---- workspace  */
+    cholmod_dense **Y_Handle,       /* workspace, or NULL */
+    cholmod_dense **E_Handle,       /* workspace, or NULL */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Yx, *Yz, *Bx, *Bz, *Xx, *Xz ;
+    cholmod_dense *Y = NULL, *X = NULL ;
+    cholmod_sparse *C, *Yset, C_header, Yset_header, *Xset ;
+    Int *Perm = NULL, *IPerm = NULL ;
+    Int n, nrhs, ncols, ctype, xtype, k1, nr, ytype, k, blen, p, i, d, nrow ;
+    Int Cp [2], Ysetp [2], *Ci, *Yseti, ysetlen ;
+    Int *Bsetp, *Bseti, *Bsetnz, *Xseti, *Xsetp, *Iwork ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (B, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (sys < CHOLMOD_A || sys > CHOLMOD_Pt)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid system") ;
+	return (FALSE) ;
+    }
+    DEBUG (CHOLMOD(dump_factor) (L, "L", Common)) ;
+    DEBUG (CHOLMOD(dump_dense) (B, "B", Common)) ;
+    nrhs = B->ncol ;
+    n = (Int) L->n ;
+    d = (Int) B->d ;
+    nrow = (Int) B->nrow ;
+    if (d < n || nrow != n)
+    {
+	ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ;
+	return (FALSE) ;
+    }
+    if (Bset)
+    {
+        if (nrhs != 1)
+        {
+            ERROR (CHOLMOD_INVALID, "Bset requires a single right-hand side") ;
+            return (FALSE) ;
+        }
+        if (L->xtype != B->xtype)
+        {
+            ERROR (CHOLMOD_INVALID, "Bset requires xtype of L and B to match") ;
+            return (FALSE) ;
+        }
+        DEBUG (CHOLMOD(dump_sparse) (Bset, "Bset", Common)) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if ((sys == CHOLMOD_P || sys == CHOLMOD_Pt || sys == CHOLMOD_A)
+	    && L->ordering != CHOLMOD_NATURAL)
+    {
+        /* otherwise, Perm is NULL, and the identity permutation is used */
+	Perm = L->Perm ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the result X (or resuse the space from a prior call) */
+    /* ---------------------------------------------------------------------- */
+
+    ctype = (Common->prefer_zomplex) ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX ;
+
+    if (Bset)
+    {
+        xtype = L->xtype ;
+    }
+    else if (sys == CHOLMOD_P || sys == CHOLMOD_Pt)
+    {
+	/* x=Pb and x=P'b return X real if B is real; X is the preferred
+	 * complex/zcomplex type if B is complex or zomplex */
+	xtype = (B->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : ctype ;
+    }
+    else if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL)
+    {
+	/* X is real if both L and B are real */
+	xtype = CHOLMOD_REAL ;
+    }
+    else
+    {
+	/* X is complex, use the preferred complex/zomplex type */
+	xtype = ctype ;
+    }
+
+    /* ensure X has the right size and type */
+    X = CHOLMOD(ensure_dense) (X_Handle, n, nrhs, n, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve using L, D, L', P, or some combination */
+    /* ---------------------------------------------------------------------- */
+
+    if (Bset)
+    {
+
+        /* ------------------------------------------------------------------ */
+        /* solve for a subset of x, with a sparse b */
+        /* ------------------------------------------------------------------ */
+
+        Int save_realloc_state ;
+
+#ifndef NSUPERNODAL
+        /* convert a supernodal L to simplicial when using Bset */
+        if (L->is_super)
+        {
+            /* Can only use Bset on a simplicial factorization.  The supernodal
+             * factor L is converted to simplicial, leaving the xtype unchanged
+             * (real, complex, or zomplex).  Since the supernodal factorization
+             * is already LL', it is left in that form.   This conversion uses
+             * the ll_super_to_simplicial_numeric function in
+             * cholmod_change_factor.
+             */
+            CHOLMOD(change_factor) (
+                CHOLMOD_REAL,   /* ignored, since L is already numeric */
+                TRUE,           /* convert to LL' (no change to num. values) */
+                FALSE,          /* convert to simplicial */
+                FALSE,          /* do not pack the columns of L */
+                FALSE,          /* (ignored) */
+                L, Common) ;
+            if (Common->status < CHOLMOD_OK)
+            {
+                /* out of memory, L is returned unchanged */
+                return (FALSE) ;
+            }
+        }
+#endif
+
+        /* L, X, and B are all the same xtype */
+        /* ensure Y is the the right size */
+	Y = CHOLMOD(ensure_dense) (Y_Handle, 1, n, 1, L->xtype, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (FALSE) ;
+	}
+
+        /* ------------------------------------------------------------------ */
+        /* get the inverse permutation, constructing it if needed */
+        /* ------------------------------------------------------------------ */
+
+        DEBUG (CHOLMOD (dump_perm) (Perm,  n,n, "Perm",  Common)) ;
+
+        if ((sys == CHOLMOD_A || sys == CHOLMOD_P) && Perm != NULL)
+        {
+            /* The inverse permutation IPerm is used for the c=Pb step,
+               which is needed only for solving Ax=b or x=Pb.  No other
+               steps should use IPerm */
+            if (L->IPerm == NULL)
+            {
+                /* construct the inverse permutation.  This is done only once
+                 * and then stored in L permanently.  */
+                L->IPerm = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+                if (Common->status < CHOLMOD_OK)
+                {
+                    /* out of memory */
+                    return (FALSE) ;
+                }
+                IPerm = L->IPerm ;
+                for (k = 0 ; k < n ; k++)
+                {
+                    IPerm [Perm [k]] = k ;
+                }
+            }
+            /* x=A\b and x=Pb both need IPerm */
+            IPerm = L->IPerm ;
+        }
+
+        if (sys == CHOLMOD_P)
+        {
+            /* x=Pb needs to turn off the subsequent x=P'b permutation */
+            Perm = NULL ;
+        }
+
+        DEBUG (CHOLMOD (dump_perm) (Perm,  n,n, "Perm",  Common)) ;
+        DEBUG (CHOLMOD (dump_perm) (IPerm, n,n, "IPerm", Common)) ;
+
+        /* ------------------------------------------------------------------ */
+        /* ensure Xset is the right size and type */
+        /* ------------------------------------------------------------------ */
+
+        /* Xset is n-by-1, nzmax >= n, pattern-only, packed, unsorted */
+        Xset = *Xset_Handle ;
+        if (Xset == NULL || (Int) Xset->nrow != n || (Int) Xset->ncol != 1 ||
+            (Int) Xset->nzmax < n || Xset->itype != CHOLMOD_PATTERN)
+        {
+            /* this is done only once, for the 1st call to cholmod_solve */
+            CHOLMOD(free_sparse) (Xset_Handle, Common) ;
+            Xset = CHOLMOD(allocate_sparse) (n, 1, n, FALSE, TRUE, 0,
+                CHOLMOD_PATTERN, Common) ;
+            *Xset_Handle = Xset ;
+        }
+        Xset->sorted = FALSE ;
+        Xset->stype = 0 ;
+        if (Common->status < CHOLMOD_OK)
+        {
+            /* out of memory */
+            return (FALSE) ;
+        }
+
+        /* -------------------------------------------------------------- */
+        /* ensure Flag of size n, and 3*n Int workspace is available */
+        /* -------------------------------------------------------------- */
+
+        /* does no work if prior calls already allocated enough space */
+        CHOLMOD(allocate_work) (n, 3*n, 0, Common) ;
+        if (Common->status < CHOLMOD_OK)
+        {
+            /* out of memory */
+            return (FALSE) ;
+        }
+
+        /* [ use Iwork (n:3n-1) for Ci and Yseti */
+        Iwork = Common->Iwork ;
+        /* Iwork (0:n-1) is not used because it is used by check_perm,
+           print_perm, check_sparse, and print_sparse */
+        Ci = Iwork + n ;
+        Yseti = Ci + n ;
+
+        /* reallocating workspace would break Ci and Yseti */
+        save_realloc_state = Common->no_workspace_reallocate ;
+        Common->no_workspace_reallocate = TRUE ;
+
+        /* -------------------------------------------------------------- */
+        /* C = permuted Bset, to correspond to the permutation of L */
+        /* -------------------------------------------------------------- */
+
+        /* C = IPerm (Bset) */
+        DEBUG (CHOLMOD(dump_sparse) (Bset, "Bset", Common)) ;
+
+        Bsetp = Bset->p ;
+        Bseti = Bset->i ;
+        Bsetnz = Bset->nz ;
+        blen = (Bset->packed) ? Bsetp [1] : Bsetnz [0] ;
+
+        /* C = spones (P*B) or C = spones (B) if IPerm is NULL */
+        C = &C_header ;
+        C->nrow = n ;
+        C->ncol = 1 ;
+        C->nzmax = n ;
+        C->packed = TRUE ;
+        C->stype = 0 ;
+        C->itype = ITYPE ;
+        C->xtype = CHOLMOD_PATTERN ;
+        C->dtype = CHOLMOD_DOUBLE ;
+        C->nz = NULL ;
+        C->p = Cp ;
+        C->i = Ci ;
+        C->x = NULL ;
+        C->z = NULL ;
+        C->sorted = FALSE ;
+        Cp [0] = 0 ;
+        Cp [1] = blen ;
+        for (p = 0 ; p < blen ; p++)
+        {
+            Int iold = Bseti [p] ;
+            Ci [p] = IPerm ? IPerm [iold] : iold ;
+        }
+        DEBUG (CHOLMOD (dump_sparse) (C, "C", Common)) ;
+
+        /* create a sparse column Yset from Iwork (n:2n-1) */
+        Yset = &Yset_header ;
+        Yset->nrow = n ;
+        Yset->ncol = 1 ;
+        Yset->nzmax = n ;
+        Yset->packed = TRUE ;
+        Yset->stype = 0 ;
+        Yset->itype = ITYPE ;
+        Yset->xtype = CHOLMOD_PATTERN ;
+        Yset->dtype = CHOLMOD_DOUBLE ;
+        Yset->nz = NULL ;
+        Yset->p = Ysetp ;
+        Yset->i = Yseti ;
+        Yset->x = NULL ;
+        Yset->z = NULL ;
+        Yset->sorted = FALSE ;
+        Ysetp [0] = 0 ;
+        Ysetp [1] = 0 ;
+        DEBUG (CHOLMOD (dump_sparse) (Yset, "Yset empty", Common)) ;
+
+        /* -------------------------------------------------------------- */
+        /* Yset = nonzero pattern of L\C, or just C itself */
+        /* -------------------------------------------------------------- */
+
+        /* this takes O(ysetlen) time  */
+        if (sys == CHOLMOD_P || sys == CHOLMOD_Pt || sys == CHOLMOD_D)
+        {
+            Ysetp [1] = blen ;
+            for (p = 0 ; p < blen ; p++)
+            {
+                Yseti [p] = Ci [p] ;
+            }
+        }
+        else
+        {
+            if (!CHOLMOD(lsolve_pattern) (C, L, Yset, Common))
+            {
+                Common->no_workspace_reallocate = save_realloc_state ;
+                return (FALSE) ;
+            }
+        }
+        DEBUG (CHOLMOD (dump_sparse) (Yset, "Yset", Common)) ;
+
+        /* -------------------------------------------------------------- */
+        /* clear the parts of Y that we will use in the solve */
+        /* -------------------------------------------------------------- */
+
+        Yx = Y->x ;
+        Yz = Y->z ;
+        ysetlen = Ysetp [1] ;
+
+        switch (L->xtype)
+        {
+
+            case CHOLMOD_REAL:
+                for (p = 0 ; p < ysetlen ; p++)
+                {
+                    i = Yseti [p] ;
+                    Yx [i] = 0 ;
+                }
+                break ;
+
+            case CHOLMOD_COMPLEX:
+                for (p = 0 ; p < ysetlen ; p++)
+                {
+                    i = Yseti [p] ;
+                    Yx [2*i  ] = 0 ;
+                    Yx [2*i+1] = 0 ;
+                }
+                break ;
+
+            case CHOLMOD_ZOMPLEX:
+                for (p = 0 ; p < ysetlen ; p++)
+                {
+                    i = Yseti [p] ;
+                    Yx [i] = 0 ;
+                    Yz [i] = 0 ;
+                }
+                break ;
+        }
+
+        DEBUG (CHOLMOD (dump_dense) (Y, "Y (Yset) = 0", Common)) ;
+
+        /* -------------------------------------------------------------- */
+        /* scatter and permute B into Y */
+        /* -------------------------------------------------------------- */
+
+        /* Y (C) = B (Bset) */
+        Bx = B->x ;
+        Bz = B->z ;
+
+        switch (L->xtype)
+        {
+
+            case CHOLMOD_REAL:
+                for (p = 0 ; p < blen ; p++)
+                {
+                    Int iold = Bseti [p] ;
+                    Int inew = Ci [p] ;
+                    Yx [inew] = Bx [iold] ;
+                }
+                break ;
+
+            case CHOLMOD_COMPLEX:
+                for (p = 0 ; p < blen ; p++)
+                {
+                    Int iold = Bseti [p] ;
+                    Int inew = Ci [p] ;
+                    Yx [2*inew  ] = Bx [2*iold  ] ;
+                    Yx [2*inew+1] = Bx [2*iold+1] ;
+                }
+                break ;
+
+            case CHOLMOD_ZOMPLEX:
+                for (p = 0 ; p < blen ; p++)
+                {
+                    Int iold = Bseti [p] ;
+                    Int inew = Ci [p] ;
+                    Yx [inew] = Bx [iold] ;
+                    Yz [inew] = Bz [iold] ;
+                }
+                break ;
+        }
+
+        DEBUG (CHOLMOD (dump_dense) (Y, "Y (C) = B (Bset)", Common)) ;
+
+        /* -------------------------------------------------------------- */
+        /* solve Y = (L' \ (L \ Y'))', or other system, with template */
+        /* -------------------------------------------------------------- */
+
+        /* the solve only iterates over columns in Yseti [0...ysetlen-1] */
+
+        if (! (sys == CHOLMOD_P || sys == CHOLMOD_Pt))
+        {
+            switch (L->xtype)
+            {
+                case CHOLMOD_REAL:
+                    r_simplicial_solver (sys, L, Y, Yseti, ysetlen) ;
+                    break ;
+
+                case CHOLMOD_COMPLEX:
+                    c_simplicial_solver (sys, L, Y, Yseti, ysetlen) ;
+                    break ;
+
+                case CHOLMOD_ZOMPLEX:
+                    z_simplicial_solver (sys, L, Y, Yseti, ysetlen) ;
+                    break ;
+            }
+        }
+
+        DEBUG (CHOLMOD (dump_dense) (Y, "Y after solve", Common)) ;
+
+        /* -------------------------------------------------------------- */
+        /* X = P'*Y, but only for rows in Yset, and create Xset */
+        /* -------------------------------------------------------------- */
+
+        /* X (Perm (Yset)) = Y (Yset) */
+        Xx = X->x ;
+        Xz = X->z ;
+        Xseti = Xset->i ;
+        Xsetp = Xset->p ;
+
+        switch (L->xtype)
+        {
+
+            case CHOLMOD_REAL:
+                for (p = 0 ; p < ysetlen ; p++)
+                {
+                    Int inew = Yseti [p] ;
+                    Int iold = Perm ? Perm [inew] : inew ;
+                    Xx [iold] = Yx [inew] ;
+                    Xseti [p] = iold ;
+                }
+                break ;
+
+            case CHOLMOD_COMPLEX:
+                for (p = 0 ; p < ysetlen ; p++)
+                {
+                    Int inew = Yseti [p] ;
+                    Int iold = Perm ? Perm [inew] : inew ;
+                    Xx [2*iold  ] = Yx [2*inew] ;
+                    Xx [2*iold+1] = Yx [2*inew+1] ;
+                    Xseti [p] = iold ;
+                }
+                break ;
+
+            case CHOLMOD_ZOMPLEX:
+                for (p = 0 ; p < ysetlen ; p++)
+                {
+                    Int inew = Yseti [p] ;
+                    Int iold = Perm ? Perm [inew] : inew ;
+                    Xx [iold] = Yx [inew] ;
+                    Xz [iold] = Yz [inew] ;
+                    Xseti [p] = iold ;
+                }
+                break ;
+        }
+
+        Xsetp [0] = 0 ;
+        Xsetp [1] = ysetlen ;
+
+        DEBUG (CHOLMOD(dump_sparse) (Xset, "Xset", Common)) ;
+        DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ;
+        Common->no_workspace_reallocate = save_realloc_state ;
+        /* done using Iwork (n:3n-1) for Ci and Yseti ] */
+
+    }
+    else if (sys == CHOLMOD_P)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* x = P*b */
+	/* ------------------------------------------------------------------ */
+
+	perm (B, Perm, 0, nrhs, X) ;
+
+    }
+    else if (sys == CHOLMOD_Pt)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* x = P'*b */
+	/* ------------------------------------------------------------------ */
+
+	iperm (B, Perm, 0, nrhs, X) ;
+
+    }
+    else if (L->is_super)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve using a supernodal LL' factorization */
+	/* ------------------------------------------------------------------ */
+
+#ifndef NSUPERNODAL
+	/* allocate workspace */
+	cholmod_dense *E ;
+	Int dual ;
+        Common->blas_ok = TRUE ;
+	dual = (L->xtype == CHOLMOD_REAL && B->xtype != CHOLMOD_REAL) ? 2 : 1 ;
+	Y = CHOLMOD(ensure_dense) (Y_Handle, n, dual*nrhs, n, L->xtype, Common);
+	E = CHOLMOD(ensure_dense) (E_Handle, dual*nrhs, L->maxesize, dual*nrhs,
+		L->xtype, Common) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+            return (FALSE) ;
+	}
+
+	perm (B, Perm, 0, nrhs, Y) ;			    /* Y = P*B */
+
+	if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt)
+	{
+	    CHOLMOD(super_lsolve) (L, Y, E, Common) ;	    /* Y = L\Y */
+            CHOLMOD(super_ltsolve) (L, Y, E, Common) ;	    /* Y = L'\Y*/
+	}
+	else if (sys == CHOLMOD_L || sys == CHOLMOD_LD)
+	{
+	    CHOLMOD(super_lsolve) (L, Y, E, Common) ;	    /* Y = L\Y */
+	}
+	else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt)
+	{
+	    CHOLMOD(super_ltsolve) (L, Y, E, Common) ;      /* Y = L'\Y*/
+	}
+
+	iperm (Y, Perm, 0, nrhs, X) ;			    /* X = P'*Y */
+
+	if (CHECK_BLAS_INT && !Common->blas_ok)
+	{
+	    /* Integer overflow in the BLAS.  This is probably impossible,
+	     * since the BLAS were used to create the supernodal factorization.
+	     * It might be possible for the calls to the BLAS to differ between
+	     * factorization and forward/backsolves, however.  This statement
+	     * is untested; it does not appear in the compiled code if
+             * CHECK_BLAS_INT is true (when the same integer is used in
+             * CHOLMOD and the BLAS. */
+	    return (FALSE) ;
+	}
+
+#else
+	/* CHOLMOD Supernodal module not installed */
+	ERROR (CHOLMOD_NOT_INSTALLED,"Supernodal module not installed") ;
+#endif
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* solve using a simplicial LL' or LDL' factorization */
+	/* ------------------------------------------------------------------ */
+
+        if (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL)
+	{
+	    /* L, B, and Y are all real */
+	    /* solve with up to 4 columns of B at a time */
+            ncols = 4 ;
+            nr = MAX (4, nrhs) ;
+	    ytype = CHOLMOD_REAL ;
+	}
+	else if (L->xtype == CHOLMOD_REAL)
+	{
+            /* L is real and B is complex or zomplex */
+	    /* solve with one column of B (real/imag), at a time */
+	    ncols = 1 ;
+	    nr = 2 ;
+	    ytype = CHOLMOD_REAL ;
+	}
+	else
+	{
+	    /* L is complex or zomplex, B is real/complex/zomplex, Y has the
+	     * same complexity as L.  Solve with one column of B at a time. */
+	    ncols = 1 ;
+	    nr = 1 ;
+	    ytype = L->xtype ;
+	}
+
+	Y = CHOLMOD(ensure_dense) (Y_Handle, nr, n, nr, ytype, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (FALSE) ;
+	}
+
+        for (k1 = 0 ; k1 < nrhs ; k1 += ncols)
+        {
+
+            /* -------------------------------------------------------------- */
+            /* Y = B (P, k1:k1+ncols-1)' = (P * B (:,...))' */
+            /* -------------------------------------------------------------- */
+
+            ptrans (B, Perm, k1, ncols, Y) ;
+
+            /* -------------------------------------------------------------- */
+            /* solve Y = (L' \ (L \ Y'))', or other system, with template */
+            /* -------------------------------------------------------------- */
+
+            switch (L->xtype)
+            {
+                case CHOLMOD_REAL:
+                    r_simplicial_solver (sys, L, Y, NULL, 0) ;
+                    break ;
+
+                case CHOLMOD_COMPLEX:
+                    c_simplicial_solver (sys, L, Y, NULL, 0) ;
+                    break ;
+
+                case CHOLMOD_ZOMPLEX:
+                    z_simplicial_solver (sys, L, Y, NULL, 0) ;
+                    break ;
+            }
+
+            /* -------------------------------------------------------------- */
+            /* X (P, k1:k2+ncols-1) = Y' */
+            /* -------------------------------------------------------------- */
+
+            iptrans (Y, Perm, k1, ncols, X) ;
+        }
+    }
+
+    /*
+    printf ("bye from solve2\n") ;
+    */
+    DEBUG (CHOLMOD(dump_dense) (X, "X result", Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/cholmod_spsolve.c b/src/CHOLMOD/Cholesky/cholmod_spsolve.c
new file mode 100644
index 0000000..1b0f71a
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/cholmod_spsolve.c
@@ -0,0 +1,396 @@
+/* ========================================================================== */
+/* === Cholesky/cholmod_spsolve ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Given an LL' or LDL' factorization of A, solve one of the following systems:
+ *
+ *	Ax=b	    0: CHOLMOD_A	also applies the permutation L->Perm
+ *	LDL'x=b	    1: CHOLMOD_LDLt	does not apply L->Perm
+ *	LDx=b	    2: CHOLMOD_LD
+ *	DL'x=b	    3: CHOLMOD_DLt
+ *	Lx=b	    4: CHOLMOD_L
+ *	L'x=b	    5: CHOLMOD_Lt
+ *	Dx=b	    6: CHOLMOD_D
+ *	x=Pb	    7: CHOLMOD_P	apply a permutation (P is L->Perm)
+ *	x=P'b	    8: CHOLMOD_Pt	apply an inverse permutation
+ *
+ * where b and x are sparse.  If L and b are real, then x is real.  Otherwise,
+ * x is complex or zomplex, depending on the Common->prefer_zomplex parameter.
+ * All xtypes of x and b are supported (real, complex, and zomplex).
+ */
+
+#ifndef NCHOLESKY
+
+#include "cholmod_internal.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === EXPAND_AS_NEEDED ===================================================== */
+/* ========================================================================== */
+
+/* Double the size of the sparse matrix X, if we have run out of space. */ 
+
+#define EXPAND_AS_NEEDED \
+if (xnz >= nzmax) \
+{ \
+    nzmax *= 2 ; \
+    CHOLMOD(reallocate_sparse) (nzmax, X, Common) ; \
+    if (Common->status < CHOLMOD_OK) \
+    { \
+	CHOLMOD(free_sparse) (&X, Common) ; \
+	CHOLMOD(free_dense) (&X4, Common) ; \
+	CHOLMOD(free_dense) (&B4, Common) ; \
+	return (NULL) ; \
+    } \
+    Xi = X->i ; \
+    Xx = X->x ; \
+    Xz = X->z ; \
+}
+
+
+/* ========================================================================== */
+/* === cholmod_spolve ======================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(spsolve)	    /* returns the sparse solution X */
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_sparse *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double x, z ;
+    cholmod_dense *X4, *B4 ;
+    cholmod_sparse *X ;
+    double *Bx, *Bz, *Xx, *Xz, *B4x, *B4z, *X4x, *X4z ;
+    Int *Bi, *Bp, *Xp, *Xi, *Bnz ;
+    Int n, nrhs, q, p, i, j, jfirst, jlast, packed, block, pend, j_n, xtype ;
+    size_t xnz, nzmax ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    if (L->n != B->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "dimensions of L and B do not match") ;
+	return (NULL) ;
+    }
+    if (B->stype)
+    {
+	ERROR (CHOLMOD_INVALID, "B cannot be stored in symmetric mode") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace B4 and initial result X */
+    /* ---------------------------------------------------------------------- */
+
+    n = L->n ;
+    nrhs = B->ncol ;
+
+    /* X is real if both L and B are real, complex/zomplex otherwise */
+    xtype = (L->xtype == CHOLMOD_REAL && B->xtype == CHOLMOD_REAL) ?
+	CHOLMOD_REAL :
+	(Common->prefer_zomplex ? CHOLMOD_ZOMPLEX : CHOLMOD_COMPLEX) ;
+
+    /* solve up to 4 columns at a time */
+    block = MIN (nrhs, 4) ;
+
+    /* initial size of X is at most 4*n */
+    nzmax = n*block ;
+
+    X = CHOLMOD(spzeros) (n, nrhs, nzmax, xtype, Common) ;
+    B4 = CHOLMOD(zeros) (n, block, B->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&X, Common) ;
+	CHOLMOD(free_dense) (&B4, Common) ;
+	return (NULL) ;
+    }
+
+    Bp = B->p ;
+    Bi = B->i ;
+    Bx = B->x ;
+    Bz = B->z ;
+    Bnz = B->nz ;
+    packed = B->packed ;
+
+    Xp = X->p ;
+    Xi = X->i ;
+    Xx = X->x ;
+    Xz = X->z ;
+
+    xnz = 0 ;
+
+    B4x = B4->x ;
+    B4z = B4->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* solve in chunks of 4 columns at a time */
+    /* ---------------------------------------------------------------------- */
+
+    for (jfirst = 0 ; jfirst < nrhs ; jfirst += block)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* adjust the number of columns of B4 */
+	/* ------------------------------------------------------------------ */
+
+	jlast = MIN (nrhs, jfirst + block) ;
+	B4->ncol = jlast - jfirst ;
+
+	/* ------------------------------------------------------------------ */
+	/* scatter B(jfirst:jlast-1) into B4 */
+	/* ------------------------------------------------------------------ */
+
+	for (j = jfirst ; j < jlast ; j++)
+	{
+	    p = Bp [j] ;
+	    pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ;
+	    j_n = (j-jfirst)*n ;
+
+	    switch (B->xtype)
+	    {
+
+		case CHOLMOD_REAL:
+		    for ( ; p < pend ; p++)
+		    {
+			B4x [Bi [p] + j_n] = Bx [p] ;
+		    }
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    for ( ; p < pend ; p++)
+		    {
+			q = Bi [p] + j_n ;
+			B4x [2*q  ] = Bx [2*p  ] ;
+			B4x [2*q+1] = Bx [2*p+1] ;
+		    }
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    for ( ; p < pend ; p++)
+		    {
+			q = Bi [p] + j_n ;
+			B4x [q] = Bx [p] ;
+			B4z [q] = Bz [p] ;
+		    }
+		    break ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* solve the system (X4 = A\B4 or other system) */
+	/* ------------------------------------------------------------------ */
+
+	X4 = CHOLMOD(solve) (sys, L, B4, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_sparse) (&X, Common) ;
+	    CHOLMOD(free_dense) (&B4, Common) ;
+	    CHOLMOD(free_dense) (&X4, Common) ;
+	    return (NULL) ;
+	}
+	ASSERT (X4->xtype == xtype) ;
+	X4x = X4->x ;
+	X4z = X4->z ;
+
+	/* ------------------------------------------------------------------ */
+	/* append the solution onto X */
+	/* ------------------------------------------------------------------ */
+
+	for (j = jfirst ; j < jlast ; j++)
+	{
+	    Xp [j] = xnz ;
+	    j_n = (j-jfirst)*n ;
+	    if ( xnz + n <= nzmax)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* X is guaranteed to be large enough */
+		/* ---------------------------------------------------------- */
+
+		switch (xtype)
+		{
+
+		    case CHOLMOD_REAL:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + j_n] ;
+			    if (IS_NONZERO (x))
+			    {
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_COMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [2*(i + j_n)  ] ;
+			    z = X4x [2*(i + j_n)+1] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				Xi [xnz] = i ;
+				Xx [2*xnz  ] = x ;
+				Xx [2*xnz+1] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_ZOMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + j_n] ;
+			    z = X4z [i + j_n] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				Xz [xnz] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+		}
+
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* X may need to increase in size */
+		/* ---------------------------------------------------------- */
+
+		switch (xtype)
+		{
+
+		    case CHOLMOD_REAL:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + j_n] ;
+			    if (IS_NONZERO (x))
+			    {
+				EXPAND_AS_NEEDED ;
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_COMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [2*(i + j_n)  ] ;
+			    z = X4x [2*(i + j_n)+1] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				EXPAND_AS_NEEDED ;
+				Xi [xnz] = i ;
+				Xx [2*xnz  ] = x ;
+				Xx [2*xnz+1] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+
+		    case CHOLMOD_ZOMPLEX:
+			for (i = 0 ; i < n ; i++)
+			{
+			    x = X4x [i + j_n] ;
+			    z = X4z [i + j_n] ;
+			    if (IS_NONZERO (x) || IS_NONZERO (z))
+			    {
+				EXPAND_AS_NEEDED ;
+				Xi [xnz] = i ;
+				Xx [xnz] = x ;
+				Xz [xnz] = z ;
+				xnz++ ;
+			    }
+			}
+			break ;
+		}
+
+	    }
+	}
+	CHOLMOD(free_dense) (&X4, Common) ;
+
+	/* ------------------------------------------------------------------ */
+	/* clear B4 for next iteration */
+	/* ------------------------------------------------------------------ */
+
+	if (jlast < nrhs)
+	{
+
+	    for (j = jfirst ; j < jlast ; j++)
+	    {
+		p = Bp [j] ;
+		pend = (packed) ? (Bp [j+1]) : (p + Bnz [j]) ;
+		j_n = (j-jfirst)*n ;
+
+		switch (B->xtype)
+		{
+
+		    case CHOLMOD_REAL:
+			for ( ; p < pend ; p++)
+			{
+			    B4x [Bi [p] + j_n] = 0 ;
+			}
+			break ;
+
+		    case CHOLMOD_COMPLEX:
+			for ( ; p < pend ; p++)
+			{
+			    q = Bi [p] + j_n ;
+			    B4x [2*q  ] = 0 ;
+			    B4x [2*q+1] = 0 ;
+			}
+			break ;
+
+		    case CHOLMOD_ZOMPLEX:
+			for ( ; p < pend ; p++)
+			{
+			    q = Bi [p] + j_n ;
+			    B4x [q] = 0 ;
+			    B4z [q] = 0 ;
+			}
+			break ;
+		}
+	    }
+	}
+    }
+
+    Xp [nrhs] = xnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce X in size, free workspace, and return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (xnz <= X->nzmax) ;
+    CHOLMOD(reallocate_sparse) (xnz, X, Common) ;
+    ASSERT (Common->status == CHOLMOD_OK) ;
+    CHOLMOD(free_dense) (&B4, Common) ;
+    return (X) ;
+}
+#endif
diff --git a/src/CHOLMOD/Cholesky/lesser.txt b/src/CHOLMOD/Cholesky/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/CHOLMOD/Cholesky/t_cholmod_lsolve.c b/src/CHOLMOD/Cholesky/t_cholmod_lsolve.c
new file mode 100644
index 0000000..c91dc2f
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/t_cholmod_lsolve.c
@@ -0,0 +1,850 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_lsolve ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine to solve Lx=b with unit or non-unit diagonal, or
+ * solve LDx=b.
+ *
+ * The numeric xtype of L and Y must match.  Y contains b on input and x on
+ * output, stored in row-form.  Y is nrow-by-n, where nrow must equal 1 for the 
+ * complex or zomplex cases, and nrow <= 4 for the real case.
+ *
+ * This file is not compiled separately.  It is included in t_cholmod_solve.c
+ * instead.  It contains no user-callable routines.
+ *
+ * workspace: none
+ *
+ * Supports real, complex, and zomplex factors.
+ */
+
+/* undefine all prior definitions */
+#undef FORM_NAME
+#undef LSOLVE
+
+/* -------------------------------------------------------------------------- */
+/* define the method */
+/* -------------------------------------------------------------------------- */
+
+#ifdef LL
+/* LL': solve Lx=b with non-unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ll_lsolve_ ## rank
+
+#elif defined (LD)
+/* LDL': solve LDx=b */
+#define FORM_NAME(prefix,rank) prefix ## ldl_ldsolve_ ## rank
+
+#else
+/* LDL': solve Lx=b with unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ldl_lsolve_ ## rank
+
+#endif
+
+/* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */
+
+#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank)
+
+#ifdef REAL
+
+/* ========================================================================== */
+/* === LSOLVE (1) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 1 column  */
+
+static void LSOLVE (PREFIX,1)
+(
+    cholmod_factor *L,
+    double X [ ]                        /* n-by-1 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y = X [j] ;
+#ifdef LL
+	    y /= Lx [p] ;
+	    X [j] = y ;
+#elif defined (LD)
+	    X [j] = y / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		X [Li [p]] -= Lx [p] * y ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2] ;
+	    Int q = Lp [j+1] ;
+#ifdef LL
+	    y [0] = X [j] / Lx [p] ;
+	    y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ;
+	    X [j  ] = y [0] ;
+	    X [j+1] = y [1] ;
+#elif defined (LD)
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    X [j  ] = y [0] / Lx [p] ;
+	    X [j+1] = y [1] / Lx [q] ;
+#else
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    X [j+1] = y [1] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+#ifdef LL
+	    y [0] = X [j] / Lx [p] ;
+	    y [1] = (X [j+1] - Lx [p+1] * y [0]) / Lx [q] ;
+	    y [2] = (X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1]) / Lx [r] ;
+	    X [j  ] = y [0] ;
+	    X [j+1] = y [1] ;
+	    X [j+2] = y [2] ;
+#elif defined (LD)
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ;
+	    X [j  ] = y [0] / Lx [p] ;
+	    X [j+1] = y [1] / Lx [q] ;
+	    X [j+2] = y [2] / Lx [r] ;
+#else
+	    y [0] = X [j] ;
+	    y [1] = X [j+1] - Lx [p+1] * y [0] ;
+	    y [2] = X [j+2] - Lx [p+2] * y [0] - Lx [q+1] * y [1] ;
+	    X [j+1] = y [1] ;
+	    X [j+2] = y [2] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		X [Li [p]] -= Lx [p] * y [0] + Lx [q] * y [1] + Lx [r] * y [2] ;
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (2) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 2 columns */
+
+static void LSOLVE (PREFIX,2)
+(
+    cholmod_factor *L,
+    double X [ ][2]		/* n-by-2 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2] ;
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+#ifdef LL
+	    y [0] /= Lx [p] ;
+	    y [1] /= Lx [p] ;
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+#elif defined (LD)
+	    X [j][0] = y [0] / Lx [p] ;
+	    X [j][1] = y [1] / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		X [i][0] -= Lx [p] * y [0] ;
+		X [i][1] -= Lx [p] * y [1] ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][2] ;
+	    Int q = Lp [j+1] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ;
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		X [i][0] -= Lx [p] * y [0][0] + Lx [q] * y [1][0] ;
+		X [i][1] -= Lx [p] * y [0][1] + Lx [q] * y [1][1] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][2] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ;
+	    y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r];
+	    y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r];
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+2][0] = y [2][0] / Lx [r] ;
+	    X [j+2][1] = y [2][1] / Lx [r] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		X[i][0] -= Lx[p] * y[0][0] + Lx[q] * y[1][0] + Lx[r] * y[2][0] ;
+		X[i][1] -= Lx[p] * y[0][1] + Lx[q] * y[1][1] + Lx[r] * y[2][1] ;
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (3) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 3 columns */
+
+static void LSOLVE (PREFIX,3)
+(
+    cholmod_factor *L,
+    double X [ ][3]			/* n-by-3 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3] ;
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+#ifdef LL
+	    y [0] /= Lx [p] ;
+	    y [1] /= Lx [p] ;
+	    y [2] /= Lx [p] ;
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+#elif defined (LD)
+	    X [j][0] = y [0] / Lx [p] ;
+	    X [j][1] = y [1] / Lx [p] ;
+	    X [j][2] = y [2] / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		double lx = Lx [p] ;
+		X [i][0] -= lx * y [0] ;
+		X [i][1] -= lx * y [1] ;
+		X [i][2] -= lx * y [2] ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][3] ;
+	    Int q = Lp [j+1] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ;
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		double lx [2] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ;
+		X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ;
+		X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][3] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ;
+	    y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r];
+	    y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r];
+	    y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r];
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+	    X [j+2][0] = y [2][0] / Lx [r] ;
+	    X [j+2][1] = y [2][1] / Lx [r] ;
+	    X [j+2][2] = y [2][2] / Lx [r] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		double lx [3] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		lx [2] = Lx [r] ;
+		X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0];
+		X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1];
+		X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2];
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (4) =========================================================== */
+/* ========================================================================== */
+
+/* Solve Lx=b, where b has 4 columns */
+
+static void LSOLVE (PREFIX,4)
+(
+    cholmod_factor *L,
+    double X [ ][4]			    /* n-by-4 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = 0 ; j < n ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j+1, and j+2) */
+	if (lnz < 4 || lnz != Lnz [j+1] + 1 || Li [p+1] != j+1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [4] ;
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+	    y [3] = X [j][3] ;
+#ifdef LL
+	    y [0] /= Lx [p] ;
+	    y [1] /= Lx [p] ;
+	    y [2] /= Lx [p] ;
+	    y [3] /= Lx [p] ;
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+	    X [j][3] = y [3] ;
+#elif defined (LD)
+	    X [j][0] = y [0] / Lx [p] ;
+	    X [j][1] = y [1] / Lx [p] ;
+	    X [j][2] = y [2] / Lx [p] ;
+	    X [j][3] = y [3] / Lx [p] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		double lx = Lx [p] ;
+		X [i][0] -= lx * y [0] ;
+		X [i][1] -= lx * y [1] ;
+		X [i][2] -= lx * y [2] ;
+		X [i][3] -= lx * y [3] ;
+	    }
+	    j++ ;	/* advance to next column of L */
+
+	}
+	else if (lnz != Lnz [j+2] + 2 || Li [p+2] != j+2)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][4] ;
+	    Int q = Lp [j+1] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+	    y [0][3] = X [j][3] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [0][3] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx [p+1] * y [0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx [p+1] * y [0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx [p+1] * y [0][2]) / Lx [q] ;
+	    y [1][3] = (X [j+1][3] - Lx [p+1] * y [0][3]) / Lx [q] ;
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j  ][3] = y [0][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j  ][3] = y [0][3] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+	    X [j+1][3] = y [1][3] / Lx [q] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+#endif
+	    for (p += 2, q++ ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		double lx [2] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		X [i][0] -= lx [0] * y [0][0] + lx [1] * y [1][0] ;
+		X [i][1] -= lx [0] * y [0][1] + lx [1] * y [1][1] ;
+		X [i][2] -= lx [0] * y [0][2] + lx [1] * y [1][2] ;
+		X [i][3] -= lx [0] * y [0][3] + lx [1] * y [1][3] ;
+	    }
+	    j += 2 ;	    /* advance to next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][4] ;
+	    Int q = Lp [j+1] ;
+	    Int r = Lp [j+2] ;
+	    y [0][0] = X [j][0] ;
+	    y [0][1] = X [j][1] ;
+	    y [0][2] = X [j][2] ;
+	    y [0][3] = X [j][3] ;
+#ifdef LL
+	    y [0][0] /= Lx [p] ;
+	    y [0][1] /= Lx [p] ;
+	    y [0][2] /= Lx [p] ;
+	    y [0][3] /= Lx [p] ;
+	    y [1][0] = (X [j+1][0] - Lx[p+1] * y[0][0]) / Lx [q] ;
+	    y [1][1] = (X [j+1][1] - Lx[p+1] * y[0][1]) / Lx [q] ;
+	    y [1][2] = (X [j+1][2] - Lx[p+1] * y[0][2]) / Lx [q] ;
+	    y [1][3] = (X [j+1][3] - Lx[p+1] * y[0][3]) / Lx [q] ;
+	    y [2][0] = (X [j+2][0] - Lx[p+2] * y[0][0] - Lx[q+1]*y[1][0])/Lx[r];
+	    y [2][1] = (X [j+2][1] - Lx[p+2] * y[0][1] - Lx[q+1]*y[1][1])/Lx[r];
+	    y [2][2] = (X [j+2][2] - Lx[p+2] * y[0][2] - Lx[q+1]*y[1][2])/Lx[r];
+	    y [2][3] = (X [j+2][3] - Lx[p+2] * y[0][3] - Lx[q+1]*y[1][3])/Lx[r];
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j  ][3] = y [0][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+	    X [j+2][3] = y [2][3] ;
+#elif defined (LD)
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ;
+	    X [j  ][0] = y [0][0] / Lx [p] ;
+	    X [j  ][1] = y [0][1] / Lx [p] ;
+	    X [j  ][2] = y [0][2] / Lx [p] ;
+	    X [j  ][3] = y [0][3] / Lx [p] ;
+	    X [j+1][0] = y [1][0] / Lx [q] ;
+	    X [j+1][1] = y [1][1] / Lx [q] ;
+	    X [j+1][2] = y [1][2] / Lx [q] ;
+	    X [j+1][3] = y [1][3] / Lx [q] ;
+	    X [j+2][0] = y [2][0] / Lx [r] ;
+	    X [j+2][1] = y [2][1] / Lx [r] ;
+	    X [j+2][2] = y [2][2] / Lx [r] ;
+	    X [j+2][3] = y [2][3] / Lx [r] ;
+#else
+	    y [1][0] = X [j+1][0] - Lx [p+1] * y [0][0] ;
+	    y [1][1] = X [j+1][1] - Lx [p+1] * y [0][1] ;
+	    y [1][2] = X [j+1][2] - Lx [p+1] * y [0][2] ;
+	    y [1][3] = X [j+1][3] - Lx [p+1] * y [0][3] ;
+	    y [2][0] = X [j+2][0] - Lx [p+2] * y [0][0] - Lx [q+1] * y [1][0] ;
+	    y [2][1] = X [j+2][1] - Lx [p+2] * y [0][1] - Lx [q+1] * y [1][1] ;
+	    y [2][2] = X [j+2][2] - Lx [p+2] * y [0][2] - Lx [q+1] * y [1][2] ;
+	    y [2][3] = X [j+2][3] - Lx [p+2] * y [0][3] - Lx [q+1] * y [1][3] ;
+	    X [j+1][0] = y [1][0] ;
+	    X [j+1][1] = y [1][1] ;
+	    X [j+1][2] = y [1][2] ;
+	    X [j+1][3] = y [1][3] ;
+	    X [j+2][0] = y [2][0] ;
+	    X [j+2][1] = y [2][1] ;
+	    X [j+2][2] = y [2][2] ;
+	    X [j+2][3] = y [2][3] ;
+#endif
+	    for (p += 3, q += 2, r++ ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		double lx [3] ;
+		lx [0] = Lx [p] ;
+		lx [1] = Lx [q] ;
+		lx [2] = Lx [r] ;
+		X [i][0] -= lx[0] * y[0][0] + lx[1] * y[1][0] + lx[2] * y[2][0];
+		X [i][1] -= lx[0] * y[0][1] + lx[1] * y[1][1] + lx[2] * y[2][1];
+		X [i][2] -= lx[0] * y[0][2] + lx[1] * y[1][2] + lx[2] * y[2][2];
+		X [i][3] -= lx[0] * y[0][3] + lx[1] * y[1][3] + lx[2] * y[2][3];
+	    }
+	    j += 3 ;	    /* advance to next column of L */
+	}
+    }
+}
+
+#endif
+
+
+/* ========================================================================== */
+/* === LSOLVE (k) =========================================================== */
+/* ========================================================================== */
+
+static void LSOLVE (PREFIX,k)
+(
+    cholmod_factor *L,
+    cholmod_dense *Y,		    /* nr-by-n where nr is 1 to 4 */
+    Int *Yseti, Int ysetlen
+)
+{
+
+    double yx [2] ;
+#ifdef ZOMPLEX
+    double yz [1] ;
+    double *Lz = L->z ;
+    double *Xz = Y->z ;
+#endif
+    double *Lx = L->x ;
+    double *Xx = Y->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int n = L->n, jj, jjiters ;
+
+    ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */
+    ASSERT (L->n == Y->ncol) ;	    /* dimensions must match */
+    ASSERT (Y->nrow == Y->d) ;	    /* leading dimension of Y = # rows of Y */
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;  /* L is not symbolic */
+    ASSERT (!(L->is_super)) ;	    /* L is simplicial LL' or LDL' */
+
+#ifdef REAL
+
+    if (Yseti == NULL)
+    {
+
+        /* ------------------------------------------------------------------ */
+        /* real case, no Yseti, with 1 to 4 RHS's and dynamic supernodes */
+        /* ------------------------------------------------------------------ */
+
+        ASSERT (Y->nrow <= 4) ;
+
+        switch (Y->nrow)
+        {
+            case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ;
+            case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ;
+            case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ;
+            case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ;
+        }
+
+    }
+    else
+#endif
+    {
+
+        /* ------------------------------------------------------------------ */
+        /* solve a complex linear system or solve with Yseti */
+        /* ------------------------------------------------------------------ */
+
+        ASSERT (Y->nrow == 1) ;
+
+        jjiters = Yseti ? ysetlen : n ;
+
+        for (jj = 0 ; jj < jjiters ; jj++)
+        {
+            Int j = Yseti ? Yseti [jj] : jj ;
+
+            /* get the start, end, and length of column j */
+            Int p = Lp [j] ;
+            Int lnz = Lnz [j] ;
+            Int pend = p + lnz ;
+
+            /* y = X [j] ; */
+            ASSIGN (yx,yz,0, Xx,Xz,j) ;
+
+#ifdef LL
+            /* y /= Lx [p] ; */
+            /* X [j] = y ; */
+            DIV_REAL (yx,yz,0, yx,yz,0, Lx,p) ;
+            ASSIGN (Xx,Xz,j, yx,yz,0) ;
+#elif defined (LD)
+            /* X [j] = y / Lx [p] ; */
+            DIV_REAL (Xx,Xz,j, yx,yz,0, Lx,p) ;
+#endif
+
+            for (p++ ; p < pend ; p++)
+            {
+                /* X [Li [p]] -= Lx [p] * y ; */
+                Int i = Li [p] ;
+                MULTSUB (Xx,Xz,i, Lx,Lz,p, yx,yz,0) ;
+            }
+        }
+    }
+}
+
+/* prepare for the next inclusion of this file in cholmod_solve.c */
+#undef LL
+#undef LD
diff --git a/src/CHOLMOD/Cholesky/t_cholmod_ltsolve.c b/src/CHOLMOD/Cholesky/t_cholmod_ltsolve.c
new file mode 100644
index 0000000..c04bbbb
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/t_cholmod_ltsolve.c
@@ -0,0 +1,849 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_ltsolve =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine to solve L'x=b with unit or non-unit diagonal, or
+ * solve DL'x=b.
+ *
+ * The numeric xtype of L and Y must match.  Y contains b on input and x on
+ * output, stored in row-form.  Y is nrow-by-n, where nrow must equal 1 for the 
+ * complex or zomplex cases, and nrow <= 4 for the real case.
+ *
+ * This file is not compiled separately.  It is included in t_cholmod_solve.c
+ * instead.  It contains no user-callable routines.
+ *
+ * workspace: none
+ *
+ * Supports real, complex, and zomplex factors.
+ */
+
+/* undefine all prior definitions */
+#undef FORM_NAME
+#undef LSOLVE
+#undef DIAG
+
+/* -------------------------------------------------------------------------- */
+/* define the method */
+/* -------------------------------------------------------------------------- */
+
+#ifdef LL
+/* LL': solve Lx=b with non-unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ll_ltsolve_ ## rank
+#define DIAG
+
+#elif defined (LD)
+/* LDL': solve LDx=b */
+#define FORM_NAME(prefix,rank) prefix ## ldl_dltsolve_ ## rank
+#define DIAG
+
+#else
+/* LDL': solve Lx=b with unit diagonal */
+#define FORM_NAME(prefix,rank) prefix ## ldl_ltsolve_ ## rank
+
+#endif
+
+/* LSOLVE(k) defines the name of a routine for an n-by-k right-hand-side. */
+#define LSOLVE(prefix,rank) FORM_NAME(prefix,rank)
+
+#ifdef REAL
+
+/* ========================================================================== */
+/* === LSOLVE (1) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 1 column  */
+
+static void LSOLVE (PREFIX,1)
+(
+    cholmod_factor *L,
+    double X [ ]                        /* n-by-1 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y = X [j] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y /= d ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		y -= Lx [p] * X [Li [p]] ;
+	    }
+#ifdef LL
+	    X [j] = y / d ;
+#else
+	    X [j] = y ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0] = X [j  ] / d [0] ;
+	    y [1] = X [j-1] / d [1] ;
+#else
+	    y [0] = X [j  ] ;
+	    y [1] = X [j-1] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i] ;
+		y [1] -= Lx [q] * X [i] ;
+	    }
+#ifdef LL
+	    y [0] /= d [0] ;
+	    y [1] = (y [1] - t * y [0]) / d [1] ;
+#else
+	    y [1] -= t * y [0] ;
+#endif
+	    X [j  ] = y [0] ;
+	    X [j-1] = y [1] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3], t [3] ;
+	    Int q = Lp [j-1] ;
+	    Int r = Lp [j-2] ;
+#ifdef DIAG
+	    double d [3] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+	    d [2] = Lx [r] ;
+#endif
+	    t [0] = Lx [q+1] ;
+	    t [1] = Lx [r+1] ;
+	    t [2] = Lx [r+2] ;
+#ifdef LD
+	    y [0] = X [j]   / d [0] ;
+	    y [1] = X [j-1] / d [1] ;
+	    y [2] = X [j-2] / d [2] ;
+#else
+	    y [0] = X [j] ;
+	    y [1] = X [j-1] ;
+	    y [2] = X [j-2] ;
+#endif
+	    for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i] ;
+		y [1] -= Lx [q] * X [i] ;
+		y [2] -= Lx [r] * X [i] ;
+	    }
+#ifdef LL
+	    y [0] /= d [0] ;
+	    y [1] = (y [1] - t [0] * y [0]) / d [1] ;
+	    y [2] = (y [2] - t [2] * y [0] - t [1] * y [1]) / d [2] ;
+#else
+	    y [1] -= t [0] * y [0] ;
+	    y [2] -= t [2] * y [0] + t [1] * y [1] ;
+#endif
+	    X [j-2] = y [2] ;
+	    X [j-1] = y [1] ;
+	    X [j  ] = y [0] ;
+	    j -= 3 ;	    /* advance to the next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (2) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 2 columns */
+
+static void LSOLVE (PREFIX,2)
+(
+    cholmod_factor *L,
+    double X [ ][2]		    /* n-by-2 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y [0] = X [j][0] / d ;
+	    y [1] = X [j][1] / d ;
+#else
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i][0] ;
+		y [1] -= Lx [p] * X [i][1] ;
+	    }
+#ifdef LL
+	    X [j][0] = y [0] / d ;
+	    X [j][1] = y [1] / d ;
+#else
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][2], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ;
+#else
+	    y [1][0] -= t * y [0][0] ;
+	    y [1][1] -= t * y [0][1] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][2], t [3] ;
+	    Int q = Lp [j-1] ;
+	    Int r = Lp [j-2] ;
+#ifdef DIAG
+	    double d [3] ; 
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+	    d [2] = Lx [r] ;
+#endif
+	    t [0] = Lx [q+1] ;
+	    t [1] = Lx [r+1] ;
+	    t [2] = Lx [r+2] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [2][0] = X [j-2][0] / d [2] ;
+	    y [2][1] = X [j-2][1] / d [2] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [2][0] = X [j-2][0] ;
+	    y [2][1] = X [j-2][1] ;
+#endif
+	    for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [2][0] -= Lx [r] * X [i][0] ;
+		y [2][1] -= Lx [r] * X [i][1] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ;
+	    y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2];
+	    y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2];
+#else
+	    y [1][0] -= t [0] * y [0][0] ;
+	    y [1][1] -= t [0] * y [0][1] ;
+	    y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ;
+	    y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-2][0] = y [2][0] ;
+	    X [j-2][1] = y [2][1] ;
+	    j -= 3 ;	    /* advance to the next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (3) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 3 columns */
+
+static void LSOLVE (PREFIX,3)
+(
+    cholmod_factor *L,
+    double X [ ][3]		    /* n-by-3 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y [0] = X [j][0] / d ;
+	    y [1] = X [j][1] / d ;
+	    y [2] = X [j][2] / d ;
+#else
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i][0] ;
+		y [1] -= Lx [p] * X [i][1] ;
+		y [2] -= Lx [p] * X [i][2] ;
+	    }
+#ifdef LL
+	    X [j][0] = y [0] / d ;
+	    X [j][1] = y [1] / d ;
+	    X [j][2] = y [2] / d ;
+#else
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else if (lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][3], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [0][2] = X [j  ][2] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [1][2] = X [j-1][2] / d [1] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [0][2] = X [j  ][2] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [1][2] = X [j-1][2] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [0][2] -= Lx [p] * X [i][2] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [1][2] -= Lx [q] * X [i][2] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [0][2] /= d [0] ;
+	    y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ;
+	    y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ;
+#else
+	    y [1][0] -= t * y [0][0] ;
+	    y [1][1] -= t * y [0][1] ;
+	    y [1][2] -= t * y [0][2] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-1][2] = y [1][2] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of three columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [3][3], t [3] ;
+	    Int q = Lp [j-1] ;
+	    Int r = Lp [j-2] ;
+#ifdef DIAG
+	    double d [3] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+	    d [2] = Lx [r] ;
+#endif
+	    t [0] = Lx [q+1] ;
+	    t [1] = Lx [r+1] ;
+	    t [2] = Lx [r+2] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [0][2] = X [j  ][2] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [1][2] = X [j-1][2] / d [1] ;
+	    y [2][0] = X [j-2][0] / d [2] ;
+	    y [2][1] = X [j-2][1] / d [2] ;
+	    y [2][2] = X [j-2][2] / d [2] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [0][2] = X [j  ][2] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [1][2] = X [j-1][2] ;
+	    y [2][0] = X [j-2][0] ;
+	    y [2][1] = X [j-2][1] ;
+	    y [2][2] = X [j-2][2] ;
+#endif
+	    for (p++, q += 2, r += 3 ; p < pend ; p++, q++, r++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [0][2] -= Lx [p] * X [i][2] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [1][2] -= Lx [q] * X [i][2] ;
+		y [2][0] -= Lx [r] * X [i][0] ;
+		y [2][1] -= Lx [r] * X [i][1] ;
+		y [2][2] -= Lx [r] * X [i][2] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [0][2] /= d [0] ;
+	    y [1][0] = (y [1][0] - t [0] * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t [0] * y [0][1]) / d [1] ;
+	    y [1][2] = (y [1][2] - t [0] * y [0][2]) / d [1] ;
+	    y [2][0] = (y [2][0] - t [2] * y [0][0] - t [1] * y [1][0]) / d [2];
+	    y [2][1] = (y [2][1] - t [2] * y [0][1] - t [1] * y [1][1]) / d [2];
+	    y [2][2] = (y [2][2] - t [2] * y [0][2] - t [1] * y [1][2]) / d [2];
+#else
+	    y [1][0] -= t [0] * y [0][0] ;
+	    y [1][1] -= t [0] * y [0][1] ;
+	    y [1][2] -= t [0] * y [0][2] ;
+	    y [2][0] -= t [2] * y [0][0] + t [1] * y [1][0] ;
+	    y [2][1] -= t [2] * y [0][1] + t [1] * y [1][1] ;
+	    y [2][2] -= t [2] * y [0][2] + t [1] * y [1][2] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-1][2] = y [1][2] ;
+	    X [j-2][0] = y [2][0] ;
+	    X [j-2][1] = y [2][1] ;
+	    X [j-2][2] = y [2][2] ;
+	    j -= 3 ;	    /* advance to the next column of L */
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === LSOLVE (4) =========================================================== */
+/* ========================================================================== */
+
+/* Solve L'x=b, where b has 4 columns */
+
+static void LSOLVE (PREFIX,4)
+(
+    cholmod_factor *L,
+    double X [ ][4]		    /* n-by-4 in row form */
+)
+{
+    double *Lx = L->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int j, n = L->n ;
+
+    for (j = n-1 ; j >= 0 ; )
+    {
+	/* get the start, end, and length of column j */
+	Int p = Lp [j] ;
+	Int lnz = Lnz [j] ;
+	Int pend = p + lnz ;
+
+	/* find a chain of supernodes (up to j, j-1, and j-2) */
+	if (j < 4 || lnz != Lnz [j-1] - 1 || Li [Lp [j-1]+1] != j)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a single column of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [4] ;
+#ifdef DIAG
+	    double d = Lx [p] ;
+#endif
+#ifdef LD
+	    y [0] = X [j][0] / d ;
+	    y [1] = X [j][1] / d ;
+	    y [2] = X [j][2] / d ;
+	    y [3] = X [j][3] / d ;
+#else
+	    y [0] = X [j][0] ;
+	    y [1] = X [j][1] ;
+	    y [2] = X [j][2] ;
+	    y [3] = X [j][3] ;
+#endif
+	    for (p++ ; p < pend ; p++)
+	    {
+		Int i = Li [p] ;
+		y [0] -= Lx [p] * X [i][0] ;
+		y [1] -= Lx [p] * X [i][1] ;
+		y [2] -= Lx [p] * X [i][2] ;
+		y [3] -= Lx [p] * X [i][3] ;
+	    }
+#ifdef LL
+	    X [j][0] = y [0] / d ;
+	    X [j][1] = y [1] / d ;
+	    X [j][2] = y [2] / d ;
+	    X [j][3] = y [3] / d ;
+#else
+	    X [j][0] = y [0] ;
+	    X [j][1] = y [1] ;
+	    X [j][2] = y [2] ;
+	    X [j][3] = y [3] ;
+#endif
+	    j-- ;	/* advance to the next column of L */
+
+	}
+	else /* if (j == 1 || lnz != Lnz [j-2]-2 || Li [Lp [j-2]+2] != j) */
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* solve with a supernode of two columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    double y [2][4], t ;
+	    Int q = Lp [j-1] ;
+#ifdef DIAG
+	    double d [2] ;
+	    d [0] = Lx [p] ;
+	    d [1] = Lx [q] ;
+#endif
+	    t = Lx [q+1] ;
+#ifdef LD
+	    y [0][0] = X [j  ][0] / d [0] ;
+	    y [0][1] = X [j  ][1] / d [0] ;
+	    y [0][2] = X [j  ][2] / d [0] ;
+	    y [0][3] = X [j  ][3] / d [0] ;
+	    y [1][0] = X [j-1][0] / d [1] ;
+	    y [1][1] = X [j-1][1] / d [1] ;
+	    y [1][2] = X [j-1][2] / d [1] ;
+	    y [1][3] = X [j-1][3] / d [1] ;
+#else
+	    y [0][0] = X [j  ][0] ;
+	    y [0][1] = X [j  ][1] ;
+	    y [0][2] = X [j  ][2] ;
+	    y [0][3] = X [j  ][3] ;
+	    y [1][0] = X [j-1][0] ;
+	    y [1][1] = X [j-1][1] ;
+	    y [1][2] = X [j-1][2] ;
+	    y [1][3] = X [j-1][3] ;
+#endif
+	    for (p++, q += 2 ; p < pend ; p++, q++)
+	    {
+		Int i = Li [p] ;
+		y [0][0] -= Lx [p] * X [i][0] ;
+		y [0][1] -= Lx [p] * X [i][1] ;
+		y [0][2] -= Lx [p] * X [i][2] ;
+		y [0][3] -= Lx [p] * X [i][3] ;
+		y [1][0] -= Lx [q] * X [i][0] ;
+		y [1][1] -= Lx [q] * X [i][1] ;
+		y [1][2] -= Lx [q] * X [i][2] ;
+		y [1][3] -= Lx [q] * X [i][3] ;
+	    }
+#ifdef LL
+	    y [0][0] /= d [0] ;
+	    y [0][1] /= d [0] ;
+	    y [0][2] /= d [0] ;
+	    y [0][3] /= d [0] ;
+	    y [1][0] = (y [1][0] - t * y [0][0]) / d [1] ;
+	    y [1][1] = (y [1][1] - t * y [0][1]) / d [1] ;
+	    y [1][2] = (y [1][2] - t * y [0][2]) / d [1] ;
+	    y [1][3] = (y [1][3] - t * y [0][3]) / d [1] ;
+#else
+	    y [1][0] -= t * y [0][0] ;
+	    y [1][1] -= t * y [0][1] ;
+	    y [1][2] -= t * y [0][2] ;
+	    y [1][3] -= t * y [0][3] ;
+#endif
+	    X [j  ][0] = y [0][0] ;
+	    X [j  ][1] = y [0][1] ;
+	    X [j  ][2] = y [0][2] ;
+	    X [j  ][3] = y [0][3] ;
+	    X [j-1][0] = y [1][0] ;
+	    X [j-1][1] = y [1][1] ;
+	    X [j-1][2] = y [1][2] ;
+	    X [j-1][3] = y [1][3] ;
+	    j -= 2 ;	    /* advance to the next column of L */
+	}
+
+	/* NOTE: with 4 right-hand-sides, it suffices to exploit dynamic
+	 * supernodes of just size 1 and 2.  3-column supernodes are not
+	 * needed. */
+    }
+}
+
+#endif
+
+/* ========================================================================== */
+/* === LSOLVE (k) =========================================================== */
+/* ========================================================================== */
+
+static void LSOLVE (PREFIX,k)
+(
+    cholmod_factor *L,
+    cholmod_dense *Y,		    /* nr-by-n where nr is 1 to 4 */
+    Int *Yseti, Int ysetlen
+)
+{
+
+#ifdef DIAG
+    double d [1] ;
+#endif
+    double yx [2] ;
+#ifdef ZOMPLEX
+    double yz [1] ;
+    double *Lz = L->z ;
+    double *Xz = Y->z ;
+#endif
+    double *Lx = L->x ;
+    double *Xx = Y->x ;
+    Int *Li = L->i ;
+    Int *Lp = L->p ;
+    Int *Lnz = L->nz ;
+    Int n = L->n, jj, jjiters ;
+
+    ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */
+    ASSERT (L->n == Y->ncol) ;	    /* dimensions must match */
+    ASSERT (Y->nrow == Y->d) ;	    /* leading dimension of Y = # rows of Y */
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;  /* L is not symbolic */
+    ASSERT (!(L->is_super)) ;	    /* L is simplicial LL' or LDL' */
+
+#ifdef REAL
+
+    if (Yseti == NULL)
+    {
+
+        /* ------------------------------------------------------------------ */
+        /* real case, no Yseti, with 1 to 4 RHS's and dynamic supernodes */
+        /* ------------------------------------------------------------------ */
+
+        ASSERT (Y->nrow <= 4) ;
+        switch (Y->nrow)
+        {
+            case 1: LSOLVE (PREFIX,1) (L, Y->x) ; break ;
+            case 2: LSOLVE (PREFIX,2) (L, Y->x) ; break ;
+            case 3: LSOLVE (PREFIX,3) (L, Y->x) ; break ;
+            case 4: LSOLVE (PREFIX,4) (L, Y->x) ; break ;
+        }
+
+    }
+    else
+#endif
+    {
+
+        /* ------------------------------------------------------------------ */
+        /* solve a complex linear system or solve with Yseti */
+        /* ------------------------------------------------------------------ */
+
+        ASSERT (Y->nrow == 1) ;
+
+        jjiters = Yseti ? ysetlen : n ;
+
+        for (jj = jjiters-1 ; jj >= 0 ; jj--)
+        {
+
+            Int j = Yseti ? Yseti [jj] : jj ;
+
+            /* get the start, end, and length of column j */
+            Int p = Lp [j] ;
+            Int lnz = Lnz [j] ;
+            Int pend = p + lnz ;
+
+            /* y = X [j] ; */
+            ASSIGN (yx,yz,0, Xx,Xz,j) ;
+
+#ifdef DIAG
+            /* d = Lx [p] ; */
+            ASSIGN_REAL (d,0, Lx,p) ;
+#endif
+#ifdef LD
+            /* y /= d ; */
+            DIV_REAL (yx,yz,0, yx,yz,0, d,0) ;
+#endif
+
+            for (p++ ; p < pend ; p++)
+            {
+                /* y -= conj (Lx [p]) * X [Li [p]] ; */
+                Int i = Li [p] ;
+                MULTSUBCONJ (yx,yz,0, Lx,Lz,p, Xx,Xz,i) ;
+            }
+
+#ifdef LL
+            /* X [j] = y / d ; */
+            DIV_REAL (Xx,Xz,j, yx,yz,0, d,0) ;
+#else
+            /* X [j] = y ; */
+            ASSIGN (Xx,Xz,j, yx,yz,0) ;
+#endif
+
+        }
+    }
+}
+
+/* prepare for the next inclusion of this file in cholmod_solve.c */
+#undef LL
+#undef LD
diff --git a/src/CHOLMOD/Cholesky/t_cholmod_rowfac.c b/src/CHOLMOD/Cholesky/t_cholmod_rowfac.c
new file mode 100644
index 0000000..c7cc49b
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/t_cholmod_rowfac.c
@@ -0,0 +1,457 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_rowfac ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_rowfac.  Supports any numeric xtype
+ * (real, complex, or zomplex).
+ *
+ * workspace: Iwork (n), Flag (n), Xwork (n if real, 2*n if complex)
+ */
+
+#include "cholmod_template.h"
+
+#ifdef MASK
+static int TEMPLATE (cholmod_rowfac_mask)
+#else
+static int TEMPLATE (cholmod_rowfac)
+#endif
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,f)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+AA' (beta [0] only) */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+#ifdef MASK
+    /* These inputs are used for cholmod_rowfac_mask only */
+    Int *mask,		/* size A->nrow. if mask[i] then W(i) is set to zero */
+    Int *RLinkUp,	/* size A->nrow. link list of rows to compute */
+#endif
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double yx [2], lx [2], fx [2], dk [1], di [1], fl = 0 ;
+#ifdef ZOMPLEX
+    double yz [1], lz [1], fz [1] ;
+#endif
+    double *Ax, *Az, *Lx, *Lz, *Wx, *Wz, *Fx, *Fz ;
+    Int *Ap, *Anz, *Ai, *Lp, *Lnz, *Li, *Lnext, *Flag, *Stack, *Fp, *Fi, *Fnz,
+	*Iwork ;
+    Int i, p, k, t, pf, pfend, top, s, mark, pend, n, lnz, is_ll, multadds,
+	use_dbound, packed, stype, Fpacked, sorted, nzmax, len, parent ;
+#ifndef REAL
+    Int dk_imaginary ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    PRINT1 (("\nin cholmod_rowfac, kstart %d kend %d stype %d\n",
+		kstart, kend, A->stype)) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "Initial L", Common)) ;
+
+    n = A->nrow ;
+    stype = A->stype ;
+
+    if (stype > 0)
+    {
+	/* symmetric upper case: F is not needed.  It may be NULL */
+	Fp = NULL ;
+	Fi = NULL ;
+	Fx = NULL ;
+	Fz = NULL ;
+	Fnz = NULL ;
+	Fpacked = TRUE ;
+    }
+    else
+    {
+	/* unsymmetric case: F is required. */
+	Fp = F->p ;
+	Fi = F->i ;
+	Fx = F->x ;
+	Fz = F->z ;
+	Fnz = F->nz ;
+	Fpacked = F->packed ;
+    }
+
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Ax = A->x ;		/* size nz, numeric values of A */
+    Az = A->z ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    sorted = A->sorted ;
+
+    use_dbound = IS_GT_ZERO (Common->dbound) ;
+
+    /* get the current factors L (and D for LDL'); allocate space if needed */
+    is_ll = L->is_ll ;
+    if (L->xtype == CHOLMOD_PATTERN)
+    {
+	/* ------------------------------------------------------------------ */
+	/* L is symbolic only; allocate and initialize L (and D for LDL') */
+	/* ------------------------------------------------------------------ */
+
+	/* workspace: none */
+	CHOLMOD(change_factor) (A->xtype, is_ll, FALSE, FALSE, TRUE, L, Common);
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (FALSE) ;
+	}
+	ASSERT (L->minor == (size_t) n) ;
+    }
+    else if (kstart == 0 && kend == (size_t) n)
+    {
+	/* ------------------------------------------------------------------ */
+	/* refactorization; reset L->nz and L->minor to restart factorization */
+	/* ------------------------------------------------------------------ */
+
+	L->minor = n ;
+	Lnz = L->nz ;
+	for (k = 0 ; k < n ; k++)
+	{
+	    Lnz [k] = 1 ;
+	}
+    }
+
+    ASSERT (is_ll == L->is_ll) ;
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "L ready", Common)) ;
+    DEBUG (CHOLMOD(dump_sparse) (A, "A ready", Common)) ;
+    DEBUG (if (stype == 0) CHOLMOD(dump_sparse) (F, "F ready", Common)) ;
+
+    /* inputs, can be modified on output: */
+    Lp = L->p ;		/* size n+1 */
+    ASSERT (Lp != NULL) ;
+
+    /* outputs, contents defined on input for incremental case only: */
+    Lnz = L->nz ;	/* size n */
+    Lnext = L->next ;	/* size n+2 */
+    Li = L->i ;		/* size L->nzmax, can change in size */
+    Lx = L->x ;		/* size L->nzmax or 2*L->nzmax, can change in size */
+    Lz = L->z ;		/* size L->nzmax for zomplex case, can change in size */
+    nzmax = L->nzmax ;
+    ASSERT (Lnz != NULL && Li != NULL && Lx != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Stack = Iwork ;		/* size n (i/i/l) */
+    Flag = Common->Flag ;	/* size n, Flag [i] < mark must hold */
+    Wx = Common->Xwork ;	/* size n if real, 2*n if complex or 
+				 * zomplex.  Xwork [i] == 0 must hold. */
+    Wz = Wx + n ;		/* size n for zomplex case only */
+    mark = Common->mark ;
+    ASSERT ((Int) Common->xworksize >= (L->xtype == CHOLMOD_REAL ? 1:2)*n) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute LDL' or LL' factorization by rows */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef MASK
+#define NEXT(k) k = RLinkUp [k]
+#else
+#define NEXT(k) k++
+#endif
+
+    for (k = kstart ; k < ((Int) kend) ; NEXT(k))
+    {
+	PRINT1 (("\n===============K "ID" Lnz [k] "ID"\n", k, Lnz [k])) ;
+
+	/* ------------------------------------------------------------------ */
+	/* compute pattern of kth row of L and scatter kth input column */
+	/* ------------------------------------------------------------------ */
+
+	/* column k of L is currently empty */
+	ASSERT (Lnz [k] == 1) ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
+
+	top = n ;		/* Stack is empty */
+	Flag [k] = mark ;	/* do not include diagonal entry in Stack */
+
+	/* use Li [Lp [i]+1] for etree */
+#define PARENT(i) (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY
+
+	if (stype > 0)
+	{
+	    /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	    p = Ap [k] ;
+	    pend = (packed) ? (Ap [k+1]) : (p + Anz [k]) ;
+	    /* W [i] = Ax [i] ; scatter column of A */
+#define SCATTER ASSIGN(Wx,Wz,i, Ax,Az,p)
+	    SUBTREE ;
+#undef SCATTER
+	}
+	else
+	{
+	    /* scatter kth col of triu (beta*I+AA'), get pattern L(k,:) */
+	    pf = Fp [k] ;
+	    pfend = (Fpacked) ? (Fp [k+1]) : (pf + Fnz [k]) ;
+	    for ( ; pf < pfend ; pf++)
+	    {
+		/* get nonzero entry F (t,k) */
+		t = Fi [pf] ;
+		/* fk = Fx [pf] */
+		ASSIGN (fx, fz, 0, Fx, Fz, pf) ;
+		p = Ap [t] ;
+		pend = (packed) ? (Ap [t+1]) : (p + Anz [t]) ;
+		multadds = 0 ;
+		/* W [i] += Ax [p] * fx ; scatter column of A*A' */
+#define SCATTER MULTADD (Wx,Wz,i, Ax,Az,p, fx,fz,0) ; multadds++  ;
+		SUBTREE ;
+#undef SCATTER
+#ifdef REAL
+		fl += 2 * ((double) multadds) ;
+#else
+		fl += 8 * ((double) multadds) ;
+#endif
+	    }
+	}
+
+#undef PARENT
+
+	/* ------------------------------------------------------------------ */
+	/* if mask is present, set the corresponding entries in W to zero */
+	/* ------------------------------------------------------------------ */
+
+#ifdef MASK
+        /* remove the dead element of Wx */
+        if (mask != NULL)
+        {
+
+#if 0
+	    /* older version */
+            for (p = n; p > top;)
+            {
+                i = Stack [--p] ;
+                if ( mask [i] >= 0 )
+		{
+		    CLEAR (Wx,Wz,i) ;	/* set W(i) to zero */
+		}
+            }
+#endif
+
+            for (s = top ; s < n ; s++)
+            {
+                i = Stack [s] ;
+                if (mask [i] >= 0)
+		{
+		    CLEAR (Wx,Wz,i) ;	/* set W(i) to zero */
+		}
+            }
+
+        }
+#endif
+
+	/* nonzero pattern of kth row of L is now in Stack [top..n-1].
+	 * Flag [Stack [top..n-1]] is equal to mark, but no longer needed */
+
+	/* mark = CHOLMOD(clear_flag) (Common) ; */
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	mark = Common->mark ;
+
+	/* ------------------------------------------------------------------ */
+	/* compute kth row of L and store in column form */
+	/* ------------------------------------------------------------------ */
+
+	/* Solve L (0:k-1, 0:k-1) * y (0:k-1) = b (0:k-1) where
+	 * b (0:k) = A (0:k,k) or A(0:k,:) * F(:,k) is in W and Stack.
+	 *
+	 * For LDL' factorization:
+	 * L (k, 0:k-1) = y (0:k-1) ./ D (0:k-1)
+	 * D (k) = b (k) - L (k, 0:k-1) * y (0:k-1)
+	 *
+	 * For LL' factorization:
+	 * L (k, 0:k-1) = y (0:k-1)
+	 * L (k,k) = sqrt (b (k) - L (k, 0:k-1) * L (0:k-1, k))
+	 */
+
+	/* dk = W [k] + beta */
+	ADD_REAL (dk,0, Wx,k, beta,0) ;
+
+#ifndef REAL
+	/* In the unsymmetric case, the imaginary part of W[k] must be real,
+	 * since F is assumed to be the complex conjugate transpose of A.  In
+	 * the symmetric case, W[k] is the diagonal of A.  If the imaginary part
+	 * of W[k] is nonzero, then the Cholesky factorization cannot be
+	 * computed; A is not positive definite */
+	dk_imaginary = (stype > 0) ? (IMAG_IS_NONZERO (Wx,Wz,k)) : FALSE ;
+#endif
+
+	/* W [k] = 0.0 ; */
+	CLEAR (Wx,Wz,k) ;
+
+	for (s = top ; s < n ; s++)
+	{
+	    /* get i for each nonzero entry L(k,i) */
+	    i = Stack [s] ;
+
+	    /* y = W [i] ; */
+	    ASSIGN (yx,yz,0, Wx,Wz,i) ;
+
+	    /* W [i] = 0.0 ; */
+	    CLEAR (Wx,Wz,i) ;
+
+	    lnz = Lnz [i] ;
+	    p = Lp [i] ;
+	    ASSERT (lnz > 0 && Li [p] == i) ;
+	    pend = p + lnz ;
+
+	    /* di = Lx [p] ; the diagonal entry L or D(i,i), which is real */
+	    ASSIGN_REAL (di,0, Lx,p) ;
+
+	    if (i >= (Int) L->minor || IS_ZERO (di [0]))
+	    {
+		/* For the LL' factorization, L(i,i) is zero.  For the LDL',
+		 * D(i,i) is zero.  Skip column i of L, and set L(k,i) = 0. */
+		CLEAR (lx,lz,0) ;
+		p = pend ;
+	    }
+	    else if (is_ll)
+	    {
+#ifdef REAL
+		fl += 2 * ((double) (pend - p - 1)) + 3 ;
+#else
+		fl += 8 * ((double) (pend - p - 1)) + 6 ;
+#endif
+		/* forward solve using L (i:(k-1),i) */
+		/* divide by L(i,i), which must be real and nonzero */
+		/* y /= di [0] */
+		DIV_REAL (yx,yz,0, yx,yz,0, di,0) ;
+		for (p++ ; p < pend ; p++)
+		{
+		    /* W [Li [p]] -= Lx [p] * y ; */
+		    MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ;
+		}
+		/* do not scale L; compute dot product for L(k,k) */
+		/* L(k,i) = conj(y) ; */
+		ASSIGN_CONJ (lx,lz,0, yx,yz,0) ;
+		/* d -= conj(y) * y ; */
+		LLDOT (dk,0, yx,yz,0) ;
+	    }
+	    else
+	    {
+#ifdef REAL
+		fl += 2 * ((double) (pend - p - 1)) + 3 ;
+#else
+		fl += 8 * ((double) (pend - p - 1)) + 6 ;
+#endif
+		/* forward solve using D (i,i) and L ((i+1):(k-1),i) */
+		for (p++ ; p < pend ; p++)
+		{
+		    /* W [Li [p]] -= Lx [p] * y ; */
+		    MULTSUB (Wx,Wz,Li[p], Lx,Lz,p, yx,yz,0) ;
+		}
+		/* Scale L (k,0:k-1) for LDL' factorization, compute D (k,k)*/
+#ifdef REAL
+		/* L(k,i) = y/d */
+		lx [0] = yx [0] / di [0] ;
+		/* d -= L(k,i) * y */
+		dk [0] -= lx [0] * yx [0] ;
+#else
+		/* L(k,i) = conj(y) ; */
+		ASSIGN_CONJ (lx,lz,0, yx,yz,0) ;
+		/* L(k,i) /= di ; */
+		DIV_REAL (lx,lz,0, lx,lz,0, di,0) ;
+		/* d -= conj(y) * y / di */
+		LDLDOT (dk,0, yx,yz,0, di,0) ;
+#endif
+	    }
+
+	    /* determine if column i of L can hold the new L(k,i) entry */
+	    if (p >= Lp [Lnext [i]])
+	    {
+		/* column i needs to grow */
+		PRINT1 (("Factor Colrealloc "ID", old Lnz "ID"\n", i, Lnz [i]));
+		if (!CHOLMOD(reallocate_column) (i, lnz + 1, L, Common))
+		{
+		    /* out of memory, L is now simplicial symbolic */
+		    for (i = 0 ; i < n ; i++)
+		    {
+			/* W [i] = 0 ; */
+			CLEAR (Wx,Wz,i) ;
+		    }
+		    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ;
+		    return (FALSE) ;
+		}
+		Li = L->i ;		/* L->i, L->x, L->z may have moved */
+		Lx = L->x ;
+		Lz = L->z ;
+		p = Lp [i] + lnz ;	/* contents of L->p changed */
+		ASSERT (p < Lp [Lnext [i]]) ;
+	    }
+
+	    /* store L (k,i) in the column form matrix of L */
+	    Li [p] = k ;
+	    /* Lx [p] = L(k,i) ; */
+	    ASSIGN (Lx,Lz,p, lx,lz,0) ;
+	    Lnz [i]++ ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* ensure abs (d) >= dbound if dbound is given, and store it in L */
+	/* ------------------------------------------------------------------ */
+
+	p = Lp [k] ;
+	Li [p] = k ;
+
+	if (k >= (Int) L->minor)
+	{
+	    /* the matrix is already not positive definite */
+	    dk [0] = 0 ;
+	}
+	else if (use_dbound)
+	{
+	    /* modify the diagonal to force LL' or LDL' to exist */
+	    dk [0] = CHOLMOD(dbound) (is_ll ? fabs (dk [0]) : dk [0], Common) ;
+	}
+	else if ((is_ll ? (IS_LE_ZERO (dk [0])) : (IS_ZERO (dk [0])))
+#ifndef REAL
+		|| dk_imaginary
+#endif
+		)
+	{
+	    /* the matrix has just been found to be not positive definite */
+	    dk [0] = 0 ;
+	    L->minor = k ;
+	    ERROR (CHOLMOD_NOT_POSDEF, "not positive definite") ;
+	}
+
+	if (is_ll)
+	{
+	    /* this is counted as one flop, below */
+	    dk [0] = sqrt (dk [0]) ;
+	}
+
+	/* Lx [p] = D(k,k) = d ; real part only */
+	ASSIGN_REAL (Lx,p, dk,0) ;
+	CLEAR_IMAG (Lx,Lz,p) ;
+    }
+
+#undef NEXT
+
+    if (is_ll) fl += MAX ((Int) kend - (Int) kstart, 0) ;   /* count sqrt's */
+    Common->rowfacfl = fl ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "final cholmod_rowfac", Common)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, n, Common)) ;
+    return (TRUE) ;
+}
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Cholesky/t_cholmod_solve.c b/src/CHOLMOD/Cholesky/t_cholmod_solve.c
new file mode 100644
index 0000000..87aa0a9
--- /dev/null
+++ b/src/CHOLMOD/Cholesky/t_cholmod_solve.c
@@ -0,0 +1,177 @@
+/* ========================================================================== */
+/* === Cholesky/t_cholmod_solve ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Cholesky Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Cholesky Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_solve.  Supports any numeric xtype (real,
+ * complex, or zomplex).  The xtypes of all matrices (L and Y) must match.
+ */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === simplicial template solvers ========================================== */
+/* ========================================================================== */
+
+/* LL': solve Lx=b with non-unit diagonal */
+#define LL
+#include "t_cholmod_lsolve.c"
+
+/* LDL': solve LDx=b */
+#define LD
+#include "t_cholmod_lsolve.c"
+
+/* LDL': solve Lx=b with unit diagonal */
+#include "t_cholmod_lsolve.c"
+
+/* LL': solve L'x=b with non-unit diagonal */
+#define LL
+#include "t_cholmod_ltsolve.c"
+
+/* LDL': solve DL'x=b */
+#define LD
+#include "t_cholmod_ltsolve.c"
+
+/* LDL': solve L'x=b with unit diagonal */
+#include "t_cholmod_ltsolve.c"
+
+
+/* ========================================================================== */
+/* === t_ldl_dsolve ========================================================= */
+/* ========================================================================== */
+
+/* Solve Dx=b for an LDL' factorization, where Y holds b' on input and x' on
+ * output.
+ *
+ * The number of right-hand-sides (nrhs) is not restricted, even if Yseti
+ * is present.
+ */
+
+static void TEMPLATE (ldl_dsolve)
+(
+    cholmod_factor *L,
+    cholmod_dense *Y,		/* nr-by-n with leading dimension nr */
+    Int *Yseti, Int ysetlen
+)
+{
+    double d [1] ;
+    double *Lx, *Yx, *Yz ;
+    Int *Lp ;
+    Int n, nrhs, k, p, k1, k2, kk, kkiters ;
+
+    ASSERT (L->xtype == Y->xtype) ; /* L and Y must have the same xtype */
+    ASSERT (L->n == Y->ncol) ;	    /* dimensions must match */
+    ASSERT (Y->nrow == Y->d) ;	    /* leading dimension of Y = # rows of Y */
+    ASSERT (L->xtype != CHOLMOD_PATTERN) ;  /* L is not symbolic */
+    ASSERT (!(L->is_super) && !(L->is_ll)) ;	/* L is simplicial LDL' */
+
+    nrhs = Y->nrow ;
+    n = L->n ;
+    Lp = L->p ;
+    Lx = L->x ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    kkiters = Yseti ? ysetlen : n ;
+    for (kk = 0 ; kk < kkiters ; kk++)
+    {
+        k = Yseti ? Yseti [kk] : kk ;
+	k1 = k*nrhs ;
+	k2 = (k+1)*nrhs ;
+	ASSIGN_REAL (d,0, Lx,Lp[k]) ;
+	for (p = k1 ; p < k2 ; p++)
+	{
+	    DIV_REAL (Yx,Yz,p, Yx,Yz,p, d,0) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === t_simplicial_solver ================================================== */
+/* ========================================================================== */
+
+/* Solve a linear system, where Y' contains the (array-transposed) right-hand
+ * side on input, and the solution on output.  No permutations are applied;
+ * these must have already been applied to Y on input.
+ *
+ * Yseti [0..ysetlen-1] is an optional list of indices from
+ * cholmod_lsolve_pattern.  The solve is performed only on the columns of L
+ * corresponding to entries in Yseti.  Ignored if NULL.  If present, most
+ * functions require that Y' consist of a single dense column.
+ */
+
+static void TEMPLATE (simplicial_solver)
+(
+    int sys,		    /* system to solve */
+    cholmod_factor *L,	    /* factor to use, a simplicial LL' or LDL' */
+    cholmod_dense *Y,	    /* right-hand-side on input, solution on output */
+    Int *Yseti, Int ysetlen
+)
+{
+    if (L->is_ll)
+    {
+	/* The factorization is LL' */
+	if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt)
+	{
+	    /* Solve Ax=b or LL'x=b */
+	    TEMPLATE (ll_lsolve_k) (L, Y, Yseti, ysetlen) ;
+	    TEMPLATE (ll_ltsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_L || sys == CHOLMOD_LD)
+	{
+	    /* Solve Lx=b */
+	    TEMPLATE (ll_lsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_Lt || sys == CHOLMOD_DLt)
+	{
+	    /* Solve L'x=b */
+	    TEMPLATE (ll_ltsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+    }
+    else
+    {
+	/* The factorization is LDL' */
+	if (sys == CHOLMOD_A || sys == CHOLMOD_LDLt)
+	{
+	    /* Solve Ax=b or LDL'x=b */
+	    TEMPLATE (ldl_lsolve_k) (L, Y, Yseti, ysetlen) ;
+	    TEMPLATE (ldl_dltsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_LD)
+	{
+	    /* Solve LDx=b */
+	    TEMPLATE (ldl_ldsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_L)
+	{
+	    /* Solve Lx=b */
+	    TEMPLATE (ldl_lsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_Lt)
+	{
+	    /* Solve L'x=b */
+	    TEMPLATE (ldl_ltsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_DLt)
+	{
+	    /* Solve DL'x=b */
+	    TEMPLATE (ldl_dltsolve_k) (L, Y, Yseti, ysetlen) ;
+	}
+	else if (sys == CHOLMOD_D)
+	{
+	    /* Solve Dx=b */
+	    TEMPLATE (ldl_dsolve) (L, Y, Yseti, ysetlen) ;
+	}
+    }
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Core/License.txt b/src/CHOLMOD/Core/License.txt
new file mode 100644
index 0000000..1c3ab99
--- /dev/null
+++ b/src/CHOLMOD/Core/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/Core Module.  Copyright (C) 2005-2006, Univ. of Florida.
+Author: Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/Core module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/CHOLMOD/Core/cholmod_aat.c b/src/CHOLMOD/Core/cholmod_aat.c
new file mode 100644
index 0000000..c62580a
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_aat.c
@@ -0,0 +1,301 @@
+/* ========================================================================== */
+/* === Core/cholmod_aat ===================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* C = A*A' or C = A(:,f)*A(:,f)'
+ *
+ * A can be packed or unpacked, sorted or unsorted, but must be stored with
+ * both upper and lower parts (A->stype of zero).  C is returned as packed,
+ * C->stype of zero (both upper and lower parts present), and unsorted.  See
+ * cholmod_ssmult in the MatrixOps Module for a more general matrix-matrix
+ * multiply.
+ *
+ * You can trivially convert C into a symmetric upper/lower matrix by
+ * changing C->stype = 1 or -1 after calling this routine.
+ *
+ * workspace:
+ *	Flag (A->nrow),
+ *	Iwork (max (A->nrow, A->ncol)) if fset present,
+ *	Iwork (A->nrow) if no fset,
+ *	W (A->nrow) if mode > 0,
+ *	allocates temporary copy for A'.
+ *
+ * A can be pattern or real.  Complex or zomplex cases are supported only
+ * if the mode is <= 0 (in which case the numerical values are ignored).
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+cholmod_sparse *CHOLMOD(aat)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* input matrix; C=A*A' is constructed */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag)
+			 * -2: pattern only, no diagonal, add 50% + n extra
+			 * space to C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double fjt ;
+    double *Ax, *Fx, *Cx, *W ;
+    Int *Ap, *Anz, *Ai, *Fp, *Fi, *Cp, *Ci, *Flag ;
+    cholmod_sparse *C, *F ;
+    Int packed, j, i, pa, paend, pf, pfend, n, mark, cnz, t, p, values, diag,
+	extra ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix cannot be symmetric") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    diag = (mode >= 0) ;
+    n = A->nrow ;
+    CHOLMOD(allocate_work) (n, MAX (A->ncol, A->nrow), values ? n : 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n : 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+
+    /* get the A matrix */
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    packed = A->packed ;
+
+    /* get workspace */
+    W = Common->Xwork ;		/* size n, unused if values is FALSE */
+    Flag = Common->Flag ;	/* size n, Flag [0..n-1] < mark on input*/
+
+    /* ---------------------------------------------------------------------- */
+    /* F = A' or A(:,f)' */
+    /* ---------------------------------------------------------------------- */
+
+    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset)*/
+    F = CHOLMOD(ptranspose) (A, values, NULL, fset, fsize, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Fp = F->p ;
+    Fi = F->i ;
+    Fx = F->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the number of entries in the result C */
+    /* ---------------------------------------------------------------------- */
+
+    cnz = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	/* clear the Flag array */
+	/* mark = CHOLMOD(clear_flag) (Common) ; */
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	mark = Common->mark ;
+
+	/* exclude the diagonal, if requested */
+	if (!diag)
+	{
+	    Flag [j] = mark ;
+	}
+
+	/* for each nonzero F(t,j) in column j, do: */
+	pfend = Fp [j+1] ;
+	for (pf = Fp [j] ; pf < pfend ; pf++)
+	{
+	    /* F(t,j) is nonzero */
+	    t = Fi [pf] ;
+
+	    /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */
+	    pa = Ap [t] ;
+	    paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ;
+	    for ( ; pa < paend ; pa++)
+	    {
+		i = Ai [pa] ;
+		if (Flag [i] != mark)
+		{
+		    Flag [i] = mark ;
+		    cnz++ ;
+		}
+	    }
+	}
+	if (cnz < 0)
+	{
+	    break ;	    /* integer overflow case */
+	}
+    }
+
+    extra = (mode == -2) ? (cnz/2 + n) : 0 ;
+
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for integer overflow */
+    /* ---------------------------------------------------------------------- */
+
+    if (cnz < 0 || (cnz + extra) < 0)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	CHOLMOD(clear_flag) (Common) ;
+	CHOLMOD(free_sparse) (&F, Common) ;
+	return (NULL) ;	    /* problem too large */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (n, n, cnz + extra, FALSE, TRUE, 0,
+	    values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&F, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = A*A' */
+    /* ---------------------------------------------------------------------- */
+
+    cnz = 0 ;
+
+    if (values)
+    {
+
+	/* pattern and values */
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* clear the Flag array */
+	    mark = CHOLMOD(clear_flag) (Common) ;
+
+	    /* start column j of C */
+	    Cp [j] = cnz ;
+
+	    /* for each nonzero F(t,j) in column j, do: */
+	    pfend = Fp [j+1] ;
+	    for (pf = Fp [j] ; pf < pfend ; pf++)
+	    {
+		/* F(t,j) is nonzero */
+		t = Fi [pf] ;
+		fjt = Fx [pf] ;
+
+		/* add the nonzero pattern of A(:,t) to the pattern of C(:,j)
+		 * and scatter the values into W */
+		pa = Ap [t] ;
+		paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ;
+		for ( ; pa < paend ; pa++)
+		{
+		    i = Ai [pa] ;
+		    if (Flag [i] != mark)
+		    {
+			Flag [i] = mark ;
+			Ci [cnz++] = i ;
+		    }
+		    W [i] += Ax [pa] * fjt ;
+		}
+	    }
+
+	    /* gather the values into C(:,j) */
+	    for (p = Cp [j] ; p < cnz ; p++)
+	    {
+		i = Ci [p] ;
+		Cx [p] = W [i] ;
+		W [i] = 0 ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* pattern only */
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* clear the Flag array */
+	    mark = CHOLMOD(clear_flag) (Common) ;
+
+	    /* exclude the diagonal, if requested */
+	    if (!diag)
+	    {
+		Flag [j] = mark ;
+	    }
+
+	    /* start column j of C */
+	    Cp [j] = cnz ;
+
+	    /* for each nonzero F(t,j) in column j, do: */
+	    pfend = Fp [j+1] ;
+	    for (pf = Fp [j] ; pf < pfend ; pf++)
+	    {
+		/* F(t,j) is nonzero */
+		t = Fi [pf] ;
+
+		/* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */
+		pa = Ap [t] ;
+		paend = (packed) ? (Ap [t+1]) : (pa + Anz [t]) ;
+		for ( ; pa < paend ; pa++)
+		{
+		    i = Ai [pa] ;
+		    if (Flag [i] != mark)
+		    {
+			Flag [i] = mark ;
+			Ci [cnz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    Cp [n] = cnz ;
+    ASSERT (IMPLIES (mode != -2, MAX (1,cnz) == C->nzmax)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace and free temporary matrices and return result */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&F, Common) ;
+    CHOLMOD(clear_flag) (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n : 0, Common)) ;
+    DEBUG (i = CHOLMOD(dump_sparse) (C, "aat", Common)) ;
+    ASSERT (IMPLIES (mode < 0, i == 0)) ;
+    return (C) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_add.c b/src/CHOLMOD/Core/cholmod_add.c
new file mode 100644
index 0000000..f7fc675
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_add.c
@@ -0,0 +1,281 @@
+/* ========================================================================== */
+/* === Core/cholmod_add ===================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* C = alpha*A + beta*B, or spones(A+B).  Result is packed, with sorted or
+ * unsorted columns.  This routine is much faster and takes less memory if C
+ * is allowed to have unsorted columns.
+ *
+ * If A and B are both symmetric (in upper form) then C is the same.  Likewise,
+ * if A and B are both symmetric (in lower form) then C is the same.
+ * Otherwise, C is unsymmetric.  A and B must have the same dimension.
+ *
+ * workspace: Flag (nrow), W (nrow) if values, Iwork (max (nrow,ncol)).
+ *	allocates temporary copies for A and B if they are symmetric.
+ *	allocates temporary copy of C if it is to be returned sorted.
+ *
+ * A and B can have an xtype of pattern or real.  Complex or zomplex cases
+ * are supported only if the "values" input parameter is FALSE.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+cholmod_sparse *CHOLMOD(add)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	    /* matrix to add */
+    cholmod_sparse *B,	    /* matrix to add */
+    double alpha [2],	    /* scale factor for A */
+    double beta [2],	    /* scale factor for B */
+    int values,		    /* if TRUE compute the numerical values of C */
+    int sorted,		    /* if TRUE, sort columns of C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Bx, *Cx, *W ;
+    Int apacked, up, lo, nrow, ncol, bpacked, nzmax, pa, paend, pb, pbend, i,
+	j, p, mark, nz ;
+    Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Flag, *Cp, *Ci ;
+    cholmod_sparse *A2, *B2, *C ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    values = values &&
+	(A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->nrow != B->nrow || A->ncol != B->ncol)
+    {
+	/* A and B must have the same dimensions */
+	ERROR (CHOLMOD_INVALID, "A and B dimesions do not match") ;
+	return (NULL) ;
+    }
+    /* A and B must have the same numerical type if values is TRUE (both must
+     * be CHOLMOD_REAL, this is implicitly checked above) */
+
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    CHOLMOD(allocate_work) (nrow, MAX (nrow,ncol), values ? nrow : 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow <= 1)
+    {
+	/* C will be implicitly sorted, so no need to sort it here */
+	sorted = FALSE ;
+    }
+
+    /* convert A or B to unsymmetric, if necessary */
+    A2 = NULL ;
+    B2 = NULL ;
+
+    if (A->stype != B->stype)
+    {
+	if (A->stype)
+	{
+	    /* workspace: Iwork (max (nrow,ncol)) */
+	    A2 = CHOLMOD(copy) (A, 0, values, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		return (NULL) ;	    /* out of memory */
+	    }
+	    A = A2 ;
+	}
+	if (B->stype)
+	{
+	    /* workspace: Iwork (max (nrow,ncol)) */
+	    B2 = CHOLMOD(copy) (B, 0, values, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		CHOLMOD(free_sparse) (&A2, Common) ;
+		return (NULL) ;	    /* out of memory */
+	    }
+	    B = B2 ;
+	}
+    }
+
+    /* get the A matrix */
+    ASSERT (A->stype == B->stype) ;
+    up = (A->stype > 0) ;
+    lo = (A->stype < 0) ;
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    apacked = A->packed ;
+
+    /* get the B matrix */
+    Bp  = B->p ;
+    Bnz = B->nz ;
+    Bi  = B->i ;
+    Bx  = B->x ;
+    bpacked = B->packed ;
+
+    /* get workspace */
+    W = Common->Xwork ;	    /* size nrow, used if values is TRUE */
+    Flag = Common->Flag ;   /* size nrow, Flag [0..nrow-1] < mark on input */
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the result C */
+    /* ---------------------------------------------------------------------- */
+
+    /* If integer overflow occurs, nzmax < 0 and the allocate fails properly
+     * (likewise in most other matrix manipulation routines). */
+
+    nzmax = CHOLMOD(nnz) (A, Common) + CHOLMOD(nnz) (B, Common) ;
+
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, FALSE, TRUE,
+	    SIGN (A->stype), values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&A2, Common) ;
+	CHOLMOD(free_sparse) (&B2, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compute C = alpha*A + beta*B */
+    /* ---------------------------------------------------------------------- */
+
+    nz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Cp [j] = nz ;
+
+	/* clear the Flag array */
+	/* mark = CHOLMOD(clear_flag) (Common) ; */
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	mark = Common->mark ;
+
+	/* scatter B into W */
+	pb = Bp [j] ;
+	pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ;
+	for (p = pb ; p < pbend ; p++)
+	{
+	    i = Bi [p] ;
+	    if ((up && i > j) || (lo && i < j))
+	    {
+		continue ;
+	    }
+	    Flag [i] = mark ;
+	    if (values)
+	    {
+		W [i] = beta [0] * Bx [p] ;
+	    }
+	}
+
+	/* add A and gather from W into C(:,j) */
+	pa = Ap [j] ;
+	paend = (apacked) ? (Ap [j+1]) : (pa + Anz [j]) ;
+	for (p = pa ; p < paend ; p++)
+	{
+	    i = Ai [p] ;
+	    if ((up && i > j) || (lo && i < j))
+	    {
+		continue ;
+	    }
+	    Flag [i] = EMPTY ;
+	    Ci [nz] = i ;
+	    if (values)
+	    {
+		Cx [nz] = W [i] + alpha [0] * Ax [p] ;
+		W [i] = 0 ;
+	    }
+	    nz++ ;
+	}
+
+	/* gather remaining entries into C(:,j), using pattern of B */
+	for (p = pb ; p < pbend ; p++)
+	{
+	    i = Bi [p] ;
+	    if ((up && i > j) || (lo && i < j))
+	    {
+		continue ;
+	    }
+	    if (Flag [i] == mark)
+	    {
+		Ci [nz] = i ;
+		if (values)
+		{
+		    Cx [nz] = W [i] ;
+		    W [i] = 0 ;
+		}
+		nz++ ;
+	    }
+	}
+    }
+
+    Cp [ncol] = nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce C in size and free temporary matrices */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (MAX (1,nz) <= C->nzmax) ;
+    CHOLMOD(reallocate_sparse) (nz, C, Common) ;
+    ASSERT (Common->status >= CHOLMOD_OK) ;
+
+    /* clear the Flag array */
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    CHOLMOD(free_sparse) (&B2, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* sort C, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    if (sorted)
+    {
+	/* workspace: Iwork (max (nrow,ncol)) */
+	if (!CHOLMOD(sort) (C, Common))
+	{
+	    CHOLMOD(free_sparse) (&C, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		return (NULL) ;		/* out of memory */
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C, "add", Common) >= 0) ;
+    return (C) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_band.c b/src/CHOLMOD/Core/cholmod_band.c
new file mode 100644
index 0000000..fd03698
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_band.c
@@ -0,0 +1,373 @@
+/* ========================================================================== */
+/* === Core/cholmod_band ==================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* C = tril (triu (A,k1), k2)
+ *
+ * C is a matrix consisting of the diagonals of A from k1 to k2.
+ *
+ * k=0 is the main diagonal of A, k=1 is the superdiagonal, k=-1 is the
+ * subdiagonal, and so on.  If A is m-by-n, then:
+ *
+ *	k1=-m		    C = tril (A,k2)
+ *	k2=n		    C = triu (A,k1)
+ *	k1=0 and k2=0	    C = diag(A), except C is a matrix, not a vector
+ *
+ * Values of k1 and k2 less than -m are treated as -m, and values greater
+ * than n are treated as n.
+ *
+ * A can be of any symmetry (upper, lower, or unsymmetric); C is returned in
+ * the same form, and packed.  If A->stype > 0, entries in the lower
+ * triangular part of A are ignored, and the opposite is true if
+ * A->stype < 0.  If A has sorted columns, then so does C.
+ * C has the same size as A.
+ *
+ * If inplace is TRUE, then the matrix A is modified in place.
+ * Only packed matrices can be converted in place.
+ *
+ * C can be returned as a numerical valued matrix (if A has numerical values
+ * and mode > 0), as a pattern-only (mode == 0), or as a pattern-only but with
+ * the diagonal entries removed (mode < 0).
+ *
+ * workspace: none
+ *
+ * A can have an xtype of pattern or real.  Complex and zomplex cases supported
+ * only if mode <= 0 (in which case the numerical values are ignored).
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+static cholmod_sparse *band		/* returns C, or NULL if failure */
+(
+    /* ---- input or in/out if inplace is TRUE --- */
+    cholmod_sparse *A,
+    /* ---- input ---- */
+    SuiteSparse_long k1,    /* ignore entries below the k1-st diagonal */
+    SuiteSparse_long k2,    /* ignore entries above the k2-nd diagonal */
+    int mode,	    /* >0: numerical, 0: pattern, <0: pattern (no diagonal) */
+    int inplace,    /* if TRUE, then convert A in place */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Cx ;
+    Int packed, nz, j, p, pend, i, ncol, nrow, jlo, jhi, ilo, ihi, sorted,
+	values, diag ;
+    Int *Ap, *Anz, *Ai, *Cp, *Ci ;
+    cholmod_sparse *C ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    packed = A->packed ;
+    diag = (mode >= 0) ;
+    if (inplace && !packed)
+    {
+	/* cannot operate on an unpacked matrix in place */
+	ERROR (CHOLMOD_INVALID, "cannot operate on unpacked matrix in-place") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+
+    PRINT1 (("k1 %ld k2 %ld\n", k1, k2)) ;
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    sorted = A->sorted ;
+
+
+    if (A->stype > 0)
+    {
+	/* ignore any entries in strictly lower triangular part of A */
+	k1 = MAX (k1, 0) ;
+    }
+    if (A->stype < 0)
+    {
+	/* ignore any entries in strictly upper triangular part of A */
+	k2 = MIN (k2, 0) ;
+    }
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+
+    /* ensure k1 and k2 are in the range -nrow to +ncol to
+     * avoid possible integer overflow if k1 and k2 are huge */
+    k1 = MAX (-nrow, k1) ;
+    k1 = MIN (k1, ncol) ;
+    k2 = MAX (-nrow, k2) ;
+    k2 = MIN (k2, ncol) ;
+
+    /* consider columns jlo to jhi.  columns outside this range are empty */
+    jlo = MAX (k1, 0) ;
+    jhi = MIN (k2+nrow, ncol) ;
+
+    if (k1 > k2)
+    {
+	/* nothing to do */
+	jlo = ncol ;
+	jhi = ncol ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C, or operate on A in place */
+    /* ---------------------------------------------------------------------- */
+
+    if (inplace)
+    {
+	/* convert A in place */
+	C = A ;
+    }
+    else
+    {
+	/* count the number of entries in the result C */
+	nz = 0 ;
+	if (sorted)
+	{
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i > ihi)
+		    {
+			break ;
+		    }
+		    if (i >= ilo && (diag || i != j))
+		    {
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= ilo && i <= ihi && (diag || i != j))
+		    {
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	/* allocate C; A will not be modified.  C is sorted if A is sorted */
+	C = CHOLMOD(allocate_sparse) (A->nrow, ncol, nz, sorted, TRUE,
+		A->stype, values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return (NULL) ;	/* out of memory */
+	}
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct C */
+    /* ---------------------------------------------------------------------- */
+
+    /* columns 0 to jlo-1 are empty */
+    for (j = 0 ; j < jlo ; j++)
+    {
+	Cp [j] = 0 ;
+    }
+
+    nz = 0 ;
+    if (sorted)
+    {
+	if (values)
+	{
+	    /* pattern and values */
+	    ASSERT (diag) ;
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i > ihi)
+		    {
+			break ;
+		    }
+		    if (i >= ilo)
+		    {
+			Ci [nz] = i ;
+			Cx [nz] = Ax [p] ;
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* pattern only, perhaps with no diagonal */
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i > ihi)
+		    {
+			break ;
+		    }
+		    if (i >= ilo && (diag || i != j))
+		    {
+			Ci [nz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (values)
+	{
+	    /* pattern and values */
+	    ASSERT (diag) ;
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= ilo && i <= ihi)
+		    {
+			Ci [nz] = i ;
+			Cx [nz] = Ax [p] ;
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* pattern only, perhaps with no diagonal */
+	    for (j = jlo ; j < jhi ; j++)
+	    {
+		ilo = j-k2 ;
+		ihi = j-k1 ;
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Cp [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= ilo && i <= ihi && (diag || i != j))
+		    {
+			Ci [nz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    /* columns jhi to ncol-1 are empty */
+    for (j = jhi ; j <= ncol ; j++)
+    {
+	Cp [j] = nz ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce A in size if done in place */
+    /* ---------------------------------------------------------------------- */
+
+    if (inplace)
+    {
+	/* free the unused parts of A, and reduce A->i and A->x in size */
+	ASSERT (MAX (1,nz) <= A->nzmax) ;
+	CHOLMOD(reallocate_sparse) (nz, A, Common) ;
+	ASSERT (Common->status >= CHOLMOD_OK) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result C */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (i = CHOLMOD(dump_sparse) (C, "band", Common)) ;
+    ASSERT (IMPLIES (mode < 0, i == 0)) ;
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_band ========================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(band)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to extract band matrix from */
+    SuiteSparse_long k1,    /* ignore entries below the k1-st diagonal */
+    SuiteSparse_long k2,    /* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (band (A, k1, k2, mode, FALSE, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_band_inplace ================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(band_inplace)
+(
+    /* ---- input ---- */
+    SuiteSparse_long k1,    /* ignore entries below the k1-st diagonal */
+    SuiteSparse_long k2,    /* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix from which entries not in band are removed */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (band (A, k1, k2, mode, TRUE, Common) != NULL) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_change_factor.c b/src/CHOLMOD/Core/cholmod_change_factor.c
new file mode 100644
index 0000000..05032b7
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_change_factor.c
@@ -0,0 +1,1226 @@
+/* ========================================================================== */
+/* === Core/cholmod_change_factor =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Change the numeric/symbolic, LL/LDL, simplicial/super, packed/unpacked,
+ * monotonic/non-monotonic status of a cholmod_factor object.
+ *
+ * There are four basic classes of factor types:
+ *
+ * (1) simplicial symbolic:  Consists of two size-n arrays: the fill-reducing
+ *	permutation (L->Perm) and the nonzero count for each column of L
+ *	(L->ColCount).  All other factor types also include this information.
+ *	L->ColCount may be exact (obtained from the analysis routines), or
+ *	it may be a guess.  During factorization, and certainly after update/
+ *	downdate, the columns of L can have a different number of nonzeros.
+ *	L->ColCount is used to allocate space.  L->ColCount is exact for the
+ *	supernodal factorizations.  The nonzero pattern of L is not kept.
+ *
+ * (2) simplicial numeric:  These represent L in a compressed column form.  The
+ *	variants of this type are:
+ *
+ *	LDL':	L is unit diagonal.  Row indices in column j are located in
+ *	    L->i [L->p [j] ... L->p [j] + L->nz [j]], and corresponding numeric
+ *	    values are in the same locations in L->x.  The total number of
+ *	    entries is the sum of L->nz [j].  The unit diagonal is not stored;
+ *	    D is stored on the diagonal of L instead.  L->p may or may not be
+ *	    monotonic.  The order of storage of the columns in L->i and L->x is
+ *	    given by a doubly-linked list (L->prev and L->next).  L->p is of
+ *	    size n+1, but only the first n entries are used (it is used if L
+ *	    is converted to a sparse matrix via cholmod_factor_to_sparse).
+ *
+ *	    For the complex case, L->x is stored interleaved with real/imag
+ *	    parts, and is of size 2*lnz*sizeof(double).  For the zomplex case,
+ *	    L->x is of size lnz*sizeof(double) and holds the real part; L->z
+ *	    is the same size and holds the imaginary part.
+ *
+ *	LL':  This is identical to the LDL' form, except that the non-unit
+ *	    diagonal of L is stored as the first entry in each column of L.
+ *
+ * (3) supernodal symbolic:  A representation of the nonzero pattern of the
+ *	supernodes for a supernodal factorization.  There are L->nsuper
+ *	supernodes.  Columns L->super [k] to L->super [k+1]-1 are in the kth
+ *	supernode.  The row indices for the kth supernode are in
+ *	L->s [L->pi [k] ... L->pi [k+1]-1].  The numerical values are not
+ *	allocated (L->x), but when they are they will be located in
+ *	L->x [L->px [k] ... L->px [k+1]-1], and the L->px array is defined
+ *	in this factor type.
+ *
+ *	For the complex case, L->x is stored interleaved with real/imag parts,
+ *	and is of size 2*L->xsize*sizeof(double).  The zomplex supernodal case
+ *	is not supported, since it is not compatible with LAPACK and the BLAS.
+ *
+ * (4) supernodal numeric:  Always an LL' factorization.  L is non-unit
+ *      diagonal.  L->x contains the numerical values of the supernodes, as
+ *      described above for the supernodal symbolic factor.
+ *	For the complex case, L->x is stored interleaved, and is of size
+ *	2*L->xsize*sizeof(double).  The zomplex supernodal case is not
+ *	supported, since it is not compatible with LAPACK and the BLAS.
+ *
+ *      FUTURE WORK: support a supernodal LDL' factor.
+ *
+ *
+ * In all cases, the row indices in each column (L->i for simplicial L and
+ * L->s for supernodal L) are kept sorted from low indices to high indices.
+ * This means the diagonal of L (or D for LDL' factors) is always kept as the
+ * first entry in each column.
+ *
+ * The cholmod_change_factor routine can do almost all possible conversions.
+ * It cannot do the following conversions:
+ *
+ *	(1) Simplicial numeric types cannot be converted to a supernodal
+ *	    symbolic type.  This would simultaneously deallocate the
+ *	    simplicial pattern and numeric values and reallocate uninitialized
+ *	    space for the supernodal pattern.  This isn't useful for the user,
+ *	    and not needed by CHOLMOD's own routines either.
+ *
+ *	(2) Only a symbolic factor (simplicial to supernodal) can be converted
+ *	    to a supernodal numeric factor.
+ *
+ * Some conversions are meant only to be used internally by other CHOLMOD
+ * routines, and should not be performed by the end user.  They allocate space
+ * whose contents are undefined:
+ *
+ *	(1) converting from simplicial symbolic to supernodal symbolic.
+ *	(2) converting any factor to supernodal numeric.
+ *
+ * workspace: no conversion routine uses workspace in Common.  No temporary
+ *	workspace is allocated.
+ *
+ * Supports all xtypes, except that there is no supernodal zomplex L.
+ *
+ * The to_xtype parameter is used only when converting from symbolic to numeric
+ * or numeric to symbolic.  It cannot be used to convert a numeric xtype (real,
+ * complex, or zomplex) to a different numeric xtype.  For that conversion,
+ * use cholmod_factor_xtype instead.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+static void natural_list (cholmod_factor *L) ;
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_change_factor.c"
+#define COMPLEX
+#include "t_cholmod_change_factor.c"
+#define ZOMPLEX
+#include "t_cholmod_change_factor.c"
+
+
+/* ========================================================================== */
+/* === L_is_packed ========================================================== */
+/* ========================================================================== */
+
+/* Return TRUE if the columns of L are packed, FALSE otherwise.  For debugging
+ * only. */
+
+#ifndef NDEBUG
+static int L_is_packed (cholmod_factor *L, cholmod_common *Common)
+{
+    Int j ;
+    Int *Lnz = L->nz ;
+    Int *Lp = L->p ;
+    Int n = L->n ;
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super)
+    {
+	return (TRUE) ;
+    }
+
+    if (Lnz == NULL || Lp == NULL)
+    {
+	return (TRUE) ;
+    }
+
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT3 (("j: "ID" Lnz "ID" Lp[j+1] "ID" Lp[j] "ID"\n", j, Lnz [j],
+		Lp [j+1], Lp [j])) ;
+	if (Lnz [j] != (Lp [j+1] - Lp [j]))
+	{
+	    PRINT2 (("L is not packed\n")) ;
+	    return (FALSE) ;
+	}
+    }
+    return (TRUE) ;
+}
+#endif
+
+
+/* ========================================================================== */
+/* === natural_list ========================================================= */
+/* ========================================================================== */
+
+/* Create a naturally-ordered doubly-linked list of columns. */
+
+static void natural_list (cholmod_factor *L)
+{
+    Int head, tail, n, j ;
+    Int *Lnext, *Lprev ;
+    Lnext = L->next ;
+    Lprev = L->prev ;
+    ASSERT (Lprev != NULL && Lnext != NULL) ;
+    n = L->n ;
+    head = n+1 ;
+    tail = n ;
+    Lnext [head] = 0 ;
+    Lprev [head] = EMPTY ;
+    Lnext [tail] = EMPTY ;
+    Lprev [tail] = n-1 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Lnext [j] = j+1 ;
+	Lprev [j] = j-1 ;
+    }
+    Lprev [0] = head ;
+    L->is_monotonic = TRUE ;
+}
+
+
+/* ========================================================================== */
+/* === allocate_simplicial_numeric ========================================== */
+/* ========================================================================== */
+
+/* Allocate O(n) arrays for simplicial numeric factorization.  Initializes
+ * the link lists only.  Does not allocate the L->i, L->x, or L->z arrays. */
+
+static int allocate_simplicial_numeric
+(
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    Int n ;
+    Int *Lp, *Lnz, *Lprev, *Lnext ;
+    size_t n1, n2 ;
+
+    PRINT1 (("Allocate simplicial\n")) ;
+
+    ASSERT (L->xtype == CHOLMOD_PATTERN || L->is_super) ;
+    ASSERT (L->p == NULL) ;
+    ASSERT (L->nz == NULL) ;
+    ASSERT (L->prev == NULL) ;
+    ASSERT (L->next == NULL) ;
+
+    n = L->n ;
+
+    /* this cannot cause size_t overflow */
+    n1 = ((size_t) n) + 1 ;
+    n2 = ((size_t) n) + 2 ;
+
+    Lp = CHOLMOD(malloc) (n1, sizeof (Int), Common) ;
+    Lnz = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    Lprev = CHOLMOD(malloc) (n2, sizeof (Int), Common) ;
+    Lnext = CHOLMOD(malloc) (n2, sizeof (Int), Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free) (n1, sizeof (Int), Lp,    Common) ;
+	CHOLMOD(free) (n,   sizeof (Int), Lnz,   Common) ;
+	CHOLMOD(free) (n2, sizeof (Int), Lprev, Common) ;
+	CHOLMOD(free) (n2, sizeof (Int), Lnext, Common) ;
+	PRINT1 (("Allocate simplicial failed\n")) ;
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    L->p = Lp ;
+    L->nz = Lnz ;
+    L->prev = Lprev ;
+    L->next = Lnext ;
+    /* initialize a doubly linked list for columns in natural order */
+    natural_list (L) ;
+    PRINT1 (("Allocate simplicial done\n")) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === simplicial_symbolic_to_super_symbolic ================================ */
+/* ========================================================================== */
+
+/* Convert a simplicial symbolic factor supernodal symbolic factor.  Does not
+ * initialize the new space. */
+
+static int simplicial_symbolic_to_super_symbolic
+(
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    Int nsuper, xsize, ssize ;
+    Int *Lsuper, *Lpi, *Lpx, *Ls ;
+    size_t nsuper1 ;
+
+    ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ;
+
+    xsize  = L->xsize ;
+    ssize  = L->ssize ;
+    nsuper = L->nsuper ;
+    nsuper1 = ((size_t) nsuper) + 1 ;
+
+    PRINT1 (("simple sym to super sym: ssize "ID" xsize "ID" nsuper "ID""
+	" status %d\n", ssize, xsize, nsuper, Common->status)) ;
+
+    /* O(nsuper) arrays, where nsuper <= n */
+    Lsuper = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
+    Lpi    = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
+    Lpx    = CHOLMOD(malloc) (nsuper1, sizeof (Int), Common) ;
+
+    /* O(ssize) array, where ssize <= nnz(L), and usually much smaller */
+    Ls = CHOLMOD(malloc) (ssize, sizeof (Int), Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free) (nsuper1, sizeof (Int), Lsuper, Common) ;
+	CHOLMOD(free) (nsuper1, sizeof (Int), Lpi,    Common) ;
+	CHOLMOD(free) (nsuper1, sizeof (Int), Lpx,    Common) ;
+	CHOLMOD(free) (ssize,    sizeof (Int), Ls,     Common) ;
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    ASSERT (Lsuper != NULL && Lpi != NULL && Lpx != NULL && Ls != NULL) ;
+
+    L->maxcsize = 0 ;
+    L->maxesize = 0 ;
+
+    L->super = Lsuper ;
+    L->pi = Lpi ;
+    L->px = Lpx ;
+    L->s  = Ls ;
+    Ls [0] = EMPTY ;	    /* supernodal pattern undefined */
+
+    L->is_super = TRUE ;
+    L->is_ll = TRUE ;	    /* supernodal LDL' not supported */
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+    L->minor = L->n ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === any_to_simplicial_symbolic =========================================== */
+/* ========================================================================== */
+
+/* Convert any factor L to a simplicial symbolic factor, leaving only L->Perm
+ * and L->ColCount.  Cannot fail.  Any of the components of L (except Perm and
+ * ColCount) may already be free'd.  */
+
+static void any_to_simplicial_symbolic
+(
+    cholmod_factor *L,
+    int to_ll,
+    cholmod_common *Common
+)
+{
+    Int n, lnz, xs, ss, s, e ;
+    size_t n1, n2 ;
+
+    /* ============================================== commit the changes to L */
+
+    n = L->n ;
+    lnz = L->nzmax ;
+    s = L->nsuper + 1 ;
+    xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ;
+    e = (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) ;
+    ss = L->ssize ;
+
+    /* this cannot cause size_t overflow */
+    n1 = ((size_t) n) + 1 ;
+    n2 = ((size_t) n) + 2 ;
+
+    /* free all but the symbolic analysis (Perm and ColCount) */
+    L->p     = CHOLMOD(free) (n1,  sizeof (Int),      L->p,     Common) ;
+    L->i     = CHOLMOD(free) (lnz, sizeof (Int),      L->i,     Common) ;
+    L->x     = CHOLMOD(free) (xs,  e*sizeof (double), L->x,     Common) ;
+    L->z     = CHOLMOD(free) (lnz, sizeof (double),   L->z,     Common) ;
+    L->nz    = CHOLMOD(free) (n,   sizeof (Int),      L->nz,    Common) ;
+    L->next  = CHOLMOD(free) (n2,  sizeof (Int),      L->next,  Common) ;
+    L->prev  = CHOLMOD(free) (n2,  sizeof (Int),      L->prev,  Common) ;
+    L->super = CHOLMOD(free) (s,   sizeof (Int),      L->super, Common) ;
+    L->pi    = CHOLMOD(free) (s,   sizeof (Int),      L->pi,    Common) ;
+    L->px    = CHOLMOD(free) (s,   sizeof (Int),      L->px,    Common) ;
+    L->s     = CHOLMOD(free) (ss,  sizeof (Int),      L->s,     Common) ;
+    L->nzmax = 0 ;
+    L->is_super = FALSE ;
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+    L->minor = n ;
+    L->is_ll = to_ll ;
+}
+
+
+/* ========================================================================== */
+/* === ll_super_to_super_symbolic =========================================== */
+/* ========================================================================== */
+
+/* Convert a numerical supernodal L to symbolic supernodal.  Cannot fail. */
+
+static void ll_super_to_super_symbolic
+(
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+
+    /* ============================================== commit the changes to L */
+
+    /* free all but the supernodal numerical factor */
+    ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_super && L->is_ll) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start to super symbolic", Common)) ;
+    L->x = CHOLMOD(free) (L->xsize,
+	    (L->xtype == CHOLMOD_COMPLEX ? 2 : 1) * sizeof (double), L->x,
+	    Common) ;
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+    L->minor = L->n ;
+    L->is_ll = TRUE ;	    /* supernodal LDL' not supported */
+    DEBUG (CHOLMOD(dump_factor) (L, "done  to super symbolic", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === simplicial_symbolic_to_simplicial_numeric ============================ */
+/* ========================================================================== */
+
+/* Convert a simplicial symbolic L to a simplicial numeric L; allocate space
+ * for L using L->ColCount from symbolic analysis, and set L to identity.
+ *
+ * If packed < 0, then this routine is creating a copy of another factor
+ * (via cholmod_copy_factor).  In this case, the space is not initialized. */
+
+static void simplicial_symbolic_to_simplicial_numeric
+(
+    cholmod_factor *L,
+    int to_ll,
+    int packed,
+    int to_xtype,
+    cholmod_common *Common
+)
+{
+    double grow0, grow1, xlen, xlnz ;
+    double *Lx, *Lz ;
+    Int *Li, *Lp, *Lnz, *ColCount ;
+    Int n, grow, grow2, p, j, lnz, len, ok, e ;
+
+    ASSERT (L->xtype == CHOLMOD_PATTERN && !(L->is_super)) ;
+    if (!allocate_simplicial_numeric (L, Common))
+    {
+	PRINT1 (("out of memory, allocate simplicial numeric\n")) ;
+	return ;	/* out of memory */
+    }
+    ASSERT (L->ColCount != NULL && L->nz != NULL && L->p != NULL) ;
+    ASSERT (L->x == NULL && L->z == NULL && L->i == NULL) ;
+
+    ColCount = L->ColCount ;
+    Lnz = L->nz ;
+    Lp = L->p ;
+    ok = TRUE ;
+    n = L->n ;
+
+    if (packed < 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* used by cholmod_copy_factor to allocate a copy of a factor object */
+	/* ------------------------------------------------------------------ */
+
+	lnz = L->nzmax ;
+	L->nzmax = 0 ;
+
+    }
+    else if (packed)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* LDL' or LL' packed */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("convert to packed LL' or LDL'\n")) ;
+	lnz = 0 ;
+	for (j = 0 ; ok && j < n ; j++)
+	{
+	    /* ensure len is in the range 1 to n-j */
+	    len = ColCount [j] ;
+	    len = MAX (1, len) ;
+	    len = MIN (len, n-j) ;
+	    lnz += len ;
+	    ok = (lnz >= 0) ;
+	}
+	for (j = 0 ; j <= n ; j++)
+	{
+	    Lp [j] = j ;
+	}
+	for (j = 0 ; j < n ; j++)
+	{
+	    Lnz [j] = 1 ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* LDL' unpacked */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("convert to unpacked\n")) ;
+	/* compute new lnzmax */
+	/* if any parameter is NaN, grow is false */
+	grow0 = Common->grow0 ;
+	grow1 = Common->grow1 ;
+	grow2 = Common->grow2 ;
+	grow0 = IS_NAN (grow0) ? 1 : grow0 ;
+	grow1 = IS_NAN (grow1) ? 1 : grow1 ;
+	/* fl.pt. compare, but no NaN's: */
+	grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ;
+	PRINT1 (("init, grow1 %g grow2 "ID"\n", grow1, grow2)) ;
+	/* initialize Lp and Lnz for each column */
+	lnz = 0 ;
+	for (j = 0 ; ok && j < n ; j++)
+	{
+	    Lp [j] = lnz ;
+	    Lnz [j] = 1 ;
+
+	    /* ensure len is in the range 1 to n-j */
+	    len = ColCount [j] ;
+	    len = MAX (1, len) ;
+	    len = MIN (len, n-j) ;
+
+	    /* compute len in double to avoid integer overflow */
+	    PRINT1 (("ColCount ["ID"] = "ID"\n", j, len)) ;
+	    if (grow)
+	    {
+		xlen = (double) len ;
+		xlen = grow1 * xlen + grow2 ;
+		xlen = MIN (xlen, n-j) ;
+		len = (Int) xlen ;
+	    }
+	    ASSERT (len >= 1 && len <= n-j) ;
+	    lnz += len ;
+	    ok = (lnz >= 0) ;
+	}
+	if (ok)
+	{
+	    Lp [n] = lnz ;
+	    if (grow)
+	    {
+		/* add extra space */
+		xlnz = (double) lnz ;
+		xlnz *= grow0 ;
+		xlnz = MIN (xlnz, Size_max) ;
+		xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ;
+		lnz = (Int) xlnz ;
+	    }
+	}
+    }
+
+    lnz = MAX (1, lnz) ;
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+    }
+
+    /* allocate L->i, L->x, and L->z */
+    PRINT1 (("resizing from zero size to lnz "ID"\n", lnz)) ;
+    ASSERT (L->nzmax == 0) ;
+    e = (to_xtype == CHOLMOD_COMPLEX ? 2 : 1) ;
+    if (!ok || !CHOLMOD(realloc_multiple) (lnz, 1, to_xtype, &(L->i), NULL,
+		&(L->x), &(L->z), &(L->nzmax), Common))
+    {
+	L->p    = CHOLMOD(free) (n+1, sizeof (Int),      L->p, Common) ;
+	L->nz   = CHOLMOD(free) (n,   sizeof (Int),      L->nz, Common) ;
+	L->prev = CHOLMOD(free) (n+2, sizeof (Int),      L->prev, Common) ;
+	L->next = CHOLMOD(free) (n+2, sizeof (Int),      L->next, Common) ;
+	L->i    = CHOLMOD(free) (lnz, sizeof (Int),      L->i, Common) ;
+	L->x    = CHOLMOD(free) (lnz, e*sizeof (double), L->x, Common) ;
+	L->z    = CHOLMOD(free) (lnz, sizeof (double),   L->z, Common) ;
+	PRINT1 (("cannot realloc simplicial numeric\n")) ;
+	return ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    /* initialize L to be the identity matrix */
+    L->xtype = to_xtype ;
+    L->dtype = DTYPE ;
+    L->minor = n ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+
+#if 0
+    if (lnz == 1)
+    {
+	/* the user won't expect to access this entry, but some CHOLMOD
+	 * routines may.  Set it to zero so that valgrind doesn't complain. */
+	switch (to_xtype)
+	{
+	    case CHOLMOD_REAL:
+		Lx [0] = 0 ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		Lx [0] = 0 ;
+		Lx [1] = 0 ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		Lx [0] = 0 ;
+		Lz [0] = 0 ;
+		break ;
+	}
+    }
+#endif
+
+    if (packed >= 0)
+    {
+	/* create the unit diagonal for either the LL' or LDL' case */
+
+	switch (L->xtype)
+	{
+	    case CHOLMOD_REAL:
+		for (j = 0 ; j < n ; j++)
+		{
+		    ASSERT (Lp [j] < Lp [j+1]) ;
+		    p = Lp [j] ;
+		    Li [p] = j ;
+		    Lx [p] = 1 ;
+		}
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		for (j = 0 ; j < n ; j++)
+		{
+		    ASSERT (Lp [j] < Lp [j+1]) ;
+		    p = Lp [j] ;
+		    Li [p] = j ;
+		    Lx [2*p  ] = 1 ;
+		    Lx [2*p+1] = 0 ;
+		}
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		for (j = 0 ; j < n ; j++)
+		{
+		    ASSERT (Lp [j] < Lp [j+1]) ;
+		    p = Lp [j] ;
+		    Li [p] = j ;
+		    Lx [p] = 1 ;
+		    Lz [p] = 0 ;
+		}
+		break ;
+	}
+    }
+
+    L->is_ll = to_ll ;
+
+    PRINT1 (("done convert simplicial symbolic to numeric\n")) ;
+}
+
+
+/* ========================================================================== */
+/* === change_simplicial_numeric ============================================ */
+/* ========================================================================== */
+
+/* Change LL' to LDL', LDL' to LL', or leave as-is.
+ *
+ * If to_packed is TRUE, then the columns of L are packed and made monotonic
+ * (to_monotonic is ignored; it is implicitly TRUE).
+ *
+ * If to_monotonic is TRUE but to_packed is FALSE, the columns of L are made
+ * monotonic but not packed.
+ *
+ * If both to_packed and to_monotonic are FALSE, then the columns of L are
+ * left as-is, and the conversion is done in place.
+ *
+ * If L is already monotonic, or if it is to be left non-monotonic, then this
+ * conversion always succeeds.
+ *
+ * When converting an LDL' to LL' factorization, any column with a negative
+ * or zero diagonal entry is not modified so that conversion back to LDL' will
+ * succeed.  This can result in a matrix L with a negative entry on the diagonal
+ * If the kth entry on the diagonal of D is negative, it and the kth column of
+ * L are left unchanged.  A subsequent conversion back to an LDL' form will also
+ * leave the column unchanged, so the correct LDL' factorization will be
+ * restored.  L->minor is set to the smallest k for which D (k,k) is negative.
+ */
+
+static void change_simplicial_numeric
+(
+    cholmod_factor *L,
+    int to_ll,
+    int to_packed,
+    int to_monotonic,
+    cholmod_common *Common
+)
+{
+    double grow0, grow1, xlen, xlnz ;
+    void *newLi, *newLx, *newLz ;
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz ;
+    Int make_monotonic, grow2, n, j, lnz, len, grow, ok, make_ll, make_ldl ;
+    size_t nzmax0 ;
+
+    PRINT1 (("\n===Change simplicial numeric: %d %d %d\n",
+	    to_ll, to_packed, to_monotonic)) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "change simplicial numeric", Common)) ;
+    ASSERT (L->xtype != CHOLMOD_PATTERN && !(L->is_super)) ;
+
+    make_monotonic = ((to_packed || to_monotonic) && !(L->is_monotonic)) ;
+    make_ll  = (to_ll && !(L->is_ll)) ;
+    make_ldl = (!to_ll && L->is_ll) ;
+
+    n = L->n ;
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lnz = L->nz ;
+
+    grow = FALSE ;
+    grow0 = Common->grow0 ;
+    grow1 = Common->grow1 ;
+    grow2 = Common->grow2 ;
+    grow0 = IS_NAN (grow0) ? 1 : grow0 ;
+    grow1 = IS_NAN (grow1) ? 1 : grow1 ;
+    ok = TRUE ;
+    newLi = NULL ;
+    newLx = NULL ; 
+    newLz = NULL ; 
+    lnz = 0 ;
+
+    if (make_monotonic)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Columns out of order, but will be reordered and optionally packed. */
+	/* ------------------------------------------------------------------ */
+
+	PRINT1 (("L is non-monotonic\n")) ;
+
+	/* compute new L->nzmax */
+	if (!to_packed)
+	{
+	    /* if any parameter is NaN, grow is false */
+	    /* fl.pt. comparisons below are false if any parameter is NaN */
+	    grow = (grow0 >= 1.0) && (grow1 >= 1.0) && (grow2 > 0) ;
+	}
+	for (j = 0 ; ok && j < n ; j++)
+	{
+	    len = Lnz [j] ;
+	    ASSERT (len >= 1 && len <= n-j) ;
+
+	    /* compute len in double to avoid integer overflow */
+	    if (grow)
+	    {
+		xlen = (double) len ;
+		xlen = grow1 * xlen + grow2 ;
+		xlen = MIN (xlen, n-j) ;
+		len = (Int) xlen ;
+	    }
+	    ASSERT (len >= Lnz [j] && len <= n-j) ;
+
+	    PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n",
+			j, Lnz [j], len, lnz)) ;
+
+	    lnz += len ;
+	    ok = (lnz >= 0) ;
+	}
+
+	if (!ok)
+	{
+	    ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	    return ;
+	}
+
+	if (grow)
+	{
+	    xlnz = (double) lnz ;
+	    xlnz *= grow0 ;
+	    xlnz = MIN (xlnz, Size_max) ;
+	    xlnz = MIN (xlnz, ((double) n * (double) n + (double) n) / 2) ;
+	    lnz = (Int) xlnz ;
+	}
+
+	lnz = MAX (1, lnz) ;
+	PRINT1 (("final lnz "ID"\n", lnz)) ;
+	nzmax0 = 0 ;
+
+	CHOLMOD(realloc_multiple) (lnz, 1, L->xtype, &newLi, NULL,
+		&newLx, &newLz, &nzmax0, Common) ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    return ;	    /* out of memory */
+	}
+    }
+
+    /* ============================================== commit the changes to L */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the simplicial L, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_change_simplicial_numeric (L, to_ll, to_packed,
+		    newLi, newLx, newLz, lnz, grow, grow1, grow2,
+		    make_ll, make_monotonic, make_ldl, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_change_simplicial_numeric (L, to_ll, to_packed,
+		    newLi, newLx, newLz, lnz, grow, grow1, grow2,
+		    make_ll, make_monotonic, make_ldl, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    z_change_simplicial_numeric (L, to_ll, to_packed,
+		    newLi, newLx, newLz, lnz, grow, grow1, grow2,
+		    make_ll, make_monotonic, make_ldl, Common) ;
+	    break ;
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "L simplicial changed", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === ll_super_to_simplicial_numeric ======================================= */
+/* ========================================================================== */
+
+/* Convert a supernodal numeric factorization to any simplicial numeric one.
+ * Leaves L->xtype unchanged (real or complex, not zomplex since there is
+ * no supernodal zomplex L). */
+
+static void ll_super_to_simplicial_numeric
+(
+    cholmod_factor *L,
+    int to_packed,
+    int to_ll,
+    cholmod_common *Common
+)
+{
+    Int *Ls, *Lpi, *Lpx, *Super, *Li ;
+    Int n, lnz, s, nsuper, psi, psend, nsrow, nscol, k1, k2, erows ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "start LL super to simplicial", Common)) ;
+    PRINT1 (("super -> simplicial (%d %d)\n", to_packed, to_ll)) ;
+    ASSERT (L->xtype != CHOLMOD_PATTERN && L->is_ll && L->is_super) ;
+    ASSERT (L->x != NULL && L->i == NULL) ;
+
+    n = L->n ;
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+
+    /* Int overflow cannot occur since supernodal L already exists */
+
+    if (to_packed)
+    {
+	/* count the number of nonzeros in L.  Each supernode is of the form
+	 *
+	 *    l	. . .	    For this example, nscol = 4 (# columns). nsrow = 9.
+	 *    l l . .	    The "." entries are allocated in the supernodal
+	 *    l l l .	    factor, but not used.  They are not copied to the
+	 *    l l l l	    simplicial factor.  Some "l" and "e" entries may be
+	 *    e e e e	    numerically zero and even symbolically zero if a
+	 *    e e e e	    tight simplicial factorization or resymbol were
+	 *    e e e e	    done, because of numerical cancellation and relaxed
+	 *    e e e e	    supernode amalgamation, respectively.
+	 *    e e e e
+	 */
+	lnz = 0 ;
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    ASSERT (nsrow >= nscol) ;
+	    erows = nsrow - nscol ;
+
+	    /* lower triangular part, including the diagonal,
+	     * counting the "l" terms in the figure above. */
+	    lnz += nscol * (nscol+1) / 2 ;
+
+	    /* rectangular part, below the diagonal block (the "e" terms) */
+	    lnz += nscol * erows ;
+	}
+	ASSERT (lnz <= (Int) (L->xsize)) ;
+    }
+    else
+    {
+	/* Li will be the same size as Lx */
+	lnz = L->xsize ;
+    }
+    ASSERT (lnz >= 0) ;
+    PRINT1 (("simplicial lnz = "ID"  to_packed: %d  to_ll: %d L->xsize %g\n",
+		lnz, to_ll, to_packed, (double) L->xsize)) ;
+
+    Li = CHOLMOD(malloc) (lnz, sizeof (Int), Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return ;	/* out of memory */
+    }
+
+    if (!allocate_simplicial_numeric (L, Common))
+    {
+	CHOLMOD(free) (lnz, sizeof (Int), Li, Common) ;
+	return ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    L->i = Li ;
+    L->nzmax = lnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the supernodal L, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free unused parts of L */
+    /* ---------------------------------------------------------------------- */
+
+    L->super = CHOLMOD(free) (nsuper+1, sizeof (Int), L->super, Common) ;
+    L->pi    = CHOLMOD(free) (nsuper+1, sizeof (Int), L->pi, Common) ;
+    L->px    = CHOLMOD(free) (nsuper+1, sizeof (Int), L->px, Common) ;
+    L->s     = CHOLMOD(free) (L->ssize, sizeof (Int), L->s, Common) ;
+
+    L->ssize = 0 ;
+    L->xsize = 0 ;
+    L->nsuper = 0 ;
+    L->maxesize = 0 ;
+    L->maxcsize = 0 ;
+
+    L->is_super = FALSE ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "done  LL super to simplicial", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === super_symbolic_to_ll_super =========================================== */
+/* ========================================================================== */
+
+/* Convert a supernodal symbolic factorization to a supernodal numeric
+ * factorization by allocating L->x.  Contents of L->x are undefined.
+ */
+
+static int super_symbolic_to_ll_super
+(
+    int to_xtype,
+    cholmod_factor *L,
+    cholmod_common *Common
+)
+{
+    double *Lx ;
+    Int wentry = (to_xtype == CHOLMOD_REAL) ? 1 : 2 ;
+    PRINT1 (("convert super sym to num\n")) ;
+    ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_super) ;
+    Lx = CHOLMOD(malloc) (L->xsize, wentry * sizeof (double), Common) ;
+    PRINT1 (("xsize %g\n", (double) L->xsize)) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ============================================== commit the changes to L */
+
+    if (L->xsize == 1)
+    {
+	/* the caller won't expect to access this entry, but some CHOLMOD
+	 * routines may.  Set it to zero so that valgrind doesn't complain. */
+	switch (to_xtype)
+	{
+	    case CHOLMOD_REAL:
+		Lx [0] = 0 ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		Lx [0] = 0 ;
+		Lx [1] = 0 ;
+		break ;
+	}
+    }
+
+    L->x = Lx ;
+    L->xtype = to_xtype ;
+    L->dtype = DTYPE ;
+    L->minor = L->n ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_change_factor ================================================ */
+/* ========================================================================== */
+
+/* Convert a factor L.  Some conversions simply allocate uninitialized space
+ * that meant to be filled later.
+ *
+ * If the conversion fails, the factor is left in its original form, with one
+ * exception.  Converting a supernodal symbolic factor to a simplicial numeric
+ * one (with L=D=I) may leave the factor in simplicial symbolic form.
+ *
+ * Memory allocated for each conversion is listed below.
+ */
+
+int CHOLMOD(change_factor)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* convert to CHOLMOD_PATTERN, _REAL, _COMPLEX, or
+			 * _ZOMPLEX */
+    int to_ll,		/* TRUE: convert to LL', FALSE: LDL' */
+    int to_super,	/* TRUE: convert to supernodal, FALSE: simplicial */
+    int to_packed,	/* TRUE: pack simplicial columns, FALSE: do not pack */
+    int to_monotonic,	/* TRUE: put simplicial columns in order, FALSE: not */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (to_xtype < CHOLMOD_PATTERN || to_xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    PRINT1 (("-----convert from (%d,%d,%d,%d,%d) to (%d,%d,%d,%d,%d)\n",
+    L->xtype, L->is_ll, L->is_super, L_is_packed (L, Common), L->is_monotonic,
+    to_xtype, to_ll,    to_super,    to_packed,               to_monotonic)) ;
+
+    /* ensure all parameters are TRUE/FALSE */
+    to_ll = BOOLEAN (to_ll) ;
+    to_super = BOOLEAN (to_super) ;
+
+    ASSERT (BOOLEAN (L->is_ll) == L->is_ll) ;
+    ASSERT (BOOLEAN (L->is_super) == L->is_super) ;
+
+    if (to_super && to_xtype == CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "supernodal zomplex L not supported") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert */
+    /* ---------------------------------------------------------------------- */
+
+    if (to_xtype == CHOLMOD_PATTERN)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert to symbolic */
+	/* ------------------------------------------------------------------ */
+
+	if (!to_super)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert any factor into a simplicial symbolic factor */
+	    /* -------------------------------------------------------------- */
+
+	    any_to_simplicial_symbolic (L, to_ll, Common) ;    /* cannot fail */
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert to a supernodal symbolic factor */
+	    /* -------------------------------------------------------------- */
+
+	    if (L->xtype != CHOLMOD_PATTERN && L->is_super)
+	    {
+		/* convert from supernodal numeric to supernodal symbolic.
+		 * this preserves symbolic pattern of L, discards numeric
+		 * values */
+		ll_super_to_super_symbolic (L, Common) ;       /* cannot fail */
+	    }
+	    else if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
+	    {
+		/* convert from simplicial symbolic to supernodal symbolic.
+		 * contents of supernodal pattern are uninitialized.  Not meant
+		 * for the end user. */
+		simplicial_symbolic_to_super_symbolic (L, Common) ;
+	    }
+	    else
+	    {
+		/* cannot convert from simplicial numeric to supernodal
+		 * symbolic */
+		ERROR (CHOLMOD_INVALID,
+			"cannot convert L to supernodal symbolic") ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert to numeric */
+	/* ------------------------------------------------------------------ */
+	    
+	if (to_super)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert to supernodal numeric factor */
+	    /* -------------------------------------------------------------- */
+
+	    if (L->xtype == CHOLMOD_PATTERN)
+	    {
+		if (L->is_super)
+		{
+		    /* Convert supernodal symbolic to supernodal numeric.
+		     * Contents of supernodal numeric values are uninitialized.
+		     * This is used by cholmod_super_numeric.  Not meant for
+		     * the end user. */
+		    super_symbolic_to_ll_super (to_xtype, L, Common) ;
+		}
+		else
+		{
+		    /* Convert simplicial symbolic to supernodal numeric.
+		     * Contents not defined.  This is used by
+		     * Core/cholmod_copy_factor only.  Not meant for the end
+		     * user. */
+		    if (!simplicial_symbolic_to_super_symbolic (L, Common))
+		    {
+			/* failure, convert back to simplicial symbolic */
+			any_to_simplicial_symbolic (L, to_ll, Common) ;
+		    }
+		    else
+		    {
+			/* conversion to super symbolic OK, allocate numeric
+			 * part */
+			super_symbolic_to_ll_super (to_xtype, L, Common) ;
+		    }
+		}
+	    }
+	    else
+	    {
+		/* nothing to do if L is already in supernodal numeric form */
+		if (!(L->is_super))
+		{
+		    ERROR (CHOLMOD_INVALID,
+			"cannot convert simplicial L to supernodal") ;
+		}
+		/* FUTURE WORK: convert to/from supernodal LL' and LDL' */
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* convert any factor to simplicial numeric */
+	    /* -------------------------------------------------------------- */
+
+	    if (L->xtype == CHOLMOD_PATTERN && !(L->is_super))
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* convert simplicial symbolic to simplicial numeric (L=I,D=I)*/
+		/* ---------------------------------------------------------- */
+
+		simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed,
+			to_xtype, Common) ;
+
+	    }
+	    else if (L->xtype != CHOLMOD_PATTERN && L->is_super)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* convert a supernodal LL' to simplicial numeric */
+		/* ---------------------------------------------------------- */
+
+		ll_super_to_simplicial_numeric (L, to_packed, to_ll, Common) ;
+
+	    }
+	    else if (L->xtype == CHOLMOD_PATTERN && L->is_super)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* convert a supernodal symbolic to simplicial numeric (L=D=I)*/
+		/* ---------------------------------------------------------- */
+
+		any_to_simplicial_symbolic (L, to_ll, Common) ;
+		/* if the following fails, it leaves the factor in simplicial
+		 * symbolic form */
+		simplicial_symbolic_to_simplicial_numeric (L, to_ll, to_packed,
+			to_xtype, Common) ;
+
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* change a simplicial numeric factor */
+		/* ---------------------------------------------------------- */
+
+		/* change LL' to LDL', LDL' to LL', or leave as-is.  pack the
+		 * columns of L, or leave as-is.  Ensure the columns are
+		 * monotonic, or leave as-is. */
+
+		change_simplicial_numeric (L, to_ll, to_packed, to_monotonic,
+			Common) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    return (Common->status >= CHOLMOD_OK) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_common.c b/src/CHOLMOD/Core/cholmod_common.c
new file mode 100644
index 0000000..2394fab
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_common.c
@@ -0,0 +1,701 @@
+/* ========================================================================== */
+/* === Core/cholmod_common ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_common object:
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_start		the first call to CHOLMOD
+ * cholmod_finish		the last call to CHOLMOD
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_defaults		restore (most) default control parameters
+ * cholmod_allocate_work	allocate (or reallocate) workspace in Common
+ * cholmod_free_work		free workspace in Common
+ * cholmod_clear_flag		clear Common->Flag in workspace
+ * cholmod_maxrank		column dimension of Common->Xwork workspace
+ *
+ * The Common object is unique.  It cannot be allocated or deallocated by
+ * CHOLMOD, since it contains the definition of the memory management routines
+ * used (pointers to malloc, free, realloc, and calloc, or their equivalent).
+ * The Common object contains workspace that is used between calls to
+ * CHOLMOD routines.  This workspace allocated by CHOLMOD as needed, by
+ * cholmod_allocate_work and cholmod_free_work.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === cholmod_start ======================================================== */
+/* ========================================================================== */
+
+/* Initialize Common default parameters and statistics.  Sets workspace
+ * pointers to NULL.
+ *
+ * This routine must be called just once, prior to calling any other CHOLMOD
+ * routine.  Do not call this routine after any other CHOLMOD routine (except
+ * cholmod_finish, to start a new CHOLMOD session), or a memory leak will
+ * occur.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(start)
+(
+    cholmod_common *Common
+)
+{
+    int k ;
+
+    if (Common == NULL)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* user error handling routine */
+    /* ---------------------------------------------------------------------- */
+
+    Common->error_handler = NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* integer and numerical types */
+    /* ---------------------------------------------------------------------- */
+
+    Common->itype = ITYPE ;
+    Common->dtype = DTYPE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* default control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(defaults) (Common) ;
+    Common->try_catch = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* memory management routines */
+    /* ---------------------------------------------------------------------- */
+
+    /* The user can replace cholmod's memory management routines by redefining
+     * these function pointers. */
+
+#ifndef NMALLOC
+    /* stand-alone ANSI C program */
+    Common->malloc_memory  = malloc ;
+    Common->free_memory    = free ;
+    Common->realloc_memory = realloc ;
+    Common->calloc_memory  = calloc ;
+#else
+    /* no memory manager defined at compile-time; MUST define one at run-time */
+    Common->malloc_memory  = NULL ;
+    Common->free_memory    = NULL ;
+    Common->realloc_memory = NULL ;
+    Common->calloc_memory  = NULL ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* complex arithmetic routines */
+    /* ---------------------------------------------------------------------- */
+
+    Common->complex_divide = CHOLMOD(divcomplex) ;
+    Common->hypotenuse = CHOLMOD(hypot) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* print routine */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NPRINT
+    /* stand-alone ANSI C program */
+    Common->print_function = printf ;
+#else
+    /* printing disabled */
+    Common->print_function = NULL ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* This code assumes the workspace held in Common is not initialized.  If
+     * it is, then a memory leak will occur because the pointers are
+     * overwritten with NULL. */
+
+    Common->nrow = 0 ;
+    Common->mark = EMPTY ;
+    Common->xworksize = 0 ;
+    Common->iworksize = 0 ;
+    Common->Flag = NULL ;
+    Common->Head = NULL ;
+    Common->Iwork = NULL ;
+    Common->Xwork = NULL ;
+    Common->no_workspace_reallocate = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* statistics */
+    /* ---------------------------------------------------------------------- */
+
+    /* fl and lnz are computed in cholmod_analyze and cholmod_rowcolcounts */
+    Common->fl = EMPTY ;
+    Common->lnz = EMPTY ;
+
+    /* modfl is computed in cholmod_updown, cholmod_rowadd, and cholmod_rowdel*/
+    Common->modfl = EMPTY ;
+
+    /* all routines use status as their error-report code */
+    Common->status = CHOLMOD_OK ;
+
+    Common->malloc_count = 0 ;	/* # calls to malloc minus # calls to free */
+    Common->memory_usage = 0 ;	/* peak memory usage (in bytes) */
+    Common->memory_inuse = 0 ;	/* current memory in use (in bytes) */
+
+    Common->nrealloc_col = 0 ;
+    Common->nrealloc_factor = 0 ;
+    Common->ndbounds_hit = 0 ;
+    Common->rowfacfl = 0 ;
+    Common->aatfl = EMPTY ;
+
+    /* Common->called_nd is TRUE if cholmod_analyze called or NESDIS */
+    Common->called_nd = FALSE ;
+
+    Common->blas_ok = TRUE ;    /* false if BLAS int overflow occurs */
+
+    /* ---------------------------------------------------------------------- */
+    /* default SuiteSparseQR knobs and statististics */
+    /* ---------------------------------------------------------------------- */
+
+    for (k = 0 ; k < 4  ; k++) Common->SPQR_xstat [k] = 0 ;
+    for (k = 0 ; k < 10 ; k++) Common->SPQR_istat [k] = 0 ;
+
+    for (k = 0 ; k < 10 ; k++) Common->other1 [k] = 0 ;
+    for (k = 0 ; k < 6  ; k++) Common->other2 [k] = 0 ;
+    for (k = 0 ; k < 10 ; k++) Common->other3 [k] = 0 ;
+    for (k = 0 ; k < 16 ; k++) Common->other4 [k] = 0 ;
+    for (k = 0 ; k < 16 ; k++) Common->other5 [k] = (void *) NULL ;
+
+    Common->SPQR_grain = 1 ;    /* no Intel TBB multitasking, by default */
+    Common->SPQR_small = 1e6 ;  /* target min task size for TBB */
+    Common->SPQR_shrink = 1 ;   /* controls SPQR shrink realloc */
+    Common->SPQR_nthreads = 0 ; /* 0: let TBB decide how many threads to use */
+
+    /* ---------------------------------------------------------------------- */
+    /* GPU initializations */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef GPU_BLAS
+    Common->cublasHandle = NULL ;
+    Common->cudaStreamSyrk = NULL ;
+    Common->cudaStreamGemm = NULL ;
+    Common->cudaStreamTrsm = NULL ;
+    Common->cudaStreamPotrf [0] = NULL ;
+    Common->cudaStreamPotrf [1] = NULL ;
+    Common->cudaStreamPotrf [2] = NULL ;
+    Common->cublasEventPotrf [0] = NULL ;
+    Common->cublasEventPotrf [1] = NULL ;
+    Common->HostPinnedMemory = NULL ;
+    Common->devPotrfWork = NULL ;
+    Common->devSyrkGemmPtrLx = NULL ;
+    Common->devSyrkGemmPtrC = NULL ;
+    Common->GemmUsed = 0 ;
+    Common->SyrkUsed = 0 ;
+    Common->syrkStart = 0 ;
+#endif
+
+    DEBUG_INIT ("cholmod start", Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_defaults ===================================================== */
+/* ========================================================================== */
+
+/* Set Common default parameters, except for the function pointers.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(defaults)
+(
+    cholmod_common *Common
+)
+{
+    Int i ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* default control parameters */
+    /* ---------------------------------------------------------------------- */
+
+    Common->dbound = 0.0 ;
+    Common->grow0 = 1.2 ;
+    Common->grow1 = 1.2 ;
+    Common->grow2 = 5 ;
+    Common->maxrank = 8 ;
+
+    Common->final_asis = TRUE ;
+    Common->final_super = TRUE ;
+    Common->final_ll = FALSE ;
+    Common->final_pack = TRUE ;
+    Common->final_monotonic = TRUE ;
+    Common->final_resymbol = FALSE ;
+
+    /* use simplicial factorization if flop/nnz(L) < 40, supernodal otherwise */
+    Common->supernodal = CHOLMOD_AUTO ;
+    Common->supernodal_switch = 40 ;
+
+    Common->nrelax [0] = 4 ;
+    Common->nrelax [1] = 16 ;
+    Common->nrelax [2] = 48 ;
+    Common->zrelax [0] = 0.8 ;
+    Common->zrelax [1] = 0.1 ;
+    Common->zrelax [2] = 0.05 ;
+
+    Common->prefer_zomplex = FALSE ;
+    Common->prefer_upper = TRUE ;
+    Common->prefer_binary = FALSE ;
+    Common->quick_return_if_not_posdef = FALSE ;
+
+    /* METIS workarounds */
+    Common->metis_memory = 0.0 ;    /* > 0 for memory guard (2 is reasonable) */
+    Common->metis_nswitch = 3000 ;
+    Common->metis_dswitch = 0.66 ;
+
+    Common->print = 3 ;
+    Common->precise = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* default ordering methods */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note that if the Partition module is not installed, the CHOLMOD_METIS
+     * and CHOLMOD_NESDIS methods will not be available.  cholmod_analyze will
+     * report the CHOLMOD_NOT_INSTALLED error, and safely skip over them.
+     */
+
+#if (CHOLMOD_MAXMETHODS < 9)
+#error "CHOLMOD_MAXMETHODS must be 9 or more (defined in cholmod_core.h)."
+#endif
+
+    /* default strategy: try given, AMD, and then METIS if AMD reports high
+     * fill-in.  NESDIS can be used instead, if Common->default_nesdis is TRUE.
+     */
+    Common->nmethods = 0 ;		/* use default strategy */
+    Common->default_nesdis = FALSE ;	/* use METIS in default strategy */
+
+    Common->current = 0 ;	/* current method being tried */
+    Common->selected = 0 ;	/* the best method selected */
+
+    /* first, fill each method with default parameters */
+    for (i = 0 ; i <= CHOLMOD_MAXMETHODS ; i++)
+    {
+	/* CHOLMOD's default method is AMD for A or AA' */
+	Common->method [i].ordering = CHOLMOD_AMD ;
+
+	/* CHOLMOD nested dissection and minimum degree parameter */
+	Common->method [i].prune_dense = 10.0 ;	/* dense row/col control */
+
+	/* min degree parameters (AMD, COLAMD, SYMAMD, CAMD, CCOLAMD, CSYMAMD)*/
+	Common->method [i].prune_dense2 = -1 ;	/* COLAMD dense row control */
+	Common->method [i].aggressive = TRUE ;	/* aggressive absorption */
+	Common->method [i].order_for_lu = FALSE ;/* order for Cholesky not LU */
+
+	/* CHOLMOD's nested dissection (METIS + constrained AMD) */
+	Common->method [i].nd_small = 200 ;	/* small graphs aren't cut */
+	Common->method [i].nd_compress = TRUE ;	/* compress graph & subgraphs */
+	Common->method [i].nd_camd = 1 ;	/* use CAMD */
+	Common->method [i].nd_components = FALSE ;  /* lump connected comp. */
+	Common->method [i].nd_oksep = 1.0 ;	/* sep ok if < oksep*n */
+
+	/* statistics for each method are not yet computed */
+	Common->method [i].fl = EMPTY ;
+	Common->method [i].lnz = EMPTY ;
+    }
+
+    Common->postorder = TRUE ;	/* follow ordering with weighted postorder */
+
+    /* Next, define some methods.  The first five use default parameters. */
+    Common->method [0].ordering = CHOLMOD_GIVEN ;   /* skip if UserPerm NULL */
+    Common->method [1].ordering = CHOLMOD_AMD ;
+    Common->method [2].ordering = CHOLMOD_METIS ;
+    Common->method [3].ordering = CHOLMOD_NESDIS ;
+    Common->method [4].ordering = CHOLMOD_NATURAL ;
+
+    /* CHOLMOD's nested dissection with large leaves of separator tree */
+    Common->method [5].ordering = CHOLMOD_NESDIS ;
+    Common->method [5].nd_small = 20000 ;
+
+    /* CHOLMOD's nested dissection with tiny leaves, and no AMD ordering */
+    Common->method [6].ordering = CHOLMOD_NESDIS ;
+    Common->method [6].nd_small = 4 ;
+    Common->method [6].nd_camd = 0 ;		/* no CSYMAMD or CAMD */
+
+    /* CHOLMOD's nested dissection with no dense node removal */
+    Common->method [7].ordering = CHOLMOD_NESDIS ;
+    Common->method [7].prune_dense = -1. ;
+
+    /* COLAMD for A*A', AMD for A */
+    Common->method [8].ordering = CHOLMOD_COLAMD ;
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_finish ======================================================= */
+/* ========================================================================== */
+
+/* The last call to CHOLMOD must be cholmod_finish.  You may call this routine
+ * more than once, and can safely call any other CHOLMOD routine after calling
+ * it (including cholmod_start).
+ *
+ * The statistics and parameter settings in Common are preserved.  The
+ * workspace in Common is freed.  This routine is just another name for
+ * cholmod_free_work.
+ */
+
+int CHOLMOD(finish)
+(
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(free_work) (Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_work ================================================ */
+/* ========================================================================== */
+
+/* Allocate and initialize workspace for CHOLMOD routines, or increase the size
+ * of already-allocated workspace.  If enough workspace is already allocated,
+ * then nothing happens.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), Iwork (iworksize), Xwork (xworksize)
+ */
+
+int CHOLMOD(allocate_work)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows in the matrix A */
+    size_t iworksize,	/* size of Iwork */
+    size_t xworksize,	/* size of Xwork */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *W ;
+    Int *Head ;
+    Int i ;
+    size_t nrow1 ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Allocate Flag (nrow) and Head (nrow+1) */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = MAX (1, nrow) ;
+
+    /* nrow1 = nrow + 1 */
+    nrow1 = CHOLMOD(add_size_t) (nrow, 1, &ok) ;
+    if (!ok)
+    {
+	/* nrow+1 causes size_t overflow ; problem is too large */
+	Common->status = CHOLMOD_TOO_LARGE ;
+	CHOLMOD(free_work) (Common) ;
+	return (FALSE) ;
+    }
+
+    if (nrow > Common->nrow)
+    {
+
+	if (Common->no_workspace_reallocate)
+	{
+	    /* CHOLMOD is not allowed to change the workspace here */
+	    Common->status = CHOLMOD_INVALID ;
+	    return (FALSE) ;
+	}
+
+	/* free the old workspace (if any) and allocate new space */
+	Common->Flag = CHOLMOD(free) (Common->nrow,  sizeof (Int), Common->Flag,
+		Common) ;
+	Common->Head = CHOLMOD(free) (Common->nrow+1,sizeof (Int), Common->Head,
+		Common) ;
+	Common->Flag = CHOLMOD(malloc) (nrow,   sizeof (Int), Common) ;
+	Common->Head = CHOLMOD(malloc) (nrow1, sizeof (Int), Common) ;
+
+	/* record the new size of Flag and Head */
+	Common->nrow = nrow ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_work) (Common) ;
+	    return (FALSE) ;
+	}
+
+	/* initialize Flag and Head */
+	Common->mark = EMPTY ;
+	CHOLMOD(clear_flag) (Common) ;
+	Head = Common->Head ;
+	for (i = 0 ; i <= (Int) (nrow) ; i++)
+	{
+	    Head [i] = EMPTY ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Allocate Iwork (iworksize) */
+    /* ---------------------------------------------------------------------- */
+
+    iworksize = MAX (1, iworksize) ;
+    if (iworksize > Common->iworksize)
+    {
+
+	if (Common->no_workspace_reallocate)
+	{
+	    /* CHOLMOD is not allowed to change the workspace here */
+	    Common->status = CHOLMOD_INVALID ;
+	    return (FALSE) ;
+	}
+
+	/* free the old workspace (if any) and allocate new space.
+	 * integer overflow safely detected in cholmod_malloc */
+	CHOLMOD(free) (Common->iworksize, sizeof (Int), Common->Iwork, Common) ;
+	Common->Iwork = CHOLMOD(malloc) (iworksize, sizeof (Int), Common) ;
+
+	/* record the new size of Iwork */
+	Common->iworksize = iworksize ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_work) (Common) ;
+	    return (FALSE) ;
+	}
+
+	/* note that Iwork does not need to be initialized */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Allocate Xwork (xworksize) and set it to ((double) 0.) */
+    /* ---------------------------------------------------------------------- */
+
+    /* make sure xworksize is >= 1 */
+    xworksize = MAX (1, xworksize) ;
+    if (xworksize > Common->xworksize)
+    {
+
+	if (Common->no_workspace_reallocate)
+	{
+	    /* CHOLMOD is not allowed to change the workspace here */
+	    Common->status = CHOLMOD_INVALID ;
+	    return (FALSE) ;
+	}
+
+	/* free the old workspace (if any) and allocate new space */
+	CHOLMOD(free) (Common->xworksize, sizeof (double), Common->Xwork,
+		Common) ;
+	Common->Xwork = CHOLMOD(malloc) (xworksize, sizeof (double), Common) ;
+
+	/* record the new size of Xwork */
+	Common->xworksize = xworksize ;
+
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free_work) (Common) ;
+	    return (FALSE) ;
+	}
+
+	/* initialize Xwork */
+	W = Common->Xwork ;
+	for (i = 0 ; i < (Int) xworksize ; i++)
+	{
+	    W [i] = 0. ;
+	}
+    }
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_work ==================================================== */
+/* ========================================================================== */
+
+/* Deallocate the CHOLMOD workspace.
+ *
+ * workspace: deallocates all workspace in Common
+ */
+
+int CHOLMOD(free_work)
+(
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->Flag  = CHOLMOD(free) (Common->nrow, sizeof (Int),
+	    Common->Flag, Common) ;
+    Common->Head  = CHOLMOD(free) (Common->nrow+1, sizeof (Int),
+	    Common->Head, Common) ;
+    Common->Iwork = CHOLMOD(free) (Common->iworksize, sizeof (Int),
+	    Common->Iwork, Common) ;
+    Common->Xwork = CHOLMOD(free) (Common->xworksize, sizeof (double),
+	    Common->Xwork, Common) ;
+    Common->nrow = 0 ;
+    Common->iworksize = 0 ;
+    Common->xworksize = 0 ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_clear_flag =================================================== */
+/* ========================================================================== */
+
+/* Increment mark to ensure Flag [0..nrow-1] < mark.  If integer overflow
+ * occurs, or mark was initially negative, reset the entire array.  This is
+ * not an error condition, but an intended function of the Flag workspace.
+ *
+ * workspace: Flag (nrow).  Does not modify Flag if nrow is zero.
+ */
+
+SuiteSparse_long CHOLMOD(clear_flag)
+(
+    cholmod_common *Common
+)
+{
+    Int i, nrow, *Flag ;
+
+    RETURN_IF_NULL_COMMON (-1) ;
+
+    Common->mark++ ;
+    if (Common->mark <= 0)
+    {
+	nrow = Common->nrow ;
+	Flag = Common->Flag ;
+	PRINT2 (("reset Flag: nrow "ID"\n", nrow)) ;
+	PRINT2 (("reset Flag: mark %ld\n", Common->mark)) ;
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Flag [i] = EMPTY ;
+	}
+	Common->mark = 0 ;
+    }
+    return (Common->mark) ;
+}
+
+
+/* ========================================================================== */
+/* ==== cholmod_maxrank ===================================================== */
+/* ========================================================================== */
+
+/* Find a valid value of Common->maxrank.  Returns 0 if error, or 2, 4, or 8
+ * if successful. */
+
+size_t CHOLMOD(maxrank)	/* returns validated value of Common->maxrank */
+(
+    /* ---- input ---- */
+    size_t n,		/* A and L will have n rows */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    size_t maxrank ;
+    RETURN_IF_NULL_COMMON (0) ;
+    maxrank = Common->maxrank ;
+    if (n > 0)
+    {
+	/* Ensure maxrank*n*sizeof(double) does not result in integer overflow.
+	 * If n is so large that 2*n*sizeof(double) results in integer overflow
+	 * (n = 268,435,455 if an Int is 32 bits), then maxrank will be 0 or 1,
+	 * but maxrank will be set to 2 below.  2*n will not result in integer
+	 * overflow, and CHOLMOD will run out of memory or safely detect integer
+	 * overflow elsewhere.
+	 */
+	maxrank = MIN (maxrank, Size_max / (n * sizeof (double))) ;
+    }
+    if (maxrank <= 2)
+    {
+	maxrank = 2 ;
+    }
+    else if (maxrank <= 4)
+    {
+	maxrank = 4 ;
+    }
+    else
+    {
+	maxrank = 8 ;
+    }
+    return (maxrank) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dbound ======================================================= */
+/* ========================================================================== */
+
+/* Ensure the absolute value of a diagonal entry, D (j,j), is greater than
+ * Common->dbound.  This routine is not meant for the user to call.  It is used
+ * by the various LDL' factorization and update/downdate routines.  The
+ * default value of Common->dbound is zero, and in that case this routine is not
+ * called at all.  No change is made if D (j,j) is NaN.  CHOLMOD does not call
+ * this routine if Common->dbound is NaN.
+ */
+
+double CHOLMOD(dbound)	/* returns modified diagonal entry of D */
+(
+    /* ---- input ---- */
+    double dj,		/* diagonal entry of D, for LDL' factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double dbound ;
+    RETURN_IF_NULL_COMMON (0) ;
+    if (!IS_NAN (dj))
+    {
+	dbound = Common->dbound ;
+	if (dj < 0)
+	{
+	    if (dj > -dbound)
+	    {
+		dj = -dbound ;
+		Common->ndbounds_hit++ ;
+		if (Common->status == CHOLMOD_OK)
+		{
+		    ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ;
+		}
+	    }
+	}
+	else
+	{
+	    if (dj < dbound)
+	    {
+		dj = dbound ;
+		Common->ndbounds_hit++ ;
+		if (Common->status == CHOLMOD_OK)
+		{
+		    ERROR (CHOLMOD_DSMALL, "diagonal below threshold") ;
+		}
+	    }
+	}
+    }
+    return (dj) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_complex.c b/src/CHOLMOD/Core/cholmod_complex.c
new file mode 100644
index 0000000..a9a853a
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_complex.c
@@ -0,0 +1,549 @@
+/* ========================================================================== */
+/* === Core/cholmod_complex ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* If you convert a matrix that contains uninitialized data, valgrind will
+ * complain.  This can occur in a factor L which has gaps (a partial
+ * factorization, or after updates that change the nonzero pattern), an
+ * unpacked sparse matrix, a dense matrix with leading dimension d > # of rows,
+ * or any matrix (dense, sparse, triplet, or factor) with more space allocated
+ * than is used.  You can safely ignore any of these complaints by valgrind. */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === cholmod_hypot ======================================================== */
+/* ========================================================================== */
+
+/* There is an equivalent routine called hypot in <math.h>, which conforms
+ * to ANSI C99.  However, CHOLMOD does not assume that ANSI C99 is available.
+ * You can use the ANSI C99 hypot routine with:
+ *
+ *	#include <math.h>
+ *	Common->hypotenuse = hypot ;
+ *
+ * Default value of the Common->hypotenuse pointer is cholmod_hypot.
+ *
+ * s = hypot (x,y) computes s = sqrt (x*x + y*y) but does so more accurately.
+ * The NaN cases for the double relops x >= y and x+y == x are safely ignored.
+ * 
+ * Source: Algorithm 312, "Absolute value and square root of a complex number,"
+ * P. Friedland, Comm. ACM, vol 10, no 10, October 1967, page 665.
+ */
+
+double CHOLMOD(hypot) (double x, double y)
+{
+    double s, r ;
+    x = fabs (x) ;
+    y = fabs (y) ;
+    if (x >= y)
+    {
+	if (x + y == x)
+	{
+	    s = x ;
+	}
+	else
+	{
+	    r = y / x ;
+	    s = x * sqrt (1.0 + r*r) ;
+	}
+    }
+    else
+    {
+	if (y + x == y)
+	{
+	    s = y ;
+	}
+	else
+	{
+	    r = x / y ;
+	    s = y * sqrt (1.0 + r*r) ;
+	}
+    } 
+    return (s) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_divcomplex =================================================== */
+/* ========================================================================== */
+
+/* c = a/b where c, a, and b are complex.  The real and imaginary parts are
+ * passed as separate arguments to this routine.  The NaN case is ignored
+ * for the double relop br >= bi.  Returns 1 if the denominator is zero,
+ * 0 otherwise.  Note that this return value is the single exception to the
+ * rule that all CHOLMOD routines that return int return TRUE if successful
+ * or FALSE otherise.
+ *
+ * This uses ACM Algo 116, by R. L. Smith, 1962, which tries to avoid
+ * underflow and overflow.
+ *
+ * c can be the same variable as a or b.
+ *
+ * Default value of the Common->complex_divide pointer is cholmod_divcomplex.
+ */
+
+int CHOLMOD(divcomplex)
+(
+    double ar, double ai,	/* real and imaginary parts of a */
+    double br, double bi,	/* real and imaginary parts of b */
+    double *cr, double *ci	/* real and imaginary parts of c */
+)
+{
+    double tr, ti, r, den ;
+    if (fabs (br) >= fabs (bi))
+    {
+	r = bi / br ;
+	den = br + r * bi ;
+	tr = (ar + ai * r) / den ;
+	ti = (ai - ar * r) / den ;
+    }
+    else
+    {
+	r = br / bi ;
+	den = r * br + bi ;
+	tr = (ar * r + ai) / den ;
+	ti = (ai * r - ar) / den ;
+    }
+    *cr = tr ;
+    *ci = ti ;
+    return (IS_ZERO (den)) ;
+}
+
+
+/* ========================================================================== */
+/* === change_complexity ==================================================== */
+/* ========================================================================== */
+
+/* X and Z represent an array of size nz, with numeric xtype given by xtype_in.
+ *
+ * If xtype_in is:
+ * CHOLMOD_PATTERN: X and Z must be NULL.
+ * CHOLMOD_REAL:    X is of size nz, Z must be NULL.
+ * CHOLMOD_COMPLEX: X is of size 2*nz, Z must be NULL.
+ * CHOLMOD_ZOMPLEX: X is of size nz, Z is of size nz.
+ *
+ * The array is changed into the numeric xtype given by xtype_out, with the
+ * same definitions of X and Z above.  Note that the input conditions, above,
+ * are not checked.  These are checked in the caller routine.
+ *
+ * Returns TRUE if successful, FALSE otherwise.  X and Z are not modified if
+ * not successful.
+ */
+
+static int change_complexity
+(
+    /* ---- input ---- */
+    Int nz,		/* size of X and/or Z */
+    int xtype_in,	/* xtype of X and Z on input */
+    int xtype_out,	/* requested xtype of X and Z on output */
+    int xtype1,		/* xtype_out must be in the range [xtype1 .. xtype2] */
+    int xtype2,
+    /* ---- in/out --- */
+    void **XX,		/* old X on input, new X on output */
+    void **ZZ,		/* old Z on input, new Z on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Xold, *Zold, *Xnew, *Znew ;
+    Int k ;
+    size_t nz2 ;
+
+    if (xtype_out < xtype1 || xtype_out > xtype2)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid xtype") ;
+	return (FALSE) ;
+    }
+
+    Common->status = CHOLMOD_OK ;
+    Xold = *XX ;
+    Zold = *ZZ ;
+
+    switch (xtype_in)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* converting from pattern */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_PATTERN:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* pattern -> real */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_REAL:
+		    /* allocate X and set to all ones */
+		    Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [k] = 1 ;
+		    }
+		    *XX = Xnew ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* pattern -> complex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_COMPLEX:
+		    /* allocate X and set to all ones */
+		    Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [2*k  ] = 1 ;
+			Xnew [2*k+1] = 0 ;
+		    }
+		    *XX = Xnew ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* pattern -> zomplex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_ZOMPLEX:
+		    /* allocate X and Z and set to all ones */
+		    Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			CHOLMOD(free) (nz, sizeof (double), Xnew, Common) ;
+			CHOLMOD(free) (nz, sizeof (double), Znew, Common) ;
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [k] = 1 ;
+			Znew [k] = 0 ;
+		    }
+		    *XX = Xnew ;
+		    *ZZ = Znew ;
+		    break ;
+	    }
+	    break ;
+
+	/* ------------------------------------------------------------------ */
+	/* converting from real */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_REAL:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* real -> pattern */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_PATTERN:
+		    /* free X */
+		    *XX = CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* real -> complex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_COMPLEX:
+		    /* allocate a new X and copy the old X */
+		    Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [2*k  ] = Xold [k] ;
+			Xnew [2*k+1] = 0 ;
+		    }
+		    CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    *XX = Xnew ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* real -> zomplex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_ZOMPLEX:
+		    /* allocate a new Z and set it to zero */
+		    Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Znew [k] = 0 ;
+		    }
+		    *ZZ = Znew ;
+		    break ;
+	    }
+	    break ;
+
+	/* ------------------------------------------------------------------ */
+	/* converting from complex */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_COMPLEX:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* complex -> pattern */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_PATTERN:
+		    /* free X */
+		    *XX = CHOLMOD(free) (nz, 2*sizeof (double), *XX, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* complex -> real */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_REAL:
+		    /* pack the real part of X, discarding the imaginary part */
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xold [k] = Xold [2*k] ;
+		    }
+		    /* shrink X in half (this cannot fail) */
+		    nz2 = 2*nz ;
+		    *XX = CHOLMOD(realloc) (nz, sizeof (double), *XX, &nz2,
+			    Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* complex -> zomplex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_ZOMPLEX:
+		    /* allocate X and Z and copy the old X into them */
+		    Xnew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    Znew = CHOLMOD(malloc) (nz, sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			CHOLMOD(free) (nz, sizeof (double), Xnew, Common) ;
+			CHOLMOD(free) (nz, sizeof (double), Znew, Common) ;
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [k] = Xold [2*k  ] ;
+			Znew [k] = Xold [2*k+1] ;
+		    }
+		    CHOLMOD(free) (nz, 2*sizeof (double), *XX, Common) ;
+		    *XX = Xnew ;
+		    *ZZ = Znew ;
+		    break ;
+	    }
+	    break ;
+
+	/* ------------------------------------------------------------------ */
+	/* converting from zomplex */
+	/* ------------------------------------------------------------------ */
+
+	case CHOLMOD_ZOMPLEX:
+
+	    switch (xtype_out)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* zomplex -> pattern */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_PATTERN:
+		    /* free X and Z */
+		    *XX = CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    *ZZ = CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* zomplex -> real */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_REAL:
+		    /* free the imaginary part */
+		    *ZZ = CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ;
+		    break ;
+
+		/* ---------------------------------------------------------- */
+		/* zomplex -> complex */
+		/* ---------------------------------------------------------- */
+
+		case CHOLMOD_COMPLEX:
+		    Xnew = CHOLMOD(malloc) (nz, 2*sizeof (double), Common) ;
+		    if (Common->status < CHOLMOD_OK)
+		    {
+			return (FALSE) ;
+		    }
+		    for (k = 0 ; k < nz ; k++)
+		    {
+			Xnew [2*k  ] = Xold [k] ;
+			Xnew [2*k+1] = Zold [k] ;
+		    }
+		    CHOLMOD(free) (nz, sizeof (double), *XX, Common) ;
+		    CHOLMOD(free) (nz, sizeof (double), *ZZ, Common) ;
+		    *XX = Xnew ;
+		    *ZZ = NULL ;
+		    break ;
+
+	    }
+	    break ;
+    }
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sparse_xtype ================================================= */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a sparse matrix.  Supports any type on input
+ * and output (pattern, real, complex, or zomplex). */
+
+int CHOLMOD(sparse_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* sparse matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+
+    ok = change_complexity (A->nzmax, A->xtype, to_xtype,
+	    CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, &(A->x), &(A->z), Common) ;
+    if (ok)
+    {
+	A->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_triplet_xtype ================================================ */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a triplet matrix.  Supports any type on input
+ * and output (pattern, real, complex, or zomplex). */
+
+int CHOLMOD(triplet_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (T, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    ok = change_complexity (T->nzmax, T->xtype, to_xtype,
+	    CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, &(T->x), &(T->z), Common) ;
+    if (ok)
+    {
+	T->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dense_xtype ================================================= */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a dense matrix.  Supports real, complex or
+ * zomplex on input and output */
+
+int CHOLMOD(dense_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_dense *X,	/* dense matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    ok = change_complexity (X->nzmax, X->xtype, to_xtype,
+	    CHOLMOD_REAL, CHOLMOD_ZOMPLEX, &(X->x), &(X->z), Common) ;
+    if (ok)
+    {
+	X->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_factor_xtype ================================================= */
+/* ========================================================================== */
+
+/* Change the numeric xtype of a factor.  Supports real, complex or zomplex on
+ * input and output.   Supernodal zomplex factors are not supported. */
+
+int CHOLMOD(factor_xtype)
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to change */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int ok ;
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (L->is_super &&
+	    (L->xtype == CHOLMOD_ZOMPLEX || to_xtype == CHOLMOD_ZOMPLEX))
+    {
+	ERROR (CHOLMOD_INVALID, "invalid xtype for supernodal L") ;
+	return (FALSE) ;
+    }
+    ok = change_complexity ((L->is_super ? L->xsize : L->nzmax), L->xtype,
+	    to_xtype, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, &(L->x), &(L->z), Common) ;
+    if (ok)
+    {
+	L->xtype = to_xtype ;
+    }
+    return (ok) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_copy.c b/src/CHOLMOD/Core/cholmod_copy.c
new file mode 100644
index 0000000..9ceb394
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_copy.c
@@ -0,0 +1,406 @@
+/* ========================================================================== */
+/* === Core/cholmod_copy ==================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* C = A, which allocates C and copies A into C, with possible change of
+ * stype.  The diagonal can optionally be removed.  The numerical entries
+ * can optionally be copied.  This routine differs from cholmod_copy_sparse,
+ * which makes an exact copy of a sparse matrix.
+ *
+ * A can be of any type (packed/unpacked, upper/lower/unsymmetric).  C is
+ * packed and can be of any stype (upper/lower/unsymmetric), except that if
+ * A is rectangular C can only be unsymmetric.  If the stype of A and C
+ * differ, then the appropriate conversion is made.
+ *
+ * Symmetry of A (A->stype):
+ * <0: lower: assume A is symmetric with just tril(A); the rest of A is ignored
+ *  0  unsym: assume A is unsymmetric; consider all entries in A
+ * >0  upper: assume A is symmetric with just triu(A); the rest of A is ignored
+ *
+ * Symmetry of C (stype parameter):
+ * <0  lower: return just tril(C)
+ *  0  unsym: return all of C
+ * >0  upper: return just triu(C)
+ *
+ * In MATLAB:					    Using cholmod_copy:
+ * ----------					    ----------------------------
+ * C = A ;					    A unsymmetric, C unsymmetric
+ * C = tril (A) ;				    A unsymmetric, C lower
+ * C = triu (A) ;				    A unsymmetric, C upper
+ * U = triu (A) ; L = tril (U',-1) ; C = L+U ;	    A upper, C unsymmetric
+ * C = triu (A)' ;				    A upper, C lower
+ * C = triu (A) ;				    A upper, C upper
+ * L = tril (A) ; U = triu (L',1) ; C = L+U ;	    A lower, C unsymmetric
+ * C = tril (A) ;				    A lower, C lower
+ * C = tril (A)' ;				    A lower, C upper
+ *
+ * workspace: Iwork (max (nrow,ncol))
+ *
+ * A can have an xtype of pattern or real.  Complex and zomplex cases only
+ * supported when mode <= 0 (in which case the numerical values are ignored).
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === copy_sym_to_unsym ==================================================== */
+/* ========================================================================== */
+
+/* Construct an unsymmetric copy of a symmetric sparse matrix.  This does the
+ * work for as C = cholmod_copy (A, 0, mode, Common) when A is symmetric.
+ * In this case, extra space can be added to C.
+ */
+
+static cholmod_sparse *copy_sym_to_unsym
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag)
+			 * -2: pattern only, no diagonal, add 50% + n extra
+			 * space to C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double aij ;
+    double *Ax, *Cx ;
+    Int *Ap, *Ai, *Anz, *Cp, *Ci, *Wj, *Iwork ;
+    cholmod_sparse *C ;
+    Int nrow, ncol, nz, packed, j, p, pend, i, pc, up, lo, values, diag,
+	astype, extra ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    packed = A->packed ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    diag = (mode >= 0) ;
+
+    astype = SIGN (A->stype) ;
+    up = (astype > 0) ;
+    lo = (astype < 0) ;
+    ASSERT (astype != 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* create an unsymmetric copy of a symmetric matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wj = Iwork ;		    /* size ncol (i/i/l) */
+
+    /* In MATLAB notation, for converting a symmetric/upper matrix:
+     *	U = triu (A) ;
+     *	L = tril (U',-1) ;
+     *	C = L + U ;
+     *
+     * For converting a symmetric/lower matrix to unsymmetric:
+     *	L = tril (A) ;
+     *	U = triu (L',1) ;
+     *	C = L + U ;
+     */
+    ASSERT (up || lo) ;
+    PRINT1 (("copy: convert symmetric to unsym\n")) ;
+
+    /* count the number of entries in each column of C */
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Wj [j] = 0 ;
+    }
+    for (j = 0 ; j < ncol ; j++)
+    {
+	p = Ap [j] ;
+	pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Ai [p] ;
+	    if (i == j)
+	    {
+		/* the diagonal entry A(i,i) will appear just once
+		 * (unless it is excluded with mode < 0) */
+		if (diag)
+		{
+		    Wj [j]++ ;
+		}
+	    }
+	    else if ((up && i < j) || (lo && i > j))
+	    {
+		/* upper case:  A(i,j) is in the strictly upper part;
+		 * A(j,i) will be added to the strictly lower part of C.
+		 * lower case is the opposite. */
+		Wj [j]++ ;
+		Wj [i]++ ;
+	    }
+	}
+    }
+    nz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	nz += Wj [j] ;
+    }
+
+    extra = (mode == -2) ? (nz/2 + ncol) : 0 ;
+
+    /* allocate C.  C is sorted if and only if A is sorted */
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nz + extra, A->sorted, TRUE, 0,
+	    values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* construct the column pointers for C */
+    p = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Cp [j] = p ;
+	p += Wj [j] ;
+    }
+    Cp [ncol] = p ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Wj [j] = Cp [j] ;
+    }
+
+    /* construct C */
+    if (values)
+    {
+
+	/* pattern and values */
+	ASSERT (diag) ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		aij = Ax [p] ;
+		if (i == j)
+		{
+		    /* add diagonal entry A(i,i) to column i */
+		    pc = Wj [i]++ ;
+		    Ci [pc] = i ;
+		    Cx [pc] = aij ;
+		}
+		else if ((up && i < j) || (lo && i > j))
+		{
+		    /* add A(i,j) to column j */
+		    pc = Wj [j]++ ;
+		    Ci [pc] = i ;
+		    Cx [pc] = aij ;
+		    /* add A(j,i) to column i */
+		    pc = Wj [i]++ ;
+		    Ci [pc] = j ;
+		    Cx [pc] = aij ;
+		}
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* pattern only, possibly excluding the diagonal */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i == j)
+		{
+		    /* add diagonal entry A(i,i) to column i
+		     * (unless it is excluded with mode < 0) */
+		    if (diag)
+		    {
+			Ci [Wj [i]++] = i ;
+		    }
+		}
+		else if ((up && i < j) || (lo && i > j))
+		{
+		    /* add A(i,j) to column j */
+		    Ci [Wj [j]++] = i ;
+		    /* add A(j,i) to column i */
+		    Ci [Wj [i]++] = j ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (i = CHOLMOD(dump_sparse) (C, "copy_sym_to_unsym", Common)) ;
+    PRINT1 (("mode %d nnzdiag "ID"\n", mode, i)) ;
+    ASSERT (IMPLIES (mode < 0, i == 0)) ;
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy ========================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(copy)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    int stype,		/* requested stype of C */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *C ;
+    Int nrow, ncol, up, lo, values, diag, astype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (mode > 0) && (A->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    if ((stype || A->stype) && nrow != ncol)
+    {
+	/* inputs invalid */
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    diag = (mode >= 0) ;
+    astype = SIGN (A->stype) ;
+    stype = SIGN (stype) ;
+    up = (astype > 0) ;
+    lo = (astype < 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (astype == stype)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* symmetry of A and C are the same */
+	/* ------------------------------------------------------------------ */
+
+	/* copy A into C, keeping the same symmetry.  If A is symmetric
+	 * entries in the ignored part of A are not copied into C */
+	C = CHOLMOD(band) (A, -nrow, ncol, mode, Common) ;
+
+    }
+    else if (!astype)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert unsymmetric matrix A into a symmetric matrix C */
+	/* ------------------------------------------------------------------ */
+
+	if (stype > 0)
+	{
+	    /* C = triu (A) */
+	    C = CHOLMOD(band) (A, 0, ncol, mode, Common) ;
+	}
+	else
+	{
+	    /* C = tril (A) */
+	    C = CHOLMOD(band) (A, -nrow, 0, mode, Common) ;
+	}
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (NULL) ;
+	}
+	C->stype = stype ;
+
+    }
+    else if (astype == -stype)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* transpose a symmetric matrix */
+	/* ------------------------------------------------------------------ */
+
+	/* converting upper to lower or lower to upper */
+	/* workspace: Iwork (nrow) */
+	C = CHOLMOD(transpose) (A, values, Common) ;
+	if (!diag)
+	{
+	    /* remove diagonal, if requested */
+	    CHOLMOD(band_inplace) (-nrow, ncol, -1, C, Common) ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* create an unsymmetric copy of a symmetric matrix */
+	/* ------------------------------------------------------------------ */
+
+	C = copy_sym_to_unsym (A, mode, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return if error */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (diag = CHOLMOD(dump_sparse) (C, "copy", Common)) ;
+    PRINT1 (("mode %d nnzdiag "ID"\n", mode, diag)) ;
+    ASSERT (IMPLIES (mode < 0, diag == 0)) ;
+    return (C) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_dense.c b/src/CHOLMOD/Core/cholmod_dense.c
new file mode 100644
index 0000000..250b596
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_dense.c
@@ -0,0 +1,701 @@
+/* ========================================================================== */
+/* === Core/cholmod_dense =================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2013,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_dense object:
+ *
+ * The solve routines and some of the MatrixOps and Modify routines use dense
+ * matrices as inputs.  These are held in column-major order.  With a leading
+ * dimension of d, the entry in row i and column j is held in x [i+j*d].
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_allocate_dense	allocate a dense matrix
+ * cholmod_free_dense		free a dense matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_zeros		allocate a dense matrix of all zeros
+ * cholmod_ones			allocate a dense matrix of all ones
+ * cholmod_eye			allocate a dense identity matrix 
+ * cholmod_sparse_to_dense	create a dense matrix copy of a sparse matrix
+ * cholmod_dense_to_sparse	create a sparse matrix copy of a dense matrix
+ * cholmod_copy_dense		create a copy of a dense matrix
+ * cholmod_copy_dense2		copy a dense matrix (pre-allocated)
+ *
+ * All routines in this file can handle the real, complex, and zomplex cases.
+ * Pattern-only dense matrices are not supported.  cholmod_sparse_to_dense can
+ * take a pattern-only input sparse matrix, however, and cholmod_dense_to_sparse
+ * can generate a pattern-only output sparse matrix.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define PATTERN
+#include "t_cholmod_dense.c"
+#define REAL
+#include "t_cholmod_dense.c"
+#define COMPLEX
+#include "t_cholmod_dense.c"
+#define ZOMPLEX
+#include "t_cholmod_dense.c"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_dense =============================================== */
+/* ========================================================================== */
+
+/* Allocate a dense matrix with leading dimension d.  The space is not
+ * initialized.
+ */
+
+cholmod_dense *CHOLMOD(allocate_dense)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    size_t d,		/* leading dimension */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    size_t nzmax, nzmax0 ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (d < nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "leading dimension invalid") ;
+	return (NULL) ;
+    }
+    if (xtype < CHOLMOD_REAL || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (NULL) ;
+    }
+
+    /* ensure the dimensions do not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ;
+
+    /* nzmax = MAX (1, d*ncol) ; */
+    nzmax = CHOLMOD(mult_size_t) (d, ncol, &ok) ;
+    nzmax = MAX (1, nzmax) ;
+
+    if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate header */
+    /* ---------------------------------------------------------------------- */
+
+    X = CHOLMOD(malloc) (sizeof (cholmod_dense), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    PRINT1 (("cholmod_allocate_dense %d-by-%d nzmax %d xtype %d\n",
+		nrow, ncol, nzmax, xtype)) ;
+
+    X->nrow = nrow ;
+    X->ncol = ncol ;
+    X->nzmax = nzmax ;
+    X->xtype = xtype ;
+    X->dtype = DTYPE ;
+    X->x = NULL ;
+    X->z = NULL ;
+    X->d = d ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix itself */
+    /* ---------------------------------------------------------------------- */
+
+    nzmax0 = 0 ;
+    CHOLMOD(realloc_multiple) (nzmax, 0, xtype, NULL, NULL, &(X->x), &(X->z),
+	    &nzmax0, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_dense) (&X, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_zeros ======================================================== */
+/* ========================================================================== */
+
+/* Allocate a dense matrix and set it to zero */
+
+cholmod_dense *CHOLMOD(zeros)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    double *Xx, *Xz ;
+    Int i, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a dense matrix and set it to zero */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    X = CHOLMOD(allocate_dense) (nrow, ncol, nrow, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* NULL Common, out of memory, or inputs invalid */
+    }
+
+    Xx = X->x ;
+    Xz = X->z ;
+    nz = MAX (1, X->nzmax) ;
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (i = 0 ; i < 2*nz ; i++)
+	    {
+		Xx [i] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 0 ;
+	    }
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xz [i] = 0 ;
+	    }
+	    break ;
+    }
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_ones ========================================================= */
+/* ========================================================================== */
+
+/* Allocate a dense matrix and set it to zero */
+
+cholmod_dense *CHOLMOD(ones)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    double *Xx, *Xz ;
+    Int i, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a dense matrix and set it to all ones */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    X = CHOLMOD(allocate_dense) (nrow, ncol, nrow, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* NULL Common, out of memory, or inputs invalid */
+    }
+
+    Xx = X->x ;
+    Xz = X->z ;
+    nz = MAX (1, X->nzmax) ;
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 1 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [2*i  ] = 1 ;
+		Xx [2*i+1] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xx [i] = 1 ;
+	    }
+	    for (i = 0 ; i < nz ; i++)
+	    {
+		Xz [i] = 0 ;
+	    }
+	    break ;
+    }
+
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_eye ========================================================== */
+/* ========================================================================== */
+
+/* Allocate a dense matrix and set it to the identity matrix */
+
+cholmod_dense *CHOLMOD(eye)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+    double *Xx, *Xz ;
+    Int i, n, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a dense matrix and set it to the identity matrix */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    X = CHOLMOD(zeros) (nrow, ncol, xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* NULL Common, out of memory, or inputs invalid */
+    }
+
+    nz = MAX (1, nrow*ncol) ;
+    Xx = X->x ;
+    Xz = X->z ;
+
+    n = MIN (nrow, ncol) ;
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	case CHOLMOD_ZOMPLEX:
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [i + i*nrow] = 1 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (i = 0 ; i < n ; i++)
+	    {
+		Xx [2 * (i + i*nrow)] = 1 ;
+	    }
+	    break ;
+    }
+
+    return (X) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_free_dense =================================================== */
+/* ========================================================================== */
+
+/* free a dense matrix
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_dense)
+(
+    /* ---- in/out --- */
+    cholmod_dense **XHandle,	/* dense matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (XHandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    X = *XHandle ;
+    if (X == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_REAL:
+	    X->x = CHOLMOD(free) (X->nzmax, sizeof (double), X->x, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    X->x = CHOLMOD(free) (X->nzmax, 2*sizeof (double), X->x, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    X->x = CHOLMOD(free) (X->nzmax, sizeof (double), X->x, Common) ;
+	    X->z = CHOLMOD(free) (X->nzmax, sizeof (double), X->z, Common) ;
+	    break ;
+    }
+
+    *XHandle = CHOLMOD(free) (1, sizeof (cholmod_dense), (*XHandle), Common) ;
+    return (TRUE) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_ensure_dense ================================================= */
+/* ========================================================================== */
+
+/* Ensure that the input matrix has a certain size and type.  If not, free
+ * the existing matrix and reallocate one of the right size and type.
+ * Returns a pointer to the cholmod_dense matrix, possibly reallocated.
+ * Also modifies the input matrix handle, XHandle, if necessary.
+ */
+
+cholmod_dense *CHOLMOD(ensure_dense)
+(
+    /* ---- input/output ---- */
+    cholmod_dense **XHandle,    /* matrix handle to check */
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    size_t d,		/* leading dimension */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (XHandle == NULL)
+    {
+        ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+        return (NULL) ;
+    }
+
+    X = *XHandle ;
+    if (X == NULL || X->nrow != nrow || X->ncol != ncol
+        || X->d != d || X->xtype != xtype)
+    {
+        /* Matrix X is not allocated, or has the wrong size.  Free it and
+         * reallocate it in the right size and shape.  If an error occurs
+         * (out of memory or inputs nrow, etc invalid), then the error is
+         * set in cholmod_allocate_dense and X is returned as NULL. */
+#if 0
+        if (X == NULL)
+        {
+            printf ("oops, X was null\n") ;
+        }
+        else
+        {
+            printf ("oops, nrow %g %g ncol %g %g d %g %g xtype %g %g\n",
+                (double) X->nrow, (double) nrow,
+                (double) X->ncol, (double) ncol,
+                (double) X->d, (double) d,
+                (double) X->xtype, (double) xtype
+                ) ;
+        }
+#endif
+        CHOLMOD(free_dense) (XHandle, Common) ;
+        X = CHOLMOD(allocate_dense) (nrow, ncol, d, xtype, Common) ;
+        *XHandle = X ;
+    }
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sparse_to_dense ============================================== */
+/* ========================================================================== */
+
+/* Convert a sparse matrix to a dense matrix.
+ * The output dense matrix has the same xtype as the input sparse matrix,
+ * except that a pattern-only sparse matrix A is converted into a real dense
+ * matrix X, with 1's and 0's.  All xtypes are supported.
+ */
+
+cholmod_dense *CHOLMOD(sparse_to_dense)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *X = NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype && A->nrow != A->ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    X = p_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    X = r_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    X = c_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    X = z_cholmod_sparse_to_dense (A, Common) ;
+	    break ;
+    }
+    return (X) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_dense_to_sparse ============================================== */
+/* ========================================================================== */
+
+/* Convert a dense matrix to a sparse matrix, similar to the MATLAB statements:
+ *
+ * C = sparse (X)			values = TRUE
+ * C = spones (sparse (X))		values = FALSE
+ *
+ * except that X must be double (it can be of many different types in MATLAB)
+ *
+ * The resulting sparse matrix C has the same numeric xtype as the input dense
+ * matrix X, unless "values" is FALSE (in which case C is real, where C(i,j)=1
+ * if (i,j) is an entry in X.
+ */
+
+cholmod_sparse *CHOLMOD(dense_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    int values,		/* TRUE if values to be copied, FALSE otherwise */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *C = NULL ;
+
+    DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (X, NULL) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    if (X->d < X->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_REAL:
+	    C = r_cholmod_dense_to_sparse (X, values, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    C = c_cholmod_dense_to_sparse (X, values, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    C = z_cholmod_dense_to_sparse (X, values, Common) ;
+	    break ;
+    }
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_dense2 ================================================== */
+/* ========================================================================== */
+
+/* Y = X, where X and Y are both already allocated.  The leading dimensions of
+ * X and Y may differ, but both must be >= the # of rows in X and Y.
+ * Entries in rows nrow to d-1 are not copied from X, since the space might not
+ * be initialized.  Y->nzmax is unchanged.  X->nzmax is typically
+ * (X->d)*(X->ncol), but a user might modify that condition outside of any
+ * CHOLMOD routine.
+ *
+ * The two dense matrices X and Y must have the same numeric xtype.
+ */
+
+int CHOLMOD(copy_dense2)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* ---- output --- */
+    cholmod_dense *Y,	/* copy of matrix X */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (Y, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (Y, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (X->nrow != Y->nrow || X->ncol != Y->ncol || X->xtype != Y->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "X and Y must have same dimensions and xtype") ;
+	return (FALSE) ;
+    }
+    if (X->d < X->nrow || Y->d < Y->nrow
+	    || (X->d * X->ncol) > X->nzmax || (Y->d * Y->ncol) > Y->nzmax)
+    {
+	ERROR (CHOLMOD_INVALID, "X and/or Y invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (X->xtype)
+    {
+	case CHOLMOD_REAL:
+	    r_cholmod_copy_dense2 (X, Y) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_cholmod_copy_dense2 (X, Y) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    z_cholmod_copy_dense2 (X, Y) ;
+	    break ;
+    }
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_dense =================================================== */
+/* ========================================================================== */
+
+/* Y = X, copy a dense matrix */
+
+cholmod_dense *CHOLMOD(copy_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *Y ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (X, NULL) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate result */
+    /* ---------------------------------------------------------------------- */
+
+    Y = CHOLMOD(allocate_dense) (X->nrow, X->ncol, X->d, X->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory or X invalid */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = X */
+    /* ---------------------------------------------------------------------- */
+
+    /* This cannot fail (X and Y are allocated, and have the same nrow, ncol
+     * d, and xtype) */
+    CHOLMOD(copy_dense2) (X, Y, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    return (Y) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_error.c b/src/CHOLMOD/Core/cholmod_error.c
new file mode 100644
index 0000000..b8f4d67
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_error.c
@@ -0,0 +1,79 @@
+/* ========================================================================== */
+/* === Core/cholmod_error =================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD error-handling routine.  */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* ==== cholmod_error ======================================================= */
+/* ========================================================================== */
+
+/* An error has occurred.  Set the status, optionally print an error message,
+ * and call the user error-handling routine (if it exists).  If
+ * Common->try_catch is TRUE, then CHOLMOD is inside a try/catch block.
+ * The status is set, but no message is printed and the user error handler
+ * is not called.  This is not (yet) an error, since CHOLMOD may recover.
+ *
+ * In the current version, this try/catch mechanism is used internally only in
+ * cholmod_analyze, which tries multiple ordering methods and picks the best
+ * one.  If one or more ordering method fails, it keeps going.  Only one
+ * ordering needs to succeed for cholmod_analyze to succeed.
+ */
+
+int CHOLMOD(error)
+(
+    /* ---- input ---- */
+    int status,		/* error status */
+    const char *file,	/* name of source code file where error occured */ 
+    int line,		/* line number in source code file where error occured*/
+    const char *message,    /* error message */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    Common->status = status ;
+
+    if (!(Common->try_catch))
+    {
+
+#ifndef NPRINT
+	/* print a warning or error message */
+	if (Common->print_function != NULL)
+	{
+	    if (status > 0 && Common->print > 1)
+	    {
+		(Common->print_function) ("CHOLMOD warning: %s\n", message) ;
+		fflush (stdout) ;
+		fflush (stderr) ;
+	    }
+	    else if (Common->print > 0)
+	    {
+		(Common->print_function) ("CHOLMOD error: %s\n", message) ;
+		fflush (stdout) ;
+		fflush (stderr) ;
+	    }
+	}
+#endif
+
+	/* call the user error handler, if it exists */
+	if (Common->error_handler != NULL)
+	{
+	    Common->error_handler (status, file, line, message) ;
+	}
+    }
+
+    return (TRUE) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_factor.c b/src/CHOLMOD/Core/cholmod_factor.c
new file mode 100644
index 0000000..3ba3be3
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_factor.c
@@ -0,0 +1,936 @@
+/* ========================================================================== */
+/* === Core/cholmod_factor ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2013,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_factor object:
+ *
+ * The data structure for an LL' or LDL' factorization is too complex to
+ * describe in one sentence.  This object can hold the symbolic analysis alone,
+ * or in combination with a "simplicial" (similar to a sparse matrix) or
+ * "supernodal" form of the numerical factorization.  Only the routine to free
+ * a factor is primary, since a factor object is created by the factorization
+ * routine (cholmod_factorize).  It must be freed with cholmod_free_factor.
+ *
+ * Primary routine:
+ * ----------------
+ * cholmod_free_factor		free a factor
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_allocate_factor	allocate a symbolic factor (LL' or LDL')
+ * cholmod_reallocate_factor	change the # entries in a factor 
+ * cholmod_change_factor	change the type of factor (e.g., LDL' to LL')
+ * cholmod_pack_factor		pack the columns of a factor
+ * cholmod_reallocate_column	resize a single column of a factor
+ * cholmod_factor_to_sparse	create a sparse matrix copy of a factor
+ * cholmod_copy_factor		create a copy of a factor
+ *
+ * Note that there is no cholmod_sparse_to_factor routine to create a factor
+ * as a copy of a sparse matrix.  It could be done, after a fashion, but a
+ * lower triangular sparse matrix would not necessarily have a chordal graph,
+ * which would break the many CHOLMOD routines that rely on this property.
+ *
+ * The cholmod_factor_to_sparse routine is provided so that matrix operations
+ * in the MatrixOps module may be applied to L.  Those operations operate on
+ * cholmod_sparse objects, and they are not guaranteed to maintain the chordal
+ * property of L.  Such a modified L cannot be safely converted back to a
+ * cholmod_factor object.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_factor ============================================== */
+/* ========================================================================== */
+
+/* Allocate a simplicial symbolic factor, with L->Perm and L->ColCount allocated
+ * and initialized to "empty" values (Perm [k] = k, and ColCount[k] = 1).
+ * The integer and numerical parts of L are not allocated.  L->xtype is returned
+ * as CHOLMOD_PATTERN and L->is_super are returned as FALSE.  L->is_ll is also
+ * returned FALSE, but this may be modified when the matrix is factorized.
+ *
+ * This is sufficient (but far from ideal) for input to cholmod_factorize,
+ * since the simplicial LL' or LDL' factorization (cholmod_rowfac) can
+ * reallocate the columns of L as needed.  The primary purpose of this routine
+ * is to allocate space for a symbolic factorization, for the "expert" user to
+ * do his or her own symbolic analysis.  The typical user should use
+ * cholmod_analyze instead of this routine.
+ *
+ * workspace: none
+ */
+
+cholmod_factor *CHOLMOD(allocate_factor)
+(
+    /* ---- input ---- */
+    size_t n,		/* L is n-by-n */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int j ;
+    Int *Perm, *ColCount ;
+    cholmod_factor *L ;
+    int ok = TRUE ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ensure the dimension does not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (n, 2, &ok) ;
+    if (!ok || n > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    L = CHOLMOD(malloc) (sizeof (cholmod_factor), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    L->n = n ;
+    L->is_ll = FALSE ;
+    L->is_super = FALSE ;
+    L->is_monotonic = TRUE ;
+    L->itype = ITYPE ;
+    L->xtype = CHOLMOD_PATTERN ;
+    L->dtype = DTYPE ;
+
+    /* allocate the purely symbolic part of L */
+    L->ordering = CHOLMOD_NATURAL ;
+    L->Perm = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+    L->IPerm = NULL ;       /* only created by cholmod_solve2 when needed */
+    L->ColCount = CHOLMOD(malloc) (n, sizeof (Int), Common) ;
+
+    /* simplicial part of L is empty */
+    L->nzmax = 0 ;
+    L->p = NULL ;
+    L->i = NULL ;
+    L->x = NULL ;
+    L->z = NULL ;
+    L->nz = NULL ;
+    L->next = NULL ;
+    L->prev = NULL ;
+
+    /* supernodal part of L is also empty */
+    L->nsuper = 0 ;
+    L->ssize = 0 ;
+    L->xsize = 0 ;
+    L->maxesize = 0 ;
+    L->maxcsize = 0 ;
+    L->super = NULL ;
+    L->pi = NULL ;
+    L->px = NULL ;
+    L->s = NULL ;
+
+    /* L has not been factorized */
+    L->minor = n ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_factor) (&L, Common) ;
+	return (NULL) ;		/* out of memory */
+    }
+
+    /* initialize Perm and ColCount */
+    Perm = L->Perm ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	Perm [j] = j ;
+    }
+    ColCount = L->ColCount ;
+    for (j = 0 ; j < ((Int) n) ; j++)
+    {
+	ColCount [j] = 1 ;
+    }
+
+    return (L) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_factor ================================================== */
+/* ========================================================================== */
+
+/* Free a factor object.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_factor)
+(
+    /* ---- in/out --- */
+    cholmod_factor **LHandle,	/* factor to free, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int n, lnz, xs, ss, s ;
+    cholmod_factor *L ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (LHandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    L = *LHandle ;
+    if (L == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    n = L->n ;
+    lnz = L->nzmax ;
+    s = L->nsuper + 1 ;
+    xs = (L->is_super) ? ((Int) (L->xsize)) : (lnz) ;
+    ss = L->ssize ;
+
+    /* symbolic part of L */
+    CHOLMOD(free) (n,   sizeof (Int), L->Perm,     Common) ;
+    CHOLMOD(free) (n,   sizeof (Int), L->IPerm,    Common) ;
+    CHOLMOD(free) (n,   sizeof (Int), L->ColCount, Common) ;
+
+    /* simplicial form of L */
+    CHOLMOD(free) (n+1, sizeof (Int), L->p,        Common) ;
+    CHOLMOD(free) (lnz, sizeof (Int), L->i,        Common) ;
+    CHOLMOD(free) (n,   sizeof (Int), L->nz,       Common) ;
+    CHOLMOD(free) (n+2, sizeof (Int), L->next,     Common) ;
+    CHOLMOD(free) (n+2, sizeof (Int), L->prev,     Common) ;
+
+    /* supernodal form of L */
+    CHOLMOD(free) (s,   sizeof (Int), L->pi,       Common) ;
+    CHOLMOD(free) (s,   sizeof (Int), L->px,       Common) ;
+    CHOLMOD(free) (s,   sizeof (Int), L->super,    Common) ;
+    CHOLMOD(free) (ss,  sizeof (Int), L->s,        Common) ;
+
+    /* numerical values for both simplicial and supernodal L */
+    if (L->xtype == CHOLMOD_REAL)
+    {
+	CHOLMOD(free) (xs, sizeof (double), L->x, Common) ;
+    }
+    else if (L->xtype == CHOLMOD_COMPLEX)
+    {
+	CHOLMOD(free) (xs, 2*sizeof (double), L->x, Common) ;
+    }
+    else if (L->xtype == CHOLMOD_ZOMPLEX)
+    {
+	CHOLMOD(free) (xs, sizeof (double), L->x, Common) ;
+	CHOLMOD(free) (xs, sizeof (double), L->z, Common) ;
+    }
+
+    *LHandle = CHOLMOD(free) (1, sizeof (cholmod_factor), (*LHandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_factor ============================================ */
+/* ========================================================================== */
+
+/* Change the size of L->i and L->x, or allocate them if their current size
+ * is zero.  L must be simplicial.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_factor)
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    PRINT1 (("realloc factor: xtype %d\n", L->xtype)) ;
+    if (L->is_super)
+    {
+	/* L must be simplicial, and not symbolic */
+	ERROR (CHOLMOD_INVALID, "L invalid") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    PRINT1 (("realloc factor %g to %g\n", (double) L->nzmax, (double) nznew)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* resize (or allocate) the L->i and L->x components of the factor */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(realloc_multiple) (nznew, 1, L->xtype, &(L->i), NULL,
+	    &(L->x), &(L->z), &(L->nzmax), Common) ;
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_column =========================================== */
+/* ========================================================================== */
+
+/* Column j needs more space, reallocate it at the end of L->i and L->x.
+ * If the reallocation fails, the factor is converted to a simplicial
+ * symbolic factor (no pattern, just L->Perm and L->ColCount).
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_column)
+(
+    /* ---- input ---- */
+    size_t j,		/* the column to reallocate */
+    size_t need,	/* required size of column j */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double xneed ;
+    double *Lx, *Lz ;
+    Int *Lp, *Lprev, *Lnext, *Li, *Lnz ;
+    Int n, pold, pnew, len, k, tail ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (L->is_super)
+    {
+	ERROR (CHOLMOD_INVALID, "L must be simplicial") ;
+	return (FALSE) ;
+    }
+    n = L->n ;
+    if (j >= L->n || need == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "j invalid") ;
+	return (FALSE) ;	    /* j out of range */
+    }
+    Common->status = CHOLMOD_OK ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "start colrealloc", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* increase the size of L if needed */
+    /* ---------------------------------------------------------------------- */
+
+    /* head = n+1 ; */
+    tail = n ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+    Lprev = L->prev ;
+    Lnext = L->next ;
+
+    ASSERT (Lnz != NULL) ;
+    ASSERT (Lnext != NULL && Lprev != NULL) ;
+    PRINT1 (("col %g need %g\n", (double) j, (double) need)) ;
+
+    /* column j cannot have more than n-j entries if all entries are present */
+    need = MIN (need, n-j) ;
+
+    /* compute need in double to avoid integer overflow */
+    if (Common->grow1 >= 1.0)
+    {
+	xneed = (double) need ;
+	xneed = Common->grow1 * xneed + Common->grow2 ;
+	xneed = MIN (xneed, n-j) ;
+	need = (Int) xneed ;
+    }
+    PRINT1 (("really new need %g current %g\n", (double) need,
+	    (double) (Lp [Lnext [j]] - Lp [j]))) ;
+    ASSERT (need >= 1 && need <= n-j) ;
+
+    if (Lp [Lnext [j]] - Lp [j] >= (Int) need)
+    {
+	/* no need to reallocate the column, it's already big enough */
+	PRINT1 (("colrealloc: quick return %g %g\n",
+	    (double) (Lp [Lnext [j]] - Lp [j]), (double) need)) ;
+	return (TRUE) ;
+
+    }
+
+    if (Lp [tail] + need > L->nzmax)
+    {
+	/* use double to avoid integer overflow */
+	xneed = (double) need ;
+	if (Common->grow0 < 1.2)	    /* fl. pt. compare, false if NaN */
+	{
+	    /* if grow0 is less than 1.2 or NaN, don't use it */
+	    xneed = 1.2 * (((double) L->nzmax) + xneed + 1) ;
+	}
+	else
+	{
+	    xneed = Common->grow0 * (((double) L->nzmax) + xneed + 1) ;
+	}
+	if (xneed > Size_max ||
+		!CHOLMOD(reallocate_factor) ((Int) xneed, L, Common))
+	{
+	    /* out of memory, convert to simplicial symbolic */
+	    CHOLMOD(change_factor) (CHOLMOD_PATTERN, L->is_ll, FALSE, TRUE,
+		    TRUE, L, Common) ;
+	    ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory; L now symbolic") ;
+	    return (FALSE) ;	    /* out of memory */
+	}
+	PRINT1 (("\n=== GROW L from %g to %g\n",
+		    (double) L->nzmax, (double) xneed)) ;
+	/* pack all columns so that each column has at most grow2 free space */
+	CHOLMOD(pack_factor) (L, Common) ;
+	ASSERT (Common->status == CHOLMOD_OK) ;
+	Common->nrealloc_factor++ ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* reallocate the column */
+    /* ---------------------------------------------------------------------- */
+
+    Common->nrealloc_col++ ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+
+    /* remove j from its current position in the list */
+    Lnext [Lprev [j]] = Lnext [j] ;
+    Lprev [Lnext [j]] = Lprev [j] ;
+
+    /* place j at the end of the list */
+    Lnext [Lprev [tail]] = j ;
+    Lprev [j] = Lprev [tail] ;
+    Lnext [j] = n ;
+    Lprev [tail] = j ;
+
+    /* L is no longer monotonic; columns are out-of-order */
+    L->is_monotonic = FALSE ;
+
+    /* allocate space for column j */
+    pold = Lp [j] ;
+    pnew = Lp [tail] ;
+    Lp [j] = pnew  ;
+    Lp [tail] += need ;
+
+    /* copy column j to the new space */
+    len = Lnz [j] ;
+    for (k = 0 ; k < len ; k++)
+    {
+	Li [pnew + k] = Li [pold + k] ;
+    }
+
+    if (L->xtype == CHOLMOD_REAL)
+    {
+	for (k = 0 ; k < len ; k++)
+	{
+	    Lx [pnew + k] = Lx [pold + k] ;
+	}
+    }
+    else if (L->xtype == CHOLMOD_COMPLEX)
+    {
+	for (k = 0 ; k < len ; k++)
+	{
+	    Lx [2*(pnew + k)  ] = Lx [2*(pold + k)  ] ;
+	    Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ;
+	}
+    }
+    else if (L->xtype == CHOLMOD_ZOMPLEX)
+    {
+	for (k = 0 ; k < len ; k++)
+	{
+	    Lx [pnew + k] = Lx [pold + k] ;
+	    Lz [pnew + k] = Lz [pold + k] ;
+	}
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "colrealloc done", Common)) ;
+
+    /* successful reallocation of column j of L */
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_pack_factor ================================================== */
+/* ========================================================================== */
+
+/* Pack the columns of a simplicial LDL' or LL' factor.  This can be followed
+ * by a call to cholmod_reallocate_factor to reduce the size of L to the exact
+ * size required by the factor, if desired.  Alternatively, you can leave the
+ * size of L->i and L->x the same, to allow space for future updates/rowadds.
+ *
+ * Each column is reduced in size so that it has at most Common->grow2 free
+ * space at the end of the column.
+ *
+ * Does nothing and returns silently if given any other type of factor.
+ *
+ * Does NOT force the columns of L to be monotonic.  It thus differs from
+ * cholmod_change_factor (xtype, -, FALSE, TRUE, TRUE, L, Common), which
+ * packs the columns and ensures that they appear in monotonic order.
+ */
+
+int CHOLMOD(pack_factor)
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz, *Lnext ;
+    Int pnew, j, k, pold, len, n, head, tail, grow2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start pack", Common)) ;
+    PRINT1 (("PACK factor %d\n", L->is_super)) ;
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super)
+    {
+	/* nothing to do unless L is simplicial numeric */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* pack */
+    /* ---------------------------------------------------------------------- */
+
+    grow2 = Common->grow2 ;
+    PRINT1 (("\nPACK grow2 "ID"\n", grow2)) ;
+
+    pnew = 0 ;
+    n = L->n ;
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lnz = L->nz ;
+    Lnext = L->next ;
+
+    head = n+1 ;
+    tail = n ;
+
+    for (j = Lnext [head] ; j != tail ; j = Lnext [j])
+    {
+	/* pack column j */
+	pold = Lp [j] ;
+	len = Lnz [j] ;
+	ASSERT (len > 0) ;
+	PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+	if (pnew < pold)
+	{
+	    PRINT2 (("    pack this column\n")) ;
+
+	    for (k = 0 ; k < len ; k++)
+	    {
+		Li [pnew + k] = Li [pold + k] ;
+	    }
+
+	    if (L->xtype == CHOLMOD_REAL)
+	    {
+		for (k = 0 ; k < len ; k++)
+		{
+		    Lx [pnew + k] = Lx [pold + k] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_COMPLEX)
+	    {
+		for (k = 0 ; k < len ; k++)
+		{
+		    Lx [2*(pnew + k)  ] = Lx [2*(pold + k)  ] ;
+		    Lx [2*(pnew + k)+1] = Lx [2*(pold + k)+1] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_ZOMPLEX)
+	    {
+		for (k = 0 ; k < len ; k++)
+		{
+		    Lx [pnew + k] = Lx [pold + k] ;
+		    Lz [pnew + k] = Lz [pold + k] ;
+		}
+	    }
+
+	    Lp [j] = pnew ;
+	}
+	len = MIN (len + grow2, n - j) ;
+	pnew = MIN (Lp [j] + len, Lp [Lnext [j]]) ;
+    }
+    PRINT2 (("final pnew = "ID"\n", pnew)) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_factor_to_sparse ============================================= */
+/* ========================================================================== */
+
+/* Constructs a column-oriented sparse matrix containing the pattern and values
+ * of a simplicial or supernodal numerical factor, and then converts the factor
+ * into a simplicial symbolic factor.  If L is already packed, monotonic,
+ * and simplicial (which is the case when cholmod_factorize uses the simplicial
+ * Cholesky factorization algorithm) then this routine requires only O(1)
+ * memory and takes O(1) time.
+ *
+ * Only operates on numeric factors (real, complex, or zomplex).  Does not
+ * change the numeric L->xtype (the resulting sparse matrix has the same xtype
+ * as L).  If this routine fails, L is left unmodified.
+ */
+
+cholmod_sparse *CHOLMOD(factor_to_sparse)
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to copy, converted to symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *Lsparse ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start convert to matrix", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to packed, monotonic, simplicial, numeric */
+    /* ---------------------------------------------------------------------- */
+
+    /* leave as LL or LDL' */
+    if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, TRUE, TRUE, L,
+		Common))
+    {
+	ERROR (CHOLMOD_INVALID, "cannot convert L") ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create Lsparse */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocate the header for Lsparse, the sparse matrix version of L */
+    Lsparse = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;		/* out of memory */
+    }
+
+    /* transfer the contents from L to Lsparse */
+    Lsparse->nrow = L->n ;
+    Lsparse->ncol = L->n ;
+    Lsparse->p = L->p ;
+    Lsparse->i = L->i ;
+    Lsparse->x = L->x ;
+    Lsparse->z = L->z ;
+    Lsparse->nz = NULL ;
+    Lsparse->stype = 0 ;
+    Lsparse->itype = L->itype ;
+    Lsparse->xtype = L->xtype ;
+    Lsparse->dtype = L->dtype ;
+    Lsparse->sorted = TRUE ;
+    Lsparse->packed = TRUE ;
+    Lsparse->nzmax = L->nzmax ;
+    ASSERT (CHOLMOD(dump_sparse) (Lsparse, "Lsparse", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert L to symbolic, but do not free contents transfered to Lsparse */
+    /* ---------------------------------------------------------------------- */
+
+    L->p = NULL ;
+    L->i = NULL ;
+    L->x = NULL ;
+    L->z = NULL ;
+    L->xtype = CHOLMOD_PATTERN ;
+    CHOLMOD(change_factor) (CHOLMOD_PATTERN, FALSE, FALSE, TRUE, TRUE, L,
+	    Common) ;
+
+    return (Lsparse) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_factor ================================================== */
+/* ========================================================================== */
+
+/* Create an exact copy of a factor, with one exception:
+ *
+ * Entries in unused space are not copied (they might not be initialized,
+ *	and copying them would cause program checkers such as purify and
+ *	valgrind to complain).
+ *
+ * Note that a supernodal L cannot be zomplex.
+ */
+
+cholmod_factor *CHOLMOD(copy_factor)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_factor *L2 ;
+    double *Lx, *L2x, *Lz, *L2z ;
+    Int *Perm, *ColCount, *Lp, *Li, *Lnz, *Lnext, *Lprev, *Lsuper, *Lpi, *Lpx,
+	*Ls, *Perm2, *ColCount2, *L2p, *L2i, *L2nz, *L2next, *L2prev, *L2super,
+	*L2pi, *L2px, *L2s ;
+    Int n, j, p, pend, s, xsize, ssize, nsuper ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (L, NULL) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_factor) (L, "start copy", Common)) ;
+
+    n = L->n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate a simplicial symbolic factor  */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocates L2->Perm and L2->ColCount */
+    L2 = CHOLMOD(allocate_factor) (n, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    ASSERT (L2->xtype == CHOLMOD_PATTERN && !(L2->is_super)) ;
+
+    Perm = L->Perm ;
+    ColCount = L->ColCount ;
+    Perm2 = L2->Perm ;
+    ColCount2 = L2->ColCount ;
+    L2->ordering = L->ordering ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	Perm2 [j] = Perm [j] ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	ColCount2 [j] = ColCount [j] ;
+    }
+    L2->is_ll = L->is_ll ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the rest of the factor */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype != CHOLMOD_PATTERN && !(L->super))
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* allocate a simplicial numeric factor */
+	/* ------------------------------------------------------------------ */
+
+	/* allocate L2->p, L2->nz, L2->prev, L2->next, L2->i, and L2->x.
+	 * packed = -1 so that cholmod_change_factor allocates space of
+	 * size L2->nzmax */
+	L2->nzmax = L->nzmax ;
+	if (!CHOLMOD(change_factor) (L->xtype, L->is_ll, FALSE, -1, TRUE,
+		    L2, Common))
+	{
+	    CHOLMOD(free_factor) (&L2, Common) ;
+	    return (NULL) ;	/* out of memory */
+	}
+	ASSERT (MAX (1, L->nzmax) == L2->nzmax) ;
+
+	/* ------------------------------------------------------------------ */
+	/* copy the contents of a simplicial numeric factor */
+	/* ------------------------------------------------------------------ */
+
+	Lp = L->p ;
+	Li = L->i ;
+	Lx = L->x ;
+	Lz = L->z ;
+	Lnz = L->nz ;
+	Lnext = L->next ;
+	Lprev = L->prev ;
+
+	L2p = L2->p ;
+	L2i = L2->i ;
+	L2x = L2->x ;
+	L2z = L2->z ;
+	L2nz = L2->nz ;
+	L2next = L2->next ;
+	L2prev = L2->prev ;
+	L2->xtype = L->xtype ;
+	L2->dtype = L->dtype ;
+
+	for (j = 0 ; j <= n ; j++)
+	{
+	    L2p [j] = Lp [j] ;
+	}
+
+	for (j = 0 ; j < n+2 ; j++)
+	{
+	    L2prev [j] = Lprev [j] ;
+	}
+
+	for (j = 0 ; j < n+2 ; j++)
+	{
+	    L2next [j] = Lnext [j] ;
+	}
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    L2nz [j] = Lnz [j] ;
+	}
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+	    for ( ; p < pend ; p++)
+	    {
+		L2i [p] = Li [p] ;
+	    }
+	    p = Lp [j] ;
+
+	    if (L->xtype == CHOLMOD_REAL)
+	    {
+		for ( ; p < pend ; p++)
+		{
+		    L2x [p] = Lx [p] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_COMPLEX)
+	    {
+		for ( ; p < pend ; p++)
+		{
+		    L2x [2*p  ] = Lx [2*p  ] ;
+		    L2x [2*p+1] = Lx [2*p+1] ;
+		}
+	    }
+	    else if (L->xtype == CHOLMOD_ZOMPLEX)
+	    {
+		for ( ; p < pend ; p++)
+		{
+		    L2x [p] = Lx [p] ;
+		    L2z [p] = Lz [p] ;
+		}
+	    }
+
+	}
+
+    }
+    else if (L->is_super)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* copy a supernodal factor */
+	/* ------------------------------------------------------------------ */
+
+	xsize = L->xsize ;
+	ssize = L->ssize ;
+	nsuper = L->nsuper ;
+
+	L2->xsize = xsize ;
+	L2->ssize = ssize ;
+	L2->nsuper = nsuper ;
+
+	/* allocate L2->super, L2->pi, L2->px, and L2->s.  Allocate L2->x if
+	 * L is numeric */
+	if (!CHOLMOD(change_factor) (L->xtype, TRUE, TRUE, TRUE, TRUE, L2,
+		    Common))
+	{
+	    CHOLMOD(free_factor) (&L2, Common) ;
+	    return (NULL) ;	/* out of memory */
+	}
+
+	ASSERT (L2->s != NULL) ;
+
+	/* ------------------------------------------------------------------ */
+	/* copy the contents of a supernodal factor */
+	/* ------------------------------------------------------------------ */
+
+	Lsuper = L->super ;
+	Lpi = L->pi ;
+	Lpx = L->px ;
+	Ls = L->s ;
+	Lx = L->x ;
+
+	L2super = L2->super ;
+	L2pi = L2->pi ;
+	L2px = L2->px ;
+	L2s = L2->s ;
+	L2x = L2->x ;
+
+	L2->maxcsize = L->maxcsize ;
+	L2->maxesize = L->maxesize ;
+
+	for (s = 0 ; s <= nsuper ; s++)
+	{
+	    L2super [s] = Lsuper [s] ;
+	}
+	for (s = 0 ; s <= nsuper ; s++)
+	{
+	    L2pi [s] = Lpi [s] ;
+	}
+	for (s = 0 ; s <= nsuper ; s++)
+	{
+	    L2px [s] = Lpx [s] ;
+	}
+
+	L2s [0] = 0 ;
+	for (p = 0 ; p < ssize ; p++)
+	{
+	    L2s [p] = Ls [p] ;
+	}
+
+	if (L->xtype == CHOLMOD_REAL)
+	{
+	    for (p = 0 ; p < xsize ; p++)
+	    {
+		L2x [p] = Lx [p] ;
+	    }
+	}
+	else if (L->xtype == CHOLMOD_COMPLEX)
+	{
+	    for (p = 0 ; p < 2*xsize ; p++)
+	    {
+		L2x [p] = Lx [p] ;
+	    }
+	}
+    }
+
+    L2->minor = L->minor ;
+    L2->is_monotonic = L->is_monotonic ;
+
+    DEBUG (CHOLMOD(dump_factor) (L2, "L2 got copied", Common)) ;
+    ASSERT (L2->xtype == L->xtype && L2->is_super == L->is_super) ;
+    return (L2) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_memory.c b/src/CHOLMOD/Core/cholmod_memory.c
new file mode 100644
index 0000000..9443fad
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_memory.c
@@ -0,0 +1,575 @@
+/* ========================================================================== */
+/* === Core/cholmod_memory ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2013,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core memory management routines:
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_malloc		malloc wrapper
+ * cholmod_free			free wrapper
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_calloc		calloc wrapper
+ * cholmod_realloc		realloc wrapper
+ * cholmod_realloc_multiple	realloc wrapper for multiple objects
+ *
+ * The user may make use of these, just like malloc and free.  You can even
+ * malloc an object and safely free it with cholmod_free, and visa versa
+ * (except that the memory usage statistics will be corrupted).  These routines
+ * do differ from malloc and free.  If cholmod_free is given a NULL pointer,
+ * for example, it does nothing (unlike the ANSI free).  cholmod_realloc does
+ * not return NULL if given a non-NULL pointer and a nonzero size, even if it
+ * fails (it sets an error code in Common->status instead).
+ *
+ * CHOLMOD keeps track of the amount of memory it has allocated, and so the
+ * cholmod_free routine includes as a parameter the size of the object being
+ * freed.  This is only used for memory usage statistics, which are very useful
+ * in finding memory leaks in your program.  If you, the user of CHOLMOD, pass
+ * the wrong size, the only consequence is that the memory usage statistics
+ * will be invalid.  This will causes assertions to fail if CHOLMOD is
+ * compiled with debugging enabled, but otherwise it will cause no errors.
+ *
+ * The cholmod_free_* routines for each CHOLMOD object keep track of the size
+ * of the blocks they free, so they do not require you to pass their sizes
+ * as a parameter.
+ *
+ * If a block of size zero is requested, these routines allocate a block of
+ * size one instead.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+/* ========================================================================== */
+/* === cholmod_add_size_t =================================================== */
+/* ========================================================================== */
+
+/* Safely compute a+b, and check for integer overflow.  If overflow occurs,
+ * return 0 and set OK to FALSE.  Also return 0 if OK is FALSE on input. */
+
+size_t CHOLMOD(add_size_t) (size_t a, size_t b, int *ok)
+{
+    size_t s = a + b ;
+    (*ok) = (*ok) && (s >= a) ;
+    return ((*ok) ? s : 0) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_mult_size_t ================================================== */
+/* ========================================================================== */
+
+/* Safely compute a*k, where k should be small, and check for integer overflow.
+ * If overflow occurs, return 0 and set OK to FALSE.  Also return 0 if OK is
+ * FALSE on input. */
+
+size_t CHOLMOD(mult_size_t) (size_t a, size_t k, int *ok)
+{
+    size_t p = 0, s ;
+    while (*ok)
+    {
+	if (k % 2)
+	{
+	    p = p + a ;
+	    (*ok) = (*ok) && (p >= a) ;
+	}
+	k = k / 2 ;
+	if (!k) return (p) ;
+	s = a + a ;
+	(*ok) = (*ok) && (s >= a) ;
+	a = s ;
+    }
+    return (0) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_malloc ======================================================= */
+/* ========================================================================== */
+
+/* Wrapper around malloc routine.  Allocates space of size MAX(1,n)*size, where
+ * size is normally a sizeof (...).
+ *
+ * This routine, cholmod_calloc, and cholmod_realloc do not set Common->status
+ * to CHOLMOD_OK on success, so that a sequence of cholmod_malloc's, _calloc's,
+ * or _realloc's can be used.  If any of them fails, the Common->status will
+ * hold the most recent error status.
+ *
+ * Usage, for a pointer to int:
+ *
+ *	p = cholmod_malloc (n, sizeof (int), Common)
+ *
+ * Uses a pointer to the malloc routine (or its equivalent) defined in Common.
+ */
+
+void *CHOLMOD(malloc)	/* returns pointer to the newly malloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    void *p ;
+    size_t s ;
+    int ok = TRUE ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (size == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0")  ;
+	p = NULL ;
+    }
+    else if (n >= (Size_max / size) || n >= Int_max)
+    {
+	/* object is too big to allocate without causing integer overflow */
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	p = NULL ;
+    }
+    else
+    {
+	/* call malloc, or its equivalent */
+	s = CHOLMOD(mult_size_t) (MAX (1,n), size, &ok) ;
+	p = ok ? ((Common->malloc_memory) (s)) : NULL ;
+	if (p == NULL)
+	{
+	    /* failure: out of memory */
+	    ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
+	}
+	else
+	{
+	    /* success: increment the count of objects allocated */
+	    Common->malloc_count++ ;
+	    Common->memory_inuse += (n * size) ;
+	    Common->memory_usage =
+		MAX (Common->memory_usage, Common->memory_inuse) ;
+	    PRINTM (("cholmod_malloc %p %g cnt: %g inuse %g\n",
+		    p, (double) n*size, (double) Common->malloc_count,
+                    (double) Common->memory_inuse)) ;
+	}
+    }
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free ========================================================= */
+/* ========================================================================== */
+
+/* Wrapper around free routine.  Returns NULL, which can be assigned to the
+ * pointer being freed, as in:
+ *
+ *	p = cholmod_free (n, sizeof (int), p, Common) ;
+ *
+ * In CHOLMOD, the syntax:
+ *
+ *	cholmod_free (n, sizeof (int), p, Common) ;
+ *
+ * is used if p is a local pointer and the routine is returning shortly.
+ * Uses a pointer to the free routine (or its equivalent) defined in Common.
+ * Nothing is freed if the pointer is NULL.
+ */
+
+void *CHOLMOD(free)	/* always returns NULL */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to free */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (p != NULL)
+    {
+	/* only free the object if the pointer is not NULL */
+	/* call free, or its equivalent */
+	(Common->free_memory) (p) ;
+	Common->malloc_count-- ;
+	Common->memory_inuse -= (n * size) ;
+	PRINTM (("cholmod_free   %p %g cnt: %g inuse %g\n",
+		p, (double) n*size, (double) Common->malloc_count,
+                (double) Common->memory_inuse)) ;
+	/* This assertion will fail if the user calls cholmod_malloc and
+	 * cholmod_free with mismatched memory sizes.  It shouldn't fail
+	 * otherwise. */
+	ASSERT (IMPLIES (Common->malloc_count == 0, Common->memory_inuse == 0));
+    }
+    /* return NULL, and the caller should assign this to p.  This avoids
+     * freeing the same pointer twice. */
+    return (NULL) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_calloc ======================================================= */
+/* ========================================================================== */
+
+/* Wrapper around calloc routine.
+ *
+ * Uses a pointer to the calloc routine (or its equivalent) defined in Common.
+ * This routine is identical to malloc, except that it zeros the newly allocated
+ * block to zero.
+ */
+
+void *CHOLMOD(calloc)	/* returns pointer to the newly calloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    void *p ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (size == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
+	p = NULL ;
+    }
+    else if (n >= (Size_max / size) || n >= Int_max)
+    {
+	/* object is too big to allocate without causing integer overflow */
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	p = NULL ;
+    }
+    else
+    {
+	/* call calloc, or its equivalent */
+	p = (Common->calloc_memory) (MAX (1,n), size) ;
+	if (p == NULL)
+	{
+	    /* failure: out of memory */
+	    ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
+	}
+	else
+	{
+	    /* success: increment the count of objects allocated */
+	    Common->malloc_count++ ;
+	    Common->memory_inuse += (n * size) ;
+	    Common->memory_usage =
+		MAX (Common->memory_usage, Common->memory_inuse) ;
+	    PRINTM (("cholmod_malloc %p %g cnt: %g inuse %g\n",
+		    p, (double) n*size, (double) Common->malloc_count,
+                    (double) Common->memory_inuse)) ;
+	}
+    }
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_realloc ====================================================== */
+/* ========================================================================== */
+
+/* Wrapper around realloc routine.  Given a pointer p to a block of size
+ * (*n)*size memory, it changes the size of the block pointed to by p to be
+ * MAX(1,nnew)*size in size.  It may return a pointer different than p.  This
+ * should be used as (for a pointer to int):
+ *
+ *	p = cholmod_realloc (nnew, sizeof (int), p, *n, Common) ;
+ *
+ * If p is NULL, this is the same as p = cholmod_malloc (...).
+ * A size of nnew=0 is treated as nnew=1.
+ *
+ * If the realloc fails, p is returned unchanged and Common->status is set
+ * to CHOLMOD_OUT_OF_MEMORY.  If successful, Common->status is not modified,
+ * and p is returned (possibly changed) and pointing to a large block of memory.
+ *
+ * Uses a pointer to the realloc routine (or its equivalent) defined in Common.
+ */
+
+void *CHOLMOD(realloc)	/* returns pointer to reallocated block */
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated block */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to realloc */
+    size_t *n,		/* current size on input, nnew on output if successful*/
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    size_t nold = (*n) ;
+    void *pnew ;
+    size_t s ;
+    int ok = TRUE ;
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (size == 0)
+    {
+	ERROR (CHOLMOD_INVALID, "sizeof(item) must be > 0") ;
+	p = NULL ;
+    }
+    else if (p == NULL)
+    {
+	/* A fresh object is being allocated. */
+	PRINT1 (("realloc fresh: %d %d\n", nnew, size)) ;
+	p = CHOLMOD(malloc) (nnew, size, Common) ;
+	*n = (p == NULL) ? 0 : nnew ;
+    }
+    else if (nold == nnew)
+    {
+	/* Nothing to do.  Do not change p or n. */
+	PRINT1 (("realloc nothing: %d %d\n", nnew, size)) ;
+    }
+    else if (nnew >= (Size_max / size) || nnew >= Int_max)
+    {
+	/* failure: nnew is too big.  Do not change p or n. */
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+    }
+    else
+    {
+	/* The object exists, and is changing to some other nonzero size. */
+	/* call realloc, or its equivalent */
+	PRINT1 (("realloc : %d to %d, %d\n", nold, nnew, size)) ;
+	pnew = NULL ;
+
+	s = CHOLMOD(mult_size_t) (MAX (1,nnew), size, &ok) ;
+	pnew = ok ? ((Common->realloc_memory) (p, s)) : NULL ;
+
+	if (pnew == NULL)
+	{
+	    /* Do not change p, since it still points to allocated memory */
+	    if (nnew <= nold)
+	    {
+		/* The attempt to reduce the size of the block from n to
+		 * nnew has failed.  The current block is not modified, so
+		 * pretend to succeed, but do not change p.  Do change
+		 * CHOLMOD's notion of the size of the block, however. */
+		*n = nnew ;
+		PRINTM (("nnew <= nold failed, pretend to succeed\n")) ;
+		PRINTM (("cholmod_free %p %g cnt: %g inuse %g\n"
+			 "cholmod_malloc %p %g cnt: %g inuse %g\n",
+		    p, (double) nold*size, (double) Common->malloc_count-1,
+		       (double) (Common->memory_inuse - nold*size),
+		    p, (double) nnew*size, (double) Common->malloc_count,
+		       (double) (Common->memory_inuse + (nnew-nold)*size))) ;
+		Common->memory_inuse += ((nnew-nold) * size) ;
+	    }
+	    else
+	    {
+		/* Increasing the size of the block has failed.
+		 * Do not change n. */
+		ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ;
+	    }
+	}
+	else
+	{
+	    /* success: return revised p and change the size of the block */
+	    PRINTM (("cholmod_free %p %g cnt: %g inuse %g\n"
+		     "cholmod_malloc %p %g cnt: %g inuse %g\n",
+		p, (double) nold*size, (double) Common->malloc_count-1,
+                   (double) (Common->memory_inuse - nold*size),
+		pnew, (double) nnew*size, (double) Common->malloc_count,
+                   (double) (Common->memory_inuse + (nnew-nold)*size))) ;
+	    p = pnew ;
+	    *n = nnew ;
+	    Common->memory_inuse += ((nnew-nold) * size) ;
+	}
+	Common->memory_usage = MAX (Common->memory_usage, Common->memory_inuse);
+    }
+
+    return (p) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_realloc_multiple ============================================= */
+/* ========================================================================== */
+
+/* reallocate multiple blocks of memory, all of the same size (up to two integer
+ * and two real blocks).  Either reallocations all succeed, or all are returned
+ * in the original size (they are freed if the original size is zero).  The nnew
+ * blocks are of size 1 or more.
+ */
+
+int CHOLMOD(realloc_multiple)
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated blocks */
+    int nint,		/* number of int/SuiteSparse_long blocks */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* ---- in/out --- */
+    void **Iblock,	/* int or SuiteSparse_long block */
+    void **Jblock,	/* int or SuiteSparse_long block */
+    void **Xblock,	/* complex or double block */
+    void **Zblock,	/* zomplex case only: double block */
+    size_t *nold_p,	/* current size of the I,J,X,Z blocks on input,
+			 * nnew on output if successful */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *xx, *zz ;
+    size_t i, j, x, z, nold ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid xtype") ;
+	return (FALSE) ;
+    }
+
+    nold = *nold_p ;
+
+    if (nint < 1 && xtype == CHOLMOD_PATTERN)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    i = nold ;
+    j = nold ;
+    x = nold ;
+    z = nold ;
+
+    if (nint > 0)
+    {
+	*Iblock = CHOLMOD(realloc) (nnew, sizeof (Int), *Iblock, &i, Common) ;
+    }
+    if (nint > 1)
+    {
+	*Jblock = CHOLMOD(realloc) (nnew, sizeof (Int), *Jblock, &j, Common) ;
+    }
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    *Xblock = CHOLMOD(realloc) (nnew, sizeof (double), *Xblock, &x,
+                    Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    *Xblock = CHOLMOD(realloc) (nnew, 2*sizeof (double), *Xblock, &x,
+                    Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    *Xblock = CHOLMOD(realloc) (nnew, sizeof (double), *Xblock, &x,
+                    Common) ;
+	    *Zblock = CHOLMOD(realloc) (nnew, sizeof (double), *Zblock, &z,
+                    Common) ;
+	    break ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* one or more realloc's failed.  Resize all back down to nold. */
+
+	if (nold == 0)
+	{
+
+	    if (nint > 0)
+	    {
+		*Iblock = CHOLMOD(free) (i, sizeof (Int), *Iblock, Common) ;
+	    }
+	    if (nint > 1)
+	    {
+		*Jblock = CHOLMOD(free) (j, sizeof (Int), *Jblock, Common) ;
+	    }
+
+	    switch (xtype)
+	    {
+		case CHOLMOD_REAL:
+		    *Xblock = CHOLMOD(free) (x, sizeof (double), *Xblock,
+                            Common) ;
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    *Xblock = CHOLMOD(free) (x, 2*sizeof (double), *Xblock,
+                            Common) ;
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    *Xblock = CHOLMOD(free) (x, sizeof (double), *Xblock,
+                            Common) ;
+		    *Zblock = CHOLMOD(free) (x, sizeof (double), *Zblock,
+                            Common) ;
+		    break ;
+	    }
+
+	}
+	else
+	{
+	    if (nint > 0)
+	    {
+		*Iblock = CHOLMOD(realloc) (nold, sizeof (Int), *Iblock, &i,
+                            Common) ;
+	    }
+	    if (nint > 1)
+	    {
+		*Jblock = CHOLMOD(realloc) (nold, sizeof (Int), *Jblock, &j,
+                            Common) ;
+	    }
+
+	    switch (xtype)
+	    {
+		case CHOLMOD_REAL:
+		    *Xblock = CHOLMOD(realloc) (nold, sizeof (double),
+                            *Xblock, &x, Common) ;
+		    break ;
+
+		case CHOLMOD_COMPLEX:
+		    *Xblock = CHOLMOD(realloc) (nold, 2*sizeof (double),
+                            *Xblock, &x, Common) ;
+		    break ;
+
+		case CHOLMOD_ZOMPLEX:
+		    *Xblock = CHOLMOD(realloc) (nold, sizeof (double),
+                            *Xblock, &x, Common) ;
+		    *Zblock = CHOLMOD(realloc) (nold, sizeof (double),
+                            *Zblock, &z, Common) ;
+		    break ;
+	    }
+
+	}
+
+	return (FALSE) ;
+    }
+
+    if (nold == 0)
+    {
+	/* New space was allocated.  Clear the first entry so that valgrind
+	 * doesn't complain about its access in change_complexity
+	 * (Core/cholmod_complex.c). */
+	xx = *Xblock ;
+	zz = *Zblock ;
+	switch (xtype)
+	{
+	    case CHOLMOD_REAL:
+		xx [0] = 0 ;
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		xx [0] = 0 ;
+		xx [1] = 0 ;
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		xx [0] = 0 ;
+		zz [0] = 0 ;
+		break ;
+	}
+    }
+
+    /* all realloc's succeeded, change size to reflect realloc'ed size. */
+    *nold_p = nnew ;
+    return (TRUE) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_sparse.c b/src/CHOLMOD/Core/cholmod_sparse.c
new file mode 100644
index 0000000..557dbc1
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_sparse.c
@@ -0,0 +1,651 @@
+/* ========================================================================== */
+/* === Core/cholmod_sparse ================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_sparse object:
+ *
+ * A sparse matrix is held in compressed column form.  In the basic type
+ * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix
+ * with nz entries is held in three arrays: p of size n+1, i of size nz, and x
+ * of size nz.  Row indices of column j are held in i [p [j] ... p [j+1]-1] and
+ * in the same locations in x.  There may be no duplicate entries in a column.
+ * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track).
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_allocate_sparse	allocate a sparse matrix
+ * cholmod_free_sparse		free a sparse matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_reallocate_sparse	change the size (# entries) of sparse matrix
+ * cholmod_nnz			number of nonzeros in a sparse matrix
+ * cholmod_speye		sparse identity matrix
+ * cholmod_spzeros		sparse zero matrix
+ * cholmod_copy_sparse		create a copy of a sparse matrix
+ *
+ * All xtypes are supported (pattern, real, complex, and zomplex)
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_sparse ============================================== */
+/* ========================================================================== */
+
+/* Allocate space for a matrix.  A->i and A->x are not initialized.  A->p
+ * (and A->nz if A is not packed) are set to zero, so a matrix containing no
+ * entries (all zero) is returned.  See also cholmod_spzeros.
+ *
+ * workspace: none
+ */
+
+cholmod_sparse *CHOLMOD(allocate_sparse)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int sorted,		/* TRUE if columns of A sorted, FALSE otherwise */
+    int packed,		/* TRUE if A will be packed, FALSE otherwise */
+    int stype,		/* stype of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *A ;
+    Int *Ap, *Anz ;
+    size_t nzmax0 ;
+    Int j ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (stype != 0 && nrow != ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ;
+	return (NULL) ;
+    }
+    if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (NULL) ;
+    }
+    /* ensure the dimensions do not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ;
+    if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate header */
+    /* ---------------------------------------------------------------------- */
+
+    A = CHOLMOD(malloc) (sizeof (cholmod_sparse), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    PRINT1 (("cholmod_allocate_sparse %d-by-%d nzmax %d sorted %d packed %d"
+		" xtype %d\n", nrow, ncol, nzmax, sorted, packed, xtype)) ;
+
+    nzmax = MAX (1, nzmax) ;
+
+    A->nrow = nrow ;
+    A->ncol = ncol ;
+    A->nzmax = nzmax ;
+    A->packed = packed ;    /* default is packed (A->nz not present) */
+    A->stype = stype ;
+    A->itype = ITYPE ;
+    A->xtype = xtype ;
+    A->dtype = DTYPE ;
+
+    A->nz = NULL ;
+    A->p = NULL ;
+    A->i = NULL ;
+    A->x = NULL ;
+    A->z = NULL ;
+
+    /* A 1-by-m matrix always has sorted columns */
+    A->sorted = (nrow <= 1) ? TRUE : sorted ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix itself */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocate O(ncol) space */
+    A->p = CHOLMOD(malloc) (((size_t) ncol)+1, sizeof (Int), Common) ;
+    if (!packed)
+    {
+	A->nz = CHOLMOD(malloc) (ncol, sizeof (Int), Common) ;
+    }
+
+    /* allocate O(nz) space */
+    nzmax0 = 0 ;
+    CHOLMOD(realloc_multiple) (nzmax, 1, xtype, &(A->i), NULL, &(A->x), &(A->z),
+	    &nzmax0, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&A, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* initialize A->p and A->nz so that A is an empty matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    for (j = 0 ; j <= (Int) ncol ; j++)
+    {
+	Ap [j] = 0 ;
+    }
+    if (!packed)
+    {
+	Anz = A->nz ;
+	for (j = 0 ; j < (Int) ncol ; j++)
+	{
+	    Anz [j] = 0 ;
+	}
+    }
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_sparse ================================================== */
+/* ========================================================================== */
+
+/* free a sparse matrix
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_sparse)
+(
+    /* ---- in/out --- */
+    cholmod_sparse **AHandle,	/* matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int n, nz ;
+    cholmod_sparse *A ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (AHandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    A = *AHandle ;
+    if (A == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    n = A->ncol ;
+    nz = A->nzmax ;
+    A->p  = CHOLMOD(free) (n+1, sizeof (Int), A->p,  Common) ;
+    A->i  = CHOLMOD(free) (nz,  sizeof (Int), A->i,  Common) ;
+    A->nz = CHOLMOD(free) (n,   sizeof (Int), A->nz, Common) ;
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_REAL:
+	    A->x = CHOLMOD(free) (nz, sizeof (double), A->x,  Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    A->x = CHOLMOD(free) (nz, 2*sizeof (double), A->x,  Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    A->x = CHOLMOD(free) (nz, sizeof (double), A->x,  Common) ;
+	    A->z = CHOLMOD(free) (nz, sizeof (double), A->z,  Common) ;
+	    break ;
+    }
+
+    *AHandle = CHOLMOD(free) (1, sizeof (cholmod_sparse), (*AHandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_sparse ============================================ */
+/* ========================================================================== */
+
+/* Change the size of A->i, A->x, and A->z, or allocate them if their current
+ * size is zero.  A->x and A->z are not modified if A->xtype is CHOLMOD_PATTERN.
+ * A->z is not modified unless A->xtype is CHOLMOD_ZOMPLEX.
+ * 
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_sparse)
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in A */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to reallocate */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    PRINT1 (("realloc matrix %d to %d, xtype: %d\n",
+		A->nzmax, nznew, A->xtype)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* resize the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(realloc_multiple) (MAX (1,nznew), 1, A->xtype, &(A->i), NULL,
+	    &(A->x), &(A->z), &(A->nzmax), Common) ;
+
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_speye ======================================================== */
+/* ========================================================================== */
+
+/* Return a sparse identity matrix. */
+
+cholmod_sparse *CHOLMOD(speye)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az ;
+    cholmod_sparse *A ;
+    Int *Ap, *Ai ;
+    Int j, n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    n = MIN (nrow, ncol) ;
+    A = CHOLMOD(allocate_sparse) (nrow, ncol, n, TRUE, TRUE, 0, xtype,
+	    Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory or inputs invalid */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* create the identity matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	Ap [j] = j ;
+    }
+    for (j = n ; j <= ((Int) ncol) ; j++)
+    {
+	Ap [j] = n ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	Ai [j] = j ;
+    }
+
+    switch (xtype)
+    {
+	case CHOLMOD_REAL:
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Ax [j] = 1 ;
+	    }
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Ax [2*j  ] = 1 ;
+		Ax [2*j+1] = 0 ;
+	    }
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Ax [j] = 1 ;
+	    }
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Az [j] = 0 ;
+	    }
+	    break ;
+    }
+
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_spzeros ====================================================== */
+/* ========================================================================== */
+
+/* Return a sparse zero matrix. */
+
+cholmod_sparse *CHOLMOD(spzeros)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    return (CHOLMOD(allocate_sparse) (nrow, ncol, nzmax, TRUE, TRUE, 0, xtype,
+	    Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_nnz ========================================================== */
+/* ========================================================================== */
+
+/* Return the number of entries in a sparse matrix.
+ *
+ * workspace: none
+ * integer overflow cannot occur, since the matrix is already allocated.
+ */
+
+SuiteSparse_long CHOLMOD(nnz)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Anz ;
+    size_t nz ;
+    Int j, ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return nnz (A) */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;
+    if (A->packed)
+    {
+	Ap = A->p ;
+	RETURN_IF_NULL (Ap, EMPTY) ;
+	nz = Ap [ncol] ;
+    }
+    else
+    {
+	Anz = A->nz ;
+	RETURN_IF_NULL (Anz, EMPTY) ;
+	nz = 0 ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    nz += MAX (0, Anz [j]) ;
+	}
+    }
+    return (nz) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_sparse ================================================== */
+/* ========================================================================== */
+
+/* C = A.  Create an exact copy of a sparse matrix, with one exception.
+ * Entries in unused space are not copied (they might not be initialized,
+ * and copying them would cause program checkers such as purify and
+ * valgrind to complain).  The xtype of the resulting matrix C is the same as
+ * the xtype of the input matrix A.
+ *
+ * See also Core/cholmod_copy, which copies a matrix with possible changes
+ * in stype, presence of diagonal entries, pattern vs. numerical values,
+ * real and/or imaginary parts, and so on.
+ */
+
+cholmod_sparse *CHOLMOD(copy_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Cx, *Az, *Cz ;
+    Int *Ap, *Ai, *Anz, *Cp, *Ci, *Cnz ;
+    cholmod_sparse *C ;
+    Int p, pend, j, ncol, packed, nzmax, nz, xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype != 0 && A->nrow != A->ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "rectangular matrix with stype != 0 invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "A original", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;
+    nzmax = A->nzmax ;
+    packed = A->packed ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    xtype = A->xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the copy */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, A->sorted,
+	    A->packed, A->stype, A->xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+    Cz = C->z ;
+    Cnz = C->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    for (j = 0 ; j <= ncol ; j++)
+    {
+	Cp [j] = Ap [j] ;
+    }
+
+    if (packed)
+    {
+	nz = Ap [ncol] ;
+	for (p = 0 ; p < nz ; p++)
+	{
+	    Ci [p] = Ai [p] ;
+	}
+
+	switch (xtype)
+	{
+	    case CHOLMOD_REAL:
+		for (p = 0 ; p < nz ; p++)
+		{
+		    Cx [p] = Ax [p] ;
+		}
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		for (p = 0 ; p < 2*nz ; p++)
+		{
+		    Cx [p] = Ax [p] ;
+		}
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		for (p = 0 ; p < nz ; p++)
+		{
+		    Cx [p] = Ax [p] ;
+		    Cz [p] = Az [p] ;
+		}
+		break ;
+	}
+
+    }
+    else
+    {
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    Cnz [j] = Anz [j] ;
+	}
+
+	switch (xtype)
+	{
+	    case CHOLMOD_PATTERN:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+		    }
+		}
+		break ;
+
+	    case CHOLMOD_REAL:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+			Cx [p] = Ax [p] ;
+		    }
+		}
+		break ;
+
+	    case CHOLMOD_COMPLEX:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+			Cx [2*p  ] = Ax [2*p  ] ;
+			Cx [2*p+1] = Ax [2*p+1] ;
+		    }
+		}
+		break ;
+
+	    case CHOLMOD_ZOMPLEX:
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			Ci [p] = Ai [p] ;
+			Cx [p] = Ax [p] ;
+			Cz [p] = Az [p] ;
+		    }
+		}
+		break ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C, "C copy", Common) >= 0) ;
+    return (C) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_transpose.c b/src/CHOLMOD/Core/cholmod_transpose.c
new file mode 100644
index 0000000..51a7035
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_transpose.c
@@ -0,0 +1,1138 @@
+/* ========================================================================== */
+/* === Core/cholmod_transpose =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_sparse object to
+ * compute the transpose or permuted transpose of a matrix:
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_transpose		transpose sparse matrix
+ * cholmod_ptranspose		transpose and permute sparse matrix
+ * cholmod_sort			sort row indices in each column of sparse matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_transpose_unsym	transpose unsymmetric sparse matrix
+ * cholmod_transpose_sym	transpose symmetric sparse matrix
+ *
+ * All xtypes (pattern, real, complex, and zomplex) are supported.
+ *
+ * ---------------------------------------
+ * Unsymmetric case: A->stype is zero.
+ * ---------------------------------------
+ *
+ * Computes F = A', F = A (:,f)' or F = A (p,f)', except that the indexing by
+ * f does not work the same as the MATLAB notation (see below).  A->stype
+ * is zero, which denotes that both the upper and lower triangular parts of
+ * A are present (and used).  A may in fact be symmetric in pattern and/or
+ * value; A->stype just denotes which part of A are stored.  A may be
+ * rectangular.
+ *
+ * p is a permutation of 0:m-1, and f is a subset of 0:n-1, where A is m-by-n.
+ * There can be no duplicate entries in p or f.
+ *
+ * The set f is held in fset and fsize.
+ *	fset = NULL means ":" in MATLAB. fsize is ignored.
+ *	fset != NULL means f = fset [0..fsize-1].
+ *	fset != NULL and fsize = 0 means f is the empty set.
+ *
+ * Columns not in the set f are considered to be zero.  That is,
+ * if A is 5-by-10 then F = A (:,[3 4])' is not 2-by-5, but 10-by-5, and rows
+ * 3 and 4 of F are equal to columns 3 and 4 of A (the other rows of F are
+ * zero).  More precisely, in MATLAB notation:
+ *
+ *	[m n] = size (A) ;
+ *	F = A ;
+ *	notf = ones (1,n) ;
+ *	notf (f) = 0 ;
+ *	F (:, find (notf)) = 0
+ *	F = F'
+ *
+ * If you want the MATLAB equivalent F=A(p,f) operation, use cholmod_submatrix
+ * instead (which does not compute the transpose).
+ *
+ * F->nzmax must be large enough to hold the matrix F.  It is not modified.
+ * If F->nz is present then F->nz [j] = # of entries in column j of F.
+ *
+ * A can be sorted or unsorted, with packed or unpacked columns.
+ *
+ * If f is present and not sorted in ascending order, then F is unsorted
+ * (that is, it may contain columns whose row indices do not appear in
+ * ascending order).  Otherwise, F is sorted (the row indices in each
+ * column of F appear in strictly ascending order).
+ *
+ * F is returned in packed or unpacked form, depending on F->packed on input.
+ * If F->packed is false, then F is returned in unpacked form (F->nz must be
+ * present).  Each row i of F is large enough to hold all the entries in row i
+ * of A, even if f is provided.  That is, F->i and
+ * F->x [F->p [i] .. F->p [i] + F->nz [i] - 1] contain all entries in A (i,f),
+ * but F->p [i+1] - F->p [i] is equal to the number of nonzeros in A (i,:),
+ * not just A (i,f).
+ *
+ * The cholmod_transpose_unsym routine is the only operation in CHOLMOD that
+ * can produce an unpacked matrix.
+ *
+ * ---------------------------------------
+ * Symmetric case: A->stype is nonzero.
+ * ---------------------------------------
+ *
+ * Computes F = A' or F = A(p,p)', the transpose or permuted transpose, where
+ * A->stype is nonzero.
+ *
+ * If A->stype > 0, then A is a symmetric matrix where just the upper part
+ * of the matrix is stored.  Entries in the lower triangular part may be
+ * present, but are ignored.  A must be square.  If F=A', then F is returned
+ * sorted; otherwise F is unsorted for the F=A(p,p)' case.
+ *
+ * There can be no duplicate entries in p.
+ * The fset and fsize parameters are not used.
+ *
+ * Three kinds of transposes are available, depending on the "values" parameter:
+ * 0: do not transpose the numerical values; create a CHOLMOD_PATTERN matrix
+ * 1: array transpose
+ * 2: complex conjugate transpose (same as 2 if input is real or pattern)
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * For cholmod_transpose_unsym and cholmod_transpose_sym, the output matrix
+ * F must already be pre-allocated by the caller, with the correct dimensions.
+ * If F is not valid or has the wrong dimensions, it is not modified.
+ * Otherwise, if F is too small, the transpose is not computed; the contents
+ * of F->p contain the column pointers of the resulting matrix, where
+ * F->p [F->ncol] > F->nzmax.  In this case, the remaining contents of F are
+ * not modified.  F can still be properly free'd with cholmod_free_sparse.
+ */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define PATTERN
+#include "t_cholmod_transpose.c"
+#define REAL
+#include "t_cholmod_transpose.c"
+#define COMPLEX
+#include "t_cholmod_transpose.c"
+#define COMPLEX
+#define NCONJUGATE
+#include "t_cholmod_transpose.c"
+#define ZOMPLEX
+#include "t_cholmod_transpose.c"
+#define ZOMPLEX
+#define NCONJUGATE
+#include "t_cholmod_transpose.c"
+
+
+/* ========================================================================== */
+/* === cholmod_transpose_unsym ============================================== */
+/* ========================================================================== */
+
+/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is
+ * already allocated.  See cholmod_transpose for a simpler routine.
+ *
+ * workspace:
+ * Iwork (MAX (nrow,ncol)) if fset is present
+ * Iwork (nrow) if fset is NULL
+ *
+ * The xtype of A and F must match, unless values is zero or F->xtype is
+ * CHOLMOD_PATTERN (in which case only the pattern of A is transpose into F).
+ */
+
+int CHOLMOD(transpose_unsym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values */
+    Int *Perm,		/* size nrow, if present (can be NULL) */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A', A(:,f)', or A(p,f)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Fp, *Fnz, *Ap, *Ai, *Anz, *Wi ;
+    Int nrow, ncol, permute, use_fset, Apacked, Fpacked, p, pend,
+	i, j, k, Fsorted, nf, jj, jlast ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (F, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->nrow != F->ncol || A->ncol != F->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "F has the wrong dimensions") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nf = fsize ;
+    use_fset = (fset != NULL) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Anz = A->nz ;
+    Apacked = A->packed ;
+    ASSERT (IMPLIES (!Apacked, Anz != NULL)) ;
+
+    permute = (Perm != NULL) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+    Fnz = F->nz ;
+    Fpacked = F->packed ;
+    ASSERT (IMPLIES (!Fpacked, Fnz != NULL)) ;
+
+    nf = (use_fset) ? nf : ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = nrow + ((fset != NULL) ? ncol : 0) */
+    s = CHOLMOD(add_size_t) (nrow, ((fset != NULL) ? ncol : 0), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    Wi = Common->Iwork ;	/* size nrow (i/l/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* check Perm and fset */
+    /* ---------------------------------------------------------------------- */
+
+    if (permute)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [i] = 1 ;
+	}
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    i = Perm [k] ;
+	    if (i < 0 || i > nrow || Wi [i] == 0)
+	    {
+		ERROR (CHOLMOD_INVALID, "invalid permutation") ;
+		return (FALSE) ;
+	    }
+	    Wi [i] = 0 ;
+	}
+    }
+
+    if (use_fset)
+    {
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    Wi [j] = 1 ;
+	}
+	for (k = 0 ; k < nf ; k++)
+	{
+	    j = fset [k] ;
+	    if (j < 0 || j > ncol || Wi [j] == 0)
+	    {
+		ERROR (CHOLMOD_INVALID, "invalid fset") ;
+		return (FALSE) ;
+	    }
+	    Wi [j] = 0 ;
+	}
+    }
+
+    /* Perm and fset are now valid */
+    ASSERT (CHOLMOD(dump_perm) (Perm, nrow, nrow, "Perm", Common)) ;
+    ASSERT (CHOLMOD(dump_perm) (fset, nf, ncol, "fset", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of A or A(:,f) */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Wi [i] = 0 ;
+    }
+
+    jlast = EMPTY ;
+    Fsorted = TRUE ;
+
+    if (use_fset)
+    {
+	/* count entries in each row of A(:,f) */
+	for (jj = 0 ; jj < nf ; jj++)
+	{
+	    j = fset [jj] ;
+	    if (j <= jlast)
+	    {
+		Fsorted = FALSE ;
+	    }
+	    p = Ap [j] ;
+	    pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Wi [Ai [p]]++ ;
+	    }
+	    jlast = j ;
+	}
+
+	/* save the nz counts if F is unpacked, and recount all of A */
+	if (!Fpacked)
+	{
+	    if (permute)
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [Perm [i]] ;
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [i] ;
+		}
+	    }
+	    for (i = 0 ; i < nrow ; i++)
+	    {
+		Wi [i] = 0 ;
+	    }
+
+	    /* count entries in each row of A */
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    Wi [Ai [p]]++ ;
+		}
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* count entries in each row of A */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Wi [Ai [p]]++ ;
+	    }
+	}
+
+	/* save the nz counts if F is unpacked */
+	if (!Fpacked)
+	{
+	    if (permute)
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [Perm [i]] ;
+		}
+	    }
+	    else
+	    {
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    Fnz [i] = Wi [i] ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    if (permute)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Fp [i] = p ;
+	    p += Wi [Perm [i]] ;
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [Perm [i]] = Fp [i] ;
+	}
+    }
+    else
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Fp [i] = p ;
+	    p += Wi [i] ;
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    Wi [i] = Fp [i] ;
+	}
+    }
+    Fp [nrow] = p ;
+
+    if (p > (Int) (F->nzmax))
+    {
+	ERROR (CHOLMOD_INVALID, "F is too small") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* transpose matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    ok = FALSE ;
+    if (values == 0 || F->xtype == CHOLMOD_PATTERN)
+    {
+	ok = p_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_REAL)
+    {
+	ok = r_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_COMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    ok = ct_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    ok = c_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+    }
+    else if (F->xtype == CHOLMOD_ZOMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    ok = zt_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    ok = z_cholmod_transpose_unsym (A, Perm, fset, nf, F, Common) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize result F */
+    /* ---------------------------------------------------------------------- */
+
+    if (ok)
+    {
+	F->sorted = Fsorted ;
+    }
+    ASSERT (CHOLMOD(dump_sparse) (F, "output F unsym", Common) >= 0) ;
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_transpose_sym ================================================ */
+/* ========================================================================== */
+
+/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated.
+ * See cholmod_transpose for a simpler routine.
+ *
+ * workspace:  Iwork (nrow) if Perm NULL, Iwork (2*nrow) if Perm non-NULL.
+ */
+
+int CHOLMOD(transpose_sym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values */
+    Int *Perm,		/* size nrow, if present (can be NULL) */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A' or A(p,p)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Anz, *Ai, *Fp, *Wi, *Pinv, *Iwork ;
+    Int p, pend, packed, upper, permute, jold, n, i, j, k, iold ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (F, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (F, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->nrow != A->ncol || A->stype == 0)
+    {
+	/* this routine handles square symmetric matrices only */
+	ERROR (CHOLMOD_INVALID, "matrix must be symmetric") ;
+	return (FALSE) ;
+    }
+    if (A->nrow != F->ncol || A->ncol != F->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "F has the wrong dimensions") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    permute = (Perm != NULL) ;
+    n = A->nrow ;
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+    upper = (A->stype > 0) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = (Perm != NULL) ? 2*n : n */
+    s = CHOLMOD(add_size_t) (n, ((Perm != NULL) ? n : 0), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wi   = Iwork ;	    /* size n (i/l/l) */
+    Pinv = Iwork + n ;	    /* size n (i/i/l) , unused if Perm NULL */
+
+    /* ---------------------------------------------------------------------- */
+    /* check Perm and construct inverse permutation */
+    /* ---------------------------------------------------------------------- */
+
+    if (permute)
+    {
+	for (i = 0 ; i < n ; i++)
+	{
+	    Pinv [i] = EMPTY ;
+	}
+	for (k = 0 ; k < n ; k++)
+	{
+	    i = Perm [k] ;
+	    if (i < 0 || i > n || Pinv [i] != EMPTY)
+	    {
+		ERROR (CHOLMOD_INVALID, "invalid permutation") ;
+		return (FALSE) ;
+	    }
+	    Pinv [i] = k ;
+	}
+    }
+
+    /* Perm is now valid */
+    ASSERT (CHOLMOD(dump_perm) (Perm, n, n, "Perm", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of F */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	Wi [i] = 0 ;
+    }
+
+    if (packed)
+    {
+	if (permute)
+	{
+	    if (upper)
+	    {
+		/* packed, permuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    pend = Ap [jold+1] ;
+		    for (p = Ap [jold] ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold <= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MIN (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* packed, permuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    pend = Ap [jold+1] ;
+		    for (p = Ap [jold] ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold >= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MAX (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (upper)
+	    {
+		/* packed, unpermuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    pend = Ap [j+1] ;
+		    for (p = Ap [j] ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i <= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* packed, unpermuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    pend = Ap [j+1] ;
+		    for (p = Ap [j] ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i >= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (permute)
+	{
+	    if (upper)
+	    {
+		/* unpacked, permuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    p = Ap [jold] ;
+		    pend = p + Anz [jold] ;
+		    for ( ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold <= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MIN (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* unpacked, permuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    jold = Perm [j] ;
+		    p = Ap [jold] ;
+		    pend = p + Anz [jold] ;
+		    for ( ; p < pend ; p++)
+		    {
+			iold = Ai [p] ;
+			if (iold >= jold)
+			{
+			    i = Pinv [iold] ;
+			    Wi [MAX (i, j)]++ ;
+			}
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    if (upper)
+	    {
+		/* unpacked, unpermuted, upper */
+		for (j = 0 ; j < n ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i <= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* unpacked, unpermuted, lower */
+		for (j = 0 ; j < n ; j++)
+		{
+		    p = Ap [j] ;
+		    pend = p + Anz [j] ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i >= j)
+			{
+			    Wi [i]++ ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Fp [i] = p ;
+	p += Wi [i] ;
+    }
+    Fp [n] = p ;
+    for (i = 0 ; i < n ; i++)
+    {
+	Wi [i] = Fp [i] ;
+    }
+
+    if (p > (Int) (F->nzmax))
+    {
+	ERROR (CHOLMOD_INVALID, "F is too small") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* transpose matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    ok = FALSE ;
+    if (values == 0 || F->xtype == CHOLMOD_PATTERN)
+    {
+	PRINT2 (("\n:::: p_transpose_sym Perm %p\n", Perm)) ;
+	ok = p_cholmod_transpose_sym (A, Perm, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_REAL)
+    {
+	PRINT2 (("\n:::: r_transpose_sym Perm %p\n", Perm)) ;
+	ok = r_cholmod_transpose_sym (A, Perm, F, Common) ;
+    }
+    else if (F->xtype == CHOLMOD_COMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    PRINT2 (("\n:::: ct_transpose_sym Perm %p\n", Perm)) ;
+	    ok = ct_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    PRINT2 (("\n:::: c_transpose_sym Perm %p\n", Perm)) ;
+	    ok = c_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+    }
+    else if (F->xtype == CHOLMOD_ZOMPLEX)
+    {
+	if (values == 1)
+	{
+	    /* array transpose */
+	    PRINT2 (("\n:::: zt_transpose_sym Perm %p\n", Perm)) ;
+	    ok = zt_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+	else
+	{
+	    /* complex conjugate transpose */
+	    PRINT2 (("\n:::: z_transpose_sym Perm %p\n", Perm)) ;
+	    ok = z_cholmod_transpose_sym (A, Perm, F, Common) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* finalize result F */
+    /* ---------------------------------------------------------------------- */
+
+    /* F is sorted if there is no permutation vector */
+    if (ok)
+    {
+	F->sorted = !permute ;
+	F->packed = TRUE ;
+	F->stype = - SIGN (A->stype) ;	/* flip the stype */
+	ASSERT (CHOLMOD(dump_sparse) (F, "output F sym", Common) >= 0) ;
+    }
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_transpose ==================================================== */
+/* ========================================================================== */
+
+/* Returns A'.  See also cholmod_ptranspose below. */
+
+cholmod_sparse *CHOLMOD(transpose)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values
+			   (returns its result as CHOLMOD_PATTERN) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(ptranspose) (A, values, NULL, NULL, 0, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_ptranspose =================================================== */
+/* ========================================================================== */
+
+/* Return A' or A(p,p)' if A is symmetric.  Return A', A(:,f)', or A(p,f)' if
+ * A is unsymmetric.
+ *
+ * workspace:
+ * Iwork (MAX (nrow,ncol)) if unsymmetric and fset is non-NULL
+ * Iwork (nrow) if unsymmetric and fset is NULL
+ * Iwork (2*nrow) if symmetric and Perm is non-NULL.
+ * Iwork (nrow) if symmetric and Perm is NULL.
+ *
+ * A simple worst-case upper bound on the workspace is nrow+ncol.
+ */
+
+cholmod_sparse *CHOLMOD(ptranspose)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 2: complex conj. transpose, 1: array transpose,
+			   0: do not transpose the numerical values */
+    Int *Perm,		/* if non-NULL, F = A(p,f) or A(p,p) */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Anz ;
+    cholmod_sparse *F ;
+    Int nrow, ncol, use_fset, j, jj, fnz, packed, stype, nf, xtype ;
+    size_t ineed ;
+    int ok = TRUE ;
+
+    nf = fsize ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    stype = A->stype ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    if (stype != 0)
+    {
+	use_fset = FALSE ;
+	if (Perm != NULL)
+	{
+	    ineed = CHOLMOD(mult_size_t) (A->nrow, 2, &ok) ;
+	}
+	else
+	{
+	    ineed = A->nrow ;
+	}
+    }
+    else
+    {
+	use_fset = (fset != NULL) ;
+	if (use_fset)
+	{
+	    ineed = MAX (A->nrow, A->ncol) ;
+	}
+	else
+	{
+	    ineed = A->nrow ;
+	}
+    }
+
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    CHOLMOD(allocate_work) (0, ineed, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+    xtype = values ? A->xtype : CHOLMOD_PATTERN ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate F */
+    /* ---------------------------------------------------------------------- */
+
+    /* determine # of nonzeros in F */
+    if (stype != 0)
+    {
+	/* F=A' or F=A(p,p)', fset is ignored */
+	fnz = CHOLMOD(nnz) (A, Common) ;
+    }
+    else
+    {
+	nf = (use_fset) ? nf : ncol ;
+	if (use_fset)
+	{
+	    fnz = 0 ;
+	    /* F=A(:,f)' or F=A(p,f)' */
+	    for (jj = 0 ; jj < nf ; jj++)
+	    {
+		/* The fset is not yet checked; it will be thoroughly checked
+		 * in cholmod_transpose_unsym.  For now, just make sure we don't
+		 * access Ap and Anz out of bounds. */
+		j = fset [jj] ;
+		if (j >= 0 && j < ncol)
+		{
+		    fnz += packed ? (Ap [j+1] - Ap [j]) : MAX (0, Anz [j]) ;
+		}
+	    }
+	}
+	else
+	{
+	    /* F=A' or F=A(p,:)' */
+	    fnz = CHOLMOD(nnz) (A, Common) ;
+	}
+    }
+
+    /* F is ncol-by-nrow, fnz nonzeros, sorted unless f is present and unsorted,
+     * packed, of opposite stype as A, and with/without numerical values */
+    F = CHOLMOD(allocate_sparse) (ncol, nrow, fnz, TRUE, TRUE, -SIGN(stype),
+	    xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* transpose and optionally permute the matrix A */
+    /* ---------------------------------------------------------------------- */
+
+    if (stype != 0)
+    {
+	/* F = A (p,p)', using upper or lower triangular part of A only */
+	ok = CHOLMOD(transpose_sym) (A, values, Perm, F, Common) ;
+    }
+    else
+    {
+	/* F = A (p,f)' */
+	ok = CHOLMOD(transpose_unsym) (A, values, Perm, fset, nf, F, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the matrix F, or NULL if an error occured */
+    /* ---------------------------------------------------------------------- */
+
+    if (!ok)
+    {
+	CHOLMOD(free_sparse) (&F, Common) ;
+    }
+    return (F) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sort ========================================================= */
+/* ========================================================================== */
+
+/* Sort the columns of A, in place.  Returns A in packed form, even if it
+ * starts as unpacked.  Removes entries in the ignored part of a symmetric
+ * matrix.
+ *
+ * workspace: Iwork (max (nrow,ncol)).  Allocates additional workspace for a
+ * temporary copy of A'.
+ */
+
+int CHOLMOD(sort)
+(
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to sort */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap ;
+    cholmod_sparse *F ;
+    Int anz, ncol, nrow, stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    nrow = A->nrow ;
+    if (nrow <= 1)
+    {
+	/* a 1-by-n sparse matrix must be sorted */
+	A->sorted = TRUE ;
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    ncol = A->ncol ;
+    CHOLMOD(allocate_work) (0, MAX (nrow, ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    anz = CHOLMOD(nnz) (A, Common) ;
+    stype = A->stype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* sort the columns of the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    /* allocate workspace for transpose: ncol-by-nrow, same # of nonzeros as A,
+     * sorted, packed, same stype as A, and of the same numeric type as A. */
+    F = CHOLMOD(allocate_sparse) (ncol, nrow, anz, TRUE, TRUE, stype,
+	    A->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;	/* out of memory */
+    }
+
+    if (stype != 0)
+    {
+	/* F = A', upper or lower triangular part only */
+	CHOLMOD(transpose_sym) (A, 1, NULL, F, Common) ;
+	A->packed = TRUE ;
+	/* A = F' */
+	CHOLMOD(transpose_sym) (F, 1, NULL, A, Common) ;
+    }
+    else
+    {
+	/* F = A' */
+	CHOLMOD(transpose_unsym) (A, 1, NULL, NULL, 0, F, Common) ;
+	A->packed = TRUE ;
+	/* A = F' */
+	CHOLMOD(transpose_unsym) (F, 1, NULL, NULL, 0, A, Common) ;
+    }
+
+    ASSERT (A->sorted && A->packed) ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "Asorted", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* reduce A in size, if needed.  This must succeed. */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    anz = Ap [ncol] ;
+    ASSERT ((size_t) anz <= A->nzmax) ;
+    CHOLMOD(reallocate_sparse) (anz, A, Common) ;
+    ASSERT (Common->status >= CHOLMOD_OK) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&F, Common) ;
+    return (TRUE) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_triplet.c b/src/CHOLMOD/Core/cholmod_triplet.c
new file mode 100644
index 0000000..a5f39b2
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_triplet.c
@@ -0,0 +1,772 @@
+/* ========================================================================== */
+/* === Core/cholmod_triplet ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Core utility routines for the cholmod_triplet object:
+ *
+ * A sparse matrix held in triplet form is the simplest one for a user to
+ * create.  It consists of a list of nz entries in arbitrary order, held in
+ * three arrays: i, j, and x, each of length nk.  The kth entry is in row i[k],
+ * column j[k], with value x[k].  There may be duplicate values; if A(i,j)
+ * appears more than once, its value is the sum of the entries with those row
+ * and column indices.
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_allocate_triplet	allocate a triplet matrix
+ * cholmod_free_triplet		free a triplet matrix
+ *
+ * Secondary routines:
+ * -------------------
+ * cholmod_reallocate_triplet	reallocate a triplet matrix
+ * cholmod_sparse_to_triplet	create a triplet matrix copy of a sparse matrix
+ * cholmod_triplet_to_sparse	create a sparse matrix copy of a triplet matrix
+ * cholmod_copy_triplet		create a copy of a triplet matrix
+ *
+ * The relationship between an m-by-n cholmod_sparse matrix A and a
+ * cholmod_triplet matrix (i, j, and x) is identical to how they are used in
+ * the MATLAB "sparse" and "find" functions:
+ *
+ *	[i j x] = find (A)
+ *	[m n] = size (A)
+ *	A = sparse (i,j,x,m,n)
+ *
+ * with the exception that the cholmod_sparse matrix may be "unpacked", may
+ * have either sorted or unsorted columns (depending on the option selected),
+ * and may be symmetric with just the upper or lower triangular part stored.
+ * Likewise, the cholmod_triplet matrix may contain just the entries in the
+ * upper or lower triangular part of a symmetric matrix.
+ *
+ * MATLAB sparse matrices are always "packed", always have sorted columns,
+ * and always store both parts of a symmetric matrix.  In some cases, MATLAB
+ * behaves like CHOLMOD by ignoring entries in the upper or lower triangular
+ * part of a matrix that is otherwise assumed to be symmetric (such as the
+ * input to chol).  In CHOLMOD, that option is a characteristic of the object.
+ * In MATLAB, that option is based on how a matrix is used as the input to
+ * a function.
+ *
+ * The triplet matrix is provided to give the user a simple way of constructing
+ * a sparse matrix.  There are very few operations supported for triplet
+ * matrices.  The assumption is that they will be converted to cholmod_sparse
+ * matrix form first.
+ *
+ * Adding two triplet matrices simply involves concatenating the contents of
+ * the three arrays (i, j, and x).   To permute a triplet matrix, just replace
+ * the row and column indices with their permuted values.  For example, if
+ * P is a permutation vector, then P [k] = j means row/column j is the kth
+ * row/column in C=P*A*P'.  In MATLAB notation, C=A(p,p).  If Pinv is an array
+ * of size n and T is the triplet form of A, then:
+ *
+ *	Ti = T->i ;
+ *	Tj = T->j ;
+ *	for (k = 0 ; k < n  ; k++) Pinv [P [k]] = k ;
+ *	for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ;
+ *	for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ;
+ *
+ * overwrites T with the triplet form of C=P*A*P'.  The conversion
+ *
+ *	C = cholmod_triplet_to_sparse (T, 0, &Common) ;
+ *
+ * will then return the matrix C = P*A*P'.
+ *
+ * Note that T->stype > 0 means that entries in the lower triangular part of
+ * T are transposed into the upper triangular part when T is converted to
+ * sparse matrix (cholmod_sparse) form with cholmod_triplet_to_sparse.  The
+ * opposite is true for T->stype < 0.
+ *
+ * Since the triplet matrix T is so simple to generate, it's quite easy
+ * to remove entries that you do not want, prior to converting T to the
+ * cholmod_sparse form.  So if you include these entries in T, CHOLMOD
+ * assumes that there must be a reason (such as the one above).  Thus,
+ * no entry in a triplet matrix is ever ignored.
+ *
+ * Other operations, such as extacting a submatrix, horizontal and vertical
+ * concatenation, multiply a triplet matrix times a dense matrix, are also
+ * simple.  Multiplying two triplet matrices is not trivial; the simplest
+ * method is to convert them to cholmod_sparse matrices first.
+ *
+ * Supports all xtypes (pattern, real, complex, and zomplex).
+ */
+ 
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define PATTERN
+#include "t_cholmod_triplet.c"
+#define REAL
+#include "t_cholmod_triplet.c"
+#define COMPLEX
+#include "t_cholmod_triplet.c"
+#define ZOMPLEX
+#include "t_cholmod_triplet.c"
+
+
+/* ========================================================================== */
+/* === cholmod_allocate_triplet ============================================= */
+/* ========================================================================== */
+
+/* allocate space for a triplet matrix
+ *
+ * workspace: none
+ */
+
+cholmod_triplet *CHOLMOD(allocate_triplet)
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of T */
+    size_t ncol,	/* # of columns of T */
+    size_t nzmax,	/* max # of nonzeros of T */
+    int stype,		/* stype of T */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_triplet *T ;
+    size_t nzmax0 ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    if (xtype < CHOLMOD_PATTERN || xtype > CHOLMOD_ZOMPLEX)
+    {
+	ERROR (CHOLMOD_INVALID, "xtype invalid") ;
+	return (NULL) ;
+    }
+    /* ensure the dimensions do not cause integer overflow */
+    (void) CHOLMOD(add_size_t) (ncol, 2, &ok) ;
+    if (!ok || nrow > Int_max || ncol > Int_max || nzmax > Int_max)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate header */
+    /* ---------------------------------------------------------------------- */
+
+    T = CHOLMOD(malloc) (sizeof (cholmod_triplet), 1, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    PRINT1 (("cholmod_allocate_triplet %d-by-%d nzmax %d xtype %d\n",
+		nrow, ncol, nzmax, xtype)) ;
+
+    nzmax = MAX (1, nzmax) ;
+
+    T->nrow = nrow ;
+    T->ncol = ncol ;
+    T->nzmax = nzmax ;
+    T->nnz = 0 ;
+    T->stype = stype ;
+    T->itype = ITYPE ;
+    T->xtype = xtype ;
+    T->dtype = DTYPE ;
+
+    T->j = NULL ;
+    T->i = NULL ;
+    T->x = NULL ;
+    T->z = NULL ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the matrix itself */
+    /* ---------------------------------------------------------------------- */
+
+    nzmax0 = 0 ;
+    CHOLMOD(realloc_multiple) (nzmax, 2, xtype, &(T->i), &(T->j),
+		&(T->x), &(T->z), &nzmax0, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_triplet) (&T, Common) ;
+	return (NULL) ;	    /* out of memory */
+    }
+
+    return (T) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_free_triplet ================================================= */
+/* ========================================================================== */
+
+/* free a triplet matrix
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(free_triplet)
+(
+    /* ---- in/out --- */
+    cholmod_triplet **THandle,    /* matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int nz ;
+    cholmod_triplet *T ;
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+
+    if (THandle == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    T = *THandle ;
+    if (T == NULL)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+    nz = T->nzmax ;
+    T->j = CHOLMOD(free) (nz, sizeof (Int), T->j, Common) ;
+    T->i = CHOLMOD(free) (nz, sizeof (Int), T->i, Common) ;
+    if (T->xtype == CHOLMOD_REAL)
+    {
+	T->x = CHOLMOD(free) (nz, sizeof (double), T->x, Common) ;
+    }
+    else if (T->xtype == CHOLMOD_COMPLEX)
+    {
+	T->x = CHOLMOD(free) (nz, 2*sizeof (double), T->x, Common) ;
+    }
+    else if (T->xtype == CHOLMOD_ZOMPLEX)
+    {
+	T->x = CHOLMOD(free) (nz, sizeof (double), T->x, Common) ;
+	T->z = CHOLMOD(free) (nz, sizeof (double), T->z, Common) ;
+    }
+    *THandle = CHOLMOD(free) (1, sizeof (cholmod_triplet), (*THandle), Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_reallocate_triplet =========================================== */
+/* ========================================================================== */
+
+/* Change the size of T->i, T->j, and T->x, or allocate them if their current
+ * size is zero.  T->x is not modified if T->xtype is CHOLMOD_PATTERN.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(reallocate_triplet)
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in T */
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (T, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    PRINT1 (("realloc triplet %d to %d, xtype: %d\n",
+		T->nzmax, nznew, T->xtype)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* resize the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(realloc_multiple) (MAX (1,nznew), 2, T->xtype, &(T->i), &(T->j),
+	    &(T->x), &(T->z), &(T->nzmax), Common) ;
+
+    return (Common->status == CHOLMOD_OK) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_triplet_to_sparse ============================================ */
+/* ========================================================================== */
+
+/* Convert a set of triplets into a cholmod_sparse matrix.  In MATLAB notation,
+ * for unsymmetric matrices:
+ *
+ *	A = sparse (Ti, Tj, Tx, nrow, ncol, nzmax) ;
+ *
+ * For the symmetric upper case:
+ *
+ *	A = sparse (min(Ti,Tj), max(Ti,Tj), Tx, nrow, ncol, nzmax) ;
+ *
+ * For the symmetric lower case:
+ *
+ *	A = sparse (max(Ti,Tj), min(Ti,Tj), Tx, nrow, ncol, nzmax) ;
+ *
+ * If Tx is NULL, then A->x is not allocated, and only the pattern of A is
+ * computed.  A is returned in packed form, and can be of any stype
+ * (upper/lower/unsymmetric).  It has enough space to hold the values in T,
+ * or nzmax, whichever is larger.
+ *
+ * workspace: Iwork (max (nrow,ncol))
+ *	allocates a temporary copy of its output matrix.
+ *
+ * The resulting sparse matrix has the same xtype as the input triplet matrix.
+ */
+
+cholmod_sparse *CHOLMOD(triplet_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    size_t nzmax,	/* allocate at least this much space in output matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *R, *A = NULL ;
+    Int *Wj, *Rp, *Ri, *Rnz, *Ti, *Tj ;
+    Int i, j, p, k, stype, nrow, ncol, nz, ok ;
+    size_t anz = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (T, NULL) ;
+    Ti = T->i ;
+    Tj = T->j ;
+    RETURN_IF_NULL (Ti, NULL) ;
+    RETURN_IF_NULL (Tj, NULL) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    stype = SIGN (T->stype) ;
+    if (stype && T->nrow != T->ncol)
+    {
+	/* inputs invalid */
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_triplet) (T, "T", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = T->nrow ;
+    ncol = T->ncol ;
+    nz = T->nnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(allocate_work) (0, MAX (nrow, ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate temporary matrix R */
+    /* ---------------------------------------------------------------------- */
+
+    R = CHOLMOD(allocate_sparse) (ncol, nrow, nz, FALSE, FALSE, -stype,
+	    T->xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    Rp = R->p ;
+    Ri = R->i ;
+    Rnz = R->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the entries in each row of A (also counting duplicates) */
+    /* ---------------------------------------------------------------------- */
+
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Rnz [i] = 0 ;	
+    }
+
+    if (stype > 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < 0 || i >= nrow || j < 0 || j >= ncol)
+	    {
+		ERROR (CHOLMOD_INVALID, "index out of range") ;
+		break ;
+	    }
+	    /* A will be symmetric with just the upper triangular part stored.
+	     * Create a matrix R that is lower triangular.  Entries in the
+	     * upper part of R are transposed to the lower part. */
+	    Rnz [MIN (i,j)]++ ;
+	}
+    }
+    else if (stype < 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < 0 || i >= nrow || j < 0 || j >= ncol)
+	    {
+		ERROR (CHOLMOD_INVALID, "index out of range") ;
+		break ;
+	    }
+	    /* A will be symmetric with just the lower triangular part stored.
+	     * Create a matrix R that is upper triangular.  Entries in the
+	     * lower part of R are transposed to the upper part. */
+	    Rnz [MAX (i,j)]++ ;
+	}
+    }
+    else
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < 0 || i >= nrow || j < 0 || j >= ncol)
+	    {
+		ERROR (CHOLMOD_INVALID, "index out of range") ;
+		break ;
+	    }
+	    /* constructing an unsymmetric matrix */
+	    Rnz [i]++ ;
+	}
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* triplet matrix is invalid */
+	CHOLMOD(free_sparse) (&R, Common) ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row pointers */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Rp [i] = p ;
+	p += Rnz [i] ;
+    }
+    Rp [nrow] = p ;
+
+    /* use Wj (i/l/l) as temporary row pointers */
+    Wj = Common->Iwork ;	/* size MAX (nrow,ncol) FUTURE WORK: (i/l/l) */
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Wj [i] = Rp [i] ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct triplet matrix, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (T->xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    anz = p_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    anz = r_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    anz = c_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    anz = z_cholmod_triplet_to_sparse (T, R, Common) ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* A = R' (array transpose, not complex conjugate transpose) */
+    /* ---------------------------------------------------------------------- */
+
+    /* workspace: Iwork (R->nrow), which is A->ncol */
+
+    ASSERT (CHOLMOD(dump_sparse) (R, "R", Common) >= 0) ;
+
+    A = CHOLMOD(allocate_sparse) (nrow, ncol, MAX (anz, nzmax), TRUE, TRUE,
+	stype, T->xtype, Common) ;
+
+    if (stype)
+    {
+	ok = CHOLMOD(transpose_sym) (R, 1, NULL, A, Common) ;
+    }
+    else
+    {
+	ok = CHOLMOD(transpose_unsym) (R, 1, NULL, NULL, 0, A, Common) ; 
+    }
+
+    CHOLMOD(free_sparse) (&R, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free_sparse) (&A, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A = triplet(T) result", Common) >= 0) ;
+    return (A) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_sparse_to_triplet ============================================ */
+/* ========================================================================== */
+
+/* Converts a sparse column-oriented matrix to triplet form.
+ * The resulting triplet matrix has the same xtype as the sparse matrix.
+ *
+ * workspace: none
+ */
+
+cholmod_triplet *CHOLMOD(sparse_to_triplet)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az, *Tx, *Tz ;
+    Int *Ap, *Ai, *Ti, *Tj, *Anz ;
+    cholmod_triplet *T ;
+    Int i, xtype, p, pend, k, j, nrow, ncol, nz, stype, packed, up, lo,
+	both ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    stype = SIGN (A->stype) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    if (stype && nrow != ncol)
+    {
+	/* inputs invalid */
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (NULL) ;
+    }
+    Ax = A->x ;
+    Az = A->z ;
+    xtype = A->xtype ;
+    Common->status = CHOLMOD_OK ;
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    nz = CHOLMOD(nnz) (A, Common) ;
+    T = CHOLMOD(allocate_triplet) (nrow, ncol, nz, A->stype, A->xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to a sparse matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+    packed = A->packed ;
+
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    T->stype = A->stype ;
+
+    both = (A->stype == 0) ;
+    up = (A->stype > 0) ;
+    lo = (A->stype < 0) ;
+
+    k = 0 ;
+
+    for (j = 0 ; j < ncol ; j++)
+    {
+	p = Ap [j] ;
+	pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Ai [p] ;
+	    if (both || (up && i <= j) || (lo && i >= j))
+	    {
+		Ti [k] = Ai [p] ;
+		Tj [k] = j ;
+
+		if (xtype == CHOLMOD_REAL)
+		{
+		    Tx [k] = Ax [p] ;
+		}
+		else if (xtype == CHOLMOD_COMPLEX)
+		{
+		    Tx [2*k  ] = Ax [2*p  ] ;
+		    Tx [2*k+1] = Ax [2*p+1] ;
+		}
+		else if (xtype == CHOLMOD_ZOMPLEX)
+		{
+		    Tx [k] = Ax [p] ;
+		    Tz [k] = Az [p] ;
+		}
+
+		k++ ;
+		ASSERT (k <= nz) ;
+	    }
+	}
+    }
+
+    T->nnz = k ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_triplet) (T, "T", Common)) ;
+    return (T) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_copy_triplet ================================================= */
+/* ========================================================================== */
+
+/* Create an exact copy of a triplet matrix, except that entries in unused
+ * space are not copied (they might not be initialized, and copying them would
+ * cause program checkers such as purify and valgrind to complain).
+ * The output triplet matrix has the same xtype as the input triplet matrix.
+ */
+
+cholmod_triplet *CHOLMOD(copy_triplet)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Tx, *Tz, *Cx, *Cz ;
+    Int *Ci, *Cj, *Ti, *Tj ;
+    cholmod_triplet *C ;
+    Int xtype, k, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (T, NULL) ;
+    RETURN_IF_XTYPE_INVALID (T, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, NULL) ;
+    nz = T->nnz ;
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    xtype = T->xtype ;
+    RETURN_IF_NULL (Ti, NULL) ;
+    RETURN_IF_NULL (Tj, NULL) ;
+    Common->status = CHOLMOD_OK ;
+    DEBUG (CHOLMOD(dump_triplet) (T, "T input", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate copy */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_triplet) (T->nrow, T->ncol, T->nzmax, T->stype,
+	    xtype, Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the triplet matrix */
+    /* ---------------------------------------------------------------------- */
+
+    Ci = C->i ;
+    Cj = C->j ;
+    Cx = C->x ;
+    Cz = C->z ;
+    C->nnz = nz ;
+
+    for (k = 0 ; k < nz ; k++)
+    {
+	Ci [k] = Ti [k] ;
+    }
+    for (k = 0 ; k < nz ; k++)
+    {
+	Cj [k] = Tj [k] ;
+    }
+
+    if (xtype == CHOLMOD_REAL)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Cx [k] = Tx [k] ;
+	}
+    }
+    else if (xtype == CHOLMOD_COMPLEX)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Cx [2*k  ] = Tx [2*k  ] ;
+	    Cx [2*k+1] = Tx [2*k+1] ;
+	}
+    }
+    else if (xtype == CHOLMOD_ZOMPLEX)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    Cx [k] = Tx [k] ;
+	    Cz [k] = Tz [k] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_triplet) (C, "C triplet copy", Common)) ;
+    return (C) ;
+}
diff --git a/src/CHOLMOD/Core/cholmod_version.c b/src/CHOLMOD/Core/cholmod_version.c
new file mode 100644
index 0000000..0cc034e
--- /dev/null
+++ b/src/CHOLMOD/Core/cholmod_version.c
@@ -0,0 +1,37 @@
+/* ========================================================================== */
+/* === Core/cholmod_version ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2013,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Return the current version of CHOLMOD.  Unlike all other functions in
+   CHOLMOD, this function does not require the CHOLMOD Common. */
+
+#include "cholmod_internal.h"
+#include "cholmod_core.h"
+
+int CHOLMOD(version)        /* returns CHOLMOD_VERSION */
+(
+    /* output, contents not defined on input.  Not used if NULL.
+        version [0] = CHOLMOD_MAIN_VERSION ;
+        version [1] = CHOLMOD_SUB_VERSION ;
+        version [2] = CHOLMOD_SUBSUB_VERSION ;
+    */
+    int version [3]
+)
+{
+    if (version != NULL)
+    {
+        version [0] = CHOLMOD_MAIN_VERSION ;
+        version [1] = CHOLMOD_SUB_VERSION ;
+        version [2] = CHOLMOD_SUBSUB_VERSION ;
+    }
+    return (CHOLMOD_VERSION) ;
+}
+
diff --git a/src/CHOLMOD/Core/lesser.txt b/src/CHOLMOD/Core/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/CHOLMOD/Core/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/CHOLMOD/Core/t_cholmod_change_factor.c b/src/CHOLMOD/Core/t_cholmod_change_factor.c
new file mode 100644
index 0000000..dd49b44
--- /dev/null
+++ b/src/CHOLMOD/Core/t_cholmod_change_factor.c
@@ -0,0 +1,660 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_change_factor ========================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_change_factor.  All xtypes supported. */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_change_simplicial_numeric ========================================== */
+/* ========================================================================== */
+
+static void TEMPLATE (change_simplicial_numeric)
+(
+    cholmod_factor *L,
+    Int to_ll,
+    Int to_packed,
+    Int *newLi,
+    double *newLx,
+    double *newLz,
+    Int lnz,
+    Int grow,
+    double grow1,
+    Int grow2,
+    Int make_ll,
+    Int make_monotonic,
+    Int make_ldl,
+    cholmod_common *Common
+)
+{
+    double xlen, dj [1], ljj [1], lj2 [1] ;
+    double *Lx, *Lz ;
+    Int *Lp, *Li, *Lnz ;
+    Int n, j, len, pnew, pold, k, p, pend ;
+
+    n = L->n ;
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lz = L->z ;
+    Lnz = L->nz ;
+
+    if (make_ll)
+    {
+	L->minor = n ;
+    }
+
+    if (make_monotonic)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* reorder the columns to make them monotonic */
+	/* ------------------------------------------------------------------ */
+
+	pnew = 0 ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* copy and pack column j */
+	    len = Lnz [j] ;
+	    PRINT2 (("j: "ID" Lnz[j] "ID" len "ID" p "ID"\n",
+			j, Lnz [j], len, pnew)) ;
+	    pold = Lp [j] ;
+	    ASSERT (Li [pold] == j) ;
+
+	    if (make_ll)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* copy and convert LDL' to LL' */
+		/* ---------------------------------------------------------- */
+
+		/* dj = Lx [pold] ; */
+		ASSIGN_REAL (dj,0, Lx,pold) ;
+
+		if (IS_LE_ZERO (dj [0]))
+		{
+		    /* Conversion has failed; matrix is not positive definite.
+		     * Do not modify the column so that the LDL' factorization
+		     * can be restored if desired, by converting back to LDL'.
+		     * Continue the conversion, but flag the error. */
+		    if (L->minor == (size_t) n)
+		    {
+			ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ;
+			L->minor = j ;
+		    }
+		    for (k = 0 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    ljj [0] = sqrt (dj [0]) ;
+		    newLi [pnew] = j ;
+		    /* newLx [pnew] = ljj ; */
+		    ASSIGN_REAL (newLx, pnew, ljj, 0) ;
+		    CLEAR_IMAG (newLx, newLz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] * ljj ; */
+			MULT_REAL (newLx, newLz, pnew+k, Lx, Lz, pold+k, ljj,0);
+		    }
+		}
+
+	    }
+	    else if (make_ldl)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* copy and convert LL' to LDL' */
+		/* ---------------------------------------------------------- */
+
+		/* ljj = Lx [pold] ; */
+		ASSIGN_REAL (ljj, 0, Lx, pold) ;
+
+		if (ljj [0] <= 0)
+		{
+		    /* matrix is not positive-definite; copy column as-is */
+		    for (k = 0 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    newLi [pnew] = j ;
+		    /* newLx [pnew] = ljj*ljj ; */
+		    lj2 [0] = ljj [0] * ljj [0] ;
+		    ASSIGN_REAL (newLx, pnew, lj2, 0) ;
+		    CLEAR_IMAG (newLx, newLz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			newLi [pnew + k] = Li [pold + k] ;
+			/* newLx [pnew + k] = Lx [pold + k] / ljj ; */
+			DIV_REAL (newLx, newLz, pnew+k, Lx, Lz, pold+k, ljj,0) ;
+		    }
+		}
+
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* copy and leave LL' or LDL' as-is */
+		/* ---------------------------------------------------------- */
+
+		for (k = 0 ; k < len ; k++)
+		{
+		    newLi [pnew + k] = Li [pold + k] ;
+		    /* newLx [pnew + k] = Lx [pold + k] ; */
+		    ASSIGN (newLx, newLz, pnew+k, Lx, Lz, pold+k) ;
+		}
+	    }
+
+	    Lp [j] = pnew ;
+
+	    /* compute len in double to avoid integer overflow */
+	    if (grow)
+	    {
+		xlen = (double) len ;
+		xlen = grow1 * xlen + grow2 ;
+		xlen = MIN (xlen, n-j) ;
+		len = (Int) xlen ;
+	    }
+	    ASSERT (len >= Lnz [j] && len <= n-j) ;
+	    pnew += len ;
+	    ASSERT (pnew > 0) ;	    /* integer overflow case already covered */
+	}
+	Lp [n] = pnew ;
+	PRINT1 (("final pnew = "ID", lnz "ID" lnzmax %g\n",
+		    pnew, lnz, (double) L->nzmax)) ;
+	ASSERT (pnew <= lnz) ;
+
+	/* free the old L->i and L->x and replace with the new ones */
+	CHOLMOD(free) (L->nzmax, sizeof (Int), L->i, Common) ;
+
+#ifdef REAL
+	CHOLMOD(free) (L->nzmax, sizeof (double), L->x, Common) ;
+#elif defined (COMPLEX)
+	CHOLMOD(free) (L->nzmax, 2*sizeof (double), L->x, Common) ;
+#else
+	CHOLMOD(free) (L->nzmax, sizeof (double), L->x, Common) ;
+	CHOLMOD(free) (L->nzmax, sizeof (double), L->z, Common) ;
+#endif
+
+	L->i = newLi ;
+	L->x = newLx ;
+	L->z = newLz ;
+	L->nzmax = lnz ;
+
+	/* reconstruct the link list */
+	natural_list (L) ;
+
+    }
+    else if (to_packed)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* already monotonic, just pack the columns of L */
+	/* ------------------------------------------------------------------ */
+
+	pnew = 0 ;
+
+	if (make_ll)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* pack and convert LDL' to LL' */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < n ; j++)
+	    {
+		/* pack column j */
+		pold = Lp [j] ;
+		len = Lnz [j] ;
+		ASSERT (len > 0) ;
+		ASSERT (Li [pold] == j) ;
+		PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+
+		/* dj = Lx [pold] ; */
+		ASSIGN_REAL (dj,0, Lx,pold) ;
+
+		if (IS_LE_ZERO (dj [0]))
+		{
+		    /* Conversion has failed; matrix is not positive definite.
+		     * Do not modify the column so that the LDL' factorization
+		     * can be restored if desired, by converting back to LDL'.
+		     * Continue the conversion, but flag the error. */
+		    if (L->minor == (size_t) n)
+		    {
+			ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ;
+			L->minor = j ;
+		    }
+		    for (k = 0 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    ljj [0] = sqrt (dj [0]) ;
+		    Li [pnew] = j ;
+
+		    /* Lx [pnew] = ljj ; */
+		    ASSIGN_REAL (Lx, pnew, ljj, 0) ;
+		    CLEAR_IMAG (Lx, Lz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] * ljj ; */
+			MULT_REAL (Lx, Lz, pnew+k, Lx, Lz, pold+k, ljj,0) ;
+		    }
+		}
+		Lp [j] = pnew ;
+		pnew += len ;
+	    }
+
+	}
+	else if (make_ldl)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* pack and convert LL' to LDL' */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < n ; j++)
+	    {
+		/* pack column j */
+		pold = Lp [j] ;
+		len = Lnz [j] ;
+
+		/* ljj = Lx [pold] ; */
+		ASSIGN_REAL (ljj, 0, Lx, pold) ;
+
+		ASSERT (len > 0) ;
+		PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+		if (ljj [0] <= 0)
+		{
+		    /* matrix is not positive-definite; pack column as-is */
+		    for (k = 0 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		}
+		else
+		{
+		    Li [pnew] = Li [pold] ;
+
+		    /* Lx [pnew] = ljj*ljj ; */
+		    lj2 [0] = ljj [0] * ljj [0] ;
+		    ASSIGN_REAL (Lx, pnew, lj2, 0) ;
+		    CLEAR_IMAG (Lx, Lz, pnew) ;
+
+		    for (k = 1 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] / ljj ; */
+			DIV_REAL (Lx, Lz, pnew+k, Lx, Lz, pold+k, ljj,0) ;
+		    }
+		}
+		Lp [j] = pnew ;
+		pnew += len ;
+	    }
+
+	}
+	else
+	{
+
+	    /* ---------------------------------------------------------- */
+	    /* pack and leave LL' or LDL' as-is */
+	    /* ---------------------------------------------------------- */
+
+	    for (j = 0 ; j < n ; j++)
+	    {
+		/* pack column j */
+		pold = Lp [j] ;
+		len = Lnz [j] ;
+		ASSERT (len > 0) ;
+		PRINT2 (("col "ID" pnew "ID" pold "ID"\n", j, pnew, pold)) ;
+		if (pnew < pold)
+		{
+		    PRINT2 (("    pack this column\n")) ;
+		    for (k = 0 ; k < len ; k++)
+		    {
+			Li [pnew + k] = Li [pold + k] ;
+			/* Lx [pnew + k] = Lx [pold + k] ; */
+			ASSIGN (Lx, Lz, pnew+k, Lx, Lz, pold+k) ;
+		    }
+		    Lp [j] = pnew ;
+		}
+		pnew += len ;
+	    }
+	}
+
+	Lp [n] = pnew ;
+	PRINT2 (("Lp [n] = "ID"\n", pnew)) ;
+
+    }
+    else if (make_ll)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert LDL' to LL', but do so in-place */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+
+	    /* dj = Lx [p] ; */
+	    ASSIGN_REAL (dj,0, Lx,p) ;
+
+	    if (IS_LE_ZERO (dj [0]))
+	    {
+		/* Conversion has failed; matrix is not positive definite.
+		 * Do not modify the column so that the LDL' factorization
+		 * can be restored if desired, by converting back to LDL'.
+		 * Continue the conversion, but flag the error. */
+		if (L->minor == (size_t) n)
+		{
+		    ERROR (CHOLMOD_NOT_POSDEF, "L not positive definite") ;
+		    L->minor = j ;
+		}
+	    }
+	    else
+	    {
+		ljj [0] = sqrt (dj [0]) ;
+		/* Lx [p] = ljj ; */
+		ASSIGN_REAL (Lx,p, ljj,0) ;
+		CLEAR_IMAG (Lx, Lz, p) ;
+
+		for (p++ ; p < pend ; p++)
+		{
+		    /* Lx [p] *= ljj ; */
+		    MULT_REAL (Lx,Lz,p, Lx,Lz,p, ljj,0) ;
+		}
+	    }
+	}
+
+    }
+    else if (make_ldl)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* convert LL' to LDL', but do so in-place */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    p = Lp [j] ;
+	    pend = p + Lnz [j] ;
+
+	    /* ljj = Lx [p] ; */
+	    ASSIGN_REAL (ljj, 0, Lx, p) ;
+
+	    if (ljj [0] > 0)
+	    {
+		/* Lx [p] = ljj*ljj ; */
+		lj2 [0] = ljj [0] * ljj [0] ;
+		ASSIGN_REAL (Lx, p, lj2, 0) ;
+		CLEAR_IMAG (Lx, Lz, p) ;
+
+		for (p++ ; p < pend ; p++)
+		{
+		    /* Lx [p] /= ljj ; */
+		    DIV_REAL (Lx,Lz,p, Lx,Lz,p, ljj,0) ;
+		}
+	    }
+	}
+    }
+
+    L->is_ll = to_ll ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "done change simplicial numeric", Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === t_ll_super_to_simplicial_numeric ===================================== */
+/* ========================================================================== */
+
+/* A supernodal L can only be real or complex, not zomplex */
+
+#ifndef ZOMPLEX
+
+static void TEMPLATE (ll_super_to_simplicial_numeric)
+(
+    cholmod_factor *L,
+    Int to_packed,
+    Int to_ll,
+    cholmod_common *Common
+)
+{
+    double ljj [1], lj2 [1] ;
+    double *Lx ;
+    Int *Ls, *Lpi, *Lpx, *Super, *Lp, *Li, *Lnz ;
+    Int n, lnz, s, nsuper, p, psi, psx, psend, nsrow, nscol, ii, jj, j, k1, k2,
+	q ;
+
+    L->is_ll = to_ll ;
+
+    Lp = L->p ;
+    Li = L->i ;
+    Lx = L->x ;
+    Lnz = L->nz ;
+    lnz = L->nzmax ;
+
+    n = L->n ;
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+
+    p = 0 ;
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	k1 = Super [s] ;
+	k2 = Super [s+1] ;
+	psi = Lpi [s] ;
+	psend = Lpi [s+1] ;
+	psx = Lpx [s] ;
+	nsrow = psend - psi ;
+	nscol = k2 - k1 ;
+
+	for (jj = 0 ; jj < nscol ; jj++)
+	{
+	    /* column j of L starts here */
+	    j = jj + k1 ;
+
+	    if (to_ll)
+	    {
+		if (to_packed)
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LL' packed */
+		    /* ------------------------------------------------------ */
+
+		    Lp [j] = p ;
+		    PRINT2 (("Col j "ID" p "ID"\n", j, p)) ;
+		    for (ii = jj ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			ASSERT (p < (Int) (L->xsize) && p <= psx+ii+jj*nsrow) ;
+			Li [p] = Ls [psi + ii] ;
+			/* Lx [p] = Lx [psx + ii + jj*nsrow] ; */
+			q = psx + ii + jj*nsrow ;
+			ASSIGN (Lx,-,p, Lx,-,q) ;
+			PRINT2 (("  i "ID" ", Li [p])) ;
+			XPRINT2 (Lx,-,q) ;
+			PRINT2 (("\n")) ;
+			p++ ;
+		    }
+		    Lnz [j] = p - Lp [j] ;
+
+		}
+		else
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LL' unpacked */
+		    /* ------------------------------------------------------ */
+
+		    p = psx + jj + jj*nsrow ;
+		    Lp [j] = p ;
+		    Li [p] = j ;
+		    Lnz [j] = nsrow - jj ;
+		    p++ ;
+		    for (ii = jj + 1 ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			Li [psx + ii + jj*nsrow] = Ls [psi + ii] ;
+		    }
+
+		}
+	    }
+	    else
+	    {
+		if (to_packed)
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LDL' packed */
+		    /* ------------------------------------------------------ */
+
+		    Lp [j] = p ;
+		    PRINT2 (("Col j "ID" p "ID"\n", Lp [j], p)) ;
+		    /* ljj = Lx [psx + jj + jj*nsrow] ; */
+		    ASSIGN_REAL (ljj, 0, Lx, psx + jj + jj*nsrow) ;
+
+		    if (ljj [0] <= 0)
+		    {
+			/* the matrix is not positive definite; do not divide */
+			/* Lx [p] = ljj ; */
+			ASSIGN_REAL (Lx, p, ljj, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+			ljj [0] = 1 ;
+		    }
+		    else
+		    {
+			lj2 [0] = ljj [0] * ljj [0] ;
+			/* Lx [p] = ljj*ljj ; */
+			ASSIGN_REAL (Lx, p, lj2, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+		    }
+		    Li [p] = j ;
+		    p++ ;
+		    for (ii = jj + 1 ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			ASSERT (p < (Int) (L->xsize) && p <= psx+ii+jj*nsrow) ;
+			Li [p] = Ls [psi + ii] ;
+
+			/* Lx [p] = Lx [psx + ii + jj*nsrow] / ljj ; */
+			q = psx + ii + jj*nsrow ;
+			DIV_REAL (Lx, Lz, p, Lx, Lz, q, ljj,0) ;
+
+			PRINT2 (("  i "ID" %g\n", Li [p], Lx [p])) ;
+			p++ ;
+		    }
+		    Lnz [j] = p - Lp [j] ;
+
+		}
+		else
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* convert to LDL' unpacked */
+		    /* ------------------------------------------------------ */
+
+		    p = psx + jj + jj*nsrow ;
+		    Lp [j] = p ;
+
+		    /* ljj = Lx [p] ; */
+		    ASSIGN_REAL (ljj,0, Lx,p) ;
+
+		    if (ljj [0] <= 0)
+		    {
+			/* the matrix is not positive definite; do not divide */
+			/* Lx [p] = ljj ; */
+			ASSIGN_REAL (Lx, p, ljj, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+			ljj [0] = 1 ;
+		    }
+		    else
+		    {
+			lj2 [0] = ljj [0] * ljj [0] ;
+			/* Lx [p] = ljj*ljj ; */
+			ASSIGN_REAL (Lx, p, lj2, 0) ;
+			CLEAR_IMAG (Lx, Lz, p) ;
+		    }
+		    Li [p] = j ;
+		    Lnz [j] = nsrow - jj ;
+		    p++ ;
+		    for (ii = jj + 1 ; ii < nsrow ; ii++)
+		    {
+			/* get L(i,j) from supernode and store in column j */
+			Li [psx + ii + jj*nsrow] = Ls [psi + ii] ;
+
+			/* Lx [psx + ii + jj*nsrow] /= ljj ; */
+			q = psx + ii + jj*nsrow ;
+			DIV_REAL (Lx, Lz, q, Lx, Lz, q, ljj,0) ;
+		    }
+		}
+	    }
+	}
+    }
+
+    if (to_packed)
+    {
+	Lp [n] = p ;
+	PRINT1 (("Final Lp "ID" n "ID" lnz "ID"\n", p, n, lnz)) ;
+	ASSERT (Lp [n] == lnz) ;
+	ASSERT (lnz <= (Int) (L->xsize)) ;
+	/* reduce size of L->x to match L->i.  This cannot fail. */
+	L->x = CHOLMOD(realloc) (lnz, 
+#ifdef COMPLEX
+		2 *
+#endif
+		sizeof (double), L->x, &(L->xsize), Common) ;
+	ASSERT (lnz == (Int) (L->xsize)) ;
+	Common->status = CHOLMOD_OK ;
+    }
+    else
+    {
+	Lp [n] = Lpx [nsuper] ;
+	ASSERT (MAX (1,Lp [n]) == (Int) (L->xsize)) ;
+	ASSERT (MAX (1,Lp [n]) == (Int) (L->nzmax)) ;
+    }
+}
+
+#endif
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Core/t_cholmod_dense.c b/src/CHOLMOD/Core/t_cholmod_dense.c
new file mode 100644
index 0000000..6f3f270
--- /dev/null
+++ b/src/CHOLMOD/Core/t_cholmod_dense.c
@@ -0,0 +1,265 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_dense ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_dense.  All xtypes supported, except that there
+ * are no dense matrices with an xtype of pattern. */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_cholmod_sparse_to_dense ============================================ */
+/* ========================================================================== */
+
+static cholmod_dense *TEMPLATE (cholmod_sparse_to_dense)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Xx, *Az, *Xz ;
+    Int *Ap, *Ai, *Anz ;
+    cholmod_dense *X ;
+    Int i, j, p, pend, nrow, ncol, packed ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+    packed = A->packed ;
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate result */
+    /* ---------------------------------------------------------------------- */
+
+    X = CHOLMOD(zeros) (nrow, ncol, XTYPE2, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    Xx = X->x ;
+    Xz = X->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy into dense matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->stype < 0)
+    {
+	/* A is symmetric with lower stored, but both parts of X are present */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i >= j)
+		{
+		    ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ;
+		    ASSIGN2_CONJ (Xx, Xz, j+i*nrow, Ax, Az, p) ;
+		}
+	    }
+	}
+    }
+    else if (A->stype > 0)
+    {
+	/* A is symmetric with upper stored, but both parts of X are present */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		if (i <= j)
+		{
+		    ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ;
+		    ASSIGN2_CONJ (Xx, Xz, j+i*nrow, Ax, Az, p) ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* both parts of A and X are present */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		ASSIGN2 (Xx, Xz, i+j*nrow, Ax, Az, p) ;
+	    }
+	}
+    }
+
+    return (X) ;
+}
+
+
+#ifndef PATTERN
+
+/* There are no dense matrices of xtype CHOLMOD_PATTERN */
+
+/* ========================================================================== */
+/* === t_cholmod_dense_to_sparse ============================================ */
+/* ========================================================================== */
+
+static cholmod_sparse *TEMPLATE (cholmod_dense_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    int values,		/* TRUE if values to be copied, FALSE otherwise */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Xx, *Cx, *Xz, *Cz ;
+    Int *Ci, *Cp ;
+    cholmod_sparse *C ;
+    Int i, j, p, d, nrow, ncol, nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* count the number of nonzeros in the result */
+    /* ---------------------------------------------------------------------- */
+
+    nz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    if (ENTRY_IS_NONZERO (Xx, Xz, i+j*d))
+	    {
+		nz++ ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the result C */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, TRUE, TRUE, 0,
+	    values ? XTYPE : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (NULL) ;	    /* out of memory */
+    }
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+    Cz = C->z ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the dense matrix X into the sparse matrix C */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Cp [j] = p ;
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    if (ENTRY_IS_NONZERO (Xx, Xz, i+j*d))
+	    {
+		Ci [p] = i ;
+		if (values)
+		{
+		    ASSIGN (Cx, Cz, p, Xx, Xz, i+j*d) ;
+		}
+		p++ ;
+	    }
+	}
+    }
+    ASSERT (p == nz) ;
+    Cp [ncol] = nz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C, "C", Common) >= 0) ;
+    return (C) ;
+}
+
+
+/* ========================================================================== */
+/* === t_cholmod_copy_dense2 ================================================ */
+/* ========================================================================== */
+
+/* Y = X, where X and Y are both already allocated.  */
+
+static int TEMPLATE (cholmod_copy_dense2)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* ---- output --- */
+    cholmod_dense *Y	/* copy of matrix X */
+)
+{
+    double *Xx, *Xz, *Yx, *Yz ;
+    Int i, j, nrow, ncol, dy, dx ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    dx = X->d ;
+    dy = Y->d ;
+    nrow = X->nrow ;
+    ncol = X->ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy */
+    /* ---------------------------------------------------------------------- */
+
+    CLEAR (Yx, Yz, 0) ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    ASSIGN (Yx, Yz, i+j*dy, Xx, Xz, i+j*dx) ;
+	}
+    }
+    return (TRUE) ;
+}
+
+#endif
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Core/t_cholmod_transpose.c b/src/CHOLMOD/Core/t_cholmod_transpose.c
new file mode 100644
index 0000000..a5dd849
--- /dev/null
+++ b/src/CHOLMOD/Core/t_cholmod_transpose.c
@@ -0,0 +1,317 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_transpose ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_transpose.  All xtypes are supported.  For
+ * complex matrices, either the array tranpose or complex conjugate transpose
+ * can be computed. */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_cholmod_transpose_unsym ============================================ */
+/* ========================================================================== */
+
+/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is
+ * already allocated.  The complex case performs either the array transpose
+ * or complex conjugate transpose.
+ *
+ * workspace:
+ * Iwork (MAX (nrow,ncol)) if fset is present
+ * Iwork (nrow) if fset is NULL
+ */
+
+static int TEMPLATE (cholmod_transpose_unsym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    Int *Perm,		/* size nrow, if present (can be NULL) */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    Int nf,		/* size of fset */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A', A(:,f)', or A(p,f)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az, *Fx, *Fz ;
+    Int *Ap, *Anz, *Ai, *Fp, *Fnz, *Fj, *Wi, *Iwork ;
+    Int j, p, pend, nrow, ncol, Apacked, use_fset, fp, Fpacked, jj, permute ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* ensure the xtype of A and F match (ignored if this is pattern version) */
+    if (!XTYPE_OK (A->xtype))
+    {
+	ERROR (CHOLMOD_INVALID, "real/complex mismatch") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    use_fset = (fset != NULL) ;
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Ax = A->x ;		/* size nz, real values of A */
+    Az = A->z ;		/* size nz, imag values of A */
+    Anz = A->nz ;
+    Apacked = A->packed ;
+    ASSERT (IMPLIES (!Apacked, Anz != NULL)) ;
+
+    permute = (Perm != NULL) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+    Fj = F->i ;		/* size nz, column indices of F */
+    Fx = F->x ;		/* size nz, real values of F */
+    Fz = F->z ;		/* size nz, imag values of F */
+    Fnz = F->nz ;
+    Fpacked = F->packed ;
+    ASSERT (IMPLIES (!Fpacked, Fnz != NULL)) ;
+
+    nf = (use_fset) ? nf : ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wi = Iwork ;		/* size nrow (i/l/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the transpose */
+    /* ---------------------------------------------------------------------- */
+
+    for (jj = 0 ; jj < nf ; jj++)
+    {
+	j = (use_fset) ? (fset [jj]) : jj ;
+	p = Ap [j] ;
+	pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    fp = Wi [Ai [p]]++ ;
+	    Fj [fp] = j ;
+#ifdef NCONJUGATE
+	    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+	    ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+	}
+    }
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === t_cholmod_transpose_sym ============================================== */
+/* ========================================================================== */
+
+/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated.
+ * The complex case performs either the array transpose or complex conjugate
+ * transpose.
+ *
+ * workspace:  Iwork (nrow) if Perm NULL, Iwork (2*nrow) if Perm non-NULL.
+ */
+
+static int TEMPLATE (cholmod_transpose_sym)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    Int *Perm,		/* size n, if present (can be NULL) */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A' or A(p,p)' */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Az, *Fx, *Fz ;
+    Int *Ap, *Anz, *Ai, *Fp, *Fj, *Wi, *Pinv, *Iwork ;
+    Int p, pend, packed, fp, upper, permute, jold, n, i, j, iold ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* ensure the xtype of A and F match (ignored if this is pattern version) */
+    if (!XTYPE_OK (A->xtype))
+    {
+	ERROR (CHOLMOD_INVALID, "real/complex mismatch") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    permute = (Perm != NULL) ;
+    n = A->nrow ;
+    Ap = A->p ;		/* size A->ncol+1, column pointers of A */
+    Ai = A->i ;		/* size nz = Ap [A->ncol], row indices of A */
+    Ax = A->x ;		/* size nz, real values of A */
+    Az = A->z ;		/* size nz, imag values of A */
+    Anz = A->nz ;
+    packed = A->packed ;
+    ASSERT (IMPLIES (!packed, Anz != NULL)) ;
+    upper = (A->stype > 0) ;
+
+    Fp = F->p ;		/* size A->nrow+1, row pointers of F */
+    Fj = F->i ;		/* size nz, column indices of F */
+    Fx = F->x ;		/* size nz, real values of F */
+    Fz = F->z ;		/* size nz, imag values of F */
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Wi = Iwork ;	/* size n (i/l/l) */
+    Pinv = Iwork + n ;	/* size n (i/i/l) , unused if Perm NULL */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the transpose */
+    /* ---------------------------------------------------------------------- */
+
+    if (permute)
+    {
+	if (upper)
+	{
+	    /* permuted, upper */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		jold = Perm [j] ;
+		p = Ap [jold] ;
+		pend = (packed) ? Ap [jold+1] : p + Anz [jold] ;
+		for ( ; p < pend ; p++)
+		{
+		    iold = Ai [p] ;
+		    if (iold <= jold)
+		    {
+			i = Pinv [iold] ;
+			if (i < j)
+			{
+			    fp = Wi [i]++ ;
+			    Fj [fp] = j ;
+#ifdef NCONJUGATE
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			    ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+			}
+			else
+			{
+			    fp = Wi [j]++ ;
+			    Fj [fp] = i ;
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+			}
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* permuted, lower */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		jold = Perm [j] ;
+		p = Ap [jold] ;
+		pend = (packed) ? Ap [jold+1] : p + Anz [jold] ;
+		for ( ; p < pend ; p++)
+		{
+		    iold = Ai [p] ;
+		    if (iold >= jold)
+		    {
+			i = Pinv [iold] ;
+			if (i > j)
+			{
+			    fp = Wi [i]++ ;
+			    Fj [fp] = j ;
+#ifdef NCONJUGATE
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			    ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+			}
+			else
+			{
+			    fp = Wi [j]++ ;
+			    Fj [fp] = i ;
+			    ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+			}
+		    }
+		}
+	    }
+	}
+    }
+    else
+    {
+	if (upper)
+	{
+	    /* unpermuted, upper */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? Ap [j+1] : p + Anz [j] ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i <= j)
+		    {
+			fp = Wi [i]++ ;
+			Fj [fp] = j ;
+#ifdef NCONJUGATE
+			ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+		    }
+		}
+	    }
+	}
+	else
+	{
+	    /* unpermuted, lower */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? Ap [j+1] : p + Anz [j] ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i >= j)
+		    {
+			fp = Wi [i]++ ;
+			Fj [fp] = j ;
+#ifdef NCONJUGATE
+			ASSIGN (Fx, Fz, fp, Ax, Az, p) ;
+#else
+			ASSIGN_CONJ (Fx, Fz, fp, Ax, Az, p) ;
+#endif
+		    }
+		}
+	    }
+	}
+    }
+
+    return (TRUE) ;
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
+#undef NCONJUGATE
diff --git a/src/CHOLMOD/Core/t_cholmod_triplet.c b/src/CHOLMOD/Core/t_cholmod_triplet.c
new file mode 100644
index 0000000..d2b1c82
--- /dev/null
+++ b/src/CHOLMOD/Core/t_cholmod_triplet.c
@@ -0,0 +1,175 @@
+/* ========================================================================== */
+/* === Core/t_cholmod_triplet =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Core Module.  Copyright (C) 2005-2006,
+ * Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Core Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_triplet.  All xtypes supported */
+
+#include "cholmod_template.h"
+
+/* ========================================================================== */
+/* === t_cholmod_triplet_to_sparse ========================================== */
+/* ========================================================================== */
+
+static size_t TEMPLATE (cholmod_triplet_to_sparse)
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    /* ---- in/out --- */
+    cholmod_sparse *R,	/* output matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Rx, *Rz, *Tx, *Tz ;
+    Int *Wj, *Rp, *Ri, *Rnz, *Ti, *Tj  ;
+    Int i, j, p, p1, p2, pdest, pj, k, stype, nrow, ncol, nz ;
+    size_t anz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* Wj contains a copy of Rp on input [ */
+    Wj = Common->Iwork ;	/* size MAX (nrow,ncol). (i/l/l) */
+
+    Rp = R->p ;
+    Ri = R->i ;
+    Rnz = R->nz ;
+    Rx = R->x ;
+    Rz = R->z ;
+
+    Ti = T->i ;
+    Tj = T->j ;
+    Tx = T->x ;
+    Tz = T->z ;
+    nz = T->nnz ;
+    nrow = T->nrow ;
+    ncol = T->ncol ;
+    stype = SIGN (T->stype) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the row form */
+    /* ---------------------------------------------------------------------- */
+
+    /* if Ti is jumbled, this part dominates the run time */
+
+    if (stype > 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i < j)
+	    {
+		/* place triplet (j,i,x) in column i of R */
+		p = Wj [i]++ ;
+		Ri [p] = j ;
+	    }
+	    else
+	    {
+		/* place triplet (i,j,x) in column j of R */
+		p = Wj [j]++ ;
+		Ri [p] = i ;
+	    }
+	    ASSIGN (Rx, Rz, p, Tx, Tz, k) ;
+	}
+    }
+    else if (stype < 0)
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    i = Ti [k] ;
+	    j = Tj [k] ;
+	    if (i > j)
+	    {
+		/* place triplet (j,i,x) in column i of R */
+		p = Wj [i]++ ;
+		Ri [p] = j ;
+	    }
+	    else
+	    {
+		/* place triplet (i,j,x) in column j of R */
+		p = Wj [j]++ ;
+		Ri [p] = i ;
+	    }
+	    ASSIGN (Rx, Rz, p, Tx, Tz, k) ;
+	}
+    }
+    else
+    {
+	for (k = 0 ; k < nz ; k++)
+	{
+	    /* place triplet (i,j,x) in column i of R */
+	    p = Wj [Ti [k]]++ ;
+	    Ri [p] = Tj [k] ;
+	    ASSIGN (Rx, Rz, p, Tx, Tz, k) ;
+	}
+    }
+
+    /* done using Wj (i/l/l) as temporary row pointers ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* sum up duplicates */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Wj (i/l/l) of size ncol to keep track of duplicates in each row [ */
+    for (j = 0 ; j < ncol ; j++)
+    {
+	Wj [j] = EMPTY ;
+    }
+
+    anz = 0 ;
+    for (i = 0 ; i < nrow ; i++)
+    {
+	p1 = Rp [i] ;
+	p2 = Rp [i+1] ;
+	pdest = p1 ;
+	/* at this point Wj [j] < p1 holds true for all columns j, because
+	 * Ri/Rx is stored in row oriented manner */
+	for (p = p1 ; p < p2 ; p++)
+	{
+	    j = Ri [p] ;
+	    pj = Wj [j] ;
+	    if (pj >= p1)
+	    {
+		/* this column index j is already in row i at position pj;
+		 * sum up the duplicate entry */
+		/* Rx [pj] += Rx [p] ; */
+		ASSEMBLE (Rx, Rz, pj, Rx, Rz, p) ;
+	    }
+	    else
+	    {
+		/* keep the entry and keep track in Wj [j] for case above */
+		Wj [j] = pdest ;
+		if (pdest != p)
+		{
+		    Ri [pdest] = j ;
+		    ASSIGN (Rx, Rz, pdest, Rx, Rz, p) ;
+		}
+		pdest++ ;
+	    }
+	}
+	Rnz [i] = pdest - p1 ;
+	anz += (pdest - p1) ;
+    }
+    /* done using Wj to keep track of duplicate entries in each row ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* return number of entries after summing up duplicates */
+    /* ---------------------------------------------------------------------- */
+
+    return (anz) ;
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Include/License.txt b/src/CHOLMOD/Include/License.txt
new file mode 100644
index 0000000..ea2c374
--- /dev/null
+++ b/src/CHOLMOD/Include/License.txt
@@ -0,0 +1,8 @@
+CHOLMOD/Include/* files.
+Copyright (C) 2005-2006, either Univ. of Florida or T. Davis,
+depending on the file.
+
+Refer to each include file in this directory; each file is licensed
+separately, according to the Module for which it contains definitions
+and prototypes.
+
diff --git a/src/CHOLMOD/Include/README.txt b/src/CHOLMOD/Include/README.txt
new file mode 100644
index 0000000..ec68624
--- /dev/null
+++ b/src/CHOLMOD/Include/README.txt
@@ -0,0 +1,25 @@
+CHOLMOD: a sparse Cholesky factorization package.  http://www.suitesparse.com
+
+The Include/*.h files in this directory provide a basic documentation of all
+user-callable routines and user-visible data structures in the CHOLMOD
+package.  Start with cholmod.h, which describes the general structure of
+the parameter lists of CHOLMOD routines.  cholmod_core.h describes the
+data structures and basic operations on them (creating and deleting them).
+
+cholmod.h		single include file for all user programs
+cholmod_config.h	CHOLMOD compile-time configuration
+
+cholmod_core.h		Core module: data structures and basic support routines
+cholmod_check.h		Check module: check/print CHOLMOD data structures
+cholmod_cholesky.h	Cholesky module: LL' and LDL' factorization
+cholmod_matrixops.h	MatrixOps module: sparse matrix operators (add, mult,..)
+cholmod_modify.h	Modify module: update/downdate/...
+cholmod_partition.h	Partition module: nested dissection ordering
+cholmod_supernodal.h	Supernodal module: supernodal Cholesky
+
+These include files are not used in user programs, but in CHOLMOD only:
+
+cholmod_blas.h		BLAS definitions
+cholmod_complexity.h	complex arithmetic
+cholmod_template.h	complex arithmetic for template routines
+cholmod_internal.h	internal definitions, not visible to user program
diff --git a/src/CHOLMOD/Include/cholmod.h b/src/CHOLMOD/Include/cholmod.h
new file mode 100644
index 0000000..11073c3
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod.h
@@ -0,0 +1,125 @@
+/* ========================================================================== */
+/* === Include/cholmod.h ==================================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod.h.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ *
+ * Portions of CHOLMOD (the Core and Partition Modules) are copyrighted by the
+ * University of Florida.  The Modify Module is co-authored by William W.
+ * Hager, Univ. of Florida.
+ *
+ * Acknowledgements:  this work was supported in part by the National Science
+ * Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia
+ * National Laboratories (Dept. of Energy) which supported the development of
+ * CHOLMOD's Partition Module.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD include file, for inclusion user programs.
+ *
+ * The include files listed below include a short description of each user-
+ * callable routine.  Each routine in CHOLMOD has a consistent interface.
+ * More details about the CHOLMOD data types is in the cholmod_core.h file.
+ *
+ * Naming convention:
+ * ------------------
+ *
+ *	All routine names, data types, and CHOLMOD library files use the
+ *	cholmod_ prefix.  All macros and other #define's use the CHOLMOD
+ *	prefix.
+ * 
+ * Return value:
+ * -------------
+ *
+ *	Most CHOLMOD routines return an int (TRUE (1) if successful, or FALSE
+ *	(0) otherwise.  A SuiteSparse_long or double return value is >= 0 if
+ *	successful, or -1 otherwise.  A size_t return value is > 0 if
+ *	successful, or 0 otherwise.
+ *
+ *	If a routine returns a pointer, it is a pointer to a newly allocated
+ *	object or NULL if a failure occured, with one exception.  cholmod_free
+ *	always returns NULL.
+ *
+ * "Common" parameter:
+ * ------------------
+ *
+ *	The last parameter in all CHOLMOD routines is a pointer to the CHOLMOD
+ *	"Common" object.  This contains control parameters, statistics, and
+ *	workspace used between calls to CHOLMOD.  It is always an input/output
+ *	parameter.
+ *
+ * Input, Output, and Input/Output parameters:
+ * -------------------------------------------
+ *
+ *	Input parameters are listed first.  They are not modified by CHOLMOD.
+ *
+ *	Input/output are listed next.  They must be defined on input, and
+ *	are modified on output.
+ *
+ *	Output parameters are listed next.  If they are pointers, they must
+ *	point to allocated space on input, but their contents are not defined
+ *	on input.
+ *
+ *	Workspace parameters appear next.  They are used in only two routines
+ *	in the Supernodal module.
+ *
+ *	The cholmod_common *Common parameter always appears as the last
+ *	parameter.  It is always an input/output parameter.
+ */
+
+#ifndef CHOLMOD_H
+#define CHOLMOD_H
+
+/* make it easy for C++ programs to include CHOLMOD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* assume large file support.  If problems occur, compile with -DNLARGEFILE */
+#include "cholmod_io64.h"
+
+#include "SuiteSparse_config.h"
+
+#include "cholmod_config.h"
+
+/* CHOLMOD always includes the Core module. */
+#include "cholmod_core.h"
+
+#ifndef NCHECK
+#include "cholmod_check.h"
+#endif
+
+#ifndef NCHOLESKY
+#include "cholmod_cholesky.h"
+#endif
+
+#ifndef NMATRIXOPS
+#include "cholmod_matrixops.h"
+#endif
+
+#ifndef NMODIFY
+#include "cholmod_modify.h"
+#endif
+
+#ifndef NCAMD
+#include "cholmod_camd.h"
+#endif
+
+#ifndef NPARTITION
+#include "cholmod_partition.h"
+#endif
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_blas.h b/src/CHOLMOD/Include/cholmod_blas.h
new file mode 100644
index 0000000..1b0b56e
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_blas.h
@@ -0,0 +1,455 @@
+/* ========================================================================== */
+/* === Include/cholmod_blas.h =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_blas.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_blas.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* This does not need to be included in the user's program. */
+
+#ifndef CHOLMOD_BLAS_H
+#define CHOLMOD_BLAS_H
+
+/* ========================================================================== */
+/* === Architecture ========================================================= */
+/* ========================================================================== */
+
+#if defined (__sun) || defined (MSOL2) || defined (ARCH_SOL2)
+#define CHOLMOD_SOL2
+#define CHOLMOD_ARCHITECTURE "Sun Solaris"
+
+#elif defined (__sgi) || defined (MSGI) || defined (ARCH_SGI)
+#define CHOLMOD_SGI
+#define CHOLMOD_ARCHITECTURE "SGI Irix"
+
+#elif defined (__linux) || defined (MGLNX86) || defined (ARCH_GLNX86)
+#define CHOLMOD_LINUX
+#define CHOLMOD_ARCHITECTURE "Linux"
+
+#elif defined (__APPLE__)
+#define CHOLMOD_MAC
+#define CHOLMOD_ARCHITECTURE "Mac"
+
+#elif defined (_AIX) || defined (MIBM_RS) || defined (ARCH_IBM_RS)
+#define CHOLMOD_AIX
+#define CHOLMOD_ARCHITECTURE "IBM AIX"
+/* recent reports from IBM AIX seem to indicate that this is not needed: */
+/* #define BLAS_NO_UNDERSCORE */
+
+#elif defined (__alpha) || defined (MALPHA) || defined (ARCH_ALPHA)
+#define CHOLMOD_ALPHA
+#define CHOLMOD_ARCHITECTURE "Compaq Alpha"
+
+#elif defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)
+#if defined (__MINGW32__) || defined (__MINGW32__)
+#define CHOLMOD_MINGW
+#elif defined (__CYGWIN32__) || defined (__CYGWIN32__)
+#define CHOLMOD_CYGWIN
+#else
+#define CHOLMOD_WINDOWS
+#define BLAS_NO_UNDERSCORE
+#endif
+#define CHOLMOD_ARCHITECTURE "Microsoft Windows"
+
+#elif defined (__hppa) || defined (__hpux) || defined (MHPUX) || defined (ARCH_HPUX)
+#define CHOLMOD_HP
+#define CHOLMOD_ARCHITECTURE "HP Unix"
+#define BLAS_NO_UNDERSCORE
+
+#elif defined (__hp700) || defined (MHP700) || defined (ARCH_HP700)
+#define CHOLMOD_HP
+#define CHOLMOD_ARCHITECTURE "HP 700 Unix"
+#define BLAS_NO_UNDERSCORE
+
+#else
+/* If the architecture is unknown, and you call the BLAS, you may need to */
+/* define BLAS_BY_VALUE, BLAS_NO_UNDERSCORE, and/or BLAS_CHAR_ARG yourself. */
+#define CHOLMOD_ARCHITECTURE "unknown"
+#endif
+
+/* ========================================================================== */
+/* === BLAS and LAPACK names ================================================ */
+/* ========================================================================== */
+
+/* Prototypes for the various versions of the BLAS.  */
+
+/* Determine if the 64-bit Sun Performance BLAS is to be used */
+#if defined(CHOLMOD_SOL2) && !defined(NSUNPERF) && defined(BLAS64)
+#define SUN64
+#endif
+
+#ifdef SUN64
+
+#define BLAS_DTRSV dtrsv_64_
+#define BLAS_DGEMV dgemv_64_
+#define BLAS_DTRSM dtrsm_64_
+#define BLAS_DGEMM dgemm_64_
+#define BLAS_DSYRK dsyrk_64_
+#define BLAS_DGER  dger_64_
+#define BLAS_DSCAL dscal_64_
+#define LAPACK_DPOTRF dpotrf_64_
+
+#define BLAS_ZTRSV ztrsv_64_
+#define BLAS_ZGEMV zgemv_64_
+#define BLAS_ZTRSM ztrsm_64_
+#define BLAS_ZGEMM zgemm_64_
+#define BLAS_ZHERK zherk_64_
+#define BLAS_ZGER  zgeru_64_
+#define BLAS_ZSCAL zscal_64_
+#define LAPACK_ZPOTRF zpotrf_64_
+
+#elif defined (BLAS_NO_UNDERSCORE)
+
+#define BLAS_DTRSV igraphdtrsv
+#define BLAS_DGEMV igraphdgemv
+#define BLAS_DTRSM igraphdtrsm
+#define BLAS_DGEMM igraphdgemm
+#define BLAS_DSYRK igraphdsyrk
+#define BLAS_DGER  igraphdger
+#define BLAS_DSCAL igraphdscal
+#define LAPACK_DPOTRF igraphdpotrf
+
+#define BLAS_ZTRSV ztrsv
+#define BLAS_ZGEMV zgemv
+#define BLAS_ZTRSM ztrsm
+#define BLAS_ZGEMM zgemm
+#define BLAS_ZHERK zherk
+#define BLAS_ZGER  zgeru
+#define BLAS_ZSCAL zscal
+#define LAPACK_ZPOTRF zpotrf
+
+#else
+
+#define BLAS_DTRSV igraphdtrsv_
+#define BLAS_DGEMV igraphdgemv_
+#define BLAS_DTRSM igraphdtrsm_
+#define BLAS_DGEMM igraphdgemm_
+#define BLAS_DSYRK igraphdsyrk_
+#define BLAS_DGER  igraphdger_
+#define BLAS_DSCAL igraphdscal_
+#define LAPACK_DPOTRF igraphdpotrf_
+
+#define BLAS_ZTRSV ztrsv_
+#define BLAS_ZGEMV zgemv_
+#define BLAS_ZTRSM ztrsm_
+#define BLAS_ZGEMM zgemm_
+#define BLAS_ZHERK zherk_
+#define BLAS_ZGER  zgeru_
+#define BLAS_ZSCAL zscal_
+#define LAPACK_ZPOTRF zpotrf_
+
+#endif
+
+/* ========================================================================== */
+/* === BLAS and LAPACK integer arguments ==================================== */
+/* ========================================================================== */
+
+/* Compile CHOLMOD, UMFPACK, and SPQR with -DBLAS64 if you have a BLAS that
+ * uses 64-bit integers */
+
+#if defined (LONGBLAS) || defined (BLAS64)
+#define BLAS_INT SuiteSparse_long
+#else
+#define BLAS_INT int
+#endif
+
+/* If the BLAS integer is smaller than the basic CHOLMOD integer, then we need
+ * to check for integer overflow when converting from Int to BLAS_INT.  If
+ * any integer overflows, the externally-defined BLAS_OK variable is
+ * set to FALSE.  BLAS_OK should be set to TRUE before calling any
+ * BLAS_* macro.
+ */
+
+#define CHECK_BLAS_INT (sizeof (BLAS_INT) < sizeof (Int))
+#define EQ(K,k) (((BLAS_INT) K) == ((Int) k))
+
+/* ========================================================================== */
+/* === BLAS and LAPACK prototypes and macros ================================ */
+/* ========================================================================== */
+
+int BLAS_DGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta,
+	double *Y, BLAS_INT *incy) ;
+
+#define BLAS_dgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \
+        EQ (INCX,incx) && EQ (INCY,incy))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_ZGEMV (char *trans, BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *A, BLAS_INT *lda, double *X, BLAS_INT *incx, double *beta,
+	double *Y, BLAS_INT *incy) ;
+
+#define BLAS_zgemv(trans,m,n,alpha,A,lda,X,incx,beta,Y,incy) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \
+        EQ (INCX,incx) && EQ (INCY,incy))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZGEMV (trans, &M, &N, alpha, A, &LDA, X, &INCX, beta, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_DTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A,
+	BLAS_INT *lda, double *X, BLAS_INT *incx) ;
+
+#define BLAS_dtrsv(uplo,trans,diag,n,A,lda,X,incx) \
+{ \
+    BLAS_INT N = n, LDA = lda, INCX = incx ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \
+    } \
+}
+
+void BLAS_ZTRSV (char *uplo, char *trans, char *diag, BLAS_INT *n, double *A,
+	BLAS_INT *lda, double *X, BLAS_INT *incx) ;
+
+#define BLAS_ztrsv(uplo,trans,diag,n,A,lda,X,incx) \
+{ \
+    BLAS_INT N = n, LDA = lda, INCX = incx ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda) && EQ (INCX,incx))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZTRSV (uplo, trans, diag, &N, A, &LDA, X, &INCX) ; \
+    } \
+}
+
+void BLAS_DTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m,
+	BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb) ;
+
+#define BLAS_dtrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \
+        EQ (LDB,ldb))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\
+    } \
+}
+
+void BLAS_ZTRSM (char *side, char *uplo, char *transa, char *diag, BLAS_INT *m,
+	BLAS_INT *n, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb) ;
+
+#define BLAS_ztrsm(side,uplo,transa,diag,m,n,alpha,A,lda,B,ldb) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, LDB = ldb ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \
+        EQ (LDB,ldb))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZTRSM (side, uplo, transa, diag, &M, &N, alpha, A, &LDA, B, &LDB);\
+    } \
+}
+
+int BLAS_DGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n,
+	BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ;
+
+#define BLAS_dgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \
+{ \
+    BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (K,k) && \
+        EQ (LDA,lda) && EQ (LDB,ldb) && EQ (LDC,ldc))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \
+	    C, &LDC) ; \
+    } \
+}
+
+void BLAS_ZGEMM (char *transa, char *transb, BLAS_INT *m, BLAS_INT *n,
+	BLAS_INT *k, double *alpha, double *A, BLAS_INT *lda, double *B,
+	BLAS_INT *ldb, double *beta, double *C, BLAS_INT *ldc) ;
+
+#define BLAS_zgemm(transa,transb,m,n,k,alpha,A,lda,B,ldb,beta,C,ldc) \
+{ \
+    BLAS_INT M = m, N = n, K = k, LDA = lda, LDB = ldb, LDC = ldc ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (K,k) && \
+        EQ (LDA,lda) && EQ (LDB,ldb) && EQ (LDC,ldc))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZGEMM (transa, transb, &M, &N, &K, alpha, A, &LDA, B, &LDB, beta, \
+	    C, &LDC) ; \
+    } \
+}
+
+void BLAS_DSYRK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k,
+	double *alpha, double *A, BLAS_INT *lda, double *beta, double *C,
+	BLAS_INT *ldc) ;
+
+#define BLAS_dsyrk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \
+{ \
+    BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && \
+        EQ (LDC,ldc))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DSYRK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \
+    } \
+} \
+
+void BLAS_ZHERK (char *uplo, char *trans, BLAS_INT *n, BLAS_INT *k,
+	double *alpha, double *A, BLAS_INT *lda, double *beta, double *C,
+	BLAS_INT *ldc) ;
+
+#define BLAS_zherk(uplo,trans,n,k,alpha,A,lda,beta,C,ldc) \
+{ \
+    BLAS_INT N = n, K = k, LDA = lda, LDC = ldc ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (K,k) && EQ (LDA,lda) && \
+        EQ (LDC,ldc))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZHERK (uplo, trans, &N, &K, alpha, A, &LDA, beta, C, &LDC) ; \
+    } \
+} \
+
+void LAPACK_DPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda,
+	BLAS_INT *info) ;
+
+#define LAPACK_dpotrf(uplo,n,A,lda,info) \
+{ \
+    BLAS_INT N = n, LDA = lda, INFO = 1 ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	LAPACK_DPOTRF (uplo, &N, A, &LDA, &INFO) ; \
+    } \
+    info = INFO ; \
+}
+
+void LAPACK_ZPOTRF (char *uplo, BLAS_INT *n, double *A, BLAS_INT *lda,
+	BLAS_INT *info) ;
+
+#define LAPACK_zpotrf(uplo,n,A,lda,info) \
+{ \
+    BLAS_INT N = n, LDA = lda, INFO = 1 ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (LDA,lda))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	LAPACK_ZPOTRF (uplo, &N, A, &LDA, &INFO) ; \
+    } \
+    info = INFO ; \
+}
+
+/* ========================================================================== */
+
+void BLAS_DSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ;
+
+#define BLAS_dscal(n,alpha,Y,incy) \
+{ \
+    BLAS_INT N = n, INCY = incy ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (INCY,incy))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DSCAL (&N, alpha, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_ZSCAL (BLAS_INT *n, double *alpha, double *Y, BLAS_INT *incy) ;
+
+#define BLAS_zscal(n,alpha,Y,incy) \
+{ \
+    BLAS_INT N = n, INCY = incy ; \
+    if (CHECK_BLAS_INT && !(EQ (N,n) && EQ (INCY,incy))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZSCAL (&N, alpha, Y, &INCY) ; \
+    } \
+}
+
+void BLAS_DGER (BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy,
+	double *A, BLAS_INT *lda) ;
+
+#define BLAS_dger(m,n,alpha,X,incx,Y,incy,A,lda) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \
+          EQ (INCX,incx) && EQ (INCY,incy))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_DGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \
+    } \
+}
+
+void BLAS_ZGER (BLAS_INT *m, BLAS_INT *n, double *alpha,
+	double *X, BLAS_INT *incx, double *Y, BLAS_INT *incy,
+	double *A, BLAS_INT *lda) ;
+
+#define BLAS_zgeru(m,n,alpha,X,incx,Y,incy,A,lda) \
+{ \
+    BLAS_INT M = m, N = n, LDA = lda, INCX = incx, INCY = incy ; \
+    if (CHECK_BLAS_INT && !(EQ (M,m) && EQ (N,n) && EQ (LDA,lda) && \
+          EQ (INCX,incx) && EQ (INCY,incy))) \
+    { \
+	BLAS_OK = FALSE ; \
+    } \
+    if (!CHECK_BLAS_INT || BLAS_OK) \
+    { \
+	BLAS_ZGER (&M, &N, alpha, X, &INCX, Y, &INCY, A, &LDA) ; \
+    } \
+}
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_camd.h b/src/CHOLMOD/Include/cholmod_camd.h
new file mode 100644
index 0000000..3e1bf8d
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_camd.h
@@ -0,0 +1,102 @@
+/* ========================================================================== */
+/* === Include/cholmod_camd.h =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_camd.h.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_partition.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Partition module, interface to CAMD, CCOLAMD, and CSYMAMD
+ *
+ * An interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering
+ * methods which order a matrix following constraints determined via nested
+ * dissection.
+ *
+ * These functions do not require METIS.  They are installed unless NCAMD
+ * is defined:
+ * cholmod_ccolamd		interface to CCOLAMD ordering
+ * cholmod_csymamd		interface to CSYMAMD ordering
+ * cholmod_camd			interface to CAMD ordering
+ *
+ * Requires the Core and Cholesky modules, and two packages: CAMD,
+ * and CCOLAMD.  Used by functions in the Partition Module.
+ */
+
+#ifndef CHOLMOD_CAMD_H
+#define CHOLMOD_CAMD_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ccolamd */
+/* -------------------------------------------------------------------------- */
+
+/* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */
+
+int cholmod_ccolamd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int *Cmember,	/* size A->nrow.  Cmember [i] = c if row i is in the
+			 * constraint set c.  c must be >= 0.  The # of
+			 * constraint sets is max (Cmember) + 1.  If Cmember is
+			 * NULL, then it is interpretted as Cmember [i] = 0 for
+			 * all i */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_ccolamd (cholmod_sparse *, SuiteSparse_long *, size_t,
+    SuiteSparse_long *, SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_csymamd */
+/* -------------------------------------------------------------------------- */
+
+/* Order A using CSYMAMD. */
+
+int cholmod_csymamd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    /* ---- output --- */
+    int *Cmember,	/* size nrow.  see cholmod_ccolamd above */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_csymamd (cholmod_sparse *, SuiteSparse_long *,
+    SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_camd */
+/* -------------------------------------------------------------------------- */
+
+/* Order A using CAMD. */
+
+int cholmod_camd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Cmember,	/* size nrow.  see cholmod_ccolamd above */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_camd (cholmod_sparse *, SuiteSparse_long *, size_t,
+    SuiteSparse_long *, SuiteSparse_long *, cholmod_common *) ;
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_check.h b/src/CHOLMOD/Include/cholmod_check.h
new file mode 100644
index 0000000..e75c415
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_check.h
@@ -0,0 +1,427 @@
+/* ========================================================================== */
+/* === Include/cholmod_check.h ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_check.h.  Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_check.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Check module.
+ *
+ * Routines that check and print the 5 basic data types in CHOLMOD, and 3 kinds
+ * of integer vectors (subset, perm, and parent), and read in matrices from a
+ * file:
+ *
+ * cholmod_check_common	    check/print the Common object
+ * cholmod_print_common
+ *
+ * cholmod_check_sparse	    check/print a sparse matrix in column-oriented form
+ * cholmod_print_sparse
+ *
+ * cholmod_check_dense	    check/print a dense matrix
+ * cholmod_print_dense
+ *
+ * cholmod_check_factor	    check/print a Cholesky factorization
+ * cholmod_print_factor
+ *
+ * cholmod_check_triplet    check/print a sparse matrix in triplet form
+ * cholmod_print_triplet
+ *
+ * cholmod_check_subset	    check/print a subset (integer vector in given range)
+ * cholmod_print_subset
+ *
+ * cholmod_check_perm	    check/print a permutation (an integer vector)
+ * cholmod_print_perm
+ *
+ * cholmod_check_parent	    check/print an elimination tree (an integer vector)
+ * cholmod_print_parent
+ *
+ * cholmod_read_triplet	    read a matrix in triplet form (any Matrix Market
+ *			    "coordinate" format, or a generic triplet format).
+ *
+ * cholmod_read_sparse	    read a matrix in sparse form (same file format as
+ *			    cholmod_read_triplet).
+ *
+ * cholmod_read_dense	    read a dense matrix (any Matrix Market "array"
+ *			    format, or a generic dense format).
+ *
+ * cholmod_write_sparse	    write a sparse matrix to a Matrix Market file.
+ *
+ * cholmod_write_dense	    write a dense matrix to a Matrix Market file.
+ *
+ * cholmod_print_common and cholmod_check_common are the only two routines that
+ * you may call after calling cholmod_finish.
+ *
+ * Requires the Core module.  Not required by any CHOLMOD module, except when
+ * debugging is enabled (in which case all modules require the Check module).
+ *
+ * See cholmod_read.c for a description of the file formats supported by the
+ * cholmod_read_* routines.
+ */
+
+#ifndef CHOLMOD_CHECK_H
+#define CHOLMOD_CHECK_H
+
+#include "cholmod_core.h"
+#include <stdio.h>
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_common:  check the Common object */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_common
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_common (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_common:  print the Common object */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_common
+(
+    /* ---- input ---- */
+    const char *name,	/* printed name of Common object */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_common (const char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_gpu_stats:  print the GPU / CPU statistics */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_gpu_stats   (cholmod_common *) ;
+int cholmod_l_gpu_stats (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_sparse:  check a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_sparse (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_sparse */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to print */
+    const char *name,	/* printed name of sparse matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_sparse (cholmod_sparse *, const char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_dense:  check a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_dense (cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_dense:  print a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* dense matrix to print */
+    const char *name,	/* printed name of dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_dense (cholmod_dense *, const char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_factor:  check a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_factor
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_factor (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_factor:  print a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_factor
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to print */
+    const char *name,	/* printed name of factor */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_factor (cholmod_factor *, const char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_triplet:  check a sparse matrix in triplet form */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_triplet
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to check */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_triplet (cholmod_triplet *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_triplet:  print a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_triplet
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* triplet matrix to print */
+    const char *name,	/* printed name of triplet matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_triplet (cholmod_triplet *, const char *, cholmod_common *);
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_subset:  check a subset */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_subset
+(
+    /* ---- input ---- */
+    int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    SuiteSparse_long len,   /* size of Set (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_subset (SuiteSparse_long *, SuiteSparse_long, size_t,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_subset:  print a subset */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_subset
+(
+    /* ---- input ---- */
+    int *Set,		/* Set [0:len-1] is a subset of 0:n-1.  Duplicates OK */
+    SuiteSparse_long len,   /* size of Set (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    const char *name,	/* printed name of Set */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_subset (SuiteSparse_long *, SuiteSparse_long, size_t,
+    const char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_perm:  check a permutation */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_perm
+(
+    /* ---- input ---- */
+    int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_perm (SuiteSparse_long *, size_t, size_t, cholmod_common *);
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_perm:  print a permutation vector */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_perm
+(
+    /* ---- input ---- */
+    int *Perm,		/* Perm [0:len-1] is a permutation of subset of 0:n-1 */
+    size_t len,		/* size of Perm (an integer array) */
+    size_t n,		/* 0:n-1 is valid range */
+    const char *name,	/* printed name of Perm */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_perm (SuiteSparse_long *, size_t, size_t, const char *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_check_parent:  check an elimination tree */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_check_parent
+(
+    /* ---- input ---- */
+    int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_check_parent (SuiteSparse_long *, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_print_parent */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_print_parent
+(
+    /* ---- input ---- */
+    int *Parent,	/* Parent [0:n-1] is an elimination tree */
+    size_t n,		/* size of Parent */
+    const char *name,	/* printed name of Parent */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_print_parent (SuiteSparse_long *, size_t, const char *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_sparse: read a sparse matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_read_sparse
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_read_sparse (FILE *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_triplet: read a triplet matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_read_triplet
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_read_triplet (FILE *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_dense: read a dense matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_read_dense
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_read_dense (FILE *, cholmod_common *) ; 
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_read_matrix: read a sparse or dense matrix from a file */
+/* -------------------------------------------------------------------------- */
+
+void *cholmod_read_matrix
+(
+    /* ---- input ---- */
+    FILE *f,		/* file to read from, must already be open */
+    int prefer,		/* If 0, a sparse matrix is always return as a
+			 *	cholmod_triplet form.  It can have any stype
+			 *	(symmetric-lower, unsymmetric, or
+			 *	symmetric-upper).
+			 * If 1, a sparse matrix is returned as an unsymmetric
+			 *	cholmod_sparse form (A->stype == 0), with both
+			 *	upper and lower triangular parts present.
+			 *	This is what the MATLAB mread mexFunction does,
+			 *	since MATLAB does not have an stype.
+			 * If 2, a sparse matrix is returned with an stype of 0
+			 *	or 1 (unsymmetric, or symmetric with upper part
+			 *	stored).
+			 * This argument has no effect for dense matrices.
+			 */
+    /* ---- output---- */
+    int *mtype,		/* CHOLMOD_TRIPLET, CHOLMOD_SPARSE or CHOLMOD_DENSE */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_read_matrix (FILE *, int, int *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_write_sparse: write a sparse matrix to a file */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_write_sparse
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_sparse *A,	    /* matrix to print */
+    cholmod_sparse *Z,	    /* optional matrix with pattern of explicit zeros */
+    const char *comments,    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_write_sparse (FILE *, cholmod_sparse *, cholmod_sparse *,
+    const char *c, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_write_dense: write a dense matrix to a file */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_write_dense
+(
+    /* ---- input ---- */
+    FILE *f,		    /* file to write to, must already be open */
+    cholmod_dense *X,	    /* matrix to print */
+    const char *comments,    /* optional filename of comments to include */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_write_dense (FILE *, cholmod_dense *, const char *,
+    cholmod_common *) ;
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_cholesky.h b/src/CHOLMOD/Include/cholmod_cholesky.h
new file mode 100644
index 0000000..aa2634a
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_cholesky.h
@@ -0,0 +1,565 @@
+/* ========================================================================== */
+/* === Include/cholmod_cholesky.h =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_cholesky.h. Copyright (C) 2005-2013, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_cholesky.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Cholesky module.
+ *
+ * Sparse Cholesky routines: analysis, factorization, and solve.
+ *
+ * The primary routines are all that a user requires to order, analyze, and
+ * factorize a sparse symmetric positive definite matrix A (or A*A'), and
+ * to solve Ax=b (or A*A'x=b).  The primary routines rely on the secondary
+ * routines, the CHOLMOD Core module, and the AMD and COLAMD packages.  They
+ * make optional use of the CHOLMOD Supernodal and Partition modules, the
+ * METIS package, and the CCOLAMD package.
+ *
+ * Primary routines:
+ * -----------------
+ *
+ * cholmod_analyze		order and analyze (simplicial or supernodal)
+ * cholmod_factorize		simplicial or supernodal Cholesky factorization
+ * cholmod_solve		solve a linear system (simplicial or supernodal)
+ * cholmod_solve2		like cholmod_solve, but reuse workspace
+ * cholmod_spsolve		solve a linear system (sparse x and b)
+ *
+ * Secondary routines:
+ * ------------------
+ *
+ * cholmod_analyze_p		analyze, with user-provided permutation or f set
+ * cholmod_factorize_p		factorize, with user-provided permutation or f
+ * cholmod_analyze_ordering	analyze a fill-reducing ordering
+ * cholmod_etree		find the elimination tree
+ * cholmod_rowcolcounts		compute the row/column counts of L
+ * cholmod_amd			order using AMD
+ * cholmod_colamd		order using COLAMD
+ * cholmod_rowfac		incremental simplicial factorization
+ * cholmod_rowfac_mask		rowfac, specific to LPDASA
+ * cholmod_row_subtree		find the nonzero pattern of a row of L
+ * cholmod_resymbol		recompute the symbolic pattern of L
+ * cholmod_resymbol_noperm	recompute the symbolic pattern of L, no L->Perm
+ * cholmod_postorder		postorder a tree
+ *
+ * Requires the Core module, and two packages: AMD and COLAMD.
+ * Optionally uses the Supernodal and Partition modules.
+ * Required by the Partition module.
+ */
+
+#ifndef CHOLMOD_CHOLESKY_H
+#define CHOLMOD_CHOLESKY_H
+
+#include "cholmod_config.h"
+#include "cholmod_core.h"
+
+#ifndef NPARTITION
+#include "cholmod_partition.h"
+#endif
+
+#ifndef NSUPERNODAL
+#include "cholmod_supernodal.h"
+#endif
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze:  order and analyze (simplicial or supernodal) */
+/* -------------------------------------------------------------------------- */
+
+/* Orders and analyzes A, AA', PAP', or PAA'P' and returns a symbolic factor
+ * that can later be passed to cholmod_factorize. */
+
+cholmod_factor *cholmod_analyze 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_analyze (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze_p:  analyze, with user-provided permutation or f set */
+/* -------------------------------------------------------------------------- */
+
+/* Orders and analyzes A, AA', PAP', PAA'P', FF', or PFF'P and returns a
+ * symbolic factor that can later be passed to cholmod_factorize, where
+ * F = A(:,fset) if fset is not NULL and A->stype is zero.
+ * UserPerm is tried if non-NULL.  */
+
+cholmod_factor *cholmod_analyze_p
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    int *UserPerm,	/* user-provided permutation, size A->nrow */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_analyze_p (cholmod_sparse *, SuiteSparse_long *,
+    SuiteSparse_long *, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze_p2:  analyze for sparse Cholesky or sparse QR */
+/* -------------------------------------------------------------------------- */
+
+cholmod_factor *cholmod_analyze_p2
+(
+    /* ---- input ---- */
+    int for_cholesky,   /* if TRUE, then analyze for Cholesky; else for QR */
+    cholmod_sparse *A,	/* matrix to order and analyze */
+    int *UserPerm,	/* user-provided permutation, size A->nrow */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_analyze_p2 (int, cholmod_sparse *, SuiteSparse_long *,
+    SuiteSparse_long *, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factorize:  simplicial or supernodal Cholesky factorization */
+/* -------------------------------------------------------------------------- */
+
+/* Factorizes PAP' (or PAA'P' if A->stype is 0), using a factor obtained
+ * from cholmod_analyze.  The analysis can be re-used simply by calling this
+ * routine a second time with another matrix.  A must have the same nonzero
+ * pattern as that passed to cholmod_analyze. */
+
+int cholmod_factorize 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_factorize (cholmod_sparse *, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factorize_p:  factorize, with user-provided permutation or fset */
+/* -------------------------------------------------------------------------- */
+
+/* Same as cholmod_factorize, but with more options. */
+
+int cholmod_factorize_p
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* resulting factorization */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_factorize_p (cholmod_sparse *, double *, SuiteSparse_long *,
+    size_t, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_solve:  solve a linear system (simplicial or supernodal) */
+/* -------------------------------------------------------------------------- */
+
+/* Solves one of many linear systems with a dense right-hand-side, using the
+ * factorization from cholmod_factorize (or as modified by any other CHOLMOD
+ * routine).  D is identity for LL' factorizations. */
+
+#define CHOLMOD_A    0		/* solve Ax=b */
+#define CHOLMOD_LDLt 1		/* solve LDL'x=b */
+#define CHOLMOD_LD   2		/* solve LDx=b */
+#define CHOLMOD_DLt  3		/* solve DL'x=b */
+#define CHOLMOD_L    4		/* solve Lx=b */
+#define CHOLMOD_Lt   5		/* solve L'x=b */
+#define CHOLMOD_D    6		/* solve Dx=b */
+#define CHOLMOD_P    7		/* permute x=Px */
+#define CHOLMOD_Pt   8		/* permute x=P'x */
+
+cholmod_dense *cholmod_solve	/* returns the solution X */
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_dense *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_solve (int, cholmod_factor *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_solve2:  like cholmod_solve, but with reusable workspace */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_solve2     /* returns TRUE on success, FALSE on failure */
+(
+    /* ---- input ---- */
+    int sys,		            /* system to solve */
+    cholmod_factor *L,	            /* factorization to use */
+    cholmod_dense *B,               /* right-hand-side */
+    cholmod_sparse *Bset,
+    /* ---- output --- */
+    cholmod_dense **X_Handle,       /* solution, allocated if need be */
+    cholmod_sparse **Xset_Handle,
+    /* ---- workspace  */
+    cholmod_dense **Y_Handle,       /* workspace, or NULL */
+    cholmod_dense **E_Handle,       /* workspace, or NULL */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_solve2 (int, cholmod_factor *, cholmod_dense *, cholmod_sparse *,
+    cholmod_dense **, cholmod_sparse **, cholmod_dense **, cholmod_dense **,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_spsolve:  solve a linear system with a sparse right-hand-side */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_spsolve
+(
+    /* ---- input ---- */
+    int sys,		/* system to solve */
+    cholmod_factor *L,	/* factorization to use */
+    cholmod_sparse *B,	/* right-hand-side */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_spsolve (int, cholmod_factor *, cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_etree: find the elimination tree of A or A'*A */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_etree
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* ---- output --- */
+    int *Parent,	/* size ncol.  Parent [j] = p if p is the parent of j */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_etree (cholmod_sparse *, SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowcolcounts: compute the row/column counts of L */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_rowcolcounts
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int *Parent,	/* size nrow.  Parent [i] = p if p is the parent of i */
+    int *Post,		/* size nrow.  Post [k] = i if i is the kth node in
+			 * the postordered etree. */
+    /* ---- output --- */
+    int *RowCount,	/* size nrow. RowCount [i] = # entries in the ith row of
+			 * L, including the diagonal. */
+    int *ColCount,	/* size nrow. ColCount [i] = # entries in the ith
+			 * column of L, including the diagonal. */
+    int *First,		/* size nrow.  First [i] = k is the least postordering
+			 * of any descendant of i. */
+    int *Level,		/* size nrow.  Level [i] is the length of the path from
+			 * i to the root, with Level [root] = 0. */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowcolcounts (cholmod_sparse *, SuiteSparse_long *, size_t,
+    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
+    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_analyze_ordering:  analyze a fill-reducing ordering */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_analyze_ordering
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int ordering,	/* ordering method used */
+    int *Perm,		/* size n, fill-reducing permutation to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Parent,	/* size n, elimination tree */
+    int *Post,		/* size n, postordering of elimination tree */
+    int *ColCount,	/* size n, nnz in each column of L */
+    /* ---- workspace  */
+    int *First,		/* size nworkspace for cholmod_postorder */
+    int *Level,		/* size n workspace for cholmod_postorder */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_analyze_ordering (cholmod_sparse *, int, SuiteSparse_long *,
+    SuiteSparse_long *, size_t, SuiteSparse_long *, SuiteSparse_long *,
+    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_amd:  order using AMD */
+/* -------------------------------------------------------------------------- */
+
+/* Finds a permutation P to reduce fill-in in the factorization of P*A*P'
+ * or P*A*A'P' */
+
+int cholmod_amd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_amd (cholmod_sparse *, SuiteSparse_long *, size_t,
+    SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_colamd:  order using COLAMD */
+/* -------------------------------------------------------------------------- */
+
+/* Finds a permutation P to reduce fill-in in the factorization of P*A*A'*P'.
+ * Orders F*F' where F = A (:,fset) if fset is not NULL */
+
+int cholmod_colamd
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with a coletree postorder */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_colamd (cholmod_sparse *, SuiteSparse_long *, size_t, int,
+    SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowfac:  incremental simplicial factorization */
+/* -------------------------------------------------------------------------- */
+
+/* Partial or complete simplicial factorization.  Rows and columns kstart:kend-1
+ * of L and D must be initially equal to rows/columns kstart:kend-1 of the
+ * identity matrix.   Row k can only be factorized if all descendants of node
+ * k in the elimination tree have been factorized. */
+
+int cholmod_rowfac
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,fset)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowfac (cholmod_sparse *, cholmod_sparse *, double *, size_t,
+    size_t, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowfac_mask:  incremental simplicial factorization */
+/* -------------------------------------------------------------------------- */
+
+/* cholmod_rowfac_mask is a version of cholmod_rowfac that is specific to
+ * LPDASA.  It is unlikely to be needed by any other application. */
+
+int cholmod_rowfac_mask
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,fset)' */
+    double beta [2],	/* factorize beta*I+A or beta*I+A'*A */
+    size_t kstart,	/* first row to factorize */
+    size_t kend,	/* last row to factorize is kend-1 */
+    int *mask,		/* if mask[i] >= 0, then set row i to zero */
+    int *RLinkUp,	/* link list of rows to compute */
+    /* ---- in/out --- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowfac_mask (cholmod_sparse *, cholmod_sparse *, double *, size_t,
+    size_t, SuiteSparse_long *, SuiteSparse_long *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_row_subtree:  find the nonzero pattern of a row of L */
+/* -------------------------------------------------------------------------- */
+
+/* Find the nonzero pattern of x for the system Lx=b where L = (0:k-1,0:k-1)
+ * and b = kth column of A or A*A' (rows 0 to k-1 only) */
+
+int cholmod_row_subtree
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* used for A*A' case only. F=A' or A(:,fset)' */
+    size_t k,		/* row k of L */
+    int *Parent,	/* elimination tree */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), n-by-1 with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_row_subtree (cholmod_sparse *, cholmod_sparse *, size_t,
+    SuiteSparse_long *, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_lsolve_pattern: find the nonzero pattern of x=L\b */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_lsolve_pattern
+(
+    /* ---- input ---- */
+    cholmod_sparse *B,	/* sparse right-hand-side (a single sparse column) */
+    cholmod_factor *L,	/* the factor L from which parent(i) is derived */
+    /* ---- output --- */
+    cholmod_sparse *X,	/* pattern of X=L\B, n-by-1 with X->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_lsolve_pattern (cholmod_sparse *, cholmod_factor *,
+    cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_row_lsubtree:  find the nonzero pattern of a row of L */
+/* -------------------------------------------------------------------------- */
+
+/* Identical to cholmod_row_subtree, except that it finds the elimination tree
+ * from L itself. */
+
+int cholmod_row_lsubtree
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *Fi, size_t fnz,    /* nonzero pattern of kth row of A', not required
+			     * for the symmetric case.  Need not be sorted. */
+    size_t k,		/* row k of L */
+    cholmod_factor *L,	/* the factor L from which parent(i) is derived */
+    /* ---- output --- */
+    cholmod_sparse *R,	/* pattern of L(k,:), n-by-1 with R->nzmax >= n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_row_lsubtree (cholmod_sparse *, SuiteSparse_long *, size_t,
+    size_t, cholmod_factor *, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_resymbol:  recompute the symbolic pattern of L */
+/* -------------------------------------------------------------------------- */
+
+/* Remove entries from L that are not in the factorization of P*A*P', P*A*A'*P',
+ * or P*F*F'*P' (depending on A->stype and whether fset is NULL or not).
+ *
+ * cholmod_resymbol is the same as cholmod_resymbol_noperm, except that it
+ * first permutes A according to L->Perm.  A can be upper/lower/unsymmetric,
+ * in contrast to cholmod_resymbol_noperm (which can be lower or unsym). */
+
+int cholmod_resymbol 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_resymbol (cholmod_sparse *, SuiteSparse_long *, size_t, int,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_resymbol_noperm:  recompute the symbolic pattern of L, no L->Perm */
+/* -------------------------------------------------------------------------- */
+
+/* Remove entries from L that are not in the factorization of A, A*A',
+ * or F*F' (depending on A->stype and whether fset is NULL or not). */
+
+int cholmod_resymbol_noperm
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int pack,		/* if TRUE, pack the columns of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization, entries pruned on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_resymbol_noperm (cholmod_sparse *, SuiteSparse_long *, size_t, int,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rcond:  compute rough estimate of reciprocal of condition number */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_rcond	    /* return min(diag(L)) / max(diag(L)) */
+(
+    /* ---- input ---- */
+    cholmod_factor *L,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_rcond (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_postorder: Compute the postorder of a tree */
+/* -------------------------------------------------------------------------- */
+
+SuiteSparse_long cholmod_postorder	/* return # of nodes postordered */
+(
+    /* ---- input ---- */
+    int *Parent,	/* size n. Parent [j] = p if p is the parent of j */
+    size_t n,
+    int *Weight_p,	/* size n, optional. Weight [j] is weight of node j */
+    /* ---- output --- */
+    int *Post,		/* size n. Post [k] = j is kth in postordered tree */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_postorder (SuiteSparse_long *, size_t,
+    SuiteSparse_long *, SuiteSparse_long *, cholmod_common *) ;
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_complexity.h b/src/CHOLMOD/Include/cholmod_complexity.h
new file mode 100644
index 0000000..a84583a
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_complexity.h
@@ -0,0 +1,264 @@
+/* ========================================================================== */
+/* === Include/cholmod_complexity.h ========================================= */
+/* ========================================================================== */
+
+/* Define operations on pattern, real, complex, and zomplex objects.
+ *
+ * The xtype of an object defines it numerical type.  A qttern object has no
+ * numerical values (A->x and A->z are NULL).  A real object has no imaginary
+ * qrt (A->x is used, A->z is NULL).  A complex object has an imaginary qrt
+ * that is stored interleaved with its real qrt (A->x is of size 2*nz, A->z
+ * is NULL).  A zomplex object has both real and imaginary qrts, which are
+ * stored seqrately, as in MATLAB (A->x and A->z are both used).
+ *
+ * XTYPE is CHOLMOD_PATTERN, _REAL, _COMPLEX or _ZOMPLEX, and is the xtype of
+ * the template routine under construction.  XTYPE2 is equal to XTYPE, except
+ * if XTYPE is CHOLMOD_PATTERN, in which case XTYPE is CHOLMOD_REAL.
+ * XTYPE and XTYPE2 are defined in cholmod_template.h.  
+ */
+
+/* -------------------------------------------------------------------------- */
+/* pattern */
+/* -------------------------------------------------------------------------- */
+
+#define P_TEMPLATE(name)		p_ ## name
+#define P_ASSIGN2(x,z,p,ax,az,q)	x [p] = 1
+#define P_PRINT(k,x,z,p)		PRK(k, ("1"))
+
+/* -------------------------------------------------------------------------- */
+/* real */
+/* -------------------------------------------------------------------------- */
+
+#define R_TEMPLATE(name)			r_ ## name
+#define R_ASSEMBLE(x,z,p,ax,az,q)		x [p] += ax [q]
+#define R_ASSIGN(x,z,p,ax,az,q)			x [p]  = ax [q]
+#define R_ASSIGN_CONJ(x,z,p,ax,az,q)		x [p]  = ax [q]
+#define R_ASSIGN_REAL(x,p,ax,q)			x [p]  = ax [q]
+#define R_XTYPE_OK(type)			((type) == CHOLMOD_REAL)
+#define R_IS_NONZERO(ax,az,q)			IS_NONZERO (ax [q])
+#define R_IS_ZERO(ax,az,q)			IS_ZERO (ax [q])
+#define R_IS_ONE(ax,az,q)			(ax [q] == 1)
+#define R_MULT(x,z,p, ax,az,q, bx,bz,r)		x [p]  = ax [q] * bx [r]
+#define R_MULTADD(x,z,p, ax,az,q, bx,bz,r)	x [p] += ax [q] * bx [r]
+#define R_MULTSUB(x,z,p, ax,az,q, bx,bz,r)	x [p] -= ax [q] * bx [r]
+#define R_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r)	x [p] += ax [q] * bx [r]
+#define R_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r)	x [p] -= ax [q] * bx [r]
+#define R_ADD(x,z,p, ax,az,q, bx,bz,r)		x [p]  = ax [q] + bx [r]
+#define R_ADD_REAL(x,p, ax,q, bx,r)		x [p]  = ax [q] + bx [r]
+#define R_CLEAR(x,z,p)				x [p]  = 0
+#define R_CLEAR_IMAG(x,z,p)
+#define R_DIV(x,z,p,ax,az,q)			x [p] /= ax [q]
+#define R_LLDOT(x,p, ax,az,q)			x [p] -= ax [q] * ax [q]
+#define R_PRINT(k,x,z,p)			PRK(k, ("%24.16e", x [p]))
+
+#define R_DIV_REAL(x,z,p, ax,az,q, bx,r)	x [p] = ax [q] / bx [r]
+#define R_MULT_REAL(x,z,p, ax,az,q, bx,r)	x [p] = ax [q] * bx [r]
+
+#define R_LDLDOT(x,p, ax,az,q, bx,r)		x [p] -=(ax[q] * ax[q])/ bx[r]
+
+/* -------------------------------------------------------------------------- */
+/* complex */
+/* -------------------------------------------------------------------------- */
+
+#define C_TEMPLATE(name)		c_ ## name
+#define CT_TEMPLATE(name)		ct_ ## name
+
+#define C_ASSEMBLE(x,z,p,ax,az,q) \
+    x [2*(p)  ] += ax [2*(q)  ] ; \
+    x [2*(p)+1] += ax [2*(q)+1]
+
+#define C_ASSIGN(x,z,p,ax,az,q) \
+    x [2*(p)  ] = ax [2*(q)  ] ; \
+    x [2*(p)+1] = ax [2*(q)+1]
+
+#define C_ASSIGN_REAL(x,p,ax,q)			x [2*(p)]  = ax [2*(q)]
+
+#define C_ASSIGN_CONJ(x,z,p,ax,az,q) \
+    x [2*(p)  ] =  ax [2*(q)  ] ; \
+    x [2*(p)+1] = -ax [2*(q)+1]
+
+#define C_XTYPE_OK(type)		((type) == CHOLMOD_COMPLEX)
+
+#define C_IS_NONZERO(ax,az,q) \
+    (IS_NONZERO (ax [2*(q)]) || IS_NONZERO (ax [2*(q)+1]))
+
+#define C_IS_ZERO(ax,az,q) \
+    (IS_ZERO (ax [2*(q)]) && IS_ZERO (ax [2*(q)+1]))
+
+#define C_IS_ONE(ax,az,q) \
+    ((ax [2*(q)] == 1) && IS_ZERO (ax [2*(q)+1]))
+
+#define C_IMAG_IS_NONZERO(ax,az,q)  (IS_NONZERO (ax [2*(q)+1]))
+
+#define C_MULT(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] = ax [2*(q)  ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+#define C_MULTADD(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] += ax [2*(q)  ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] += ax [2*(q)+1] * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+#define C_MULTSUB(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] -= ax [2*(q)  ] * bx [2*(r)] - ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] -= ax [2*(q)+1] * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+/* s += conj(a)*b */
+#define C_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] +=   ax [2*(q)  ]  * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] += (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+/* s -= conj(a)*b */
+#define C_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \
+x [2*(p)  ] -=   ax [2*(q)  ]  * bx [2*(r)] + ax [2*(q)+1] * bx [2*(r)+1] ; \
+x [2*(p)+1] -= (-ax [2*(q)+1]) * bx [2*(r)] + ax [2*(q)  ] * bx [2*(r)+1]
+
+#define C_ADD(x,z,p, ax,az,q, bx,bz,r) \
+    x [2*(p)  ] = ax [2*(q)  ] + bx [2*(r)  ] ; \
+    x [2*(p)+1] = ax [2*(q)+1] + bx [2*(r)+1]
+
+#define C_ADD_REAL(x,p, ax,q, bx,r) \
+    x [2*(p)] = ax [2*(q)] + bx [2*(r)]
+
+#define C_CLEAR(x,z,p) \
+    x [2*(p)  ] = 0 ; \
+    x [2*(p)+1] = 0
+
+#define C_CLEAR_IMAG(x,z,p) \
+    x [2*(p)+1] = 0
+
+/* s = s / a */
+#define C_DIV(x,z,p,ax,az,q) \
+    Common->complex_divide ( \
+	      x [2*(p)],  x [2*(p)+1], \
+	     ax [2*(q)], ax [2*(q)+1], \
+	     &x [2*(p)], &x [2*(p)+1])
+
+/* s -= conj(a)*a ; note that the result of conj(a)*a is real */
+#define C_LLDOT(x,p, ax,az,q) \
+    x [2*(p)] -= ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1]
+
+#define C_PRINT(k,x,z,p) PRK(k, ("(%24.16e,%24.16e)", x [2*(p)], x [2*(p)+1]))
+
+#define C_DIV_REAL(x,z,p, ax,az,q, bx,r) \
+    x [2*(p)  ] = ax [2*(q)  ] / bx [2*(r)] ; \
+    x [2*(p)+1] = ax [2*(q)+1] / bx [2*(r)]
+
+#define C_MULT_REAL(x,z,p, ax,az,q, bx,r) \
+    x [2*(p)  ] = ax [2*(q)  ] * bx [2*(r)] ; \
+    x [2*(p)+1] = ax [2*(q)+1] * bx [2*(r)]
+
+/* s -= conj(a)*a/t */
+#define C_LDLDOT(x,p, ax,az,q, bx,r) \
+    x [2*(p)] -= (ax [2*(q)] * ax [2*(q)] + ax [2*(q)+1] * ax [2*(q)+1]) / bx[r]
+
+/* -------------------------------------------------------------------------- */
+/* zomplex */
+/* -------------------------------------------------------------------------- */
+
+#define Z_TEMPLATE(name)		z_ ## name
+#define ZT_TEMPLATE(name)		zt_ ## name
+
+#define Z_ASSEMBLE(x,z,p,ax,az,q) \
+    x [p] += ax [q] ; \
+    z [p] += az [q]
+
+#define Z_ASSIGN(x,z,p,ax,az,q) \
+    x [p] = ax [q] ; \
+    z [p] = az [q]
+
+#define Z_ASSIGN_REAL(x,p,ax,q)			x [p]  = ax [q]
+
+#define Z_ASSIGN_CONJ(x,z,p,ax,az,q) \
+    x [p] =  ax [q] ; \
+    z [p] = -az [q]
+
+#define Z_XTYPE_OK(type)		((type) == CHOLMOD_ZOMPLEX)
+
+#define Z_IS_NONZERO(ax,az,q) \
+    (IS_NONZERO (ax [q]) || IS_NONZERO (az [q]))
+
+#define Z_IS_ZERO(ax,az,q) \
+    (IS_ZERO (ax [q]) && IS_ZERO (az [q]))
+
+#define Z_IS_ONE(ax,az,q) \
+    ((ax [q] == 1) && IS_ZERO (az [q]))
+
+#define Z_IMAG_IS_NONZERO(ax,az,q)  (IS_NONZERO (az [q]))
+
+#define Z_MULT(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] = ax [q] * bx [r] - az [q] * bz [r] ; \
+    z [p] = az [q] * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTADD(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] += ax [q] * bx [r] - az [q] * bz [r] ; \
+    z [p] += az [q] * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTSUB(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] -= ax [q] * bx [r] - az [q] * bz [r] ; \
+    z [p] -= az [q] * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTADDCONJ(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] +=   ax [q]  * bx [r] + az [q] * bz [r] ; \
+    z [p] += (-az [q]) * bx [r] + ax [q] * bz [r]
+
+#define Z_MULTSUBCONJ(x,z,p, ax,az,q, bx,bz,r) \
+    x [p] -=   ax [q]  * bx [r] + az [q] * bz [r] ; \
+    z [p] -= (-az [q]) * bx [r] + ax [q] * bz [r]
+
+#define Z_ADD(x,z,p, ax,az,q, bx,bz,r) \
+	x [p] = ax [q] + bx [r] ; \
+	z [p] = az [q] + bz [r]
+
+#define Z_ADD_REAL(x,p, ax,q, bx,r) \
+	x [p] = ax [q] + bx [r]
+
+#define Z_CLEAR(x,z,p) \
+    x [p] = 0 ; \
+    z [p] = 0
+
+#define Z_CLEAR_IMAG(x,z,p) \
+    z [p] = 0
+
+/* s = s/a */
+#define Z_DIV(x,z,p,ax,az,q) \
+    Common->complex_divide (x [p], z [p], ax [q], az [q], &x [p], &z [p])
+
+/* s -= conj(a)*a ; note that the result of conj(a)*a is real */
+#define Z_LLDOT(x,p, ax,az,q) \
+    x [p] -= ax [q] * ax [q] + az [q] * az [q]
+
+#define Z_PRINT(k,x,z,p)	PRK(k, ("(%24.16e,%24.16e)", x [p], z [p]))
+
+#define Z_DIV_REAL(x,z,p, ax,az,q, bx,r) \
+    x [p] = ax [q] / bx [r] ; \
+    z [p] = az [q] / bx [r]
+
+#define Z_MULT_REAL(x,z,p, ax,az,q, bx,r) \
+    x [p] = ax [q] * bx [r] ; \
+    z [p] = az [q] * bx [r]
+
+/* s -= conj(a)*a/t */
+#define Z_LDLDOT(x,p, ax,az,q, bx,r) \
+    x [p] -= (ax [q] * ax [q] + az [q] * az [q]) / bx[r]
+
+/* -------------------------------------------------------------------------- */
+/* all classes */
+/* -------------------------------------------------------------------------- */
+
+/* Check if A->xtype and the two arrays A->x and A->z are valid.  Set status to
+ * invalid, unless status is already "out of memory".  A can be a sparse matrix,
+ * dense matrix, factor, or triplet. */
+
+#define RETURN_IF_XTYPE_INVALID(A,xtype1,xtype2,result) \
+{ \
+    if ((A)->xtype < (xtype1) || (A)->xtype > (xtype2) || \
+        ((A)->xtype != CHOLMOD_PATTERN && ((A)->x) == NULL) || \
+	((A)->xtype == CHOLMOD_ZOMPLEX && ((A)->z) == NULL)) \
+    { \
+	if (Common->status != CHOLMOD_OUT_OF_MEMORY) \
+	{ \
+	    ERROR (CHOLMOD_INVALID, "invalid xtype") ; \
+	} \
+	return (result) ; \
+    } \
+}
diff --git a/src/CHOLMOD/Include/cholmod_config.h b/src/CHOLMOD/Include/cholmod_config.h
new file mode 100644
index 0000000..5ada402
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_config.h
@@ -0,0 +1,85 @@
+/* ========================================================================== */
+/* === Include/cholmod_config.h ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_config.h.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_config.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD configuration file, for inclusion in user programs.
+ *
+ * You do not have to edit any CHOLMOD files to compile and install CHOLMOD.
+ * However, if you do not use all of CHOLMOD's modules, you need to compile
+ * with the appropriate flag, or edit this file to add the appropriate #define.
+ *
+ * If you wish to use CHOLMOD under the GNU LGPL license only, then you must
+ * compile CHOLMOD with -DNMATRIXOPS -DNSUPERNODAL and -DNMODIFY.  This can
+ * be done using just -DNGPL.
+ *
+ * Compiler flags for CHOLMOD:
+ *
+ * -DNCHECK	    do not include the Check module.        License: GNU LGPL
+ * -DNCHOLESKY	    do not include the Cholesky module.     License: GNU LGPL
+ * -DNPARTITION	    do not include the Partition module.    License: GNU LGPL
+ * -DNCAMD          do not include the interfaces to CAMD,
+ *                  CCOLAMD, CSYMAND in Partition module.   License: GNU LGPL
+ *
+ * -DNGPL	    do not include any GNU GPL Modules in the CHOLMOD library.
+ * -DNMATRIXOPS	    do not include the MatrixOps module.    License: GNU GPL
+ * -DNMODIFY	    do not include the Modify module.       License: GNU GPL
+ * -DNSUPERNODAL    do not include the Supernodal module.   License: GNU GPL
+ *
+ * -DNPRINT	    do not print anything
+ *
+ * -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+ *		    LAPACK and the BLAS.  Use LONGBLAS=long on Solaris to use
+ *		    the 64-bit Sun Performance BLAS in cholmod_l_* routines.
+ *		    You may need to use -D'LONGBLAS=long long' on the SGI
+ *		    (this is not tested).
+ *
+ * -DNSUNPERF	    for Solaris only.  If defined, do not use the Sun
+ *		    Performance Library.  The default is to use SunPerf.
+ *		    You must compile CHOLMOD with -xlic_lib=sunperf.
+ *
+ * The Core Module (License GNU LGPL) is always included in the CHOLMOD library.
+ */
+
+#ifndef CHOLMOD_CONFIG_H
+#define CHOLMOD_CONFIG_H
+
+/* Use the compiler flag, or uncomment the definition(s), if you want to use
+ * one or more non-default installation options: */
+
+/*
+#define NCHECK
+#define NCHOLESKY
+#define NCAMD
+#define NPARTITION
+
+#define NGPL  
+#define NMATRIXOPS
+#define NMODIFY
+#define NSUPERNODAL
+
+#define NPRINT
+
+#define LONGBLAS long
+#define LONGBLAS long long
+#define NSUNPERF
+*/
+
+/* -------------------------------------------------------------------------- */
+/* if NGPL is defined, disable all GNU GPL Modules */
+/* -------------------------------------------------------------------------- */
+
+#ifdef NGPL
+#define NMATRIXOPS
+#define NMODIFY
+#define NSUPERNODAL
+#endif
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_core.h b/src/CHOLMOD/Include/cholmod_core.h
new file mode 100644
index 0000000..a435e5f
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_core.h
@@ -0,0 +1,2395 @@
+/* ========================================================================== */
+/* === Include/cholmod_core.h =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_core.h.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_core.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Core module: basic CHOLMOD objects and routines.
+ * Required by all CHOLMOD modules.  Requires no other module or package.
+ *
+ * The CHOLMOD modules are:
+ *
+ * Core		basic data structures and definitions
+ * Check	check/print the 5 CHOLMOD objects, & 3 types of integer vectors
+ * Cholesky	sparse Cholesky factorization
+ * Modify	sparse Cholesky update/downdate/row-add/row-delete
+ * MatrixOps	sparse matrix functions (add, multiply, norm, ...)
+ * Supernodal	supernodal sparse Cholesky factorization
+ * Partition	graph-partitioning based orderings
+ *
+ * The CHOLMOD objects:
+ * --------------------
+ *
+ * cholmod_common   parameters, statistics, and workspace
+ * cholmod_sparse   a sparse matrix in compressed column form
+ * cholmod_factor   an LL' or LDL' factorization
+ * cholmod_dense    a dense matrix
+ * cholmod_triplet  a sparse matrix in "triplet" form
+ *
+ * The Core module described here defines the CHOLMOD data structures, and
+ * basic operations on them.  To create and solve a sparse linear system Ax=b,
+ * the user must create A and b, populate them with values, and then pass them
+ * to the routines in the CHOLMOD Cholesky module.  There are two primary
+ * methods for creating A: (1) allocate space for a column-oriented sparse
+ * matrix and fill it with pattern and values, or (2) create a triplet form
+ * matrix and convert it to a sparse matrix.  The latter option is simpler.
+ *
+ * The matrices b and x are typically dense matrices, but can also be sparse.
+ * You can allocate and free them as dense matrices with the
+ * cholmod_allocate_dense and cholmod_free_dense routines.
+ *
+ * The cholmod_factor object contains the symbolic and numeric LL' or LDL'
+ * factorization of sparse symmetric matrix.  The matrix must be positive
+ * definite for an LL' factorization.  It need only be symmetric and have well-
+ * conditioned leading submatrices for it to have an LDL' factorization
+ * (CHOLMOD does not pivot for numerical stability).  It is typically created
+ * with the cholmod_factorize routine in the Cholesky module, but can also
+ * be initialized to L=D=I in the Core module and then modified by the Modify
+ * module.  It must be freed with cholmod_free_factor, defined below.
+ *
+ * The Core routines for each object are described below.  Each list is split
+ * into two parts: the primary routines and secondary routines.
+ *
+ * ============================================================================
+ * === cholmod_common =========================================================
+ * ============================================================================
+ *
+ * The Common object contains control parameters, statistics, and
+ * You must call cholmod_start before calling any other CHOLMOD routine, and
+ * must call cholmod_finish as your last call to CHOLMOD, with two exceptions:
+ * you may call cholmod_print_common and cholmod_check_common in the Check
+ * module after calling cholmod_finish.
+ *
+ * cholmod_start		first call to CHOLMOD
+ * cholmod_finish		last call to CHOLMOD
+ * -----------------------------
+ * cholmod_defaults		restore default parameters
+ * cholmod_maxrank		maximum rank for update/downdate
+ * cholmod_allocate_work	allocate workspace in Common
+ * cholmod_free_work		free workspace in Common
+ * cholmod_clear_flag		clear Flag workspace in Common
+ * cholmod_error		called when CHOLMOD encounters an error
+ * cholmod_dbound		for internal use in CHOLMOD only
+ * cholmod_hypot		compute sqrt (x*x + y*y) accurately
+ * cholmod_divcomplex		complex division, c = a/b
+ *
+ * ============================================================================
+ * === cholmod_sparse =========================================================
+ * ============================================================================
+ *
+ * A sparse matrix is held in compressed column form.  In the basic type
+ * ("packed", which corresponds to a MATLAB sparse matrix), an n-by-n matrix
+ * with nz entries is held in three arrays: p of size n+1, i of size nz, and x
+ * of size nz.  Row indices of column j are held in i [p [j] ... p [j+1]-1] and
+ * in the same locations in x.  There may be no duplicate entries in a column.
+ * Row indices in each column may be sorted or unsorted (CHOLMOD keeps track).
+ * A->stype determines the storage mode: 0 if both upper/lower parts are stored,
+ * -1 if A is symmetric and just tril(A) is stored, +1 if symmetric and triu(A)
+ * is stored.
+ *
+ * cholmod_allocate_sparse	allocate a sparse matrix
+ * cholmod_free_sparse		free a sparse matrix
+ * -----------------------------
+ * cholmod_reallocate_sparse	change the size (# entries) of sparse matrix
+ * cholmod_nnz			number of nonzeros in a sparse matrix
+ * cholmod_speye		sparse identity matrix
+ * cholmod_spzeros		sparse zero matrix
+ * cholmod_transpose		transpose a sparse matrix
+ * cholmod_ptranspose		transpose/permute a sparse matrix
+ * cholmod_transpose_unsym	transpose/permute an unsymmetric sparse matrix
+ * cholmod_transpose_sym	transpose/permute a symmetric sparse matrix
+ * cholmod_sort			sort row indices in each column of sparse matrix
+ * cholmod_band			C = tril (triu (A,k1), k2)
+ * cholmod_band_inplace		A = tril (triu (A,k1), k2)
+ * cholmod_aat			C = A*A'
+ * cholmod_copy_sparse		C = A, create an exact copy of a sparse matrix
+ * cholmod_copy			C = A, with possible change of stype
+ * cholmod_add			C = alpha*A + beta*B
+ * cholmod_sparse_xtype		change the xtype of a sparse matrix
+ *
+ * ============================================================================
+ * === cholmod_factor =========================================================
+ * ============================================================================
+ *
+ * The data structure for an LL' or LDL' factorization is too complex to
+ * describe in one sentence.  This object can hold the symbolic analysis alone,
+ * or in combination with a "simplicial" (similar to a sparse matrix) or
+ * "supernodal" form of the numerical factorization.  Only the routine to free
+ * a factor is primary, since a factor object is created by the factorization
+ * routine (cholmod_factorize).  It must be freed with cholmod_free_factor.
+ *
+ * cholmod_free_factor		free a factor
+ * -----------------------------
+ * cholmod_allocate_factor	allocate a factor (LL' or LDL')
+ * cholmod_reallocate_factor	change the # entries in a factor
+ * cholmod_change_factor	change the type of factor (e.g., LDL' to LL')
+ * cholmod_pack_factor		pack the columns of a factor
+ * cholmod_reallocate_column	resize a single column of a factor
+ * cholmod_factor_to_sparse	create a sparse matrix copy of a factor
+ * cholmod_copy_factor		create a copy of a factor
+ * cholmod_factor_xtype		change the xtype of a factor
+ *
+ * Note that there is no cholmod_sparse_to_factor routine to create a factor
+ * as a copy of a sparse matrix.  It could be done, after a fashion, but a
+ * lower triangular sparse matrix would not necessarily have a chordal graph,
+ * which would break the many CHOLMOD routines that rely on this property.
+ *
+ * ============================================================================
+ * === cholmod_dense ==========================================================
+ * ============================================================================
+ *
+ * The solve routines and some of the MatrixOps and Modify routines use dense
+ * matrices as inputs.  These are held in column-major order.  With a leading
+ * dimension of d, the entry in row i and column j is held in x [i+j*d].
+ *
+ * cholmod_allocate_dense	allocate a dense matrix
+ * cholmod_free_dense		free a dense matrix
+ * -----------------------------
+ * cholmod_zeros		allocate a dense matrix of all zeros
+ * cholmod_ones			allocate a dense matrix of all ones
+ * cholmod_eye			allocate a dense identity matrix
+ * cholmod_sparse_to_dense	create a dense matrix copy of a sparse matrix
+ * cholmod_dense_to_sparse	create a sparse matrix copy of a dense matrix
+ * cholmod_copy_dense		create a copy of a dense matrix
+ * cholmod_copy_dense2		copy a dense matrix (pre-allocated)
+ * cholmod_dense_xtype		change the xtype of a dense matrix
+ * cholmod_ensure_dense  	ensure a dense matrix has a given size and type
+ *
+ * ============================================================================
+ * === cholmod_triplet ========================================================
+ * ============================================================================
+ *
+ * A sparse matrix held in triplet form is the simplest one for a user to
+ * create.  It consists of a list of nz entries in arbitrary order, held in
+ * three arrays: i, j, and x, each of length nk.  The kth entry is in row i[k],
+ * column j[k], with value x[k].  There may be duplicate values; if A(i,j)
+ * appears more than once, its value is the sum of the entries with those row
+ * and column indices.
+ *
+ * cholmod_allocate_triplet	allocate a triplet matrix
+ * cholmod_triplet_to_sparse	create a sparse matrix copy of a triplet matrix
+ * cholmod_free_triplet		free a triplet matrix
+ * -----------------------------
+ * cholmod_reallocate_triplet	change the # of entries in a triplet matrix
+ * cholmod_sparse_to_triplet	create a triplet matrix copy of a sparse matrix
+ * cholmod_copy_triplet		create a copy of a triplet matrix
+ * cholmod_triplet_xtype	change the xtype of a triplet matrix
+ *
+ * ============================================================================
+ * === memory management ======================================================
+ * ============================================================================
+ *
+ * cholmod_malloc		malloc wrapper
+ * cholmod_calloc		calloc wrapper
+ * cholmod_free			free wrapper
+ * cholmod_realloc		realloc wrapper
+ * cholmod_realloc_multiple	realloc wrapper for multiple objects
+ *
+ * ============================================================================
+ * === Core CHOLMOD prototypes ================================================
+ * ============================================================================
+ *
+ * All CHOLMOD routines (in all modules) use the following protocol for return
+ * values, with one exception:
+ *
+ * int			TRUE (1) if successful, or FALSE (0) otherwise.
+ *			(exception: cholmod_divcomplex)
+ * SuiteSparse_long     a value >= 0 if successful, or -1 otherwise.
+ * double		a value >= 0 if successful, or -1 otherwise.
+ * size_t		a value > 0 if successful, or 0 otherwise.
+ * void *		a non-NULL pointer to newly allocated memory if
+ *			successful, or NULL otherwise.
+ * cholmod_sparse *	a non-NULL pointer to a newly allocated matrix
+ *			if successful, or NULL otherwise.
+ * cholmod_factor *	a non-NULL pointer to a newly allocated factor
+ *			if successful, or NULL otherwise.
+ * cholmod_triplet *	a non-NULL pointer to a newly allocated triplet
+ *			matrix if successful, or NULL otherwise.
+ * cholmod_dense *	a non-NULL pointer to a newly allocated triplet
+ *			matrix if successful, or NULL otherwise.
+ *
+ * The last parameter to all routines is always a pointer to the CHOLMOD
+ * Common object.
+ *
+ * TRUE and FALSE are not defined here, since they may conflict with the user
+ * program.  A routine that described here returning TRUE or FALSE returns 1
+ * or 0, respectively.  Any TRUE/FALSE parameter is true if nonzero, false if
+ * zero.
+ */
+
+#ifndef CHOLMOD_CORE_H
+#define CHOLMOD_CORE_H
+
+/* ========================================================================== */
+/* === CHOLMOD version ====================================================== */
+/* ========================================================================== */
+
+/* All versions of CHOLMOD will include the following definitions.
+ * As an example, to test if the version you are using is 1.3 or later:
+ *
+ *	if (CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3)) ...
+ *
+ * This also works during compile-time:
+ *
+ *	#if CHOLMOD_VERSION >= CHOLMOD_VER_CODE (1,3)
+ *	    printf ("This is version 1.3 or later\n") ;
+ *	#else
+ *	    printf ("This is version is earlier than 1.3\n") ;
+ *	#endif
+ */
+
+#define CHOLMOD_HAS_VERSION_FUNCTION
+
+#define CHOLMOD_DATE "April 25, 2013"
+#define CHOLMOD_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define CHOLMOD_MAIN_VERSION 2
+#define CHOLMOD_SUB_VERSION 1
+#define CHOLMOD_SUBSUB_VERSION 2
+#define CHOLMOD_VERSION \
+    CHOLMOD_VER_CODE(CHOLMOD_MAIN_VERSION,CHOLMOD_SUB_VERSION)
+
+
+/* ========================================================================== */
+/* === non-CHOLMOD include files ============================================ */
+/* ========================================================================== */
+
+/* This is the only non-CHOLMOD include file imposed on the user program.
+ * It required for size_t definition used here.  CHOLMOD itself includes other
+ * ANSI C89 standard #include files, but does not expose them to the user.
+ *
+ * CHOLMOD assumes that your C compiler is ANSI C89 compliant.  It does not make
+ * use of ANSI C99 features.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === CUDA BLAS for the GPU ================================================ */
+/* ========================================================================== */
+
+#ifdef GPU_BLAS
+#include <cuda_runtime.h>
+#include <cublas_v2.h>
+#endif
+
+
+/* ========================================================================== */
+/* === CHOLMOD objects ====================================================== */
+/* ========================================================================== */
+
+/* Each CHOLMOD object has its own type code. */
+
+#define CHOLMOD_COMMON 0
+#define CHOLMOD_SPARSE 1
+#define CHOLMOD_FACTOR 2
+#define CHOLMOD_DENSE 3
+#define CHOLMOD_TRIPLET 4
+
+/* ========================================================================== */
+/* === CHOLMOD Common ======================================================= */
+/* ========================================================================== */
+
+/* itype defines the types of integer used: */
+#define CHOLMOD_INT 0		/* all integer arrays are int */
+#define CHOLMOD_INTLONG 1	/* most are int, some are SuiteSparse_long */
+#define CHOLMOD_LONG 2		/* all integer arrays are SuiteSparse_long */
+
+/* The itype of all parameters for all CHOLMOD routines must match.
+ * FUTURE WORK: CHOLMOD_INTLONG is not yet supported.
+ */
+
+/* dtype defines what the numerical type is (double or float): */
+#define CHOLMOD_DOUBLE 0	/* all numerical values are double */
+#define CHOLMOD_SINGLE 1	/* all numerical values are float */
+
+/* The dtype of all parameters for all CHOLMOD routines must match.
+ *
+ * Scalar floating-point values are always passed as double arrays of size 2
+ * (for the real and imaginary parts).  They are typecast to float as needed.
+ * FUTURE WORK: the float case is not supported yet.
+ */
+
+/* xtype defines the kind of numerical values used: */
+#define CHOLMOD_PATTERN 0	/* pattern only, no numerical values */
+#define CHOLMOD_REAL 1		/* a real matrix */
+#define CHOLMOD_COMPLEX 2	/* a complex matrix (ANSI C99 compatible) */
+#define CHOLMOD_ZOMPLEX 3	/* a complex matrix (MATLAB compatible) */
+
+/* The xtype of all parameters for all CHOLMOD routines must match.
+ *
+ * CHOLMOD_PATTERN: x and z are ignored.
+ * CHOLMOD_DOUBLE:  x is non-null of size nzmax, z is ignored.
+ * CHOLMOD_COMPLEX: x is non-null of size 2*nzmax doubles, z is ignored.
+ * CHOLMOD_ZOMPLEX: x and z are non-null of size nzmax
+ *
+ * In the real case, z is ignored.  The kth entry in the matrix is x [k].
+ * There are two methods for the complex case.  In the ANSI C99-compatible
+ * CHOLMOD_COMPLEX case, the real and imaginary parts of the kth entry
+ * are in x [2*k] and x [2*k+1], respectively.  z is ignored.  In the
+ * MATLAB-compatible CHOLMOD_ZOMPLEX case, the real and imaginary
+ * parts of the kth entry are in x [k] and z [k].
+ *
+ * Scalar floating-point values are always passed as double arrays of size 2
+ * (real and imaginary parts).  The imaginary part of a scalar is ignored if
+ * the routine operates on a real matrix.
+ *
+ * These Modules support complex and zomplex matrices, with a few exceptions:
+ *
+ *	Check	    all routines
+ *	Cholesky    all routines
+ *	Core	    all except cholmod_aat, add, band, copy
+ *	Demo	    all routines
+ *	Partition   all routines
+ *	Supernodal  all routines support any real, complex, or zomplex input.
+ *			There will never be a supernodal zomplex L; a complex
+ *			supernodal L is created if A is zomplex.
+ *	Tcov	    all routines
+ *	Valgrind    all routines
+ *
+ * These Modules provide partial support for complex and zomplex matrices:
+ *
+ *	MATLAB	    all routines support real and zomplex only, not complex,
+ *			with the exception of ldlupdate, which supports
+ *			real matrices only.  This is a minor constraint since
+ *			MATLAB's matrices are all real or zomplex.
+ *	MatrixOps   only norm_dense, norm_sparse, and sdmult support complex
+ *			and zomplex
+ *
+ * These Modules do not support complex and zomplex matrices at all:
+ *
+ *	Modify	    all routines support real matrices only
+ */
+
+/* Definitions for cholmod_common: */
+#define CHOLMOD_MAXMETHODS 9	/* maximum number of different methods that */
+				/* cholmod_analyze can try. Must be >= 9. */
+
+/* Common->status values.  zero means success, negative means a fatal error,
+ * positive is a warning. */
+#define CHOLMOD_OK 0			/* success */
+#define CHOLMOD_NOT_INSTALLED (-1)	/* failure: method not installed */
+#define CHOLMOD_OUT_OF_MEMORY (-2)	/* failure: out of memory */
+#define CHOLMOD_TOO_LARGE (-3)		/* failure: integer overflow occured */
+#define CHOLMOD_INVALID (-4)		/* failure: invalid input */
+#define CHOLMOD_GPU_PROBLEM (-5)        /* failure: GPU fatal error */
+#define CHOLMOD_NOT_POSDEF (1)		/* warning: matrix not pos. def. */
+#define CHOLMOD_DSMALL (2)		/* warning: D for LDL'  or diag(L) or */
+					/* LL' has tiny absolute value */
+
+/* ordering method (also used for L->ordering) */
+#define CHOLMOD_NATURAL 0	/* use natural ordering */
+#define CHOLMOD_GIVEN 1		/* use given permutation */
+#define CHOLMOD_AMD 2		/* use minimum degree (AMD) */
+#define CHOLMOD_METIS 3		/* use METIS' nested dissection */
+#define CHOLMOD_NESDIS 4	/* use CHOLMOD's version of nested dissection:*/
+				/* node bisector applied recursively, followed
+				 * by constrained minimum degree (CSYMAMD or
+				 * CCOLAMD) */
+#define CHOLMOD_COLAMD 5	/* use AMD for A, COLAMD for A*A' */
+
+/* POSTORDERED is not a method, but a result of natural ordering followed by a
+ * weighted postorder.  It is used for L->ordering, not method [ ].ordering. */
+#define CHOLMOD_POSTORDERED 6	/* natural ordering, postordered. */
+
+/* supernodal strategy (for Common->supernodal) */
+#define CHOLMOD_SIMPLICIAL 0	/* always do simplicial */
+#define CHOLMOD_AUTO 1		/* select simpl/super depending on matrix */
+#define CHOLMOD_SUPERNODAL 2	/* always do supernodal */
+
+typedef struct cholmod_common_struct
+{
+    /* ---------------------------------------------------------------------- */
+    /* parameters for symbolic/numeric factorization and update/downdate */
+    /* ---------------------------------------------------------------------- */
+
+    double dbound ;	/* Smallest absolute value of diagonal entries of D
+			 * for LDL' factorization and update/downdate/rowadd/
+	* rowdel, or the diagonal of L for an LL' factorization.
+	* Entries in the range 0 to dbound are replaced with dbound.
+	* Entries in the range -dbound to 0 are replaced with -dbound.  No
+	* changes are made to the diagonal if dbound <= 0.  Default: zero */
+
+    double grow0 ;	/* For a simplicial factorization, L->i and L->x can
+			 * grow if necessary.  grow0 is the factor by which
+	* it grows.  For the initial space, L is of size MAX (1,grow0) times
+	* the required space.  If L runs out of space, the new size of L is
+	* MAX(1.2,grow0) times the new required space.   If you do not plan on
+	* modifying the LDL' factorization in the Modify module, set grow0 to
+	* zero (or set grow2 to 0, see below).  Default: 1.2 */
+
+    double grow1 ;
+
+    size_t grow2 ;	/* For a simplicial factorization, each column j of L
+			 * is initialized with space equal to
+	* grow1*L->ColCount[j] + grow2.  If grow0 < 1, grow1 < 1, or grow2 == 0,
+	* then the space allocated is exactly equal to L->ColCount[j].  If the
+	* column j runs out of space, it increases to grow1*need + grow2 in
+	* size, where need is the total # of nonzeros in that column.  If you do
+	* not plan on modifying the factorization in the Modify module, set
+	* grow2 to zero.  Default: grow1 = 1.2, grow2 = 5. */
+
+    size_t maxrank ;	/* rank of maximum update/downdate.  Valid values:
+			 * 2, 4, or 8.  A value < 2 is set to 2, and a
+	* value > 8 is set to 8.  It is then rounded up to the next highest
+	* power of 2, if not already a power of 2.  Workspace (Xwork, below) of
+	* size nrow-by-maxrank double's is allocated for the update/downdate.
+	* If an update/downdate of rank-k is requested, with k > maxrank,
+	* it is done in steps of maxrank.  Default: 8, which is fastest.
+	* Memory usage can be reduced by setting maxrank to 2 or 4.
+	*/
+
+    double supernodal_switch ;	/* supernodal vs simplicial factorization */
+    int supernodal ;		/* If Common->supernodal <= CHOLMOD_SIMPLICIAL
+				 * (0) then cholmod_analyze performs a
+	* simplicial analysis.  If >= CHOLMOD_SUPERNODAL (2), then a supernodal
+	* analysis is performed.  If == CHOLMOD_AUTO (1) and
+	* flop/nnz(L) < Common->supernodal_switch, then a simplicial analysis
+	* is done.  A supernodal analysis done otherwise.
+	* Default:  CHOLMOD_AUTO.  Default supernodal_switch = 40 */
+
+    int final_asis ;	/* If TRUE, then ignore the other final_* parameters
+			 * (except for final_pack).
+			 * The factor is left as-is when done.  Default: TRUE.*/
+
+    int final_super ;	/* If TRUE, leave a factor in supernodal form when
+			 * supernodal factorization is finished.  If FALSE,
+			 * then convert to a simplicial factor when done.
+			 * Default: TRUE */
+
+    int final_ll ;	/* If TRUE, leave factor in LL' form when done.
+			 * Otherwise, leave in LDL' form.  Default: FALSE */
+
+    int final_pack ;	/* If TRUE, pack the columns when done.  If TRUE, and
+			 * cholmod_factorize is called with a symbolic L, L is
+	* allocated with exactly the space required, using L->ColCount.  If you
+	* plan on modifying the factorization, set Common->final_pack to FALSE,
+	* and each column will be given a little extra slack space for future
+	* growth in fill-in due to updates.  Default: TRUE */
+
+    int final_monotonic ;   /* If TRUE, ensure columns are monotonic when done.
+			 * Default: TRUE */
+
+    int final_resymbol ;/* if cholmod_factorize performed a supernodal
+			 * factorization, final_resymbol is true, and
+	* final_super is FALSE (convert a simplicial numeric factorization),
+	* then numerically zero entries that resulted from relaxed supernodal
+	* amalgamation are removed.  This does not remove entries that are zero
+	* due to exact numeric cancellation, since doing so would break the
+	* update/downdate rowadd/rowdel routines.  Default: FALSE. */
+
+    /* supernodal relaxed amalgamation parameters: */
+    double zrelax [3] ;
+    size_t nrelax [3] ;
+
+	/* Let ns be the total number of columns in two adjacent supernodes.
+	 * Let z be the fraction of zero entries in the two supernodes if they
+	 * are merged (z includes zero entries from prior amalgamations).  The
+	 * two supernodes are merged if:
+	 *    (ns <= nrelax [0]) || (no new zero entries added) ||
+	 *    (ns <= nrelax [1] && z < zrelax [0]) ||
+	 *    (ns <= nrelax [2] && z < zrelax [1]) || (z < zrelax [2])
+	 *
+	 * Default parameters result in the following rule:
+	 *    (ns <= 4) || (no new zero entries added) ||
+	 *    (ns <= 16 && z < 0.8) || (ns <= 48 && z < 0.1) || (z < 0.05)
+	 */
+
+    int prefer_zomplex ;    /* X = cholmod_solve (sys, L, B, Common) computes
+			     * x=A\b or solves a related system.  If L and B are
+	 * both real, then X is real.  Otherwise, X is returned as
+	 * CHOLMOD_COMPLEX if Common->prefer_zomplex is FALSE, or
+	 * CHOLMOD_ZOMPLEX if Common->prefer_zomplex is TRUE.  This parameter
+	 * is needed because there is no supernodal zomplex L.  Suppose the
+	 * caller wants all complex matrices to be stored in zomplex form
+	 * (MATLAB, for example).  A supernodal L is returned in complex form
+	 * if A is zomplex.  B can be real, and thus X = cholmod_solve (L,B)
+	 * should return X as zomplex.  This cannot be inferred from the input
+	 * arguments L and B.  Default: FALSE, since all data types are
+	 * supported in CHOLMOD_COMPLEX form and since this is the native type
+	 * of LAPACK and the BLAS.  Note that the MATLAB/cholmod.c mexFunction
+	 * sets this parameter to TRUE, since MATLAB matrices are in
+	 * CHOLMOD_ZOMPLEX form.
+	 */
+
+    int prefer_upper ;	    /* cholmod_analyze and cholmod_factorize work
+			     * fastest when a symmetric matrix is stored in
+	 * upper triangular form when a fill-reducing ordering is used.  In
+	 * MATLAB, this corresponds to how x=A\b works.  When the matrix is
+	 * ordered as-is, they work fastest when a symmetric matrix is in lower
+	 * triangular form.  In MATLAB, R=chol(A) does the opposite.  This
+	 * parameter affects only how cholmod_read returns a symmetric matrix.
+	 * If TRUE (the default case), a symmetric matrix is always returned in
+	 * upper-triangular form (A->stype = 1).  */
+
+    int quick_return_if_not_posdef ;	/* if TRUE, the supernodal numeric
+					 * factorization will return quickly if
+	* the matrix is not positive definite.  Default: FALSE. */
+
+    /* ---------------------------------------------------------------------- */
+    /* printing and error handling options */
+    /* ---------------------------------------------------------------------- */
+
+    int print ;		/* print level. Default: 3 */
+    int precise ;	/* if TRUE, print 16 digits.  Otherwise print 5 */
+    int (*print_function) (const char *, ...) ;	/* pointer to printf */
+
+    int try_catch ;	/* if TRUE, then ignore errors; CHOLMOD is in the middle
+			 * of a try/catch block.  No error message is printed
+	 * and the Common->error_handler function is not called. */
+
+    void (*error_handler) (int status, const char *file,
+        int line, const char *message) ;
+
+	/* Common->error_handler is the user's error handling routine.  If not
+	 * NULL, this routine is called if an error occurs in CHOLMOD.  status
+	 * can be CHOLMOD_OK (0), negative for a fatal error, and positive for
+	 * a warning. file is a string containing the name of the source code
+	 * file where the error occured, and line is the line number in that
+	 * file.  message is a string describing the error in more detail. */
+
+    /* ---------------------------------------------------------------------- */
+    /* ordering options */
+    /* ---------------------------------------------------------------------- */
+
+    /* The cholmod_analyze routine can try many different orderings and select
+     * the best one.  It can also try one ordering method multiple times, with
+     * different parameter settings.  The default is to use three orderings,
+     * the user's permutation (if provided), AMD which is the fastest ordering
+     * and generally gives good fill-in, and METIS.  CHOLMOD's nested dissection
+     * (METIS with a constrained AMD) usually gives a better ordering than METIS
+     * alone (by about 5% to 10%) but it takes more time.
+     *
+     * If you know the method that is best for your matrix, set Common->nmethods
+     * to 1 and set Common->method [0] to the set of parameters for that method.
+     * If you set it to 1 and do not provide a permutation, then only AMD will
+     * be called.
+     *
+     * If METIS is not available, the default # of methods tried is 2 (the user
+     * permutation, if any, and AMD).
+     *
+     * To try other methods, set Common->nmethods to the number of methods you
+     * want to try.  The suite of default methods and their parameters is
+     * described in the cholmod_defaults routine, and summarized here:
+     *
+     *	    Common->method [i]:
+     *	    i = 0: user-provided ordering (cholmod_analyze_p only)
+     *	    i = 1: AMD (for both A and A*A')
+     *	    i = 2: METIS
+     *	    i = 3: CHOLMOD's nested dissection (NESDIS), default parameters
+     *	    i = 4: natural
+     *	    i = 5: NESDIS with nd_small = 20000
+     *	    i = 6: NESDIS with nd_small = 4, no constrained minimum degree
+     *	    i = 7: NESDIS with no dense node removal
+     *	    i = 8: AMD for A, COLAMD for A*A'
+     *
+     * You can modify the suite of methods you wish to try by modifying
+     * Common.method [...] after calling cholmod_start or cholmod_defaults.
+     *
+     * For example, to use AMD, followed by a weighted postordering:
+     *
+     *	    Common->nmethods = 1 ;
+     *	    Common->method [0].ordering = CHOLMOD_AMD ;
+     *	    Common->postorder = TRUE ;
+     *
+     * To use the natural ordering (with no postordering):
+     *
+     *	    Common->nmethods = 1 ;
+     *	    Common->method [0].ordering = CHOLMOD_NATURAL ;
+     *	    Common->postorder = FALSE ;
+     *
+     * If you are going to factorize hundreds or more matrices with the same
+     * nonzero pattern, you may wish to spend a great deal of time finding a
+     * good permutation.  In this case, try setting Common->nmethods to 9.
+     * The time spent in cholmod_analysis will be very high, but you need to
+     * call it only once.
+     *
+     * cholmod_analyze sets Common->current to a value between 0 and nmethods-1.
+     * Each ordering method uses the set of options defined by this parameter.
+     */
+
+    int nmethods ;	/* The number of ordering methods to try.  Default: 0.
+			 * nmethods = 0 is a special case.  cholmod_analyze
+	* will try the user-provided ordering (if given) and AMD.  Let fl and
+	* lnz be the flop count and nonzeros in L from AMD's ordering.  Let
+	* anz be the number of nonzeros in the upper or lower triangular part
+	* of the symmetric matrix A.  If fl/lnz < 500 or lnz/anz < 5, then this
+	* is a good ordering, and METIS is not attempted.  Otherwise, METIS is
+	* tried.   The best ordering found is used.  If nmethods > 0, the
+	* methods used are given in the method[ ] array, below.  The first
+	* three methods in the default suite of orderings is (1) use the given
+	* permutation (if provided), (2) use AMD, and (3) use METIS.  Maximum
+	* allowed value is CHOLMOD_MAXMETHODS.  */
+
+    int current ;	/* The current method being tried.  Default: 0.  Valid
+			 * range is 0 to nmethods-1. */
+
+    int selected ;	/* The best method found. */
+
+    /* The suite of ordering methods and parameters: */
+
+    struct cholmod_method_struct
+    {
+	/* statistics for this method */
+	double lnz ;	    /* nnz(L) excl. zeros from supernodal amalgamation,
+			     * for a "pure" L */
+
+	double fl ;	    /* flop count for a "pure", real simplicial LL'
+			     * factorization, with no extra work due to
+	    * amalgamation.  Subtract n to get the LDL' flop count.   Multiply
+	    * by about 4 if the matrix is complex or zomplex. */
+
+	/* ordering method parameters */
+	double prune_dense ;/* dense row/col control for AMD, SYMAMD, CSYMAMD,
+			     * and NESDIS (cholmod_nested_dissection).  For a
+	    * symmetric n-by-n matrix, rows/columns with more than
+	    * MAX (16, prune_dense * sqrt (n)) entries are removed prior to
+	    * ordering.  They appear at the end of the re-ordered matrix.
+	    *
+	    * If prune_dense < 0, only completely dense rows/cols are removed.
+	    *
+	    * This paramater is also the dense column control for COLAMD and
+	    * CCOLAMD.  For an m-by-n matrix, columns with more than
+	    * MAX (16, prune_dense * sqrt (MIN (m,n))) entries are removed prior
+	    * to ordering.  They appear at the end of the re-ordered matrix.
+	    * CHOLMOD factorizes A*A', so it calls COLAMD and CCOLAMD with A',
+	    * not A.  Thus, this parameter affects the dense *row* control for
+	    * CHOLMOD's matrix, and the dense *column* control for COLAMD and
+	    * CCOLAMD.
+	    *
+	    * Removing dense rows and columns improves the run-time of the
+	    * ordering methods.  It has some impact on ordering quality
+	    * (usually minimal, sometimes good, sometimes bad).
+	    *
+	    * Default: 10. */
+
+	double prune_dense2 ;/* dense row control for COLAMD and CCOLAMD.
+			    *  Rows with more than MAX (16, dense2 * sqrt (n))
+	    * for an m-by-n matrix are removed prior to ordering.  CHOLMOD's
+	    * matrix is transposed before ordering it with COLAMD or CCOLAMD,
+	    * so this controls the dense *columns* of CHOLMOD's matrix, and
+	    * the dense *rows* of COLAMD's or CCOLAMD's matrix.
+	    *
+	    * If prune_dense2 < 0, only completely dense rows/cols are removed.
+	    *
+	    * Default: -1.  Note that this is not the default for COLAMD and
+	    * CCOLAMD.  -1 is best for Cholesky.  10 is best for LU.  */
+
+	double nd_oksep ;   /* in NESDIS, when a node separator is computed, it
+			     * discarded if nsep >= nd_oksep*n, where nsep is
+	    * the number of nodes in the separator, and n is the size of the
+	    * graph being cut.  Valid range is 0 to 1.  If 1 or greater, the
+	    * separator is discarded if it consists of the entire graph.
+	    * Default: 1 */
+
+	double other_1 [4] ; /* future expansion */
+
+	size_t nd_small ;    /* do not partition graphs with fewer nodes than
+			     * nd_small, in NESDIS.  Default: 200 (same as
+			     * METIS) */
+
+	size_t other_2 [4] ; /* future expansion */
+
+	int aggressive ;    /* Aggresive absorption in AMD, COLAMD, SYMAMD,
+			     * CCOLAMD, and CSYMAMD.  Default: TRUE */
+
+	int order_for_lu ;  /* CCOLAMD can be optimized to produce an ordering
+			     * for LU or Cholesky factorization.  CHOLMOD only
+	    * performs a Cholesky factorization.  However, you may wish to use
+	    * CHOLMOD as an interface for CCOLAMD but use it for your own LU
+	    * factorization.  In this case, order_for_lu should be set to FALSE.
+	    * When factorizing in CHOLMOD itself, you should *** NEVER *** set
+	    * this parameter FALSE.  Default: TRUE. */
+
+	int nd_compress ;   /* If TRUE, compress the graph and subgraphs before
+			     * partitioning them in NESDIS.  Default: TRUE */
+
+	int nd_camd ;	    /* If 1, follow the nested dissection ordering
+			     * with a constrained minimum degree ordering that
+	    * respects the partitioning just found (using CAMD).  If 2, use
+	    * CSYMAMD instead.  If you set nd_small very small, you may not need
+	    * this ordering, and can save time by setting it to zero (no
+	    * constrained minimum degree ordering).  Default: 1. */
+
+	int nd_components ; /* The nested dissection ordering finds a node
+			     * separator that splits the graph into two parts,
+	    * which may be unconnected.  If nd_components is TRUE, each of
+	    * these connected components is split independently.  If FALSE,
+	    * each part is split as a whole, even if it consists of more than
+	    * one connected component.  Default: FALSE */
+
+	/* fill-reducing ordering to use */
+	int ordering ;
+
+	size_t other_3 [4] ; /* future expansion */
+
+    } method [CHOLMOD_MAXMETHODS + 1] ;
+
+    int postorder ;	/* If TRUE, cholmod_analyze follows the ordering with a
+			 * weighted postorder of the elimination tree.  Improves
+	* supernode amalgamation.  Does not affect fundamental nnz(L) and
+	* flop count.  Default: TRUE. */
+
+    /* ---------------------------------------------------------------------- */
+    /* memory management routines */
+    /* ---------------------------------------------------------------------- */
+
+    void *(*malloc_memory) (size_t) ;		/* pointer to malloc */
+    void *(*realloc_memory) (void *, size_t) ;  /* pointer to realloc */
+    void (*free_memory) (void *) ;		/* pointer to free */
+    void *(*calloc_memory) (size_t, size_t) ;	/* pointer to calloc */
+
+    /* ---------------------------------------------------------------------- */
+    /* routines for complex arithmetic */
+    /* ---------------------------------------------------------------------- */
+
+    int (*complex_divide) (double ax, double az, double bx, double bz,
+	    double *cx, double *cz) ;
+
+	/* flag = complex_divide (ax, az, bx, bz, &cx, &cz) computes the complex
+	 * division c = a/b, where ax and az hold the real and imaginary part
+	 * of a, and b and c are stored similarly.  flag is returned as 1 if
+	 * a divide-by-zero occurs, or 0 otherwise.  By default, the function
+	 * pointer Common->complex_divide is set equal to cholmod_divcomplex.
+	 */
+
+    double (*hypotenuse) (double x, double y) ;
+
+	/* s = hypotenuse (x,y) computes s = sqrt (x*x + y*y), but does so more
+	 * accurately.  By default, the function pointer Common->hypotenuse is
+	 * set equal to cholmod_hypot.  See also the hypot function in the C99
+	 * standard, which has an identical syntax and function.  If you have
+	 * a C99-compliant compiler, you can set Common->hypotenuse = hypot.  */
+
+    /* ---------------------------------------------------------------------- */
+    /* METIS workarounds */
+    /* ---------------------------------------------------------------------- */
+
+    double metis_memory ;   /* This is a parameter for CHOLMOD's interface to
+			     * METIS, not a parameter to METIS itself.  METIS
+	* uses an amount of memory that is difficult to estimate precisely
+	* beforehand.  If it runs out of memory, it terminates your program.
+	* All routines in CHOLMOD except for CHOLMOD's interface to METIS
+	* return an error status and safely return to your program if they run
+	* out of memory.  To mitigate this problem, the CHOLMOD interface
+	* can allocate a single block of memory equal in size to an empirical
+	* upper bound of METIS's memory usage times the Common->metis_memory
+	* parameter, and then immediately free it.  It then calls METIS.  If
+	* this pre-allocation fails, it is possible that METIS will fail as
+	* well, and so CHOLMOD returns with an out-of-memory condition without
+	* calling METIS.
+	*
+	* METIS_NodeND (used in the CHOLMOD_METIS ordering option) with its
+	* default parameter settings typically uses about (4*nz+40n+4096)
+	* times sizeof(int) memory, where nz is equal to the number of entries
+	* in A for the symmetric case or AA' if an unsymmetric matrix is
+	* being ordered (where nz includes both the upper and lower parts
+	* of A or AA').  The observed "upper bound" (with 2 exceptions),
+	* measured in an instrumented copy of METIS 4.0.1 on thousands of
+	* matrices, is (10*nz+50*n+4096) * sizeof(int).  Two large matrices
+	* exceeded this bound, one by almost a factor of 2 (Gupta/gupta2).
+	*
+	* If your program is terminated by METIS, try setting metis_memory to
+	* 2.0, or even higher if needed.  By default, CHOLMOD assumes that METIS
+	* does not have this problem (so that CHOLMOD will work correctly when
+	* this issue is fixed in METIS).  Thus, the default value is zero.
+	* This work-around is not guaranteed anyway.
+	*
+	* If a matrix exceeds this predicted memory usage, AMD is attempted
+	* instead.  It, too, may run out of memory, but if it does so it will
+	* not terminate your program.
+	*/
+
+    double metis_dswitch ;	/* METIS_NodeND in METIS 4.0.1 gives a seg */
+    size_t metis_nswitch ;	/* fault with one matrix of order n = 3005 and
+				 * nz = 6,036,025.  This is a very dense graph.
+     * The workaround is to use AMD instead of METIS for matrices of dimension
+     * greater than Common->metis_nswitch (default 3000) or more and with
+     * density of Common->metis_dswitch (default 0.66) or more.
+     * cholmod_nested_dissection has no problems with the same matrix, even
+     * though it uses METIS_NodeComputeSeparator on this matrix.  If this
+     * seg fault does not affect you, set metis_nswitch to zero or less,
+     * and CHOLMOD will not switch to AMD based just on the density of the
+     * matrix (it will still switch to AMD if the metis_memory parameter
+     * causes the switch).
+     */
+
+    /* ---------------------------------------------------------------------- */
+    /* workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* CHOLMOD has several routines that take less time than the size of
+     * workspace they require.  Allocating and initializing the workspace would
+     * dominate the run time, unless workspace is allocated and initialized
+     * just once.  CHOLMOD allocates this space when needed, and holds it here
+     * between calls to CHOLMOD.  cholmod_start sets these pointers to NULL
+     * (which is why it must be the first routine called in CHOLMOD).
+     * cholmod_finish frees the workspace (which is why it must be the last
+     * call to CHOLMOD).
+     */
+
+    size_t nrow ;	/* size of Flag and Head */
+    SuiteSparse_long mark ;	/* mark value for Flag array */
+    size_t iworksize ;	/* size of Iwork.  Upper bound: 6*nrow+ncol */
+    size_t xworksize ;	/* size of Xwork,  in bytes.
+			 * maxrank*nrow*sizeof(double) for update/downdate.
+			 * 2*nrow*sizeof(double) otherwise */
+
+    /* initialized workspace: contents needed between calls to CHOLMOD */
+    void *Flag ;	/* size nrow, an integer array.  Kept cleared between
+			 * calls to cholmod rouines (Flag [i] < mark) */
+
+    void *Head ;	/* size nrow+1, an integer array. Kept cleared between
+			 * calls to cholmod routines (Head [i] = EMPTY) */
+
+    void *Xwork ; 	/* a double array.  Its size varies.  It is nrow for
+			 * most routines (cholmod_rowfac, cholmod_add,
+	* cholmod_aat, cholmod_norm, cholmod_ssmult) for the real case, twice
+	* that when the input matrices are complex or zomplex.  It is of size
+	* 2*nrow for cholmod_rowadd and cholmod_rowdel.  For cholmod_updown,
+	* its size is maxrank*nrow where maxrank is 2, 4, or 8.  Kept cleared
+	* between calls to cholmod (set to zero). */
+
+    /* uninitialized workspace, contents not needed between calls to CHOLMOD */
+    void *Iwork ;	/* size iworksize, 2*nrow+ncol for most routines,
+			 * up to 6*nrow+ncol for cholmod_analyze. */
+
+    int itype ;		/* If CHOLMOD_LONG, Flag, Head, and Iwork are
+                         * SuiteSparse_long.  Otherwise all three are int. */
+
+    int dtype ;		/* double or float */
+
+	/* Common->itype and Common->dtype are used to define the types of all
+	 * sparse matrices, triplet matrices, dense matrices, and factors
+	 * created using this Common struct.  The itypes and dtypes of all
+	 * parameters to all CHOLMOD routines must match.  */
+
+    int no_workspace_reallocate ;   /* this is an internal flag, used as a
+	* precaution by cholmod_analyze.  It is normally false.  If true,
+	* cholmod_allocate_work is not allowed to reallocate any workspace;
+	* they must use the existing workspace in Common (Iwork, Flag, Head,
+	* and Xwork).  Added for CHOLMOD v1.1 */
+
+    /* ---------------------------------------------------------------------- */
+    /* statistics */
+    /* ---------------------------------------------------------------------- */
+
+    /* fl and lnz are set only in cholmod_analyze and cholmod_rowcolcounts,
+     * in the Cholesky modudle.  modfl is set only in the Modify module. */
+
+    int status ;	    /* error code */
+    double fl ;		    /* LL' flop count from most recent analysis */
+    double lnz ;	    /* fundamental nz in L */
+    double anz ;	    /* nonzeros in tril(A) if A is symmetric/lower,
+			     * triu(A) if symmetric/upper, or tril(A*A') if
+			     * unsymmetric, in last call to cholmod_analyze. */
+    double modfl ;	    /* flop count from most recent update/downdate/
+			     * rowadd/rowdel (excluding flops to modify the
+			     * solution to Lx=b, if computed) */
+    size_t malloc_count ;   /* # of objects malloc'ed minus the # free'd*/
+    size_t memory_usage ;   /* peak memory usage in bytes */
+    size_t memory_inuse ;   /* current memory usage in bytes */
+
+    double nrealloc_col ;   /* # of column reallocations */
+    double nrealloc_factor ;/* # of factor reallocations due to col. reallocs */
+    double ndbounds_hit ;   /* # of times diagonal modified by dbound */
+
+    double rowfacfl ;	    /* # of flops in last call to cholmod_rowfac */
+    double aatfl ;	    /* # of flops to compute A(:,f)*A(:,f)' */
+
+    /* ---------------------------------------------------------------------- */
+    /* statistics, parameters, and future expansion */
+    /* ---------------------------------------------------------------------- */
+
+    /* The goal for future expansion is to keep sizeof(Common) unchanged. */
+
+    double other1 [10] ;        /* [0..9] for CHOLMOD GPU/CPU numerical
+                                   factorization statistics, and  [0..3]
+                                   used by SuiteSparseQR statistics */
+
+    double SPQR_xstat [4] ;     /* for SuiteSparseQR statistics */
+
+    /* SuiteSparseQR control parameters: */
+    double SPQR_grain ;         /* task size is >= max (total flops / grain) */
+    double SPQR_small ;         /* task size is >= small */
+
+    /* ---------------------------------------------------------------------- */
+    SuiteSparse_long SPQR_istat [10] ;   /* for SuiteSparseQR statistics */
+    SuiteSparse_long other2 [6] ;        /* unused (for future expansion) */
+
+    /* ---------------------------------------------------------------------- */
+    int other3 [10] ;           /* unused (for future expansion) */
+
+    int prefer_binary ;	    /* cholmod_read_triplet converts a symmetric
+			     * pattern-only matrix into a real matrix.  If
+	* prefer_binary is FALSE, the diagonal entries are set to 1 + the degree
+	* of the row/column, and off-diagonal entries are set to -1 (resulting
+	* in a positive definite matrix if the diagonal is zero-free).  Most
+	* symmetric patterns are the pattern a positive definite matrix.  If
+	* this parameter is TRUE, then the matrix is returned with a 1 in each
+	* entry, instead.  Default: FALSE.  Added in v1.3. */
+
+    /* control parameter (added for v1.2): */
+    int default_nesdis ;    /* Default: FALSE.  If FALSE, then the default
+			     * ordering strategy (when Common->nmethods == 0)
+	* is to try the given ordering (if present), AMD, and then METIS if AMD
+	* reports high fill-in.  If Common->default_nesdis is TRUE then NESDIS
+	* is used instead in the default strategy. */
+
+    /* statistic (added for v1.2): */
+    int called_nd ;	    /* TRUE if the last call to
+			     * cholmod_analyze called NESDIS or METIS. */
+
+    int blas_ok ;           /* FALSE if BLAS int overflow; TRUE otherwise */
+
+    /* SuiteSparseQR control parameters: */
+    int SPQR_shrink ;        /* controls stack realloc method */
+    int SPQR_nthreads ;      /* number of TBB threads, 0 = auto */
+
+    /* ---------------------------------------------------------------------- */
+    size_t  other4 [16] ;    /* [0..7] for CHOLMOD GPU/CPU numerical
+                                factorization statistics, remainder
+                                unused (for future expansion) */
+
+    /* ---------------------------------------------------------------------- */
+    void   *other5 [16] ;    /* unused (for future expansion) */
+
+    /* ---------------------------------------------------------------------- */
+    /* GPU configuration */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef GPU_BLAS
+    /* gpuConfig_t gpuConfig ; */
+
+    cublasHandle_t cublasHandle ;
+    cudaStream_t   cudaStreamSyrk ;
+    cudaStream_t   cudaStreamGemm ;
+    cudaStream_t   cudaStreamTrsm ;
+    cudaStream_t   cudaStreamPotrf [3] ;
+    cudaEvent_t    cublasEventPotrf [2] ;
+    void *HostPinnedMemory ;
+    void *devPotrfWork ;
+    void *devSyrkGemmPtrLx ;
+    void *devSyrkGemmPtrC ;
+    int GemmUsed ;              /* TRUE if cuda dgemm used, false otherwise */
+    int SyrkUsed ;              /* TRUE if cuda dsyrk used, false otherwise */
+    double syrkStart ;          /* time syrk started */
+
+#endif
+
+} cholmod_common ;
+
+/* size_t BLAS statistcs in Common: */
+#define CHOLMOD_CPU_GEMM_CALLS      other4 [0]
+#define CHOLMOD_CPU_SYRK_CALLS      other4 [1]
+#define CHOLMOD_CPU_TRSM_CALLS      other4 [2]
+#define CHOLMOD_CPU_POTRF_CALLS     other4 [3]
+#define CHOLMOD_GPU_GEMM_CALLS      other4 [4]
+#define CHOLMOD_GPU_SYRK_CALLS      other4 [5]
+#define CHOLMOD_GPU_TRSM_CALLS      other4 [6]
+#define CHOLMOD_GPU_POTRF_CALLS     other4 [7]
+
+/* double BLAS statistics in Common: */
+#define CHOLMOD_CPU_GEMM_TIME       other1 [0]
+#define CHOLMOD_CPU_SYRK_TIME       other1 [1]
+#define CHOLMOD_CPU_TRSM_TIME       other1 [2]
+#define CHOLMOD_CPU_POTRF_TIME      other1 [3]
+#define CHOLMOD_GPU_GEMM_TIME       other1 [4]
+#define CHOLMOD_GPU_SYRK_TIME       other1 [5]
+#define CHOLMOD_GPU_TRSM_TIME       other1 [6]
+#define CHOLMOD_GPU_POTRF_TIME      other1 [7]
+#define CHOLMOD_ASSEMBLE_TIME       other1 [8]
+#define CHOLMOD_ASSEMBLE_TIME2      other1 [9]
+
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_start:  first call to CHOLMOD */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_start
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_start (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_finish:  last call to CHOLMOD */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_finish
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_finish (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_defaults:  restore default parameters */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_defaults
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_defaults (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_maxrank:  return valid maximum rank for update/downdate */
+/* -------------------------------------------------------------------------- */
+
+size_t cholmod_maxrank	/* returns validated value of Common->maxrank */
+(
+    /* ---- input ---- */
+    size_t n,		/* A and L will have n rows */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+size_t cholmod_l_maxrank (size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_work:  allocate workspace in Common */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_allocate_work
+(
+    /* ---- input ---- */
+    size_t nrow,	/* size: Common->Flag (nrow), Common->Head (nrow+1) */
+    size_t iworksize,	/* size of Common->Iwork */
+    size_t xworksize,	/* size of Common->Xwork */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_allocate_work (size_t, size_t, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_work:  free workspace in Common */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_work
+(
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_work (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_clear_flag:  clear Flag workspace in Common */
+/* -------------------------------------------------------------------------- */
+
+/* use a macro for speed */
+#define CHOLMOD_CLEAR_FLAG(Common) \
+{ \
+    Common->mark++ ; \
+    if (Common->mark <= 0) \
+    { \
+	Common->mark = EMPTY ; \
+	CHOLMOD (clear_flag) (Common) ; \
+    } \
+}
+
+SuiteSparse_long cholmod_clear_flag
+(
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_clear_flag (cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_error:  called when CHOLMOD encounters an error */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_error
+(
+    /* ---- input ---- */
+    int status,		/* error status */
+    const char *file,	/* name of source code file where error occured */
+    int line,		/* line number in source code file where error occured*/
+    const char *message,/* error message */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_error (int, const char *, int, const char *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_dbound:  for internal use in CHOLMOD only */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_dbound	/* returns modified diagonal entry of D or L */
+(
+    /* ---- input ---- */
+    double dj,		/* diagonal entry of D for LDL' or L for LL' */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_dbound (double, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_hypot:  compute sqrt (x*x + y*y) accurately */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_hypot
+(
+    /* ---- input ---- */
+    double x, double y
+) ;
+
+double cholmod_l_hypot (double, double) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_divcomplex:  complex division, c = a/b */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_divcomplex		/* return 1 if divide-by-zero, 0 otherise */
+(
+    /* ---- input ---- */
+    double ar, double ai,	/* real and imaginary parts of a */
+    double br, double bi,	/* real and imaginary parts of b */
+    /* ---- output --- */
+    double *cr, double *ci	/* real and imaginary parts of c */
+) ;
+
+int cholmod_l_divcomplex (double, double, double, double, double *, double *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_sparse ================================================== */
+/* ========================================================================== */
+
+/* A sparse matrix stored in compressed-column form. */
+
+typedef struct cholmod_sparse_struct
+{
+    size_t nrow ;	/* the matrix is nrow-by-ncol */
+    size_t ncol ;
+    size_t nzmax ;	/* maximum number of entries in the matrix */
+
+    /* pointers to int or SuiteSparse_long: */
+    void *p ;		/* p [0..ncol], the column pointers */
+    void *i ;		/* i [0..nzmax-1], the row indices */
+
+    /* for unpacked matrices only: */
+    void *nz ;		/* nz [0..ncol-1], the # of nonzeros in each col.  In
+			 * packed form, the nonzero pattern of column j is in
+	* A->i [A->p [j] ... A->p [j+1]-1].  In unpacked form, column j is in
+	* A->i [A->p [j] ... A->p [j]+A->nz[j]-1] instead.  In both cases, the
+	* numerical values (if present) are in the corresponding locations in
+	* the array x (or z if A->xtype is CHOLMOD_ZOMPLEX). */
+
+    /* pointers to double or float: */
+    void *x ;		/* size nzmax or 2*nzmax, if present */
+    void *z ;		/* size nzmax, if present */
+
+    int stype ;		/* Describes what parts of the matrix are considered:
+			 *
+	* 0:  matrix is "unsymmetric": use both upper and lower triangular parts
+	*     (the matrix may actually be symmetric in pattern and value, but
+	*     both parts are explicitly stored and used).  May be square or
+	*     rectangular.
+	* >0: matrix is square and symmetric, use upper triangular part.
+	*     Entries in the lower triangular part are ignored.
+	* <0: matrix is square and symmetric, use lower triangular part.
+	*     Entries in the upper triangular part are ignored.
+	*
+	* Note that stype>0 and stype<0 are different for cholmod_sparse and
+	* cholmod_triplet.  See the cholmod_triplet data structure for more
+	* details.
+	*/
+
+    int itype ;		/* CHOLMOD_INT:     p, i, and nz are int.
+			 * CHOLMOD_INTLONG: p is SuiteSparse_long,
+                         *                  i and nz are int.
+			 * CHOLMOD_LONG:    p, i, and nz are SuiteSparse_long */
+
+    int xtype ;		/* pattern, real, complex, or zomplex */
+    int dtype ;		/* x and z are double or float */
+    int sorted ;	/* TRUE if columns are sorted, FALSE otherwise */
+    int packed ;	/* TRUE if packed (nz ignored), FALSE if unpacked
+			 * (nz is required) */
+
+} cholmod_sparse ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_sparse:  allocate a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_allocate_sparse
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int sorted,		/* TRUE if columns of A sorted, FALSE otherwise */
+    int packed,		/* TRUE if A will be packed, FALSE otherwise */
+    int stype,		/* stype of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_allocate_sparse (size_t, size_t, size_t, int, int,
+    int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_sparse:  free a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_sparse
+(
+    /* ---- in/out --- */
+    cholmod_sparse **A,	/* matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_sparse (cholmod_sparse **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_sparse:  change the size (# entries) of sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_sparse
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in A */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to reallocate */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_sparse ( size_t, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_nnz:  return number of nonzeros in a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+SuiteSparse_long cholmod_nnz
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_nnz (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_speye:  sparse identity matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_speye
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_speye (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_spzeros:  sparse zero matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_spzeros
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of A */
+    size_t ncol,	/* # of columns of A */
+    size_t nzmax,	/* max # of nonzeros of A */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_spzeros (size_t, size_t, size_t, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_transpose:  transpose a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Return A' or A.'  The "values" parameter is 0, 1, or 2 to denote the pattern
+ * transpose, the array transpose (A.'), and the complex conjugate transpose
+ * (A').
+ */
+
+cholmod_sparse *cholmod_transpose
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_transpose (cholmod_sparse *, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_transpose_unsym:  transpose an unsymmetric sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Compute F = A', A (:,f)', or A (p,f)', where A is unsymmetric and F is
+ * already allocated.  See cholmod_transpose for a simpler routine. */
+
+int cholmod_transpose_unsym
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    int *Perm,		/* size nrow, if present (can be NULL) */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A', A(:,f)', or A(p,f)' */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_transpose_unsym (cholmod_sparse *, int, SuiteSparse_long *,
+    SuiteSparse_long *, size_t, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_transpose_sym:  transpose a symmetric sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Compute F = A' or A (p,p)', where A is symmetric and F is already allocated.
+ * See cholmod_transpose for a simpler routine. */
+
+int cholmod_transpose_sym
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    int *Perm,		/* size nrow, if present (can be NULL) */
+    /* ---- output --- */
+    cholmod_sparse *F,	/* F = A' or A(p,p)' */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_transpose_sym (cholmod_sparse *, int, SuiteSparse_long *,
+    cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ptranspose:  transpose a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+/* Return A' or A(p,p)' if A is symmetric.  Return A', A(:,f)', or A(p,f)' if
+ * A is unsymmetric. */
+
+cholmod_sparse *cholmod_ptranspose
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to transpose */
+    int values,		/* 0: pattern, 1: array transpose, 2: conj. transpose */
+    int *Perm,		/* if non-NULL, F = A(p,f) or A(p,p) */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_ptranspose (cholmod_sparse *, int, SuiteSparse_long *,
+    SuiteSparse_long *, size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sort:  sort row indices in each column of sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_sort
+(
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to sort */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_sort (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_band:  C = tril (triu (A,k1), k2) */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_band
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to extract band matrix from */
+    SuiteSparse_long k1,    /* ignore entries below the k1-st diagonal */
+    SuiteSparse_long k2,    /* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_band (cholmod_sparse *, SuiteSparse_long,
+    SuiteSparse_long, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_band_inplace:  A = tril (triu (A,k1), k2) */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_band_inplace
+(
+    /* ---- input ---- */
+    SuiteSparse_long k1,    /* ignore entries below the k1-st diagonal */
+    SuiteSparse_long k2,    /* ignore entries above the k2-nd diagonal */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix from which entries not in band are removed */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_band_inplace (SuiteSparse_long, SuiteSparse_long, int,
+    cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_aat:  C = A*A' or A(:,f)*A(:,f)' */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_aat
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* input matrix; C=A*A' is constructed */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag),
+			 * -2: pattern only, no diagonal, add 50%+n extra
+			 * space to C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_aat (cholmod_sparse *, SuiteSparse_long *, size_t,
+    int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_sparse:  C = A, create an exact copy of a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_copy_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_copy_sparse (cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy:  C = A, with possible change of stype */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_copy 
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    int stype,		/* requested stype of C */
+    int mode,		/* >0: numerical, 0: pattern, <0: pattern (no diag) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_copy (cholmod_sparse *, int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_add: C = alpha*A + beta*B */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_add
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	    /* matrix to add */
+    cholmod_sparse *B,	    /* matrix to add */
+    double alpha [2],	    /* scale factor for A */
+    double beta [2],	    /* scale factor for B */
+    int values,		    /* if TRUE compute the numerical values of C */
+    int sorted,		    /* if TRUE, sort columns of C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_add (cholmod_sparse *, cholmod_sparse *, double *,
+    double *, int, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sparse_xtype: change the xtype of a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_sparse_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (pattern, real, complex, zomplex) */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* sparse matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_sparse_xtype (int, cholmod_sparse *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_factor ================================================== */
+/* ========================================================================== */
+
+/* A symbolic and numeric factorization, either simplicial or supernodal.
+ * In all cases, the row indices in the columns of L are kept sorted. */
+
+typedef struct cholmod_factor_struct
+{
+    /* ---------------------------------------------------------------------- */
+    /* for both simplicial and supernodal factorizations */
+    /* ---------------------------------------------------------------------- */
+
+    size_t n ;		/* L is n-by-n */
+
+    size_t minor ;	/* If the factorization failed, L->minor is the column
+			 * at which it failed (in the range 0 to n-1).  A value
+			 * of n means the factorization was successful or
+			 * the matrix has not yet been factorized. */
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic ordering and analysis */
+    /* ---------------------------------------------------------------------- */
+
+    void *Perm ;	/* size n, permutation used */
+    void *ColCount ;	/* size n, column counts for simplicial L */
+
+    void *IPerm ;       /* size n, inverse permutation.  Only created by
+                         * cholmod_solve2 if Bset is used. */
+
+    /* ---------------------------------------------------------------------- */
+    /* simplicial factorization */
+    /* ---------------------------------------------------------------------- */
+
+    size_t nzmax ;	/* size of i and x */
+
+    void *p ;		/* p [0..ncol], the column pointers */
+    void *i ;		/* i [0..nzmax-1], the row indices */
+    void *x ;		/* x [0..nzmax-1], the numerical values */
+    void *z ;
+    void *nz ;		/* nz [0..ncol-1], the # of nonzeros in each column.
+			 * i [p [j] ... p [j]+nz[j]-1] contains the row indices,
+			 * and the numerical values are in the same locatins
+			 * in x. The value of i [p [k]] is always k. */
+
+    void *next ;	/* size ncol+2. next [j] is the next column in i/x */
+    void *prev ;	/* size ncol+2. prev [j] is the prior column in i/x.
+			 * head of the list is ncol+1, and the tail is ncol. */
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal factorization */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note that L->x is shared with the simplicial data structure.  L->x has
+     * size L->nzmax for a simplicial factor, and size L->xsize for a supernodal
+     * factor. */
+
+    size_t nsuper ;	/* number of supernodes */
+    size_t ssize ;	/* size of s, integer part of supernodes */
+    size_t xsize ;	/* size of x, real part of supernodes */
+    size_t maxcsize ;	/* size of largest update matrix */
+    size_t maxesize ;	/* max # of rows in supernodes, excl. triangular part */
+
+    void *super ;	/* size nsuper+1, first col in each supernode */
+    void *pi ;		/* size nsuper+1, pointers to integer patterns */
+    void *px ;		/* size nsuper+1, pointers to real parts */
+    void *s ;		/* size ssize, integer part of supernodes */
+
+    /* ---------------------------------------------------------------------- */
+    /* factorization type */
+    /* ---------------------------------------------------------------------- */
+
+    int ordering ;	/* ordering method used */
+
+    int is_ll ;		/* TRUE if LL', FALSE if LDL' */
+    int is_super ;	/* TRUE if supernodal, FALSE if simplicial */
+    int is_monotonic ;	/* TRUE if columns of L appear in order 0..n-1.
+			 * Only applicable to simplicial numeric types. */
+
+    /* There are 8 types of factor objects that cholmod_factor can represent
+     * (only 6 are used):
+     *
+     * Numeric types (xtype is not CHOLMOD_PATTERN)
+     * --------------------------------------------
+     *
+     * simplicial LDL':  (is_ll FALSE, is_super FALSE).  Stored in compressed
+     *	    column form, using the simplicial components above (nzmax, p, i,
+     *	    x, z, nz, next, and prev).  The unit diagonal of L is not stored,
+     *	    and D is stored in its place.  There are no supernodes.
+     *
+     * simplicial LL': (is_ll TRUE, is_super FALSE).  Uses the same storage
+     *	    scheme as the simplicial LDL', except that D does not appear.
+     *	    The first entry of each column of L is the diagonal entry of
+     *	    that column of L.
+     *
+     * supernodal LDL': (is_ll FALSE, is_super TRUE).  Not used.
+     *	    FUTURE WORK:  add support for supernodal LDL'
+     *
+     * supernodal LL': (is_ll TRUE, is_super TRUE).  A supernodal factor,
+     *	    using the supernodal components described above (nsuper, ssize,
+     *	    xsize, maxcsize, maxesize, super, pi, px, s, x, and z).
+     *
+     *
+     * Symbolic types (xtype is CHOLMOD_PATTERN)
+     * -----------------------------------------
+     *
+     * simplicial LDL': (is_ll FALSE, is_super FALSE).  Nothing is present
+     *	    except Perm and ColCount.
+     *
+     * simplicial LL': (is_ll TRUE, is_super FALSE).  Identical to the
+     *	    simplicial LDL', except for the is_ll flag.
+     *
+     * supernodal LDL': (is_ll FALSE, is_super TRUE).  Not used.
+     *	    FUTURE WORK:  add support for supernodal LDL'
+     *
+     * supernodal LL': (is_ll TRUE, is_super TRUE).  A supernodal symbolic
+     *	    factorization.  The simplicial symbolic information is present
+     *	    (Perm and ColCount), as is all of the supernodal factorization
+     *	    except for the numerical values (x and z).
+     */
+
+    int itype ; /* The integer arrays are Perm, ColCount, p, i, nz,
+                 * next, prev, super, pi, px, and s.  If itype is
+		 * CHOLMOD_INT, all of these are int arrays.
+		 * CHOLMOD_INTLONG: p, pi, px are SuiteSparse_long, others int.
+		 * CHOLMOD_LONG:    all integer arrays are SuiteSparse_long. */
+    int xtype ; /* pattern, real, complex, or zomplex */
+    int dtype ; /* x and z double or float */
+
+} cholmod_factor ;
+
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_factor: allocate a factor (symbolic LL' or LDL') */
+/* -------------------------------------------------------------------------- */
+
+cholmod_factor *cholmod_allocate_factor
+(
+    /* ---- input ---- */
+    size_t n,		/* L is n-by-n */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_allocate_factor (size_t, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_factor:  free a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_factor
+(
+    /* ---- in/out --- */
+    cholmod_factor **L,	/* factor to free, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_factor (cholmod_factor **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_factor:  change the # entries in a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_factor
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_factor (size_t, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_change_factor:  change the type of factor (e.g., LDL' to LL') */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_change_factor
+(
+    /* ---- input ---- */
+    int to_xtype,	/* to CHOLMOD_PATTERN, _REAL, _COMPLEX, _ZOMPLEX */
+    int to_ll,		/* TRUE: convert to LL', FALSE: LDL' */
+    int to_super,	/* TRUE: convert to supernodal, FALSE: simplicial */
+    int to_packed,	/* TRUE: pack simplicial columns, FALSE: do not pack */
+    int to_monotonic,	/* TRUE: put simplicial columns in order, FALSE: not */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_change_factor ( int, int, int, int, int, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_pack_factor:  pack the columns of a factor */
+/* -------------------------------------------------------------------------- */
+
+/* Pack the columns of a simplicial factor.  Unlike cholmod_change_factor,
+ * it can pack the columns of a factor even if they are not stored in their
+ * natural order (non-monotonic). */
+
+int cholmod_pack_factor
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_pack_factor (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_column:  resize a single column of a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_column
+(
+    /* ---- input ---- */
+    size_t j,		/* the column to reallocate */
+    size_t need,	/* required size of column j */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_column (size_t, size_t, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factor_to_sparse:  create a sparse matrix copy of a factor */
+/* -------------------------------------------------------------------------- */
+
+/* Only operates on numeric factors, not symbolic ones */
+
+cholmod_sparse *cholmod_factor_to_sparse
+(
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to copy, converted to symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_factor_to_sparse (cholmod_factor *,
+	cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_factor:  create a copy of a factor */
+/* -------------------------------------------------------------------------- */
+
+cholmod_factor *cholmod_copy_factor
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_factor *cholmod_l_copy_factor (cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_factor_xtype: change the xtype of a factor */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_factor_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (real, complex, or zomplex) */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_factor_xtype (int, cholmod_factor *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_dense =================================================== */
+/* ========================================================================== */
+
+/* A dense matrix in column-oriented form.  It has no itype since it contains
+ * no integers.  Entry in row i and column j is located in x [i+j*d].
+ */
+
+typedef struct cholmod_dense_struct
+{
+    size_t nrow ;	/* the matrix is nrow-by-ncol */
+    size_t ncol ;
+    size_t nzmax ;	/* maximum number of entries in the matrix */
+    size_t d ;		/* leading dimension (d >= nrow must hold) */
+    void *x ;		/* size nzmax or 2*nzmax, if present */
+    void *z ;		/* size nzmax, if present */
+    int xtype ;		/* pattern, real, complex, or zomplex */
+    int dtype ;		/* x and z double or float */
+
+} cholmod_dense ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_dense:  allocate a dense matrix (contents uninitialized) */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_allocate_dense
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    size_t d,		/* leading dimension */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_allocate_dense (size_t, size_t, size_t, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_zeros: allocate a dense matrix and set it to zero */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_zeros
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_zeros (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ones: allocate a dense matrix and set it to all ones */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_ones
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_ones (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_eye: allocate a dense matrix and set it to the identity matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_eye
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_eye (size_t, size_t, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_dense:  free a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_dense
+(
+    /* ---- in/out --- */
+    cholmod_dense **X,	/* dense matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_dense (cholmod_dense **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ensure_dense:  ensure a dense matrix has a given size and type */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_ensure_dense
+(
+    /* ---- input/output ---- */
+    cholmod_dense **XHandle,    /* matrix handle to check */
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of matrix */
+    size_t ncol,	/* # of columns of matrix */
+    size_t d,		/* leading dimension */
+    int xtype,		/* CHOLMOD_REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_ensure_dense (cholmod_dense **, size_t, size_t, size_t,
+    int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sparse_to_dense:  create a dense matrix copy of a sparse matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_sparse_to_dense
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_sparse_to_dense (cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_dense_to_sparse:  create a sparse matrix copy of a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_dense_to_sparse
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    int values,		/* TRUE if values to be copied, FALSE otherwise */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_dense_to_sparse (cholmod_dense *, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_dense:  create a copy of a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_dense *cholmod_copy_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_dense *cholmod_l_copy_dense (cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_dense2:  copy a dense matrix (pre-allocated) */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_copy_dense2
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to copy */
+    /* ---- output --- */
+    cholmod_dense *Y,	/* copy of matrix X */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_copy_dense2 (cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_dense_xtype: change the xtype of a dense matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_dense_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (real, complex,or zomplex) */
+    /* ---- in/out --- */
+    cholmod_dense *X,	/* dense matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_dense_xtype (int, cholmod_dense *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_triplet ================================================= */
+/* ========================================================================== */
+
+/* A sparse matrix stored in triplet form. */
+
+typedef struct cholmod_triplet_struct
+{
+    size_t nrow ;	/* the matrix is nrow-by-ncol */
+    size_t ncol ;
+    size_t nzmax ;	/* maximum number of entries in the matrix */
+    size_t nnz ;	/* number of nonzeros in the matrix */
+
+    void *i ;		/* i [0..nzmax-1], the row indices */
+    void *j ;		/* j [0..nzmax-1], the column indices */
+    void *x ;		/* size nzmax or 2*nzmax, if present */
+    void *z ;		/* size nzmax, if present */
+
+    int stype ;		/* Describes what parts of the matrix are considered:
+			 *
+	* 0:  matrix is "unsymmetric": use both upper and lower triangular parts
+	*     (the matrix may actually be symmetric in pattern and value, but
+	*     both parts are explicitly stored and used).  May be square or
+	*     rectangular.
+	* >0: matrix is square and symmetric.  Entries in the lower triangular
+	*     part are transposed and added to the upper triangular part when
+	*     the matrix is converted to cholmod_sparse form.
+	* <0: matrix is square and symmetric.  Entries in the upper triangular
+	*     part are transposed and added to the lower triangular part when
+	*     the matrix is converted to cholmod_sparse form.
+	*
+	* Note that stype>0 and stype<0 are different for cholmod_sparse and
+	* cholmod_triplet.  The reason is simple.  You can permute a symmetric
+	* triplet matrix by simply replacing a row and column index with their
+	* new row and column indices, via an inverse permutation.  Suppose
+	* P = L->Perm is your permutation, and Pinv is an array of size n.
+	* Suppose a symmetric matrix A is represent by a triplet matrix T, with
+	* entries only in the upper triangular part.  Then the following code:
+	*
+	*	Ti = T->i ;
+	*	Tj = T->j ;
+	*	for (k = 0 ; k < n  ; k++) Pinv [P [k]] = k ;
+	*	for (k = 0 ; k < nz ; k++) Ti [k] = Pinv [Ti [k]] ;
+	*	for (k = 0 ; k < nz ; k++) Tj [k] = Pinv [Tj [k]] ;
+	*
+	* creates the triplet form of C=P*A*P'.  However, if T initially
+	* contains just the upper triangular entries (T->stype = 1), after
+	* permutation it has entries in both the upper and lower triangular
+	* parts.  These entries should be transposed when constructing the
+	* cholmod_sparse form of A, which is what cholmod_triplet_to_sparse
+	* does.  Thus:
+	*
+	*	C = cholmod_triplet_to_sparse (T, 0, &Common) ;
+	*
+	* will return the matrix C = P*A*P'.
+	*
+	* Since the triplet matrix T is so simple to generate, it's quite easy
+	* to remove entries that you do not want, prior to converting T to the
+	* cholmod_sparse form.  So if you include these entries in T, CHOLMOD
+	* assumes that there must be a reason (such as the one above).  Thus,
+	* no entry in a triplet matrix is ever ignored.
+	*/
+
+    int itype ; /* CHOLMOD_LONG: i and j are SuiteSparse_long.  Otherwise int */
+    int xtype ; /* pattern, real, complex, or zomplex */
+    int dtype ; /* x and z are double or float */
+
+} cholmod_triplet ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_allocate_triplet:  allocate a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_allocate_triplet
+(
+    /* ---- input ---- */
+    size_t nrow,	/* # of rows of T */
+    size_t ncol,	/* # of columns of T */
+    size_t nzmax,	/* max # of nonzeros of T */
+    int stype,		/* stype of T */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_allocate_triplet (size_t, size_t, size_t, int, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_free_triplet:  free a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_free_triplet
+(
+    /* ---- in/out --- */
+    cholmod_triplet **T,    /* triplet matrix to deallocate, NULL on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_free_triplet (cholmod_triplet **, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_reallocate_triplet:  change the # of entries in a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_reallocate_triplet
+(
+    /* ---- input ---- */
+    size_t nznew,	/* new # of entries in T */
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_reallocate_triplet (size_t, cholmod_triplet *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sparse_to_triplet:  create a triplet matrix copy of a sparse matrix*/
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_sparse_to_triplet
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_sparse_to_triplet (cholmod_sparse *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_triplet_to_sparse:  create a sparse matrix copy of a triplet matrix*/
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_triplet_to_sparse
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    size_t nzmax,	/* allocate at least this much space in output matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_triplet_to_sparse (cholmod_triplet *, size_t,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_copy_triplet:  create a copy of a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+cholmod_triplet *cholmod_copy_triplet
+(
+    /* ---- input ---- */
+    cholmod_triplet *T,	/* matrix to copy */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_triplet *cholmod_l_copy_triplet (cholmod_triplet *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_triplet_xtype: change the xtype of a triplet matrix */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_triplet_xtype
+(
+    /* ---- input ---- */
+    int to_xtype,	/* requested xtype (pattern, real, complex,or zomplex)*/
+    /* ---- in/out --- */
+    cholmod_triplet *T,	/* triplet matrix to change */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_triplet_xtype (int, cholmod_triplet *, cholmod_common *) ;
+
+
+/* ========================================================================== */
+/* === Core/cholmod_memory ================================================== */
+/* ========================================================================== */
+
+/* The user may make use of these, just like malloc and free.  You can even
+ * malloc an object and safely free it with cholmod_free, and visa versa
+ * (except that the memory usage statistics will be corrupted).  These routines
+ * do differ from malloc and free.  If cholmod_free is given a NULL pointer,
+ * for example, it does nothing (unlike the ANSI free).  cholmod_realloc does
+ * not return NULL if given a non-NULL pointer and a nonzero size, even if it
+ * fails (it returns the original pointer and sets an error code in
+ * Common->status instead).
+ *
+ * CHOLMOD keeps track of the amount of memory it has allocated, and so the
+ * cholmod_free routine also takes the size of the object being freed.  This
+ * is only used for statistics.  If you, the user of CHOLMOD, pass the wrong
+ * size, the only consequence is that the memory usage statistics will be
+ * corrupted.
+ */
+
+void *cholmod_malloc	/* returns pointer to the newly malloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_malloc (size_t, size_t, cholmod_common *) ;
+
+void *cholmod_calloc	/* returns pointer to the newly calloc'd block */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_calloc (size_t, size_t, cholmod_common *) ;
+
+void *cholmod_free	/* always returns NULL */
+(
+    /* ---- input ---- */
+    size_t n,		/* number of items */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to free */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_free (size_t, size_t, void *, cholmod_common *) ;
+
+void *cholmod_realloc	/* returns pointer to reallocated block */
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated block */
+    size_t size,	/* size of each item */
+    /* ---- in/out --- */
+    void *p,		/* block of memory to realloc */
+    size_t *n,		/* current size on input, nnew on output if successful*/
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+void *cholmod_l_realloc (size_t, size_t, void *, size_t *, cholmod_common *) ;
+
+int cholmod_realloc_multiple
+(
+    /* ---- input ---- */
+    size_t nnew,	/* requested # of items in reallocated blocks */
+    int nint,		/* number of int/SuiteSparse_long blocks */
+    int xtype,		/* CHOLMOD_PATTERN, _REAL, _COMPLEX, or _ZOMPLEX */
+    /* ---- in/out --- */
+    void **Iblock,	/* int or SuiteSparse_long block */
+    void **Jblock,	/* int or SuiteSparse_long block */
+    void **Xblock,	/* complex, double, or float block */
+    void **Zblock,	/* zomplex case only: double or float block */
+    size_t *n,		/* current size of the I,J,X,Z blocks on input,
+			 * nnew on output if successful */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_realloc_multiple (size_t, int, int, void **, void **, void **,
+    void **, size_t *, cholmod_common *) ;
+
+/* ========================================================================== */
+/* === version control ====================================================== */
+/* ========================================================================== */
+
+int cholmod_version     /* returns CHOLMOD_VERSION */
+(
+    /* output, contents not defined on input.  Not used if NULL.
+        version [0] = CHOLMOD_MAIN_VERSION
+        version [1] = CHOLMOD_SUB_VERSION
+        version [2] = CHOLMOD_SUBSUB_VERSION
+    */
+    int version [3]
+) ;
+
+int cholmod_l_version (int version [3]) ;
+
+/* Versions prior to 2.1.1 do not have the above function.  The following
+   code fragment will work with any version of CHOLMOD:
+   #ifdef CHOLMOD_HAS_VERSION_FUNCTION
+   v = cholmod_version (NULL) ;
+   #else
+   v = CHOLMOD_VERSION ;
+   #endif
+*/
+
+/* ========================================================================== */
+/* === symmetry types ======================================================= */
+/* ========================================================================== */
+
+#define CHOLMOD_MM_RECTANGULAR 1
+#define CHOLMOD_MM_UNSYMMETRIC 2
+#define CHOLMOD_MM_SYMMETRIC 3
+#define CHOLMOD_MM_HERMITIAN 4
+#define CHOLMOD_MM_SKEW_SYMMETRIC 5
+#define CHOLMOD_MM_SYMMETRIC_POSDIAG 6
+#define CHOLMOD_MM_HERMITIAN_POSDIAG 7
+
+/* ========================================================================== */
+/* === Numerical relop macros =============================================== */
+/* ========================================================================== */
+
+/* These macros correctly handle the NaN case.
+ *
+ *  CHOLMOD_IS_NAN(x):
+ *	True if x is NaN.  False otherwise.  The commonly-existing isnan(x)
+ *	function could be used, but it's not in Kernighan & Ritchie 2nd edition
+ *	(ANSI C89).  It may appear in <math.h>, but I'm not certain about
+ *	portability.  The expression x != x is true if and only if x is NaN,
+ *	according to the IEEE 754 floating-point standard.
+ *
+ *  CHOLMOD_IS_ZERO(x):
+ *	True if x is zero.  False if x is nonzero, NaN, or +/- Inf.
+ *	This is (x == 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_NONZERO(x):
+ *	True if x is nonzero, NaN, or +/- Inf.  False if x zero.
+ *	This is (x != 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_LT_ZERO(x):
+ *	True if x is < zero or -Inf.  False if x is >= 0, NaN, or +Inf.
+ *	This is (x < 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_GT_ZERO(x):
+ *	True if x is > zero or +Inf.  False if x is <= 0, NaN, or -Inf.
+ *	This is (x > 0) if the compiler is IEEE 754 compliant.
+ *
+ *  CHOLMOD_IS_LE_ZERO(x):
+ *	True if x is <= zero or -Inf.  False if x is > 0, NaN, or +Inf.
+ *	This is (x <= 0) if the compiler is IEEE 754 compliant.
+ */
+
+#ifdef CHOLMOD_WINDOWS
+
+/* Yes, this is exceedingly ugly.  Blame Microsoft, which hopelessly */
+/* violates the IEEE 754 floating-point standard in a bizarre way. */
+/* If you're using an IEEE 754-compliant compiler, then x != x is true */
+/* iff x is NaN.  For Microsoft, (x < x) is true iff x is NaN. */
+/* So either way, this macro safely detects a NaN. */
+#define CHOLMOD_IS_NAN(x)	(((x) != (x)) || (((x) < (x))))
+#define CHOLMOD_IS_ZERO(x)	(((x) == 0.) && !CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_NONZERO(x)	(((x) != 0.) || CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_LT_ZERO(x)	(((x) < 0.) && !CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_GT_ZERO(x)	(((x) > 0.) && !CHOLMOD_IS_NAN(x))
+#define CHOLMOD_IS_LE_ZERO(x)	(((x) <= 0.) && !CHOLMOD_IS_NAN(x))
+
+#else
+
+/* These all work properly, according to the IEEE 754 standard ... except on */
+/* a PC with windows.  Works fine in Linux on the same PC... */
+#define CHOLMOD_IS_NAN(x)	((x) != (x))
+#define CHOLMOD_IS_ZERO(x)	((x) == 0.)
+#define CHOLMOD_IS_NONZERO(x)	((x) != 0.)
+#define CHOLMOD_IS_LT_ZERO(x)	((x) < 0.)
+#define CHOLMOD_IS_GT_ZERO(x)	((x) > 0.)
+#define CHOLMOD_IS_LE_ZERO(x)	((x) <= 0.)
+
+#endif
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_internal.h b/src/CHOLMOD/Include/cholmod_internal.h
new file mode 100644
index 0000000..4a5f506
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_internal.h
@@ -0,0 +1,404 @@
+/* ========================================================================== */
+/* === Include/cholmod_internal.h =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_internal.h.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_internal.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD internal include file.
+ *
+ * This file contains internal definitions for CHOLMOD, not meant to be included
+ * in user code.  They define macros that are not prefixed with CHOLMOD_.  This
+ * file can safely #include'd in user code if you want to make use of the
+ * macros defined here, and don't mind the possible name conflicts with your
+ * code, however.
+ *
+ * Required by all CHOLMOD routines.  Not required by any user routine that
+ * uses CHOLMOMD.  Unless debugging is enabled, this file does not require any
+ * CHOLMOD module (not even the Core module).
+ *
+ * If debugging is enabled, all CHOLMOD modules require the Check module.
+ * Enabling debugging requires that this file be editted.  Debugging cannot be
+ * enabled with a compiler flag.  This is because CHOLMOD is exceedingly slow
+ * when debugging is enabled.  Debugging is meant for development of CHOLMOD
+ * itself, not by users of CHOLMOD.
+ */
+
+#ifndef CHOLMOD_INTERNAL_H
+#define CHOLMOD_INTERNAL_H
+
+/* ========================================================================== */
+/* === large file I/O ======================================================= */
+/* ========================================================================== */
+
+/* Definitions for large file I/O must come before any other #includes.  If
+ * this causes problems (may not be portable to all platforms), then compile
+ * CHOLMOD with -DNLARGEFILE.  You must do this for MATLAB 6.5 and earlier,
+ * for example. */
+
+#include "cholmod_io64.h"
+
+/* ========================================================================== */
+/* === debugging and basic includes ========================================= */
+/* ========================================================================== */
+
+/* turn off debugging */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* Uncomment this line to enable debugging.  CHOLMOD will be very slow.
+#undef NDEBUG
+ */
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#endif
+
+#if !defined(NPRINT) || !defined(NDEBUG)
+#include <stdio.h>
+#endif
+
+#include <stddef.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === basic definitions ==================================================== */
+/* ========================================================================== */
+
+/* Some non-conforming compilers insist on defining TRUE and FALSE. */
+#undef TRUE
+#undef FALSE
+#define TRUE 1
+#define FALSE 0
+#define BOOLEAN(x) ((x) ? TRUE : FALSE)
+
+/* NULL should already be defined, but ensure it is here. */
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* FLIP is a "negation about -1", and is used to mark an integer i that is
+ * normally non-negative.  FLIP (EMPTY) is EMPTY.  FLIP of a number > EMPTY
+ * is negative, and FLIP of a number < EMTPY is positive.  FLIP (FLIP (i)) = i
+ * for all integers i.  UNFLIP (i) is >= EMPTY. */
+#define EMPTY (-1)
+#define FLIP(i) (-(i)-2)
+#define UNFLIP(i) (((i) < EMPTY) ? FLIP (i) : (i))
+
+/* MAX and MIN are not safe to use for NaN's */
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MAX3(a,b,c) (((a) > (b)) ? (MAX (a,c)) : (MAX (b,c)))
+#define MAX4(a,b,c,d) (((a) > (b)) ? (MAX3 (a,c,d)) : (MAX3 (b,c,d)))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define IMPLIES(p,q) (!(p) || (q))
+
+/* find the sign: -1 if x < 0, 1 if x > 0, zero otherwise.
+ * Not safe for NaN's */
+#define SIGN(x) (((x) < 0) ? (-1) : (((x) > 0) ? 1 : 0))
+
+/* round up an integer x to a multiple of s */
+#define ROUNDUP(x,s) ((s) * (((x) + ((s) - 1)) / (s)))
+
+#define ERROR(status,msg) \
+    CHOLMOD(error) (status, __FILE__, __LINE__, msg, Common)
+
+/* Check a pointer and return if null.  Set status to invalid, unless the
+ * status is already "out of memory" */
+#define RETURN_IF_NULL(A,result) \
+{ \
+    if ((A) == NULL) \
+    { \
+	if (Common->status != CHOLMOD_OUT_OF_MEMORY) \
+	{ \
+	    ERROR (CHOLMOD_INVALID, "argument missing") ; \
+	} \
+	return (result) ; \
+    } \
+}
+
+/* Return if Common is NULL or invalid */
+#define RETURN_IF_NULL_COMMON(result) \
+{ \
+    if (Common == NULL) \
+    { \
+	return (result) ; \
+    } \
+    if (Common->itype != ITYPE || Common->dtype != DTYPE) \
+    { \
+	Common->status = CHOLMOD_INVALID ; \
+	return (result) ; \
+    } \
+}
+
+#define IS_NAN(x)	CHOLMOD_IS_NAN(x)
+#define IS_ZERO(x)	CHOLMOD_IS_ZERO(x)
+#define IS_NONZERO(x)	CHOLMOD_IS_NONZERO(x)
+#define IS_LT_ZERO(x)	CHOLMOD_IS_LT_ZERO(x)
+#define IS_GT_ZERO(x)	CHOLMOD_IS_GT_ZERO(x)
+#define IS_LE_ZERO(x)	CHOLMOD_IS_LE_ZERO(x)
+
+/* 1e308 is a huge number that doesn't take many characters to print in a
+ * file, in CHOLMOD/Check/cholmod_read and _write.  Numbers larger than this
+ * are interpretted as Inf, since sscanf doesn't read in Inf's properly.
+ * This assumes IEEE double precision arithmetic.  DBL_MAX would be a little
+ * better, except that it takes too many digits to print in a file. */
+#define HUGE_DOUBLE 1e308
+
+/* ========================================================================== */
+/* === int/long and double/float definitions ================================ */
+/* ========================================================================== */
+
+/* CHOLMOD is designed for 3 types of integer variables:
+ *
+ *	(1) all integers are int
+ *	(2) most integers are int, some are SuiteSparse_long
+ *	(3) all integers are SuiteSparse_long
+ *
+ * and two kinds of floating-point values:
+ *
+ *	(1) double
+ *	(2) float
+ *
+ * the complex types (ANSI-compatible complex, and MATLAB-compatable zomplex)
+ * are based on the double or float type, and are not selected here.  They
+ * are typically selected via template routines.
+ *
+ * This gives 6 different modes in which CHOLMOD can be compiled (only the
+ * first two are currently supported):
+ *
+ *	DINT	double, int			prefix: cholmod_
+ *	DLONG	double, SuiteSparse_long	prefix: cholmod_l_
+ *	DMIX	double, mixed int/SuiteSparse_long	prefix: cholmod_m_
+ *	SINT	float, int			prefix: cholmod_si_
+ *	SLONG	float, SuiteSparse_long		prefix: cholmod_sl_
+ *	SMIX	float, mixed int/log		prefix: cholmod_sm_
+ *
+ * These are selected with compile time flags (-DDLONG, for example).  If no
+ * flag is selected, the default is DINT.
+ *
+ * All six versions use the same include files.  The user-visible include files
+ * are completely independent of which int/long/double/float version is being
+ * used.  The integer / real types in all data structures (sparse, triplet,
+ * dense, common, and triplet) are defined at run-time, not compile-time, so
+ * there is only one "cholmod_sparse" data type.  Void pointers are used inside
+ * that data structure to point to arrays of the proper type.  Each data
+ * structure has an itype and dtype field which determines the kind of basic
+ * types used.  These are defined in Include/cholmod_core.h.
+ *
+ * FUTURE WORK: support all six types (float, and mixed int/long)
+ *
+ * SuiteSparse_long is normally defined as long.  However, for WIN64 it is
+ * __int64.  It can also be redefined for other platforms, by modifying
+ * SuiteSparse_config.h.
+ */
+
+#include "SuiteSparse_config.h"
+
+/* -------------------------------------------------------------------------- */
+/* Size_max: the largest value of size_t */
+/* -------------------------------------------------------------------------- */
+
+#define Size_max ((size_t) (-1))
+
+/* routines for doing arithmetic on size_t, and checking for overflow */
+size_t cholmod_add_size_t (size_t a, size_t b, int *ok) ;
+size_t cholmod_mult_size_t (size_t a, size_t k, int *ok) ;
+size_t cholmod_l_add_size_t (size_t a, size_t b, int *ok) ;
+size_t cholmod_l_mult_size_t (size_t a, size_t k, int *ok) ;
+
+/* -------------------------------------------------------------------------- */
+/* double (also complex double), SuiteSparse_long */
+/* -------------------------------------------------------------------------- */
+
+#ifdef DLONG
+#define Real double
+#define Int SuiteSparse_long
+#define Int_max SuiteSparse_long_max
+#define CHOLMOD(name) cholmod_l_ ## name
+#define LONG
+#define DOUBLE
+#define ITYPE CHOLMOD_LONG
+#define DTYPE CHOLMOD_DOUBLE
+#define ID SuiteSparse_long_id
+
+/* -------------------------------------------------------------------------- */
+/* double, int/SuiteSparse_long */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (DMIX)
+#error "mixed int/SuiteSparse_long not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* single, int */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (SINT)
+#error "single-precision not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* single, SuiteSparse_long */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (SLONG)
+#error "single-precision not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* single, int/SuiteSparse_long */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (SMIX)
+#error "single-precision not yet supported"
+
+/* -------------------------------------------------------------------------- */
+/* double (also complex double), int: this is the default */
+/* -------------------------------------------------------------------------- */
+
+#else
+
+#ifndef DINT
+#define DINT
+#endif
+#define INT
+#define DOUBLE
+
+#define Real double
+#define Int int
+#define Int_max INT_MAX
+#define CHOLMOD(name) cholmod_ ## name
+#define ITYPE CHOLMOD_INT
+#define DTYPE CHOLMOD_DOUBLE
+#define ID "%d"
+
+#endif
+
+
+/* ========================================================================== */
+/* === real/complex arithmetic ============================================== */
+/* ========================================================================== */
+
+#include "cholmod_complexity.h"
+
+/* ========================================================================== */
+/* === Architecture and BLAS ================================================ */
+/* ========================================================================== */
+
+#define BLAS_OK Common->blas_ok
+#include "cholmod_blas.h"
+
+/* ========================================================================== */
+/* === debugging definitions ================================================ */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#include <assert.h>
+#include "cholmod.h"
+
+/* The cholmod_dump routines are in the Check module.  No CHOLMOD routine
+ * calls the cholmod_check_* or cholmod_print_* routines in the Check module,
+ * since they use Common workspace that may already be in use.  Instead, they
+ * use the cholmod_dump_* routines defined there, which allocate their own
+ * workspace if they need it. */
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/* double, int */
+EXTERN int cholmod_dump ;
+EXTERN int cholmod_dump_malloc ;
+SuiteSparse_long cholmod_dump_sparse (cholmod_sparse  *, const char *,
+    cholmod_common *) ;
+int  cholmod_dump_factor (cholmod_factor  *, const char *, cholmod_common *) ;
+int  cholmod_dump_triplet (cholmod_triplet *, const char *, cholmod_common *) ;
+int  cholmod_dump_dense (cholmod_dense   *, const char *, cholmod_common *) ;
+int  cholmod_dump_subset (int *, size_t, size_t, const char *,
+    cholmod_common *) ;
+int  cholmod_dump_perm (int *, size_t, size_t, const char *, cholmod_common *) ;
+int  cholmod_dump_parent (int *, size_t, const char *, cholmod_common *) ;
+void cholmod_dump_init (const char *, cholmod_common *) ;
+int  cholmod_dump_mem (const char *, SuiteSparse_long, cholmod_common *) ;
+void cholmod_dump_real (const char *, Real *, SuiteSparse_long,
+    SuiteSparse_long, int, int, cholmod_common *) ;
+void cholmod_dump_super (SuiteSparse_long, int *, int *, int *, int *, double *,
+    int, cholmod_common *) ;
+int  cholmod_dump_partition (SuiteSparse_long, int *, int *, int *, int *,
+    SuiteSparse_long, cholmod_common *) ;
+int  cholmod_dump_work(int, int, SuiteSparse_long, cholmod_common *) ;
+
+/* double, SuiteSparse_long */
+EXTERN int cholmod_l_dump ;
+EXTERN int cholmod_l_dump_malloc ;
+SuiteSparse_long cholmod_l_dump_sparse (cholmod_sparse  *, const char *,
+    cholmod_common *) ;
+int  cholmod_l_dump_factor (cholmod_factor  *, const char *, cholmod_common *) ;
+int  cholmod_l_dump_triplet (cholmod_triplet *, const char *, cholmod_common *);
+int  cholmod_l_dump_dense (cholmod_dense   *, const char *, cholmod_common *) ;
+int  cholmod_l_dump_subset (SuiteSparse_long *, size_t, size_t, const char *,
+    cholmod_common *) ;
+int  cholmod_l_dump_perm (SuiteSparse_long *, size_t, size_t, const char *,
+    cholmod_common *) ;
+int  cholmod_l_dump_parent (SuiteSparse_long *, size_t, const char *,
+    cholmod_common *) ;
+void cholmod_l_dump_init (const char *, cholmod_common *) ;
+int  cholmod_l_dump_mem (const char *, SuiteSparse_long, cholmod_common *) ;
+void cholmod_l_dump_real (const char *, Real *, SuiteSparse_long,
+    SuiteSparse_long, int, int, cholmod_common *) ;
+void cholmod_l_dump_super (SuiteSparse_long, SuiteSparse_long *,
+    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
+    double *, int, cholmod_common *) ;
+int  cholmod_l_dump_partition (SuiteSparse_long, SuiteSparse_long *,
+    SuiteSparse_long *, SuiteSparse_long *,
+    SuiteSparse_long *, SuiteSparse_long, cholmod_common *) ;
+int  cholmod_l_dump_work(int, int, SuiteSparse_long, cholmod_common *) ;
+
+#define DEBUG_INIT(s,Common)  { CHOLMOD(dump_init)(s, Common) ; }
+#define ASSERT(expression) (assert (expression))
+
+#define PRK(k,params) \
+{ \
+    if (CHOLMOD(dump) >= (k) && Common->print_function != NULL) \
+    { \
+	(Common->print_function) params ; \
+    } \
+}
+
+#define PRINT0(params) PRK (0, params)
+#define PRINT1(params) PRK (1, params)
+#define PRINT2(params) PRK (2, params)
+#define PRINT3(params) PRK (3, params)
+
+#define PRINTM(params) \
+{ \
+    if (CHOLMOD(dump_malloc) > 0) \
+    { \
+	printf params ; \
+    } \
+}
+
+#define DEBUG(statement) statement
+
+#else
+
+/* Debugging disabled (the normal case) */
+#define PRK(k,params)
+#define DEBUG_INIT(s,Common)
+#define PRINT0(params)
+#define PRINT1(params)
+#define PRINT2(params)
+#define PRINT3(params)
+#define PRINTM(params)
+#define ASSERT(expression)
+#define DEBUG(statement)
+#endif
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_io64.h b/src/CHOLMOD/Include/cholmod_io64.h
new file mode 100644
index 0000000..1964418
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_io64.h
@@ -0,0 +1,45 @@
+/* ========================================================================== */
+/* === Include/cholmod_io64 ================================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_io64.h.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_io64.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* Definitions required for large file I/O, which must come before any other
+ * #includes.  These are not used if -DNLARGEFILE is defined at compile time.
+ * Large file support may not be portable across all platforms and compilers;
+ * if you encounter an error here, compile your code with -DNLARGEFILE.  In
+ * particular, you must use -DNLARGEFILE for MATLAB 6.5 or earlier (which does
+ * not have the io64.h include file).
+ */
+
+#ifndef CHOLMOD_IO_H
+#define CHOLMOD_IO_H
+
+/* skip all of this if NLARGEFILE is defined at the compiler command line */
+#ifndef NLARGEFILE
+
+#if defined(MATLAB_MEX_FILE) || defined(MATHWORKS)
+
+/* CHOLMOD is being compiled as a MATLAB mexFunction, or for use in MATLAB */
+#include "io64.h"
+
+#else
+
+/* CHOLMOD is being compiled in a stand-alone library */
+#undef  _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#undef  _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+
+#endif
+
+#endif
+
+#endif
+
diff --git a/src/CHOLMOD/Include/cholmod_matrixops.h b/src/CHOLMOD/Include/cholmod_matrixops.h
new file mode 100644
index 0000000..7cce7b2
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_matrixops.h
@@ -0,0 +1,237 @@
+/* ========================================================================== */
+/* === Include/cholmod_matrixops.h ========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_matrixops.h.
+ * Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_matrixops.h is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD MatrixOps module.
+ *
+ * Basic operations on sparse and dense matrices.
+ *
+ * cholmod_drop		    A = entries in A with abs. value >= tol
+ * cholmod_norm_dense	    s = norm (X), 1-norm, inf-norm, or 2-norm
+ * cholmod_norm_sparse	    s = norm (A), 1-norm or inf-norm
+ * cholmod_horzcat	    C = [A,B]
+ * cholmod_scale	    A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s)
+ * cholmod_sdmult	    Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y
+ * cholmod_ssmult	    C = A*B
+ * cholmod_submatrix	    C = A (i,j), where i and j are arbitrary vectors
+ * cholmod_vertcat	    C = [A ; B]
+ *
+ * A, B, C: sparse matrices (cholmod_sparse)
+ * X, Y: dense matrices (cholmod_dense)
+ * s: scalar or vector
+ *
+ * Requires the Core module.  Not required by any other CHOLMOD module.
+ */
+
+#ifndef CHOLMOD_MATRIXOPS_H
+#define CHOLMOD_MATRIXOPS_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_drop:  drop entries with small absolute value */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_drop
+(
+    /* ---- input ---- */
+    double tol,		/* keep entries with absolute value > tol */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to drop entries from */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_drop (double, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_norm_dense:  s = norm (X), 1-norm, inf-norm, or 2-norm */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_norm_dense
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to compute the norm of */
+    int norm,		/* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_norm_dense (cholmod_dense *, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_norm_sparse:  s = norm (A), 1-norm or inf-norm */
+/* -------------------------------------------------------------------------- */
+
+double cholmod_norm_sparse
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to compute the norm of */
+    int norm,		/* type of norm: 0: inf. norm, 1: 1-norm */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+double cholmod_l_norm_sparse (cholmod_sparse *, int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_horzcat:  C = [A,B] */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_horzcat
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to concatenate */
+    cholmod_sparse *B,	/* right matrix to concatenate */
+    int values,		/* if TRUE compute the numerical values of C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_horzcat (cholmod_sparse *, cholmod_sparse *, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_scale:  A = diag(s)*A, A*diag(s), s*A or diag(s)*A*diag(s) */
+/* -------------------------------------------------------------------------- */
+
+/* scaling modes, selected by the scale input parameter: */
+#define CHOLMOD_SCALAR 0	/* A = s*A */
+#define CHOLMOD_ROW 1		/* A = diag(s)*A */
+#define CHOLMOD_COL 2		/* A = A*diag(s) */
+#define CHOLMOD_SYM 3		/* A = diag(s)*A*diag(s) */
+
+int cholmod_scale
+(
+    /* ---- input ---- */
+    cholmod_dense *S,	/* scale factors (scalar or vector) */
+    int scale,		/* type of scaling to compute */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to scale */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_scale (cholmod_dense *, int, cholmod_sparse *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_sdmult:  Y = alpha*(A*X) + beta*Y or alpha*(A'*X) + beta*Y */
+/* -------------------------------------------------------------------------- */
+
+/* Sparse matrix times dense matrix */
+
+int cholmod_sdmult
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to multiply */
+    int transpose,	/* use A if 0, or A' otherwise */
+    double alpha [2],   /* scale factor for A */
+    double beta [2],    /* scale factor for Y */
+    cholmod_dense *X,	/* dense matrix to multiply */
+    /* ---- in/out --- */
+    cholmod_dense *Y,	/* resulting dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_sdmult (cholmod_sparse *, int, double *, double *,
+    cholmod_dense *, cholmod_dense *Y, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_ssmult:  C = A*B */
+/* -------------------------------------------------------------------------- */
+
+/* Sparse matrix times sparse matrix */
+
+cholmod_sparse *cholmod_ssmult
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to multiply */
+    cholmod_sparse *B,	/* right matrix to multiply */
+    int stype,		/* requested stype of C */
+    int values,		/* TRUE: do numerical values, FALSE: pattern only */
+    int sorted,		/* if TRUE then return C with sorted columns */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_ssmult (cholmod_sparse *, cholmod_sparse *, int, int,
+    int, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_submatrix:  C = A (r,c), where i and j are arbitrary vectors */
+/* -------------------------------------------------------------------------- */
+
+/* rsize < 0 denotes ":" in MATLAB notation, or more precisely 0:(A->nrow)-1.
+ * In this case, r can be NULL.  An rsize of zero, or r = NULL and rsize >= 0,
+ * denotes "[ ]" in MATLAB notation (the empty set).
+ * Similar rules hold for csize.
+ */
+
+cholmod_sparse *cholmod_submatrix
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to subreference */
+    int *rset,		/* set of row indices, duplicates OK */
+    SuiteSparse_long rsize,	/* size of r; rsize < 0 denotes ":" */
+    int *cset,		/* set of column indices, duplicates OK */
+    SuiteSparse_long csize,	/* size of c; csize < 0 denotes ":" */
+    int values,		/* if TRUE compute the numerical values of C */
+    int sorted,		/* if TRUE then return C with sorted columns */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_submatrix (cholmod_sparse *, SuiteSparse_long *,
+    SuiteSparse_long, SuiteSparse_long *, SuiteSparse_long, int, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_vertcat:  C = [A ; B] */
+/* -------------------------------------------------------------------------- */
+
+cholmod_sparse *cholmod_vertcat
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to concatenate */
+    cholmod_sparse *B,	/* right matrix to concatenate */
+    int values,		/* if TRUE compute the numerical values of C */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+cholmod_sparse *cholmod_l_vertcat (cholmod_sparse *, cholmod_sparse *, int,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_symmetry: determine if a sparse matrix is symmetric */
+/* -------------------------------------------------------------------------- */
+
+int cholmod_symmetry
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    int option,
+    /* ---- output ---- */
+    int *xmatched,
+    int *pmatched,
+    int *nzoffdiag,
+    int *nzdiag,
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_symmetry (cholmod_sparse *, int, SuiteSparse_long *,
+    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
+    cholmod_common *) ;
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_modify.h b/src/CHOLMOD/Include/cholmod_modify.h
new file mode 100644
index 0000000..12a884c
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_modify.h
@@ -0,0 +1,306 @@
+/* ========================================================================== */
+/* === Include/cholmod_modify.h ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_modify.h.
+ * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager
+ * CHOLMOD/Include/cholmod_modify.h is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Modify module.
+ *
+ * Sparse Cholesky modification routines: update / downdate / rowadd / rowdel.
+ * Can also modify a corresponding solution to Lx=b when L is modified.  This
+ * module is most useful when applied on a Cholesky factorization computed by
+ * the Cholesky module, but it does not actually require the Cholesky module.
+ * The Core module can create an identity Cholesky factorization (LDL' where
+ * L=D=I) that can then by modified by these routines.
+ *
+ * Primary routines:
+ * -----------------
+ *
+ * cholmod_updown	    multiple rank update/downdate
+ * cholmod_rowadd	    add a row to an LDL' factorization
+ * cholmod_rowdel	    delete a row from an LDL' factorization
+ *
+ * Secondary routines:
+ * -------------------
+ *
+ * cholmod_updown_solve	    update/downdate, and modify solution to Lx=b
+ * cholmod_updown_mark	    update/downdate, and modify solution to partial Lx=b
+ * cholmod_updown_mask	    update/downdate for LPDASA
+ * cholmod_rowadd_solve	    add a row, and update solution to Lx=b
+ * cholmod_rowadd_mark	    add a row, and update solution to partial Lx=b
+ * cholmod_rowdel_solve	    delete a row, and downdate Lx=b
+ * cholmod_rowdel_mark	    delete a row, and downdate solution to partial Lx=b
+ *
+ * Requires the Core module.  Not required by any other CHOLMOD module.
+ */
+
+#ifndef CHOLMOD_MODIFY_H
+#define CHOLMOD_MODIFY_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown:  multiple rank update/downdate */
+/* -------------------------------------------------------------------------- */
+
+/* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC'
+ * (a downdate).  The factor object L need not be an LDL' factorization; it
+ * is converted to one if it isn't. */
+
+int cholmod_updown 
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown (int, cholmod_sparse *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown_solve:  update/downdate, and modify solution to Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_updown, except that it also updates/downdates the
+ * solution to Lx=b+DeltaB.  x and b must be n-by-1 dense matrices.  b is not
+ * need as input to this routine, but a sparse change to b is (DeltaB).  Only
+ * entries in DeltaB corresponding to columns modified in L are accessed; the
+ * rest must be zero. */
+
+int cholmod_updown_solve
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown_solve (int, cholmod_sparse *, cholmod_factor *,
+    cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown_mark:  update/downdate, and modify solution to partial Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_updown_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  See cholmod_updown.c for
+ * a description of colmark. */
+
+int cholmod_updown_mark
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown_mark (int, cholmod_sparse *, SuiteSparse_long *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_updown_mask:  update/downdate, for LPDASA */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_updown_mark, except has an additional "mask"
+ * argument.  This routine is an "expert" routine.  It is meant for use in
+ * LPDASA only.  See cholmod_updown.c for a description of mask. */
+
+int cholmod_updown_mask
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    int *mask,		/* size n */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_updown_mask (int, cholmod_sparse *, SuiteSparse_long *,
+    SuiteSparse_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowadd:  add a row to an LDL' factorization (a rank-2 update) */
+/* -------------------------------------------------------------------------- */
+
+/* cholmod_rowadd adds a row to the LDL' factorization.  It computes the kth
+ * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n)
+ * accordingly.  The kth row and column of L must originally be equal to the
+ * kth row and column of the identity matrix.  The kth row/column of L is
+ * computed as the factorization of the kth row/column of the matrix to
+ * factorize, which is provided as a single n-by-1 sparse matrix R. */
+
+int cholmod_rowadd 
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowadd (size_t, cholmod_sparse *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowadd_solve:  add a row, and update solution to Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowadd, and also updates the solution to Lx=b
+ * See cholmod_updown for a description of how Lx=b is updated.  There is on
+ * additional parameter:  bk specifies the new kth entry of b. */
+
+int cholmod_rowadd_solve
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    double bk [2],	/* kth entry of the right-hand-side b */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowadd_solve (size_t, cholmod_sparse *, double *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowadd_mark:  add a row, and update solution to partial Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowadd_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  */
+
+int cholmod_rowadd_mark
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    double bk [2],	/* kth entry of the right hand side, b */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowadd_mark (size_t, cholmod_sparse *, double *,
+    SuiteSparse_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowdel:  delete a row from an LDL' factorization (a rank-2 update) */
+/* -------------------------------------------------------------------------- */
+
+/* Sets the kth row and column of L to be the kth row and column of the identity
+ * matrix, and updates L(k+1:n,k+1:n) accordingly.   To reduce the running time,
+ * the caller can optionally provide the nonzero pattern (or an upper bound) of
+ * kth row of L, as the sparse n-by-1 vector R.  Provide R as NULL if you want
+ * CHOLMOD to determine this itself, which is easier for the caller, but takes
+ * a little more time.
+ */
+
+int cholmod_rowdel 
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowdel (size_t, cholmod_sparse *, cholmod_factor *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowdel_solve:  delete a row, and downdate Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b.
+ * When row/column k of A is "deleted" from the system A*y=b, this can induce
+ * a change to x, in addition to changes arising when L and b are modified.
+ * If this is the case, the kth entry of y is required as input (yk) */
+
+int cholmod_rowdel_solve
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    double yk [2],	/* kth entry in the solution to A*y=b */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowdel_solve (size_t, cholmod_sparse *, double *,
+    cholmod_factor *, cholmod_dense *, cholmod_dense *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_rowdel_mark:  delete a row, and downdate solution to partial Lx=b */
+/* -------------------------------------------------------------------------- */
+
+/* Does the same as cholmod_rowdel_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  */
+
+int cholmod_rowdel_mark
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    double yk [2],	/* kth entry in the solution to A*y=b */
+    int *colmark,	/* int array of size n.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_rowdel_mark (size_t, cholmod_sparse *, double *,
+    SuiteSparse_long *, cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_partition.h b/src/CHOLMOD/Include/cholmod_partition.h
new file mode 100644
index 0000000..1e8ecd3
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_partition.h
@@ -0,0 +1,166 @@
+/* ========================================================================== */
+/* === Include/cholmod_partition.h ========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_partition.h.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * CHOLMOD/Include/cholmod_partition.h is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Partition module.
+ *
+ * Graph partitioning and graph-partition-based orderings.  Includes an
+ * interface to CCOLAMD and CSYMAMD, constrained minimum degree ordering
+ * methods which order a matrix following constraints determined via nested
+ * dissection.
+ *
+ * These functions require METIS:
+ * cholmod_nested_dissection	CHOLMOD nested dissection ordering
+ * cholmod_metis		METIS nested dissection ordering (METIS_NodeND)
+ * cholmod_bisect		graph partitioner (currently based on METIS)
+ * cholmod_metis_bisector	direct interface to METIS_NodeComputeSeparator
+ *
+ * Requires the Core and Cholesky modules, and three packages: METIS, CAMD,
+ * and CCOLAMD.  Optionally used by the Cholesky module.
+ *
+ * Note that METIS does not have a version that uses SuiteSparse_long integers.
+ * If you try to use cholmod_nested_dissection, cholmod_metis, cholmod_bisect,
+ * or cholmod_metis_bisector on a matrix that is too large, an error code will
+ * be returned.  METIS does have an "idxtype", which could be redefined as
+ * SuiteSparse_long, if you wish to edit METIS or use compile-time flags to
+ * redefine idxtype.
+ */
+
+#ifndef CHOLMOD_PARTITION_H
+#define CHOLMOD_PARTITION_H
+
+#include "cholmod_core.h"
+#include "cholmod_camd.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_nested_dissection */
+/* -------------------------------------------------------------------------- */
+
+/* Order A, AA', or A(:,f)*A(:,f)' using CHOLMOD's nested dissection method
+ * (METIS's node bisector applied recursively to compute the separator tree
+ * and constraint sets, followed by CCOLAMD using the constraints).  Usually
+ * finds better orderings than METIS_NodeND, but takes longer.
+ */
+
+SuiteSparse_long cholmod_nested_dissection	/* returns # of components */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    int *CParent,	/* size A->nrow.  On output, CParent [c] is the parent
+			 * of component c, or EMPTY if c is a root, and where
+			 * c is in the range 0 to # of components minus 1 */
+    int *Cmember,	/* size A->nrow.  Cmember [j] = c if node j of A is
+			 * in component c */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_nested_dissection (cholmod_sparse *,
+    SuiteSparse_long *, size_t, SuiteSparse_long *, SuiteSparse_long *,
+    SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_metis */
+/* -------------------------------------------------------------------------- */
+
+/* Order A, AA', or A(:,f)*A(:,f)' using METIS_NodeND. */
+
+int cholmod_metis
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with etree or coletree postorder */
+    /* ---- output --- */
+    int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_metis (cholmod_sparse *, SuiteSparse_long *, size_t, int,
+    SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_bisect */
+/* -------------------------------------------------------------------------- */
+
+/* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'. */
+
+SuiteSparse_long cholmod_bisect	/* returns # of nodes in separator */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to bisect */
+    int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int compress,	/* if TRUE, compress the graph first */
+    /* ---- output --- */
+    int *Partition,	/* size A->nrow.  Node i is in the left graph if
+			 * Partition [i] = 0, the right graph if 1, and in the
+			 * separator if 2. */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_bisect (cholmod_sparse *, SuiteSparse_long *,
+    size_t, int, SuiteSparse_long *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_metis_bisector */
+/* -------------------------------------------------------------------------- */
+
+/* Find a set of nodes that bisects the graph of A or AA' (direct interface
+ * to METIS_NodeComputeSeparator). */
+
+SuiteSparse_long cholmod_metis_bisector	/* returns separator size */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to bisect */
+    int *Anw,		/* size A->nrow, node weights */
+    int *Aew,		/* size nz, edge weights */
+    /* ---- output --- */
+    int *Partition,	/* size A->nrow.  see cholmod_bisect above. */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_metis_bisector (cholmod_sparse *,
+    SuiteSparse_long *, SuiteSparse_long *, SuiteSparse_long *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_collapse_septree */
+/* -------------------------------------------------------------------------- */
+
+/* Collapse nodes in a separator tree. */
+
+SuiteSparse_long cholmod_collapse_septree
+(
+    /* ---- input ---- */
+    size_t n,		/* # of nodes in the graph */
+    size_t ncomponents,	/* # of nodes in the separator tree (must be <= n) */
+    double nd_oksep,    /* collapse if #sep >= nd_oksep * #nodes in subtree */
+    size_t nd_small,    /* collapse if #nodes in subtree < nd_small */
+    /* ---- in/out --- */
+    int *CParent,	/* size ncomponents; from cholmod_nested_dissection */
+    int *Cmember,	/* size n; from cholmod_nested_dissection */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+SuiteSparse_long cholmod_l_collapse_septree (size_t, size_t, double, size_t,
+    SuiteSparse_long *, SuiteSparse_long *, cholmod_common *) ;
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_supernodal.h b/src/CHOLMOD/Include/cholmod_supernodal.h
new file mode 100644
index 0000000..9636168
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_supernodal.h
@@ -0,0 +1,172 @@
+/* ========================================================================== */
+/* === Include/cholmod_supernodal.h ========================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Include/cholmod_supernodal.h.
+ * Copyright (C) 2005-2006, Timothy A. Davis
+ * CHOLMOD/Include/cholmod_supernodal.h is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD Supernodal module.
+ *
+ * Supernodal analysis, factorization, and solve.  The simplest way to use
+ * these routines is via the Cholesky module.  It does not provide any
+ * fill-reducing orderings, but does accept the orderings computed by the
+ * Cholesky module.  It does not require the Cholesky module itself, however.
+ *
+ * Primary routines:
+ * -----------------
+ * cholmod_super_symbolic	supernodal symbolic analysis
+ * cholmod_super_numeric	supernodal numeric factorization
+ * cholmod_super_lsolve		supernodal Lx=b solve
+ * cholmod_super_ltsolve	supernodal L'x=b solve
+ *
+ * Prototypes for the BLAS and LAPACK routines that CHOLMOD uses are listed
+ * below, including how they are used in CHOLMOD.
+ *
+ * BLAS routines:
+ * --------------
+ * dtrsv	solve Lx=b or L'x=b, L non-unit diagonal, x and b stride-1
+ * dtrsm	solve LX=B or L'X=b, L non-unit diagonal
+ * dgemv	y=y-A*x or y=y-A'*x (x and y stride-1)
+ * dgemm	C=A*B', C=C-A*B, or C=C-A'*B
+ * dsyrk	C=tril(A*A')
+ *
+ * LAPACK routines:
+ * ----------------
+ * dpotrf	LAPACK: A=chol(tril(A))
+ *
+ * Requires the Core module, and two external packages: LAPACK and the BLAS.
+ * Optionally used by the Cholesky module.
+ */
+
+#ifndef CHOLMOD_SUPERNODAL_H
+#define CHOLMOD_SUPERNODAL_H
+
+#include "cholmod_core.h"
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_symbolic */
+/* -------------------------------------------------------------------------- */
+
+/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric
+ * factorization.  The user need not call this directly; cholmod_analyze is
+ * a "simple" wrapper for this routine.
+ */
+
+int cholmod_super_symbolic
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    int *Parent,	/* elimination tree */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* simplicial symbolic on input,
+			 * supernodal symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_symbolic (cholmod_sparse *, cholmod_sparse *,
+    SuiteSparse_long *, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_symbolic2 */
+/* -------------------------------------------------------------------------- */
+
+/* Analyze for supernodal Cholesky or multifrontal QR.  CHOLMOD itself always
+ * analyzes for supernodal Cholesky, of course.  This "for_cholesky = TRUE"
+ * option is used by SuiteSparseQR only.   Added for V1.7 */
+
+int cholmod_super_symbolic2
+(
+    /* ---- input ---- */
+    int for_cholesky,   /* Cholesky if TRUE, QR if FALSE */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    int *Parent,	/* elimination tree */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* simplicial symbolic on input,
+			 * supernodal symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_symbolic2 (int, cholmod_sparse *, cholmod_sparse *,
+    SuiteSparse_long *, cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_numeric */
+/* -------------------------------------------------------------------------- */
+
+/* Computes the numeric LL' factorization of A, AA', or A(:,f)*A(:,f)' using
+ * a BLAS-based supernodal method.  The user need not call this directly;
+ * cholmod_factorize is a "simple" wrapper for this routine.
+ */
+
+int cholmod_super_numeric
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    double beta [2],	/* beta*I is added to diagonal of matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_numeric (cholmod_sparse *, cholmod_sparse *, double *,
+    cholmod_factor *, cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_lsolve */
+/* -------------------------------------------------------------------------- */
+
+/* Solve Lx=b where L is from a supernodal numeric factorization.  The user
+ * need not call this routine directly.  cholmod_solve is a "simple" wrapper
+ * for this routine. */
+
+int cholmod_super_lsolve
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace   */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_lsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+/* -------------------------------------------------------------------------- */
+/* cholmod_super_ltsolve */
+/* -------------------------------------------------------------------------- */
+
+/* Solve L'x=b where L is from a supernodal numeric factorization.  The user
+ * need not call this routine directly.  cholmod_solve is a "simple" wrapper
+ * for this routine. */
+
+int cholmod_super_ltsolve
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the backsolve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to L'x=b on output */
+    /* ---- workspace   */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+) ;
+
+int cholmod_l_super_ltsolve (cholmod_factor *, cholmod_dense *, cholmod_dense *,
+    cholmod_common *) ;
+
+#endif
diff --git a/src/CHOLMOD/Include/cholmod_template.h b/src/CHOLMOD/Include/cholmod_template.h
new file mode 100644
index 0000000..aa45b4d
--- /dev/null
+++ b/src/CHOLMOD/Include/cholmod_template.h
@@ -0,0 +1,238 @@
+/* ========================================================================== */
+/* === Include/cholmod_template.h =========================================== */
+/* ========================================================================== */
+
+/* -------------------------------------------------------------------------- */
+/* undefine current xtype macros, and then define macros for current type */
+/* -------------------------------------------------------------------------- */
+
+#undef TEMPLATE
+#undef XTYPE
+#undef XTYPE2
+#undef XTYPE_OK
+#undef ENTRY_IS_NONZERO
+#undef ENTRY_IS_ZERO
+#undef ENTRY_IS_ONE
+#undef IMAG_IS_NONZERO
+
+#undef ASSEMBLE
+#undef ASSIGN
+#undef ASSIGN_CONJ
+#undef ASSIGN2
+#undef ASSIGN2_CONJ
+#undef ASSIGN_REAL
+#undef MULT
+#undef MULTADD
+#undef ADD
+#undef ADD_REAL
+#undef MULTSUB
+#undef MULTADDCONJ
+#undef MULTSUBCONJ
+#undef LLDOT
+#undef CLEAR
+#undef DIV
+#undef DIV_REAL
+#undef MULT_REAL
+#undef CLEAR_IMAG
+#undef LDLDOT
+#undef PREFIX
+
+#undef ENTRY_SIZE
+
+#undef XPRINT0
+#undef XPRINT1
+#undef XPRINT2
+#undef XPRINT3
+
+/* -------------------------------------------------------------------------- */
+/* pattern */
+/* -------------------------------------------------------------------------- */
+
+
+#ifdef PATTERN
+
+#define PREFIX				    p_
+#define TEMPLATE(name)			    P_TEMPLATE(name)
+#define XTYPE				    CHOLMOD_PATTERN
+#define XTYPE2				    CHOLMOD_REAL
+#define XTYPE_OK(type)			    (TRUE)
+#define ENTRY_IS_NONZERO(ax,az,q)	    (TRUE)
+#define ENTRY_IS_ZERO(ax,az,q)		    (FALSE)
+#define ENTRY_IS_ONE(ax,az,q)		    (TRUE)
+#define IMAG_IS_NONZERO(ax,az,q)	    (FALSE)
+#define ENTRY_SIZE			    0
+
+#define ASSEMBLE(x,z,p,ax,az,q)
+#define ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    P_ASSIGN2(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    P_ASSIGN2(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)
+#define CLEAR_IMAG(x,z,p)
+#define DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    P_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    P_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    P_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    P_PRINT(3,x,z,p)
+
+/* -------------------------------------------------------------------------- */
+/* real */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (REAL)
+
+#define PREFIX				    r_
+#define TEMPLATE(name)			    R_TEMPLATE(name)
+#define XTYPE				    CHOLMOD_REAL
+#define XTYPE2				    CHOLMOD_REAL
+#define XTYPE_OK(type)			    R_XTYPE_OK(type)
+#define ENTRY_IS_NONZERO(ax,az,q)	    R_IS_NONZERO(ax,az,q)
+#define ENTRY_IS_ZERO(ax,az,q)		    R_IS_ZERO(ax,az,q)
+#define ENTRY_IS_ONE(ax,az,q)		    R_IS_ONE(ax,az,q)
+#define IMAG_IS_NONZERO(ax,az,q)	    (FALSE)
+#define ENTRY_SIZE			    1
+
+#define ASSEMBLE(x,z,p,ax,az,q)		    R_ASSEMBLE(x,z,p,ax,az,q) 
+#define ASSIGN(x,z,p,ax,az,q)		    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)	    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    R_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)		    R_ASSIGN_REAL(x,p,ax,q)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)	    R_MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)     R_MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)	    R_ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)	    R_ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)     R_MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    R_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    R_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)		    R_LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)			    R_CLEAR(x,z,p) 
+#define CLEAR_IMAG(x,z,p)		    R_CLEAR_IMAG(x,z,p) 
+#define DIV(x,z,p,ax,az,q)		    R_DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)	    R_DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)	    R_MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)	    R_LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    R_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    R_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    R_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    R_PRINT(3,x,z,p)
+
+/* -------------------------------------------------------------------------- */
+/* complex */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (COMPLEX)
+
+#define PREFIX				    c_
+
+#ifdef NCONJUGATE
+#define TEMPLATE(name)			    CT_TEMPLATE(name)
+#else
+#define TEMPLATE(name)			    C_TEMPLATE(name)
+#endif
+
+#define ASSEMBLE(x,z,p,ax,az,q)		    C_ASSEMBLE(x,z,p,ax,az,q) 
+#define ASSIGN(x,z,p,ax,az,q)		    C_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)	    C_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    C_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    C_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)		    C_ASSIGN_REAL(x,p,ax,q)
+#define XTYPE				    CHOLMOD_COMPLEX
+#define XTYPE2				    CHOLMOD_COMPLEX
+#define XTYPE_OK(type)			    C_XTYPE_OK(type)
+#define ENTRY_IS_NONZERO(ax,az,q)	    C_IS_NONZERO(ax,az,q)
+#define ENTRY_IS_ZERO(ax,az,q)		    C_IS_ZERO(ax,az,q)
+#define ENTRY_IS_ONE(ax,az,q)		    C_IS_ONE(ax,az,q)
+#define IMAG_IS_NONZERO(ax,az,q)	    C_IMAG_IS_NONZERO(ax,az,q)
+#define ENTRY_SIZE			    2
+
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)     C_MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)	    C_MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)	    C_ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)	    C_ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)     C_MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    C_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    C_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)		    C_LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)			    C_CLEAR(x,z,p) 
+#define CLEAR_IMAG(x,z,p)		    C_CLEAR_IMAG(x,z,p) 
+#define DIV(x,z,p,ax,az,q)		    C_DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)	    C_DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)	    C_MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)	    C_LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    C_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    C_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    C_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    C_PRINT(3,x,z,p)
+
+/* -------------------------------------------------------------------------- */
+/* zomplex */
+/* -------------------------------------------------------------------------- */
+
+#elif defined (ZOMPLEX)
+
+#define PREFIX				    z_
+
+#ifdef NCONJUGATE
+#define TEMPLATE(name)			    ZT_TEMPLATE(name)
+#else
+#define TEMPLATE(name)			    Z_TEMPLATE(name)
+#endif
+
+#define ASSEMBLE(x,z,p,ax,az,q)		    Z_ASSEMBLE(x,z,p,ax,az,q) 
+#define ASSIGN(x,z,p,ax,az,q)		    Z_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN_CONJ(x,z,p,ax,az,q)	    Z_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN2(x,z,p,ax,az,q)		    Z_ASSIGN(x,z,p,ax,az,q)
+#define ASSIGN2_CONJ(x,z,p,ax,az,q)	    Z_ASSIGN_CONJ(x,z,p,ax,az,q)
+#define ASSIGN_REAL(x,p,ax,q)		    Z_ASSIGN_REAL(x,p,ax,q)
+#define XTYPE				    CHOLMOD_ZOMPLEX
+#define XTYPE2				    CHOLMOD_ZOMPLEX
+#define XTYPE_OK(type)			    Z_XTYPE_OK(type)
+#define ENTRY_IS_NONZERO(ax,az,q)	    Z_IS_NONZERO(ax,az,q)
+#define ENTRY_IS_ZERO(ax,az,q)		    Z_IS_ZERO(ax,az,q)
+#define ENTRY_IS_ONE(ax,az,q)		    Z_IS_ONE(ax,az,q)
+#define IMAG_IS_NONZERO(ax,az,q)	    Z_IMAG_IS_NONZERO(ax,az,q)
+#define ENTRY_SIZE			    1
+
+#define MULTADD(x,z,p,ax,az,q,bx,bz,pb)     Z_MULTADD(x,z,p,ax,az,q,bx,bz,pb)
+#define MULT(x,z,p,ax,az,q,bx,bz,pb)	    Z_MULT(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD(x,z,p,ax,az,q,bx,bz,pb)	    Z_ADD(x,z,p,ax,az,q,bx,bz,pb)
+#define ADD_REAL(x,p, ax,q, bx,r)	    Z_ADD_REAL(x,p, ax,q, bx,r)
+#define MULTSUB(x,z,p,ax,az,q,bx,bz,pb)     Z_MULTSUB(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    Z_MULTADDCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb) \
+    Z_MULTSUBCONJ(x,z,p,ax,az,q,bx,bz,pb)
+#define LLDOT(x,p,ax,az,q)		    Z_LLDOT(x,p,ax,az,q)
+#define CLEAR(x,z,p)			    Z_CLEAR(x,z,p) 
+#define CLEAR_IMAG(x,z,p)		    Z_CLEAR_IMAG(x,z,p) 
+#define DIV(x,z,p,ax,az,q)		    Z_DIV(x,z,p,ax,az,q)
+#define DIV_REAL(x,z,p, ax,az,q, bx,r)	    Z_DIV_REAL(x,z,p, ax,az,q, bx,r)
+#define MULT_REAL(x,z,p, ax,az,q, bx,r)	    Z_MULT_REAL(x,z,p, ax,az,q, bx,r)
+#define LDLDOT(x,p, ax,az,q, bx,r)	    Z_LDLDOT(x,p, ax,az,q, bx,r)
+
+#define XPRINT0(x,z,p)			    Z_PRINT(0,x,z,p)
+#define XPRINT1(x,z,p)			    Z_PRINT(1,x,z,p)
+#define XPRINT2(x,z,p)			    Z_PRINT(2,x,z,p)
+#define XPRINT3(x,z,p)			    Z_PRINT(3,x,z,p)
+
+#endif
diff --git a/src/CHOLMOD/Makefile b/src/CHOLMOD/Makefile
new file mode 100644
index 0000000..b6d3b5b
--- /dev/null
+++ b/src/CHOLMOD/Makefile
@@ -0,0 +1,75 @@
+#-------------------------------------------------------------------------------
+# CHOLMOD Makefile
+#-------------------------------------------------------------------------------
+
+VERSION = 2.1.2
+
+# Note: If you do not have METIS, or do not wish to use it in CHOLMOD, you must
+# compile CHOLMOD with the -DNPARTITION flag.
+# See ../SuiteSparse_config/SuiteSparse_config.mk .
+
+default: all
+
+include ../SuiteSparse_config/SuiteSparse_config.mk
+
+# Compile the C-callable libraries and the Demo programs.
+all:
+	( cd Demo ; $(MAKE) )
+
+# Compile the C-callable libraries only.
+library:
+	( cd Lib ; $(MAKE) )
+
+# Remove all files not in the original distribution
+purge:
+	( cd Tcov ; $(MAKE) purge )
+	( cd Lib ; $(MAKE) purge )
+	( cd Valgrind ; $(MAKE) dopurge )
+	( cd Demo ; $(MAKE) purge )
+	( cd Doc ; $(MAKE) purge )
+	( cd MATLAB ; $(RM) $(CLEAN) rename.h *.mex* )
+
+# Remove all files not in the original distribution, except keep the 
+# compiled libraries.
+clean:
+	( cd Tcov ; $(MAKE) clean )
+	( cd Lib ; $(MAKE) clean )
+	( cd Valgrind ; $(MAKE) clean )
+	( cd Demo ; $(MAKE) clean )
+	( cd MATLAB ; $(RM) $(CLEAN) )
+
+distclean: purge
+
+ccode: all
+
+# Run the test coverage suite.  Takes about 40 minutes on a 3.2GHz Pentium.
+# Requires Linux (gcc, gcov).
+cov:
+	( cd Tcov ; $(MAKE) )
+
+# Run the test coverage suite using Valgrind.  This takes a *** long *** time.
+valgrind:
+	( cd Valgrind ; $(MAKE) )
+
+# Compile the C-callable libraries and the Demo programs.
+demos:
+	( cd Demo ; $(MAKE) )
+
+# create PDF documents for the original distribution
+docs:
+	( cd Doc    ; $(MAKE) )
+
+# install CHOLMOD
+install:
+	$(CP) Lib/libcholmod.a $(INSTALL_LIB)/libcholmod.$(VERSION).a
+	( cd $(INSTALL_LIB) ; ln -sf libcholmod.$(VERSION).a libcholmod.a )
+	$(CP) Include/cholmod*.h $(INSTALL_INCLUDE)
+	$(RM) $(INSTALL_INCLUDE)/cholmod_internal.h
+	chmod 644 $(INSTALL_LIB)/libcholmod*.a
+	chmod 644 $(INSTALL_INCLUDE)/cholmod*.h
+
+# uninstall CHOLMOD
+uninstall:
+	$(RM) $(INSTALL_LIB)/libcholmod*.a
+	$(RM) $(INSTALL_INCLUDE)/cholmod*.h
+
diff --git a/src/CHOLMOD/MatrixOps/License.txt b/src/CHOLMOD/MatrixOps/License.txt
new file mode 100644
index 0000000..8c23f46
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006,
+Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/MatrixOps module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module 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 Module 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 Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff --git a/src/CHOLMOD/MatrixOps/cholmod_drop.c b/src/CHOLMOD/MatrixOps/cholmod_drop.c
new file mode 100644
index 0000000..69eb0fa
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_drop.c
@@ -0,0 +1,183 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_drop =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Drop small entries from A, and entries in the ignored part of A if A
+ * is symmetric.  None of the matrix operations drop small numerical entries
+ * from a matrix, except for this one.  NaN's and Inf's are kept.
+ *
+ * workspace: none
+ *
+ * Supports pattern and real matrices, complex and zomplex not supported.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === cholmod_drop ========================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(drop)
+(
+    /* ---- input ---- */
+    double tol,		/* keep entries with absolute value > tol */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to drop entries from */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double aij ;
+    double *Ax ;
+    Int *Ap, *Ai, *Anz ;
+    Int packed, i, j, nrow, ncol, p, pend, nz, values ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "A predrop", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+    values = (A->xtype != CHOLMOD_PATTERN) ;
+    nz = 0 ;
+
+    if (values)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* drop small numerical entries from A, and entries in ignored part */
+	/* ------------------------------------------------------------------ */
+
+	if (A->stype > 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* A is symmetric, with just upper triangular part stored */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Ap [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    aij = Ax [p] ;
+		    if (i <= j && (fabs (aij) > tol || IS_NAN (aij)))
+		    {
+			Ai [nz] = i ;
+			Ax [nz] = aij ;
+			nz++ ;
+		    }
+		}
+	    }
+
+	}
+	else if (A->stype < 0)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* A is symmetric, with just lower triangular part stored */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Ap [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    aij = Ax [p] ;
+		    if (i >= j && (fabs (aij) > tol || IS_NAN (aij)))
+		    {
+			Ai [nz] = i ;
+			Ax [nz] = aij ;
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* both parts of A present, just drop small entries */
+	    /* -------------------------------------------------------------- */
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		Ap [j] = nz ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    aij = Ax [p] ;
+		    if (fabs (aij) > tol || IS_NAN (aij))
+		    {
+			Ai [nz] = i ;
+			Ax [nz] = aij ;
+			nz++ ;
+		    }
+		}
+	    }
+	}
+	Ap [ncol] = nz ;
+
+	/* reduce A->i and A->x in size */
+	ASSERT (MAX (1,nz) <= A->nzmax) ;
+	CHOLMOD(reallocate_sparse) (nz, A, Common) ;
+	ASSERT (Common->status >= CHOLMOD_OK) ;
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* consider only the pattern of A */
+	/* ------------------------------------------------------------------ */
+
+	/* Note that cholmod_band_inplace calls cholmod_reallocate_sparse */
+	if (A->stype > 0)
+	{
+	    CHOLMOD(band_inplace) (0, ncol, 0, A, Common) ;
+	}
+	else if (A->stype < 0)
+	{
+	    CHOLMOD(band_inplace) (-nrow, 0, 0, A, Common) ;
+	}
+    }
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A dropped", Common) >= 0) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_horzcat.c b/src/CHOLMOD/MatrixOps/cholmod_horzcat.c
new file mode 100644
index 0000000..9388e9a
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_horzcat.c
@@ -0,0 +1,203 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_horzcat ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Horizontal concatenation, C = [A , B] in MATLAB notation.
+ *
+ * A and B can be up/lo/unsym; C is unsymmetric and packed.
+ * A and B must have the same number of rows.
+ * C is sorted if both A and B are sorted.
+ *
+ * workspace: Iwork (max (A->nrow, A->ncol, B->nrow, B->ncol)).
+ *	allocates temporary copies of A and B if they are symmetric.
+ *
+ * A and B must have the same numeric xtype, unless values is FALSE.
+ * A and B cannot be complex or zomplex, unless values is FALSE.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === cholmod_horzcat ====================================================== */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(horzcat)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to concatenate */
+    cholmod_sparse *B,	/* right matrix to concatenate */
+    int values,		/* if TRUE compute the numerical values of C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Bx, *Cx ;
+    Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Cp, *Ci ;
+    cholmod_sparse *C, *A2, *B2 ;
+    Int apacked, bpacked, ancol, bncol, ncol, nrow, anz, bnz, nz, j, p, pend,
+	pdest ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    values = values &&
+	(A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->nrow != B->nrow)
+    {
+	/* A and B must have the same number of rows */
+	ERROR (CHOLMOD_INVALID, "A and B must have same # rows") ;
+	return (NULL) ;
+    }
+    /* A and B must have the same numerical type if values is TRUE (both must
+     * be CHOLMOD_REAL, this is implicitly checked above) */
+
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    ancol = A->ncol ;
+    bncol = B->ncol ;
+    nrow = A->nrow ;
+    CHOLMOD(allocate_work) (0, MAX3 (nrow, ancol, bncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* convert A to unsymmetric, if necessary */
+    A2 = NULL ;
+    if (A->stype != 0)
+    {
+	/* workspace: Iwork (max (A->nrow,A->ncol)) */
+	A2 = CHOLMOD(copy) (A, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (NULL) ;
+	}
+	A = A2 ;
+    }
+
+    /* convert B to unsymmetric, if necessary */
+    B2 = NULL ;
+    if (B->stype != 0)
+    {
+	/* workspace: Iwork (max (B->nrow,B->ncol)) */
+	B2 = CHOLMOD(copy) (B, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    CHOLMOD(free_sparse) (&A2, Common) ;
+	    return (NULL) ;
+	}
+	B = B2 ;
+    }
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    apacked = A->packed ;
+
+    Bp  = B->p ;
+    Bnz = B->nz ;
+    Bi  = B->i ;
+    Bx  = B->x ;
+    bpacked = B->packed ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C */
+    /* ---------------------------------------------------------------------- */
+
+    anz = CHOLMOD(nnz) (A, Common) ;
+    bnz = CHOLMOD(nnz) (B, Common) ;
+    ncol = ancol + bncol ;
+    nz = anz + bnz ;
+
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, A->sorted && B->sorted, TRUE,
+	    0, values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	CHOLMOD(free_sparse) (&A2, Common) ;
+	CHOLMOD(free_sparse) (&B2, Common) ;
+	return (NULL) ;
+    }
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = [A , B] */
+    /* ---------------------------------------------------------------------- */
+
+    pdest = 0 ;
+
+    /* copy A as the first A->ncol columns of C */
+    for (j = 0 ; j < ancol ; j++)
+    {
+	/* A(:,j) is the jth column of C */
+	p = Ap [j] ;
+	pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	Cp [j] = pdest ;
+	for ( ; p < pend ; p++)
+	{
+	    Ci [pdest] = Ai [p] ;
+	    if (values) Cx [pdest] = Ax [p] ;
+	    pdest++ ;
+	}
+    }
+
+    /* copy B as the next B->ncol columns of C */
+    for (j = 0 ; j < bncol ; j++)
+    {
+	/* B(:,j) is the (ancol+j)th column of C */
+	p = Bp [j] ;
+	pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ;
+	Cp [ancol + j] = pdest ;
+	for ( ; p < pend ; p++)
+	{
+	    Ci [pdest] = Bi [p] ;
+	    if (values) Cx [pdest] = Bx [p] ;
+	    pdest++ ;
+	}
+    }
+    Cp [ncol] = pdest ;
+    ASSERT (pdest == anz + bnz) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the unsymmetric copies of A and B, and return C */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    CHOLMOD(free_sparse) (&B2, Common) ;
+    return (C) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_norm.c b/src/CHOLMOD/MatrixOps/cholmod_norm.c
new file mode 100644
index 0000000..75eea79
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_norm.c
@@ -0,0 +1,452 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_norm =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* r = norm (A), compute the infinity-norm, 1-norm, or 2-norm of a sparse or
+ * dense matrix.  Can compute the 2-norm only for a dense column vector.
+ * Returns -1 if an error occurs.
+ *
+ * Pattern, real, complex, and zomplex sparse matrices are supported.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === abs_value ============================================================ */
+/* ========================================================================== */
+
+/* Compute the absolute value of a real, complex, or zomplex value */
+
+static double abs_value
+(
+    int xtype,
+    double *Ax,
+    double *Az,
+    Int p,
+    cholmod_common *Common
+)
+{
+    double s = 0 ;
+    switch (xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    s = 1 ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    s = fabs (Ax [p]) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    s = Common->hypotenuse (Ax [2*p], Ax [2*p+1]) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    s = Common->hypotenuse (Ax [p], Az [p]) ;
+	    break ;
+    }
+    return (s) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_norm_dense =================================================== */
+/* ========================================================================== */
+
+double CHOLMOD(norm_dense)
+(
+    /* ---- input ---- */
+    cholmod_dense *X,	/* matrix to compute the norm of */
+    int norm,		/* type of norm: 0: inf. norm, 1: 1-norm, 2: 2-norm */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double xnorm, s, x, z ;
+    double *Xx, *Xz, *W ;
+    Int nrow, ncol, d, i, j, use_workspace, xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (X, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+    ncol = X->ncol ;
+    if (norm < 0 || norm > 2 || (norm == 2 && ncol > 1))
+    {
+	ERROR (CHOLMOD_INVALID, "invalid norm") ;
+	return (EMPTY) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = X->nrow ;
+    d = X->d ;
+    Xx = X->x ;
+    Xz = X->z ;
+    xtype = X->xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace, if needed */
+    /* ---------------------------------------------------------------------- */
+
+    W = NULL ;
+    use_workspace = (norm == 0 && ncol > 4) ;
+    if (use_workspace)
+    {
+	CHOLMOD(allocate_work) (0, 0, nrow, Common) ;
+	W = Common->Xwork ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* oops, no workspace */
+	    use_workspace = FALSE ;
+	}
+    }
+
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the norm */
+    /* ---------------------------------------------------------------------- */
+
+    xnorm = 0 ;
+
+    if (use_workspace)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* infinity-norm = max row sum, using stride-1 access of X */
+	/* ------------------------------------------------------------------ */
+
+	DEBUG (for (i = 0 ; i < nrow ; i++) ASSERT (W [i] == 0)) ;
+
+	/* this is faster than stride-d, but requires O(nrow) workspace */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    for (i = 0 ; i < nrow ; i++)
+	    {
+		W [i] += abs_value (xtype, Xx, Xz, i+j*d, Common) ;
+	    }
+	}
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    s = W [i] ;
+	    if ((IS_NAN (s) || s > xnorm) && !IS_NAN (xnorm))
+	    {
+		xnorm = s ;
+	    }
+	    W [i] = 0 ;
+	}
+
+    }
+    else if (norm == 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* infinity-norm = max row sum, using stride-d access of X */
+	/* ------------------------------------------------------------------ */
+
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    s = 0 ;
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		s += abs_value (xtype, Xx, Xz, i+j*d, Common) ;
+	    }
+	    if ((IS_NAN (s) || s > xnorm) && !IS_NAN (xnorm))
+	    {
+		xnorm = s ;
+	    }
+	}
+
+    }
+    else if (norm == 1)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* 1-norm = max column sum */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    s = 0 ;
+	    for (i = 0 ; i < nrow ; i++)
+	    {
+		s += abs_value (xtype, Xx, Xz, i+j*d, Common) ;
+	    }
+	    if ((IS_NAN (s) || s > xnorm) && !IS_NAN (xnorm))
+	    {
+		xnorm = s ;
+	    }
+	}
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* 2-norm = sqrt (sum (X.^2)) */
+	/* ------------------------------------------------------------------ */
+
+	switch (xtype)
+	{
+
+	    case CHOLMOD_REAL:
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    x = Xx [i] ;
+		    xnorm += x*x ;
+		}
+		break ; 
+
+	    case CHOLMOD_COMPLEX:
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    x = Xx [2*i  ] ;
+		    z = Xx [2*i+1] ;
+		    xnorm += x*x + z*z ;
+		}
+		break ; 
+
+	    case CHOLMOD_ZOMPLEX:
+		for (i = 0 ; i < nrow ; i++)
+		{
+		    x = Xx [i] ;
+		    z = Xz [i] ;
+		    xnorm += x*x + z*z ;
+		}
+		break ; 
+	}
+
+	xnorm = sqrt (xnorm) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    return (xnorm) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_norm_sparse ================================================== */
+/* ========================================================================== */
+
+double CHOLMOD(norm_sparse)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to compute the norm of */
+    int norm,		/* type of norm: 0: inf. norm, 1: 1-norm */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double anorm, s ;
+    double *Ax, *Az, *W ;
+    Int *Ap, *Ai, *Anz ;
+    Int i, j, p, pend, nrow, ncol, packed, xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+    if (norm < 0 || norm > 1)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid norm") ;
+	return (EMPTY) ;
+    }
+    if (A->stype && nrow != ncol)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix invalid") ;
+	return (EMPTY) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    xtype = A->xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace, if needed */
+    /* ---------------------------------------------------------------------- */
+
+    W = NULL ;
+    if (A->stype || norm == 0)
+    {
+	CHOLMOD(allocate_work) (0, 0, nrow, Common) ;
+	W = Common->Xwork ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (EMPTY) ;
+	}
+	DEBUG (for (i = 0 ; i < nrow ; i++) ASSERT (W [i] == 0)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the norm */
+    /* ---------------------------------------------------------------------- */
+
+    anorm = 0 ;
+
+    if (A->stype > 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A is symmetric with upper triangular part stored */
+	/* ------------------------------------------------------------------ */
+
+	/* infinity-norm = 1-norm = max row/col sum */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		s = abs_value (xtype, Ax, Az, p, Common) ;
+		if (i == j)
+		{
+		    W [i] += s ;
+		}
+		else if (i < j)
+		{
+		    W [i] += s ;
+		    W [j] += s ;
+		}
+	    }
+	}
+
+    }
+    else if (A->stype < 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A is symmetric with lower triangular part stored */
+	/* ------------------------------------------------------------------ */
+
+	/* infinity-norm = 1-norm = max row/col sum */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		i = Ai [p] ;
+		s = abs_value (xtype, Ax, Az, p, Common) ;
+		if (i == j)
+		{
+		    W [i] += s ;
+		}
+		else if (i > j)
+		{
+		    W [i] += s ;
+		    W [j] += s ;
+		}
+	    }
+	}
+
+    }
+    else if (norm == 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A is unsymmetric, compute the infinity-norm */
+	/* ------------------------------------------------------------------ */
+
+	/* infinity-norm = max row sum */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		W [Ai [p]] += abs_value (xtype, Ax, Az, p, Common) ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A is unsymmetric, compute the 1-norm */
+	/* ------------------------------------------------------------------ */
+
+	/* 1-norm = max column sum */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    if (xtype == CHOLMOD_PATTERN)
+	    {
+		s = pend - p ;
+	    }
+	    else
+	    {
+		s = 0 ;
+		for ( ; p < pend ; p++)
+		{
+		    s += abs_value (xtype, Ax, Az, p, Common) ;
+		}
+	    }
+	    if ((IS_NAN (s) || s > anorm) && !IS_NAN (anorm))
+	    {
+		anorm = s ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute the max row sum */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->stype || norm == 0)
+    {
+	for (i = 0 ; i < nrow ; i++)
+	{
+	    s = W [i] ;
+	    if ((IS_NAN (s) || s > anorm) && !IS_NAN (anorm))
+	    {
+		anorm = s ;
+	    }
+	    W [i] = 0 ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    return (anorm) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_scale.c b/src/CHOLMOD/MatrixOps/cholmod_scale.c
new file mode 100644
index 0000000..2f722c6
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_scale.c
@@ -0,0 +1,217 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_scale ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* scale a matrix:  A = diag(s)*A, A*diag(s), s*A, or diag(s)*A*diag(s)
+ *
+ * A can be of any type (packed/unpacked, upper/lower/unsymmetric).
+ * The symmetry of A is ignored; all entries in the matrix are modified.
+ *
+ * If A is m-by-n unsymmetric but scaled symmtrically, the result is
+ * A = diag (s (1:m)) * A * diag (s (1:n)).
+ *
+ * Note: diag(s) should be interpretted as spdiags(s,0,n,n) where n=length(s).
+ *
+ * Row or column scaling of a symmetric matrix still results in a symmetric
+ * matrix, since entries are still ignored by other routines.
+ * For example, when row-scaling a symmetric matrix where just the upper
+ * triangular part is stored (and lower triangular entries ignored)
+ * A = diag(s)*triu(A) is performed, where the result A is also
+ * symmetric-upper.  This has the effect of modifying the implicit lower
+ * triangular part.  In MATLAB notation:
+ *
+ *	U = diag(s)*triu(A) ;
+ *	L = tril (U',-1)
+ *	A = L + U ;
+ *
+ * The scale parameter determines the kind of scaling to perform:
+ *
+ *	 CHOLMOD_SCALAR: s[0]*A
+ *	 CHOLMOD_ROW:    diag(s)*A
+ *	 CHOLMOD_COL:    A*diag(s)
+ *	 CHOLMOD_SYM:    diag(s)*A*diag(s)
+ *
+ * The size of S depends on the scale parameter:
+ *
+ *	 CHOLMOD_SCALAR: size 1
+ *	 CHOLMOD_ROW:    size nrow-by-1 or 1-by-nrow
+ *	 CHOLMOD_COL:    size ncol-by-1 or 1-by-ncol
+ *	 CHOLMOD_SYM:    size max(nrow,ncol)-by-1, or 1-by-max(nrow,ncol)
+ *
+ * workspace: none
+ *
+ * Only real matrices are supported.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === cholmod_scale ======================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(scale)
+(
+    /* ---- input ---- */
+    cholmod_dense *S,	/* scale factors (scalar or vector) */
+    int scale,		/* type of scaling to compute */
+    /* ---- in/out --- */
+    cholmod_sparse *A,	/* matrix to scale */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double t ;
+    double *Ax, *s ;
+    Int *Ap, *Anz, *Ai ;
+    Int packed, j, ncol, nrow, p, pend, sncol, snrow, nn, ok ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (S, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (S, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+    sncol = S->ncol ;
+    snrow = S->nrow ;
+    if (scale == CHOLMOD_SCALAR)
+    {
+	ok = (snrow == 1 && sncol == 1) ;
+    }
+    else if (scale == CHOLMOD_ROW)
+    {
+	ok = (snrow == nrow && sncol == 1) || (snrow == 1 && sncol == nrow) ;
+    }
+    else if (scale == CHOLMOD_COL)
+    {
+	ok = (snrow == ncol && sncol == 1) || (snrow == 1 && sncol == ncol) ;
+    }
+    else if (scale == CHOLMOD_SYM)
+    {
+	nn = MAX (nrow, ncol) ;
+	ok = (snrow == nn && sncol == 1) || (snrow == 1 && sncol == nn) ;
+    }
+    else
+    {
+	/* scale invalid */
+	ERROR (CHOLMOD_INVALID, "invalid scaling option") ;
+	return (FALSE) ;
+    }
+    if (!ok)
+    {
+	/* S is wrong size */
+	ERROR (CHOLMOD_INVALID, "invalid scale factors") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    packed = A->packed ;
+    s = S->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* scale the matrix */
+    /* ---------------------------------------------------------------------- */
+
+    if (scale == CHOLMOD_ROW)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A = diag(s)*A, row scaling */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Ax [p] *= s [Ai [p]] ;
+	    }
+	}
+
+    }
+    else if (scale == CHOLMOD_COL)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A = A*diag(s), column scaling */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    t = s [j] ;
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Ax [p] *= t ;
+	    }
+	}
+
+    }
+    else if (scale == CHOLMOD_SYM)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A = diag(s)*A*diag(s), symmetric scaling */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    t = s [j] ;
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Ax [p] *= t * s [Ai [p]] ;
+	    }
+	}
+
+    }
+    else if (scale == CHOLMOD_SCALAR)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* A = s[0] * A, scalar scaling */
+	/* ------------------------------------------------------------------ */
+
+	t = s [0] ;
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Ax [p] *= t ;
+	    }
+	}
+    }
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A scaled", Common) >= 0) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_sdmult.c b/src/CHOLMOD/MatrixOps/cholmod_sdmult.c
new file mode 100644
index 0000000..fd40b48
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_sdmult.c
@@ -0,0 +1,149 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_sdmult ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Sparse matrix times dense matrix:
+ * Y = alpha*(A*X) + beta*Y or Y = alpha*(A'*X) + beta*Y,
+ * where A is sparse and X and Y are dense.
+ *
+ * when using A,  X has A->ncol columns and Y has A->nrow rows
+ * when using A', X has A->nrow columns and Y has A->ncol rows
+ *
+ * workspace: none in Common.  Temporary workspace of size 4*(X->nrow) is used
+ * if A is stored in symmetric form and X has four columns or more.  If the
+ * workspace is not available, a slower method is used instead that requires
+ * no workspace.
+ *
+ * transpose = 0: use A
+ * otherwise, use A'  (complex conjugate transpose)
+ *
+ * transpose is ignored if the matrix is symmetric or Hermitian.
+ * (the array transpose A.' is not supported).
+ *
+ * Supports real, complex, and zomplex matrices, but the xtypes of A, X, and Y
+ * must all match.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_sdmult.c"
+#define COMPLEX
+#include "t_cholmod_sdmult.c"
+#define ZOMPLEX
+#include "t_cholmod_sdmult.c"
+
+/* ========================================================================== */
+/* === cholmod_sdmult ======================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(sdmult)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to multiply */
+    int transpose,	/* use A if 0, otherwise use A' */
+    double alpha [2],   /* scale factor for A */
+    double beta [2],    /* scale factor for Y */
+    cholmod_dense *X,	/* dense matrix to multiply */
+    /* ---- in/out --- */
+    cholmod_dense *Y,	/* resulting dense matrix */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *w ;
+    size_t nx, ny ;
+    Int e ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (Y, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (Y, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    ny = transpose ? A->ncol : A->nrow ;	/* required length of Y */
+    nx = transpose ? A->nrow : A->ncol ;	/* required length of X */
+    if (X->nrow != nx || X->ncol != Y->ncol || Y->nrow != ny)
+    {
+	/* X and/or Y have the wrong dimension */
+	ERROR (CHOLMOD_INVALID, "X and/or Y have wrong dimensions") ;
+	return (FALSE) ;
+    }
+    if (A->xtype != X->xtype || A->xtype != Y->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "A, X, and Y must have same xtype") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace, if required */
+    /* ---------------------------------------------------------------------- */
+
+    w = NULL ;
+    e = (A->xtype == CHOLMOD_REAL ? 1:2) ;
+    if (A->stype && X->ncol >= 4)
+    {
+	w = CHOLMOD(malloc) (nx, 4*e*sizeof (double), Common) ;
+    }
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;    /* out of memory */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = alpha*op(A)*X + beta*Y via template routine */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+    DEBUG (CHOLMOD(dump_dense) (X, "X", Common)) ;
+    DEBUG (if (IS_NONZERO (beta [0])
+	   || (IS_NONZERO (beta [1]) && A->xtype != CHOLMOD_REAL))
+	    CHOLMOD(dump_dense) (Y, "Y", Common)) ;
+
+    switch (A->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_cholmod_sdmult (A, transpose, alpha, beta, X, Y, w) ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    c_cholmod_sdmult (A, transpose, alpha, beta, X, Y, w) ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    z_cholmod_sdmult (A, transpose, alpha, beta, X, Y, w) ;
+	    break ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free) (4*nx, e*sizeof (double), w, Common) ;
+    DEBUG (CHOLMOD(dump_dense) (Y, "Y", Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_ssmult.c b/src/CHOLMOD/MatrixOps/cholmod_ssmult.c
new file mode 100644
index 0000000..fbdf0ce
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_ssmult.c
@@ -0,0 +1,487 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_ssmult ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* C = A*B.  Multiply two sparse matrices.
+ *
+ * A and B can be packed or unpacked, sorted or unsorted, and of any stype.
+ * If A or B are symmetric, an internal unsymmetric copy is made first, however.
+ * C is computed as if A and B are unsymmetric, and then if the stype input
+ * parameter requests a symmetric form (upper or lower) the matrix is converted
+ * into that form.
+ *
+ * C is returned as packed, and either unsorted or sorted, depending on the
+ * "sorted" input parameter.  If C is returned sorted, then either C = (B'*A')'
+ * or C = (A*B)'' is computed, depending on the number of nonzeros in A, B, and
+ * C.
+ *
+ * workspace:
+ *	if C unsorted: Flag (A->nrow), W (A->nrow) if values
+ *	if C sorted:   Flag (B->ncol), W (B->ncol) if values
+ *	Iwork (max (A->ncol, A->nrow, B->nrow, B->ncol))
+ *	allocates temporary copies for A, B, and C, if required.
+ *
+ * Only pattern and real matrices are supported.  Complex and zomplex matrices
+ * are supported only when the numerical values are not computed ("values"
+ * is FALSE).
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === cholmod_ssmult ======================================================= */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(ssmult)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to multiply */
+    cholmod_sparse *B,	/* right matrix to multiply */
+    int stype,		/* requested stype of C */
+    int values,		/* TRUE: do numerical values, FALSE: pattern only */
+    int sorted,		/* if TRUE then return C with sorted columns */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double bjt ;
+    double *Ax, *Bx, *Cx, *W ;
+    Int *Ap, *Anz, *Ai, *Bp, *Bnz, *Bi, *Cp, *Ci, *Flag ;
+    cholmod_sparse *C, *A2, *B2, *A3, *B3, *C2 ;
+    Int apacked, bpacked, j, i, pa, paend, pb, pbend, ncol, mark, cnz, t, p,
+	nrow, anz, bnz, do_swap_and_transpose, n1, n2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    values = values &&
+	(A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, 
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN, 
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->ncol != B->nrow)
+    {
+	/* inner dimensions must agree */
+	ERROR (CHOLMOD_INVALID, "A and B inner dimensions must match") ;
+	return (NULL) ;
+    }
+    /* A and B must have the same numerical type if values is TRUE (both must
+     * be CHOLMOD_REAL, this is implicitly checked above) */
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->nrow <= 1)
+    {
+	/* C will be implicitly sorted, so no need to sort it here */
+	sorted = FALSE ;
+    }
+    if (sorted)
+    {
+	n1 = MAX (A->nrow, B->ncol) ;
+    }
+    else
+    {
+	n1 = A->nrow ;
+    }
+    n2 = MAX4 (A->ncol, A->nrow, B->nrow, B->ncol) ;
+    CHOLMOD(allocate_work) (n1, n2, values ? n1 : 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1 : 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* convert A to unsymmetric, if necessary */
+    A2 = NULL ;
+    B2 = NULL ;
+    if (A->stype)
+    {
+	/* workspace: Iwork (max (A->nrow,A->ncol)) */
+	A2 = CHOLMOD(copy) (A, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ;
+	    return (NULL) ;
+	}
+	A = A2 ;
+    }
+
+    /* convert B to unsymmetric, if necessary */
+    if (B->stype)
+    {
+	/* workspace: Iwork (max (B->nrow,B->ncol)) */
+	B2 = CHOLMOD(copy) (B, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    CHOLMOD(free_sparse) (&A2, Common) ;
+	    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ;
+	    return (NULL) ;
+	}
+	B = B2 ;
+    }
+
+    ASSERT (CHOLMOD(dump_sparse) (A, "A", Common) >= 0) ;
+    ASSERT (CHOLMOD(dump_sparse) (B, "B", Common) >= 0) ;
+
+    /* get the A matrix */
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    apacked = A->packed ;
+
+    /* get the B matrix */
+    Bp  = B->p ;
+    Bnz = B->nz ;
+    Bi  = B->i ;
+    Bx  = B->x ;
+    bpacked = B->packed ;
+
+    /* get the size of C */
+    nrow = A->nrow ;
+    ncol = B->ncol ;
+
+    /* get workspace */
+    W = Common->Xwork ;		/* size nrow, unused if values is FALSE */
+    Flag = Common->Flag ;	/* size nrow, Flag [0..nrow-1] < mark on input*/
+
+    /* ---------------------------------------------------------------------- */
+    /* count the number of entries in the result C */
+    /* ---------------------------------------------------------------------- */
+
+    cnz = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	/* clear the Flag array */
+	/* mark = CHOLMOD(clear_flag) (Common) ; */
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	mark = Common->mark ;
+
+	/* for each nonzero B(t,j) in column j, do: */
+	pb = Bp [j] ;
+	pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ;
+	for ( ; pb < pbend ; pb++)
+	{
+	    /* B(t,j) is nonzero */
+	    t = Bi [pb] ;
+
+	    /* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */
+	    pa = Ap [t] ;
+	    paend = (apacked) ? (Ap [t+1]) : (pa + Anz [t]) ;
+	    for ( ; pa < paend ; pa++)
+	    {
+		i = Ai [pa] ;
+		if (Flag [i] != mark)
+		{
+		    Flag [i] = mark ;
+		    cnz++ ;
+		}
+	    }
+	}
+	if (cnz < 0)
+	{
+	    break ;	    /* integer overflow case */
+	}
+    }
+
+    /* mark = CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    mark = Common->mark ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check for integer overflow */
+    /* ---------------------------------------------------------------------- */
+
+    if (cnz < 0)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	CHOLMOD(free_sparse) (&A2, Common) ;
+	CHOLMOD(free_sparse) (&B2, Common) ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ;
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Determine how to return C sorted (if requested) */
+    /* ---------------------------------------------------------------------- */
+
+    do_swap_and_transpose = FALSE ;
+
+    if (sorted)
+    {
+	/* Determine the best way to return C with sorted columns.  Computing
+	 * C = (B'*A')' takes cnz + anz + bnz time (ignoring O(n) terms).
+	 * Sorting C when done, C = (A*B)'', takes 2*cnz time.  Pick the one
+	 * with the least amount of work. */
+
+	anz = CHOLMOD(nnz) (A, Common) ;
+	bnz = CHOLMOD(nnz) (B, Common) ;
+
+	do_swap_and_transpose = (anz + bnz < cnz) ;
+
+	if (do_swap_and_transpose)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* C = (B'*A')' */
+	    /* -------------------------------------------------------------- */
+
+	    /* workspace: Iwork (A->nrow) */
+	    A3 = CHOLMOD(ptranspose) (A, values, NULL, NULL, 0, Common) ;
+	    CHOLMOD(free_sparse) (&A2, Common) ;
+	    A2 = A3 ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		/* out of memory */
+		CHOLMOD(free_sparse) (&A2, Common) ;
+		CHOLMOD(free_sparse) (&B2, Common) ;
+		ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common));
+		return (NULL) ;
+	    }
+	    /* workspace: Iwork (B->nrow) */
+	    B3 = CHOLMOD(ptranspose) (B, values, NULL, NULL, 0, Common) ;
+	    CHOLMOD(free_sparse) (&B2, Common) ;
+	    B2 = B3 ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		/* out of memory */
+		CHOLMOD(free_sparse) (&A2, Common) ;
+		CHOLMOD(free_sparse) (&B2, Common) ;
+		ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common));
+		return (NULL) ;
+	    }
+	    A = B2 ;
+	    B = A2 ;
+
+	    /* get the new A matrix */
+	    Ap  = A->p ;
+	    Anz = A->nz ;
+	    Ai  = A->i ;
+	    Ax  = A->x ;
+	    apacked = A->packed ;
+
+	    /* get the new B matrix */
+	    Bp  = B->p ;
+	    Bnz = B->nz ;
+	    Bi  = B->i ;
+	    Bx  = B->x ;
+	    bpacked = B->packed ;
+
+	    /* get the size of C' */
+	    nrow = A->nrow ;
+	    ncol = B->ncol ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, cnz, FALSE, TRUE, 0,
+	    values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	CHOLMOD(free_sparse) (&A2, Common) ;
+	CHOLMOD(free_sparse) (&B2, Common) ;
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ;
+	return (NULL) ;
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = A*B */
+    /* ---------------------------------------------------------------------- */
+
+    cnz = 0 ;
+
+    if (values)
+    {
+
+	/* pattern and values */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    /* clear the Flag array */
+	    /* mark = CHOLMOD(clear_flag (Common)) ; */
+	    CHOLMOD_CLEAR_FLAG (Common) ;
+	    mark = Common->mark ;
+
+	    /* start column j of C */
+	    Cp [j] = cnz ;
+
+	    /* for each nonzero B(t,j) in column j, do: */
+	    pb = Bp [j] ;
+	    pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ;
+	    for ( ; pb < pbend ; pb++)
+	    {
+		/* B(t,j) is nonzero */
+		t = Bi [pb] ;
+		bjt = Bx [pb] ;
+
+		/* add the nonzero pattern of A(:,t) to the pattern of C(:,j)
+		 * and scatter the values into W */
+		pa = Ap [t] ;
+		paend = (apacked) ? (Ap [t+1]) : (pa + Anz [t]) ;
+		for ( ; pa < paend ; pa++)
+		{
+		    i = Ai [pa] ;
+		    if (Flag [i] != mark)
+		    {
+			Flag [i] = mark ;
+			Ci [cnz++] = i ;
+		    }
+		    W [i] += Ax [pa] * bjt ;
+		}
+	    }
+
+	    /* gather the values into C(:,j) */
+	    for (p = Cp [j] ; p < cnz ; p++)
+	    {
+		i = Ci [p] ;
+		Cx [p] = W [i] ;
+		W [i] = 0 ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* pattern only */
+	for (j = 0 ; j < ncol ; j++)
+	{
+	    /* clear the Flag array */
+	    /* mark = CHOLMOD(clear_flag) (Common) ; */
+	    CHOLMOD_CLEAR_FLAG (Common) ;
+	    mark = Common->mark ;
+
+	    /* start column j of C */
+	    Cp [j] = cnz ;
+
+	    /* for each nonzero B(t,j) in column j, do: */
+	    pb = Bp [j] ;
+	    pbend = (bpacked) ? (Bp [j+1]) : (pb + Bnz [j]) ;
+	    for ( ; pb < pbend ; pb++)
+	    {
+		/* B(t,j) is nonzero */
+		t = Bi [pb] ;
+
+		/* add the nonzero pattern of A(:,t) to the pattern of C(:,j) */
+		pa = Ap [t] ;
+		paend = (apacked) ? (Ap [t+1]) : (pa + Anz [t]) ;
+		for ( ; pa < paend ; pa++)
+		{
+		    i = Ai [pa] ;
+		    if (Flag [i] != mark)
+		    {
+			Flag [i] = mark ;
+			Ci [cnz++] = i ;
+		    }
+		}
+	    }
+	}
+    }
+
+    Cp [ncol] = cnz ;
+    ASSERT (MAX (1,cnz) == C->nzmax) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace and free temporary matrices */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    CHOLMOD(free_sparse) (&B2, Common) ;
+    /* CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert C to a symmetric upper/lower matrix if requested */
+    /* ---------------------------------------------------------------------- */
+
+    /* convert C in place, which cannot fail since no memory is allocated */
+    if (stype > 0)
+    {
+	/* C = triu (C), in place */
+	(void) CHOLMOD(band_inplace) (0, ncol, values, C, Common) ;
+	C->stype = 1 ;
+    }
+    else if (stype < 0)
+    {
+	/* C = tril (C), in place */
+	(void) CHOLMOD(band_inplace) (-nrow, 0, values, C, Common) ;
+	C->stype = -1 ;
+    }
+    ASSERT (Common->status >= CHOLMOD_OK) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* sort C, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    if (sorted)
+    {
+	if (do_swap_and_transpose)
+	{
+	    /* workspace: Iwork (C->ncol), which is A->nrow since C=(B'*A') */
+	    C2 = CHOLMOD(ptranspose) (C, values, NULL, NULL, 0, Common) ;
+	    CHOLMOD(free_sparse) (&C, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		/* out of memory */
+		ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common));
+		return (NULL) ;
+	    }
+	    C = C2 ;
+	}
+	else
+	{
+	    /* workspace: Iwork (max (C->nrow,C->ncol)) */
+	    if (!CHOLMOD(sort) (C, Common))
+	    {
+		/* out of memory */
+		CHOLMOD(free_sparse) (&C, Common) ;
+		ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common));
+		return (NULL) ;
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (CHOLMOD(dump_sparse) (C, "ssmult", Common) >= 0) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, values ? n1:0, Common)) ;
+    return (C) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_submatrix.c b/src/CHOLMOD/MatrixOps/cholmod_submatrix.c
new file mode 100644
index 0000000..a412053
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_submatrix.c
@@ -0,0 +1,425 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_submatrix ========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* C = A (rset,cset), where C becomes length(rset)-by-length(cset) in dimension.
+ * rset and cset can have duplicate entries.  A and C must be unsymmetric.   C
+ * is packed.  If the sorted flag is TRUE on input, or rset is sorted and A is
+ * sorted, then C is sorted; otherwise C is unsorted.
+ *
+ * A NULL rset or cset means "[ ]" in MATLAB notation.
+ * If the length of rset or cset is negative, it denotes ":" in MATLAB notation.
+ *
+ * For permuting a matrix, this routine is an alternative to cholmod_ptranspose
+ * (which permutes and transposes a matrix and can work on symmetric matrices).
+ *
+ * The time taken by this routine is O(A->nrow) if the Common workspace needs
+ * to be initialized, plus O(C->nrow + C->ncol + nnz (A (:,cset))).  Thus, if C
+ * is small and the workspace is not initialized, the time can be dominated by
+ * the call to cholmod_allocate_work.  However, once the workspace is
+ * allocated, subsequent calls take less time.
+ *
+ * workspace:  Iwork (max (A->nrow + length (rset), length (cset))).
+ *	allocates temporary copy of C if it is to be returned sorted.
+ *
+ * Future work:  A common case occurs where A has sorted columns, and rset is in
+ * the form lo:hi in MATLAB notation.  This routine could exploit that case
+ * to run even faster when the matrix is sorted, particularly when lo is small.
+ *
+ * Only pattern and real matrices are supported.  Complex and zomplex matrices
+ * are supported only when "values" is FALSE.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+/* ========================================================================== */
+/* === check_subset ========================================================= */
+/* ========================================================================== */
+
+/* Check the rset or cset, and return TRUE if valid, FALSE if invalid */
+
+static int check_subset (Int *set, Int len, Int n)
+{
+    Int k ;
+    if (set == NULL)
+    {
+	return (TRUE) ;
+    }
+    for (k = 0 ; k < len ; k++)
+    {
+	if (set [k] < 0 || set [k] >= n)
+	{
+	    return (FALSE) ;
+	}
+    }
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_submatrix ==================================================== */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(submatrix)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to subreference */
+    Int *rset,		/* set of row indices, duplicates OK */
+    SuiteSparse_long rsize,	/* size of rset, or -1 for ":" */
+    Int *cset,		/* set of column indices, duplicates OK */
+    SuiteSparse_long csize,	/* size of cset, or -1 for ":" */
+    int values,		/* if TRUE compute the numerical values of C */
+    int sorted,		/* if TRUE then return C with sorted columns */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double aij = 0 ;
+    double *Ax, *Cx ;
+    Int *Ap, *Ai, *Anz, *Ci, *Cp, *Head, *Rlen, *Rnext, *Iwork ;
+    cholmod_sparse *C ;
+    Int packed, ancol, anrow, cnrow, cncol, nnz, i, j, csorted, ilast, p,
+	pend, pdest, ci, cj, head, nr, nc ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    values = (values && (A->xtype != CHOLMOD_PATTERN)) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->stype != 0)
+    {
+	/* A must be unsymmetric */
+	ERROR (CHOLMOD_INVALID, "symmetric upper or lower case not supported") ;
+	return (NULL) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    ancol = A->ncol ;
+    anrow = A->nrow ;
+    nr = rsize ;
+    nc = csize ;
+    if (rset == NULL)
+    {
+	/* nr = 0 denotes rset = [ ], nr < 0 denotes rset = 0:anrow-1 */
+	nr = (nr < 0) ? (-1) : 0 ;
+    }
+    if (cset == NULL)
+    {
+	/* nr = 0 denotes cset = [ ], nr < 0 denotes cset = 0:ancol-1 */
+	nc = (nc < 0) ? (-1) : 0 ;
+    }
+    cnrow = (nr < 0) ? anrow : nr ;  /* negative rset means rset = 0:anrow-1 */
+    cncol = (nc < 0) ? ancol : nc ;  /* negative cset means cset = 0:ancol-1 */
+
+    if (nr < 0 && nc < 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* C = A (:,:), use cholmod_copy instead */
+	/* ------------------------------------------------------------------ */
+
+	/* workspace: Iwork (max (C->nrow,C->ncol)) */
+	PRINT1 (("submatrix C = A (:,:)\n")) ;
+	C = CHOLMOD(copy) (A, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (NULL) ;
+	}
+	return (C) ;
+    }
+    PRINT1 (("submatrix nr "ID" nc "ID" Cnrow "ID" Cncol "ID""
+	    "  Anrow "ID" Ancol "ID"\n", nr, nc, cnrow, cncol, anrow, ancol)) ;
+
+    /* s = MAX3 (anrow+MAX(0,nr), cncol, cnrow) ; */
+    s = CHOLMOD(add_size_t) (anrow, MAX (0,nr), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (NULL) ;
+    }
+    s = MAX3 (s, ((size_t) cncol), ((size_t) cnrow)) ;
+
+    CHOLMOD(allocate_work) (anrow, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    packed = A->packed ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Head  = Common->Head ;	    /* size anrow */
+    Iwork = Common->Iwork ;
+    Rlen  = Iwork ;		    /* size anrow (i/i/l) */
+    Rnext = Iwork + anrow ;	    /* size nr (i/i/l), not used if nr < 0 */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct inverse of rset and compute nnz (C) */
+    /* ---------------------------------------------------------------------- */
+
+    PRINT1 (("nr "ID" nc "ID"\n", nr, nc)) ;
+    PRINT1 (("anrow "ID" ancol "ID"\n", anrow, ancol)) ;
+    PRINT1 (("cnrow "ID" cncol "ID"\n", cnrow, cncol)) ;
+    DEBUG (for (i = 0 ; i < nr ; i++) PRINT2 (("rset ["ID"] = "ID"\n",
+		    i, rset [i])));
+    DEBUG (for (i = 0 ; i < nc ; i++) PRINT2 (("cset ["ID"] = "ID"\n",
+		    i, cset [i])));
+
+    /* C is sorted if A and rset are sorted, or if C has one row or less */
+    csorted = A->sorted || (cnrow <= 1) ;
+
+    if (!check_subset (rset, nr, anrow))
+    {
+	ERROR (CHOLMOD_INVALID, "invalid rset") ;
+	return (NULL) ;
+    }
+
+    if (!check_subset (cset, nc, ancol))
+    {
+	ERROR (CHOLMOD_INVALID, "invalid cset") ;
+	return (NULL) ;
+    }
+
+    nnz = 0 ;
+    if (nr < 0)
+    {
+	/* C = A (:,cset) where cset = [ ] or cset is not empty */
+	ASSERT (IMPLIES (cncol > 0, cset != NULL)) ;
+	for (cj = 0 ; cj < cncol ; cj++)
+	{
+	    /* construct column cj of C, which is column j of A */
+	    j = cset [cj] ;
+	    nnz += (packed) ? (Ap [j+1] - Ap [j]) : MAX (0, Anz [j]) ;
+	}
+    }
+    else
+    {
+	/* C = A (rset,cset), where rset is not empty but cset might be empty */
+	/* create link lists in reverse order to preserve natural order */
+	ilast = anrow ;
+	for (ci = nr-1 ; ci >= 0 ; ci--)
+	{
+	    /* row i of A becomes row ci of C; add ci to ith link list */
+	    i = rset [ci] ;
+	    head = Head [i] ;
+	    Rlen [i] = (head == EMPTY) ? 1 : (Rlen [i] + 1) ;
+	    Rnext [ci] = head ;
+	    Head [i] = ci ;
+	    if (i > ilast)
+	    {
+		/* row indices in columns of C will not be sorted */
+		csorted = FALSE ;
+	    }
+	    ilast = i ;
+	}
+
+#ifndef NDEBUG
+	for (i = 0 ; i < anrow ; i++)
+	{
+	    Int k = 0 ;
+	    Int rlen = (Head [i] != EMPTY) ? Rlen [i] : -1 ;
+	    PRINT1 (("Row "ID" Rlen "ID": ", i, rlen)) ;
+	    for (ci = Head [i] ; ci != EMPTY ; ci = Rnext [ci])
+	    {
+		k++ ;
+		PRINT2 ((""ID" ", ci)) ;
+	    }
+	    PRINT1 (("\n")) ;
+	    ASSERT (IMPLIES (Head [i] != EMPTY, k == Rlen [i])) ;
+	}
+#endif
+
+	/* count nonzeros in C */
+	for (cj = 0 ; cj < cncol ; cj++)
+	{
+	    /* count rows in column cj of C, which is column j of A */
+	    j = (nc < 0) ? cj : (cset [cj]) ;
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		/* row i of A becomes multiple rows (ci) of C */
+		i = Ai [p] ;
+		ASSERT (i >= 0 && i < anrow) ;
+		if (Head [i] != EMPTY)
+		{
+		    nnz += Rlen [i] ;
+		}
+	    }
+	}
+    }
+    PRINT1 (("nnz (C) "ID"\n", nnz)) ;
+
+    /* rset and cset are now valid */
+    DEBUG (CHOLMOD(dump_subset) (rset, rsize, anrow, "rset", Common)) ;
+    DEBUG (CHOLMOD(dump_subset) (cset, csize, ancol, "cset", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_sparse) (cnrow, cncol, nnz, csorted, TRUE, 0,
+	    values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	for (i = 0 ; i < anrow ; i++)
+	{
+	    Head [i] = EMPTY ;
+	}
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+	return (NULL) ;
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = A (rset,cset) */
+    /* ---------------------------------------------------------------------- */
+
+    pdest = 0 ;
+    if (nnz == 0)
+    {
+	/* C has no nonzeros */
+	for (cj = 0 ; cj <= cncol ; cj++)
+	{
+	    Cp [cj] = 0 ;
+	}
+    }
+    else if (nr < 0)
+    {
+	/* C = A (:,cset), where cset is not empty */
+	for (cj = 0 ; cj < cncol ; cj++)
+	{
+	    /* construct column cj of C, which is column j of A */
+	    PRINT1 (("construct cj = j = "ID"\n", cj)) ;
+	    j = cset [cj] ;
+	    Cp [cj] = pdest ;
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		Ci [pdest] = Ai [p] ;
+		if (values)
+		{
+		    Cx [pdest] = Ax [p] ;
+		}
+		pdest++ ;
+		ASSERT (pdest <= nnz) ;
+	    }
+	}
+    }
+    else
+    {
+	/* C = A (rset,cset), where rset is not empty but cset might be empty */
+	for (cj = 0 ; cj < cncol ; cj++)
+	{
+	    /* construct column cj of C, which is column j of A */
+	    PRINT1 (("construct cj = "ID"\n", cj)) ;
+	    j = (nc < 0) ? cj : (cset [cj]) ;
+	    PRINT1 (("cj = "ID"\n", j)) ;
+	    Cp [cj] = pdest ;
+	    p = Ap [j] ;
+	    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+	    for ( ; p < pend ; p++)
+	    {
+		/* row (Ai [p]) of A becomes multiple rows (ci) of C */
+		PRINT2 (("i: "ID" becomes: ", Ai [p])) ;
+		if (values)
+		{
+		    aij = Ax [p] ;
+		}
+		for (ci = Head [Ai [p]] ; ci != EMPTY ; ci = Rnext [ci])
+		{
+		    PRINT3 ((""ID" ", ci)) ;
+		    Ci [pdest] = ci ;
+		    if (values)
+		    {
+			Cx [pdest] = aij ;
+		    }
+		    pdest++ ;
+		    ASSERT (pdest <= nnz) ;
+		}
+		PRINT2 (("\n")) ;
+	    }
+	}
+    }
+    Cp [cncol] = pdest ;
+    ASSERT (nnz == pdest) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace */
+    /* ---------------------------------------------------------------------- */
+
+    for (ci = 0 ; ci < nr ; ci++)
+    {
+	Head [rset [ci]] = EMPTY ;
+    }
+
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* sort C, if requested */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C , "C before sort", Common) >= 0) ;
+
+    if (sorted && !csorted)
+    {
+	/* workspace: Iwork (max (C->nrow,C->ncol)) */
+	if (!CHOLMOD(sort) (C, Common))
+	{
+	    /* out of memory */
+	    CHOLMOD(free_sparse) (&C, Common) ;
+	    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+	    return (NULL) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return result */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_sparse) (C , "Final C", Common) >= 0) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (C) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_symmetry.c b/src/CHOLMOD/MatrixOps/cholmod_symmetry.c
new file mode 100644
index 0000000..6bda9dc
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_symmetry.c
@@ -0,0 +1,488 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_symmetry =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Determines if a sparse matrix is rectangular, unsymmetric, symmetric,
+ * skew-symmetric, or Hermitian.  It does so by looking at its numerical values
+ * of both upper and lower triangular parts of a CHOLMOD "unsymmetric"
+ * matrix, where A->stype == 0.  The transpose of A is NOT constructed.
+ *
+ * If not unsymmetric, it also determines if the matrix has a diagonal whose
+ * entries are all real and positive (and thus a candidate for sparse Cholesky
+ * if A->stype is changed to a nonzero value).
+ *
+ * Note that a Matrix Market "general" matrix is either rectangular or
+ * unsymmetric.
+ *
+ * The row indices in the column of each matrix MUST be sorted for this function
+ * to work properly (A->sorted must be TRUE).  This routine returns EMPTY if
+ * A->stype is not zero, or if A->sorted is FALSE.  The exception to this rule
+ * is if A is rectangular.
+ *
+ * If option == 0, then this routine returns immediately when it finds a
+ * non-positive diagonal entry (or one with nonzero imaginary part).   If the
+ * matrix is not a candidate for sparse Cholesky, it returns the value
+ * CHOLMOD_MM_UNSYMMETRIC, even if the matrix might in fact be symmetric or
+ * Hermitian.
+ *
+ * This routine is useful inside the MATLAB backslash, which must look at an
+ * arbitrary matrix (A->stype == 0) and determine if it is a candidate for
+ * sparse Cholesky.  In that case, option should be 0.
+ *
+ * This routine is also useful when writing a MATLAB matrix to a file in
+ * Rutherford/Boeing or Matrix Market format.  Those formats require a
+ * determination as to the symmetry of the matrix, and thus this routine should
+ * not return upon encountering the first non-positive diagonal.  In this case,
+ * option should be 1.
+ *
+ * If option is 2, this function can be used to compute the numerical and
+ * pattern symmetry, where 0 is a completely unsymmetric matrix, and 1 is a
+ * perfectly symmetric matrix.  This option is used when computing the following
+ * statistics for the matrices in the UF Sparse Matrix Collection.
+ *
+ *	numerical symmetry: number of matched offdiagonal nonzeros over
+ *	the total number of offdiagonal entries.  A real entry A(i,j), i ~= j,
+ *	is matched if A (j,i) == A (i,j), but this is only counted if both
+ *	A(j,i) and A(i,j) are nonzero.  This does not depend on Z.
+ *	(If A is complex, then the above test is modified; A (i,j) is matched
+ *	if conj (A (j,i)) == A (i,j)).
+ *
+ *	Then numeric symmetry = xmatched / nzoffdiag, or 1 if nzoffdiag = 0.
+ *  
+ *	pattern symmetry: number of matched offdiagonal entries over the
+ *	total number of offdiagonal entries.  An entry A(i,j), i ~= j, is
+ *	matched if A (j,i) is also an entry.
+ *
+ *	Then pattern symmetry = pmatched / nzoffdiag, or 1 if nzoffdiag = 0.
+ *  
+ * The symmetry of a matrix with no offdiagonal entries is equal to 1.
+ *
+ * A workspace of size ncol integers is allocated; EMPTY is returned if this
+ * allocation fails.
+ *
+ * Summary of return values:
+ *
+ *  EMPTY (-1)			    out of memory, stype not zero, A not sorted
+ *  CHOLMOD_MM_RECTANGULAR 1	    A is rectangular
+ *  CHOLMOD_MM_UNSYMMETRIC 2	    A is unsymmetric
+ *  CHOLMOD_MM_SYMMETRIC 3	    A is symmetric, but with non-pos. diagonal
+ *  CHOLMOD_MM_HERMITIAN 4	    A is Hermitian, but with non-pos. diagonal
+ *  CHOLMOD_MM_SKEW_SYMMETRIC 5	    A is skew symmetric
+ *  CHOLMOD_MM_SYMMETRIC_POSDIAG 6  A is symmetric with positive diagonal
+ *  CHOLMOD_MM_HERMITIAN_POSDIAG 7  A is Hermitian with positive diagonal
+ *
+ * See also the spsym mexFunction, which is a MATLAB interface for this code.
+ *
+ * If the matrix is a candidate for sparse Cholesky, it will return a result
+ * CHOLMOD_MM_SYMMETRIC_POSDIAG if real, or CHOLMOD_MM_HERMITIAN_POSDIAG if
+ * complex.  Otherwise, it will return a value less than this.  This is true
+ * regardless of the value of the option parameter.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === get_value ============================================================ */
+/* ========================================================================== */
+
+/* Get the pth value in the matrix. */
+
+static void get_value
+(
+    double *Ax,	    /* real values, or real/imag. for CHOLMOD_COMPLEX type */
+    double *Az,	    /* imaginary values for CHOLMOD_ZOMPLEX type */
+    Int p,	    /* get the pth entry */
+    Int xtype,	    /* A->xtype: pattern, real, complex, or zomplex */
+    double *x,	    /* the real part */
+    double *z	    /* the imaginary part */
+)
+{
+    switch (xtype)
+    {
+	case CHOLMOD_PATTERN:
+	    *x = 1 ;
+	    *z = 0 ;
+	    break ;
+
+	case CHOLMOD_REAL:
+	    *x = Ax [p] ;
+	    *z = 0 ;
+	    break ;
+
+	case CHOLMOD_COMPLEX:
+	    *x = Ax [2*p] ;
+	    *z = Ax [2*p+1] ;
+	    break ;
+
+	case CHOLMOD_ZOMPLEX:
+	    *x = Ax [p] ;
+	    *z = Az [p] ;
+	    break ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_symmetry ===================================================== */
+/* ========================================================================== */
+
+/* Determine the symmetry of a matrix, and check its diagonal.
+ *
+ * option 0:  Do not count # of matched pairs.  Quick return if the
+ *	      the matrix has a zero, negative, or imaginary diagonal entry.
+ *
+ * option 1:  Do not count # of matched pairs.  Do not return quickly if
+ *	      the matrix has a zero, negative, or imaginary diagonal entry.
+ *	The result 1 to 7 is accurately computed:
+ *
+ *	EMPTY (-1)		out of memory, stype not zero, A not sorted
+ *	CHOLMOD_MM_RECTANGULAR 1	A is rectangular
+ *	CHOLMOD_MM_UNSYMMETRIC 2	A is unsymmetric
+ *	CHOLMOD_MM_SYMMETRIC 3		A is symmetric, with non-pos. diagonal
+ *	CHOLMOD_MM_HERMITIAN 4		A is Hermitian, with non-pos. diagonal
+ *	CHOLMOD_MM_SKEW_SYMMETRIC 5	A is skew symmetric
+ *	CHOLMOD_MM_SYMMETRIC_POSDIAG 6  is symmetric with positive diagonal
+ *	CHOLMOD_MM_HERMITIAN_POSDIAG 7  A is Hermitian with positive diagonal
+ *
+ *	The routine returns as soon as the above is determined (that is, it
+ *	can return as soon as it determines the matrix is unsymmetric).
+ *
+ * option 2:  All of the above, but also compute the number of matched off-
+ *	diagonal entries (of two types).  xmatched is the number of 
+ *	nonzero entries for which A(i,j) = conj(A(j,i)).  pmatched is
+ *	the number of entries (i,j) for which A(i,j) and A(j,i) are both in
+ *	the pattern of A (the value doesn't matter).  nzoffdiag is the total
+ *	number of off-diagonal entries in the pattern.  nzdiag is the number of
+ *	diagonal entries in the pattern.
+ *
+ * With option 0 or 1, or if the matrix is rectangular, xmatched, pmatched,
+ * nzoffdiag, and nzdiag are not computed.
+ *
+ * Note that a matched pair, A(i,j) and A(j,i) for i != j, is counted twice
+ * (once per entry).
+ */
+
+int CHOLMOD(symmetry)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,
+    int option,			/* option 0, 1, or 2 (see above) */
+    /* ---- output --- */	/* outputs ignored if any are NULL */
+    Int *p_xmatched,		/* # of matched numerical entries */
+    Int *p_pmatched,		/* # of matched entries in pattern */
+    Int *p_nzoffdiag,		/* # of off diagonal entries */
+    Int *p_nzdiag,		/* # of diagonal entries */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double aij_real = 0, aij_imag = 0, aji_real = 0, aji_imag = 0 ;
+    double *Ax, *Az ;
+    Int *Ap, *Ai, *Anz, *munch ;
+    Int packed, nrow, ncol, xtype, is_symmetric, is_skew, is_hermitian, posdiag,
+	j, p, pend, i, piend, result, xmatched, pmatched, nzdiag, i2, found ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+    ASSERT (CHOLMOD(dump_sparse) (A, "cholmod_symmetry", Common) >= 0) ;
+
+    if (p_xmatched == NULL || p_pmatched == NULL
+	|| p_nzoffdiag == NULL || p_nzdiag == NULL)
+    {
+	/* option 2 is not performed if any output parameter is NULL */
+	option = MAX (option, 1) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    packed = A->packed ;
+    ncol = A->ncol ;
+    nrow = A->nrow ;
+    xtype = A->xtype ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check if rectangular, unsorted, or stype is not zero */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrow != ncol)
+    {
+	/* matrix is rectangular */
+	return (CHOLMOD_MM_RECTANGULAR) ;
+    }
+
+    if (!(A->sorted) || A->stype != 0)
+    {
+	/* this function cannot determine the type or symmetry */
+	return (EMPTY) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* this function requires uninitialized Int workspace of size ncol */
+    CHOLMOD(allocate_work) (0, ncol, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (EMPTY) ;
+    }
+
+    munch = Common->Iwork ;	    /* the munch array is size ncol */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine symmetry of a square matrix */
+    /* ---------------------------------------------------------------------- */
+
+    /* a complex or zomplex matrix is Hermitian until proven otherwise */
+    is_hermitian = (xtype >= CHOLMOD_COMPLEX) ;
+
+    /* any matrix is symmetric until proven otherwise */
+    is_symmetric = TRUE ;
+
+    /* a non-pattern matrix is skew-symmetric until proven otherwise */
+    is_skew = (xtype != CHOLMOD_PATTERN) ;
+
+    /* a matrix has positive diagonal entries until proven otherwise */
+    posdiag = TRUE ;
+
+    /* munch pointers start at the top of each column */
+    for (j = 0 ; j < ncol ; j++)
+    {
+	munch [j] = Ap [j] ;
+    }
+
+    xmatched = 0 ;
+    pmatched = 0 ;
+    nzdiag = 0 ;
+
+    for (j = 0 ; j < ncol ; j++)	/* examine each column of A */
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* look at the entire munch column j */
+	/* ------------------------------------------------------------------ */
+
+	/* start at the munch point of column j, and go to end of the column */
+	p = munch [j] ;
+	pend = (packed) ? (Ap [j+1]) : (Ap [j] + Anz [j]) ;
+
+	for ( ; p < pend ; p++)
+	{
+	    /* get the row index of A(i,j) */
+	    i = Ai [p] ;
+
+	    if (i < j)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* A(i,j) in triu(A), but matching A(j,i) not in tril(A) */
+		/* ---------------------------------------------------------- */
+
+		/* entry A(i,j) is unmatched; it appears in the upper triangular
+		 * part, but not the lower triangular part.  The matrix is
+		 * unsymmetric. */
+		is_hermitian = FALSE ;
+		is_symmetric = FALSE ;
+		is_skew = FALSE ;
+
+	    }
+	    else if (i == j)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* the diagonal A(j,j) is present; check its value */
+		/* ---------------------------------------------------------- */
+
+		get_value (Ax, Az, p, xtype, &aij_real, &aij_imag) ;
+		if (aij_real != 0. || aij_imag != 0.)
+		{
+		    /* diagonal is nonzero; matrix is not skew-symmetric */
+		    nzdiag++ ;
+		    is_skew = FALSE ;
+		}
+		if (aij_real <= 0. || aij_imag != 0.)
+		{
+		    /* diagonal negative or imaginary; not chol candidate */
+		    posdiag = FALSE ;
+		}
+		if (aij_imag != 0.)
+		{
+		    /* imaginary part is present; not Hermitian */
+		    is_hermitian = FALSE ;
+		}
+
+	    }
+	    else /* i > j */
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* consider column i, up to and including row j */
+		/* ---------------------------------------------------------- */
+
+		/* munch the entry at top of column i up to and incl row j */
+		piend = (packed) ? (Ap [i+1]) : (Ap [i] + Anz [i]) ;
+
+		found = FALSE ;
+
+		for ( ; munch [i] < piend ; munch [i]++)
+		{
+
+		    i2 = Ai [munch [i]] ;
+
+		    if (i2 < j)
+		    {
+
+			/* -------------------------------------------------- */
+			/* A(i2,i) in triu(A) but A(i,i2) not in tril(A) */
+			/* -------------------------------------------------- */
+
+			/* The matrix is unsymmetric. */
+			is_hermitian = FALSE ;
+			is_symmetric = FALSE ;
+			is_skew = FALSE ;
+
+		    }
+		    else if (i2 == j)
+		    {
+
+			/* -------------------------------------------------- */
+			/* both A(i,j) and A(j,i) exist in the matrix */
+			/* -------------------------------------------------- */
+
+			/* this is one more matching entry in the pattern */
+			pmatched += 2 ;
+			found = TRUE ;
+
+			/* get the value of A(i,j) */
+			get_value (Ax, Az, p, xtype, &aij_real, &aij_imag) ;
+
+			/* get the value of A(j,i) */
+			get_value (Ax, Az, munch [i],
+			    xtype, &aji_real, &aji_imag) ;
+
+			/* compare A(i,j) with A(j,i) */
+			if (aij_real != aji_real || aij_imag != aji_imag)
+			{
+			    /* the matrix cannot be symmetric */
+			    is_symmetric = FALSE ;
+			}
+			if (aij_real != -aji_real || aij_imag != aji_imag)
+			{
+			    /* the matrix cannot be skew-symmetric */
+			    is_skew = FALSE ;
+			}
+			if (aij_real != aji_real || aij_imag != -aji_imag)
+			{
+			    /* the matrix cannot be Hermitian */
+			    is_hermitian = FALSE ;
+			}
+			else
+			{
+			    /* A(i,j) and A(j,i) are numerically matched */
+			    xmatched += 2 ;
+			}
+
+		    }
+		    else /* i2 > j */
+		    {
+
+			/* -------------------------------------------------- */
+			/* entry A(i2,i) is not munched; consider it later */
+			/* -------------------------------------------------- */
+
+			break ;
+		    }
+		}
+
+		if (!found)
+		{
+		    /* A(i,j) in tril(A) but A(j,i) not in triu(A).
+		     * The matrix is unsymmetric. */
+		    is_hermitian = FALSE ;
+		    is_symmetric = FALSE ;
+		    is_skew = FALSE ;
+		}
+	    }
+
+	    if (option < 2 && !(is_symmetric || is_skew || is_hermitian))
+	    {
+		/* matrix is unsymmetric; terminate the test */
+		return (CHOLMOD_MM_UNSYMMETRIC) ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* quick return if not Cholesky candidate */
+	/* ------------------------------------------------------------------ */
+
+	if (option < 1 && (!posdiag || nzdiag < ncol))
+	{
+	    /* Diagonal entry not present, or present but negative or with
+	     * nonzero imaginary part.  Quick return for option 0. */
+	    return (CHOLMOD_MM_UNSYMMETRIC) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the results */
+    /* ---------------------------------------------------------------------- */
+
+    if (nzdiag < ncol)
+    {
+        /* not all diagonal entries are present */
+        posdiag = FALSE ;
+    }
+
+    if (option >= 2)
+    {
+	*p_xmatched = xmatched ;
+	*p_pmatched = pmatched ;
+	*p_nzoffdiag = CHOLMOD(nnz) (A, Common) - nzdiag ;
+	*p_nzdiag = nzdiag ;
+    }
+
+    result = CHOLMOD_MM_UNSYMMETRIC ;
+    if (is_hermitian)
+    {
+	/* complex Hermitian matrix, with either pos. or non-pos. diagonal */
+	result = posdiag ? CHOLMOD_MM_HERMITIAN_POSDIAG : CHOLMOD_MM_HERMITIAN ;
+    }
+    else if (is_symmetric)
+    {
+	/* real or complex symmetric matrix, with pos. or non-pos. diagonal */
+	result = posdiag ? CHOLMOD_MM_SYMMETRIC_POSDIAG : CHOLMOD_MM_SYMMETRIC ;
+    }
+    else if (is_skew)
+    {
+	/* real or complex skew-symmetric matrix */
+	result = CHOLMOD_MM_SKEW_SYMMETRIC ;
+    }
+    return (result) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/cholmod_vertcat.c b/src/CHOLMOD/MatrixOps/cholmod_vertcat.c
new file mode 100644
index 0000000..4199a91
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/cholmod_vertcat.c
@@ -0,0 +1,201 @@
+/* ========================================================================== */
+/* === MatrixOps/cholmod_vertcat ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Vertical concatenation, C = [A ; B] in MATLAB notation.
+ *
+ * A and B can be up/lo/unsym; C is unsymmetric and packed.
+ * A and B must have the same number of columns.
+ * C is sorted if both A and B are sorted.
+ *
+ * workspace: Iwork (max (A->nrow, A->ncol, B->nrow, B->ncol)).
+ *	allocates temporary copies of A and B if they are symmetric.
+ *
+ * Only pattern and real matrices are supported.  Complex and zomplex matrices
+ * are supported only if "values" is FALSE.
+ */
+
+#ifndef NMATRIXOPS
+
+#include "cholmod_internal.h"
+#include "cholmod_matrixops.h"
+
+
+/* ========================================================================== */
+/* === cholmod_vertcat ====================================================== */
+/* ========================================================================== */
+
+cholmod_sparse *CHOLMOD(vertcat)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* left matrix to concatenate */
+    cholmod_sparse *B,	/* right matrix to concatenate */
+    int values,		/* if TRUE compute the numerical values of C */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Ax, *Bx, *Cx ;
+    Int *Ap, *Ai, *Anz, *Bp, *Bi, *Bnz, *Cp, *Ci ;
+    cholmod_sparse *C, *A2, *B2 ;
+    Int apacked, bpacked, anrow, bnrow, ncol, nrow, anz, bnz, nz, j, p, pend,
+	pdest ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (NULL) ;
+    RETURN_IF_NULL (A, NULL) ;
+    RETURN_IF_NULL (B, NULL) ;
+    values = values &&
+	(A->xtype != CHOLMOD_PATTERN) && (B->xtype != CHOLMOD_PATTERN) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    RETURN_IF_XTYPE_INVALID (B, CHOLMOD_PATTERN,
+	    values ? CHOLMOD_REAL : CHOLMOD_ZOMPLEX, NULL) ;
+    if (A->ncol != B->ncol)
+    {
+	/* A and B must have the same number of columns */
+	ERROR (CHOLMOD_INVALID, "A and B must have same # of columns") ;
+	return (NULL) ;
+    }
+    /* A and B must have the same numerical type if values is TRUE (both must
+     * be CHOLMOD_REAL, this is implicitly checked above) */
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    anrow = A->nrow ;
+    bnrow = B->nrow ;
+    ncol = A->ncol ;
+    CHOLMOD(allocate_work) (0, MAX3 (anrow, bnrow, ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (NULL) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* convert A to unsymmetric, if necessary */
+    A2 = NULL ;
+    if (A->stype != 0)
+    {
+	/* workspace: Iwork (max (A->nrow,A->ncol)) */
+	A2 = CHOLMOD(copy) (A, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    return (NULL) ;
+	}
+	A = A2 ;
+    }
+
+    /* convert B to unsymmetric, if necessary */
+    B2 = NULL ;
+    if (B->stype != 0)
+    {
+	/* workspace: Iwork (max (B->nrow,B->ncol)) */
+	B2 = CHOLMOD(copy) (B, 0, values, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    CHOLMOD(free_sparse) (&A2, Common) ;
+	    return (NULL) ;
+	}
+	B = B2 ;
+    }
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    apacked = A->packed ;
+
+    Bp  = B->p ;
+    Bnz = B->nz ;
+    Bi  = B->i ;
+    Bx  = B->x ;
+    bpacked = B->packed ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate C */
+    /* ---------------------------------------------------------------------- */
+
+    anz = CHOLMOD(nnz) (A, Common) ;
+    bnz = CHOLMOD(nnz) (B, Common) ;
+    nrow = anrow + bnrow ;
+    nz = anz + bnz ;
+
+    C = CHOLMOD(allocate_sparse) (nrow, ncol, nz, A->sorted && B->sorted, TRUE,
+	    0, values ? A->xtype : CHOLMOD_PATTERN, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	CHOLMOD(free_sparse) (&A2, Common) ;
+	CHOLMOD(free_sparse) (&B2, Common) ;
+	return (NULL) ;
+    }
+    Cp = C->p ;
+    Ci = C->i ;
+    Cx = C->x ;
+
+    /* ---------------------------------------------------------------------- */
+    /* C = [A ; B] */
+    /* ---------------------------------------------------------------------- */
+
+    pdest = 0 ;
+    for (j = 0 ; j < ncol ; j++)
+    {
+	/* attach A(:,j) as the first part of C(:,j) */
+	p = Ap [j] ;
+	pend = (apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+	Cp [j] = pdest ;
+	for ( ; p < pend ; p++)
+	{
+	    Ci [pdest] = Ai [p] ;
+	    if (values)
+	    {
+		Cx [pdest] = Ax [p] ;
+	    }
+	    pdest++ ;
+	}
+
+	/* attach B(:,j) as the second part of C(:,j) */
+	p = Bp [j] ;
+	pend = (bpacked) ? (Bp [j+1]) : (p + Bnz [j]) ;
+	for ( ; p < pend ; p++)
+	{
+	    Ci [pdest] = Bi [p] + anrow ;
+	    if (values)
+	    {
+		Cx [pdest] = Bx [p] ;
+	    }
+	    pdest++ ;
+	}
+    }
+    Cp [ncol] = pdest ;
+    ASSERT (pdest == nz) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the unsymmetric copies of A and B, and return C */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&A2, Common) ;
+    CHOLMOD(free_sparse) (&B2, Common) ;
+    return (C) ;
+}
+#endif
diff --git a/src/CHOLMOD/MatrixOps/gpl.txt b/src/CHOLMOD/MatrixOps/gpl.txt
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/gpl.txt
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/CHOLMOD/MatrixOps/t_cholmod_sdmult.c b/src/CHOLMOD/MatrixOps/t_cholmod_sdmult.c
new file mode 100644
index 0000000..7ddd3b6
--- /dev/null
+++ b/src/CHOLMOD/MatrixOps/t_cholmod_sdmult.c
@@ -0,0 +1,726 @@
+/* ========================================================================== */
+/* === MatrixOps/t_cholmod_sdmult =========================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/MatrixOps Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/MatrixOps Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_sdmult */
+
+#include "cholmod_template.h"
+
+#undef ADVANCE
+
+#ifdef REAL
+#define ADVANCE(x,z,d) x += d
+#elif defined (COMPLEX)
+#define ADVANCE(x,z,d) x += 2*d
+#else
+#define ADVANCE(x,z,d) x += d ; z += d
+#endif
+
+/* ========================================================================== */
+/* === t_cholmod_sdmult ===================================================== */
+/* ========================================================================== */
+
+static void TEMPLATE (cholmod_sdmult)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* sparse matrix to multiply */
+    int transpose,	/* use A if 0, or A' otherwise */
+    double alpha [2],   /* scale factor for A */
+    double beta [2],    /* scale factor for Y */
+    cholmod_dense *X,	/* dense matrix to multiply */
+    /* ---- in/out --- */
+    cholmod_dense *Y,	/* resulting dense matrix */
+    /* -- workspace -- */
+    double *W		/* size 4*nx if needed, twice that for c/zomplex case */
+)
+{
+
+    double yx [8], xx [8], ax [2] ;
+#ifdef ZOMPLEX
+    double yz [4], xz [4], az [1] ;
+    double betaz [1], alphaz [1] ;
+#endif
+
+    double *Ax, *Az, *Xx, *Xz, *Yx, *Yz, *w, *Wz ;
+    Int *Ap, *Ai, *Anz ;
+    size_t nx, ny, dx, dy ;
+    Int packed, nrow, ncol, j, k, p, pend, kcol, i ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef ZOMPLEX
+    betaz  [0] = beta  [1] ;
+    alphaz [0] = alpha [1] ;
+#endif
+
+    ny = transpose ? A->ncol : A->nrow ;	/* required length of Y */
+    nx = transpose ? A->nrow : A->ncol ;	/* required length of X */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    Ap  = A->p ;
+    Anz = A->nz ;
+    Ai  = A->i ;
+    Ax  = A->x ;
+    Az  = A->z ;
+    packed = A->packed ;
+    Xx = X->x ;
+    Xz = X->z ;
+    Yx = Y->x ;
+    Yz = Y->z ;
+    kcol = X->ncol ;
+    dy = Y->d ;
+    dx = X->d ;
+    w = W ;
+    Wz = W + 4*nx ;
+
+    /* ---------------------------------------------------------------------- */
+    /* Y = beta * Y */
+    /* ---------------------------------------------------------------------- */
+
+    if (ENTRY_IS_ZERO (beta, betaz, 0))
+    {
+	for (k = 0 ; k < kcol ; k++)
+	{
+	    for (i = 0 ; i < ((Int) ny) ; i++)
+	    {
+		/* y [i] = 0. ; */
+		CLEAR (Yx, Yz, i) ;
+	    }
+	    /* y += dy ; */
+	    ADVANCE (Yx,Yz,dy) ;
+	}
+    }
+    else if (!ENTRY_IS_ONE (beta, betaz, 0))
+    {
+	for (k = 0 ; k < kcol ; k++)
+	{
+	    for (i = 0 ; i < ((Int) ny) ; i++)
+	    {
+		/* y [i] *= beta [0] ; */
+		MULT (Yx,Yz,i, Yx,Yz,i, beta,betaz, 0) ;
+	    }
+	    /* y += dy ; */
+	    ADVANCE (Yx,Yz,dy) ;
+	}
+    }
+
+    if (ENTRY_IS_ZERO (alpha, alphaz, 0))
+    {
+	/* nothing else to do */
+	return ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* Y += alpha * op(A) * X, where op(A)=A or A' */
+    /* ---------------------------------------------------------------------- */
+
+    Yx = Y->x ;
+    Yz = Y->z ;
+
+    k = 0 ;
+
+    if (A->stype == 0)
+    {
+
+	if (transpose)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* Y += alpha * A' * x, unsymmetric case */
+	    /* -------------------------------------------------------------- */
+
+	    if (kcol % 4 == 1)
+	    {
+
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* yj = 0. ; */
+		    CLEAR (yx, yz, 0) ;
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			/* yj += conj(Ax [p]) * x [Ai [p]] ; */
+			i = Ai [p] ;
+			ASSIGN_CONJ (ax,az,0, Ax,Az,p) ;
+			MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ;
+		    }
+		    /* y [j] += alpha [0] * yj ; */
+		    MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ;
+		}
+		/* y += dy ; */
+		/* x += dx ; */
+		ADVANCE (Yx,Yz,dy) ;
+		ADVANCE (Xx,Xz,dx) ;
+		k++ ;
+
+	    }
+	    else if (kcol % 4 == 2)
+	    {
+
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* yj0 = 0. ; */
+		    /* yj1 = 0. ; */
+		    CLEAR (yx,yz,0) ;
+		    CLEAR (yx,yz,1) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			/* aij = conj (Ax [p]) ; */
+			ASSIGN_CONJ (ax,az,0, Ax,Az,p) ;
+
+			/* yj0 += aij * x [i   ] ; */
+			/* yj1 += aij * x [i+dx] ; */
+			MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ;
+			MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ;
+		    }
+		    /* y [j   ] += alpha [0] * yj0 ; */
+		    /* y [j+dy] += alpha [0] * yj1 ; */
+		    MULTADD (Yx,Yz,j,      alpha,alphaz,0, yx,yz,0) ;
+		    MULTADD (Yx,Yz,j+dy,   alpha,alphaz,0, yx,yz,1) ;
+		}
+		/* y += 2*dy ; */
+		/* x += 2*dx ; */
+		ADVANCE (Yx,Yz,2*dy) ;
+		ADVANCE (Xx,Xz,2*dx) ;
+		k += 2 ;
+
+	    }
+	    else if (kcol % 4 == 3)
+	    {
+
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* yj0 = 0. ; */
+		    /* yj1 = 0. ; */
+		    /* yj2 = 0. ; */
+		    CLEAR (yx,yz,0) ;
+		    CLEAR (yx,yz,1) ;
+		    CLEAR (yx,yz,2) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			/* aij = conj (Ax [p]) ; */
+			ASSIGN_CONJ (ax,az,0, Ax,Az,p) ;
+
+			/* yj0 += aij * x [i     ] ; */
+			/* yj1 += aij * x [i+  dx] ; */
+			/* yj2 += aij * x [i+2*dx] ; */
+			MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ;
+			MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ;
+			MULTADD (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ;
+		    }
+		    /* y [j     ] += alpha [0] * yj0 ; */
+		    /* y [j+  dy] += alpha [0] * yj1 ; */
+		    /* y [j+2*dy] += alpha [0] * yj2 ; */
+		    MULTADD (Yx,Yz,j,      alpha,alphaz,0, yx,yz,0) ;
+		    MULTADD (Yx,Yz,j+dy,   alpha,alphaz,0, yx,yz,1) ;
+		    MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ;
+		}
+		/* y += 3*dy ; */
+		/* x += 3*dx ; */
+		ADVANCE (Yx,Yz,3*dy) ;
+		ADVANCE (Xx,Xz,3*dx) ;
+		k += 3 ;
+	    }
+
+	    for ( ; k < kcol ; k += 4)
+	    {
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* yj0 = 0. ; */
+		    /* yj1 = 0. ; */
+		    /* yj2 = 0. ; */
+		    /* yj3 = 0. ; */
+		    CLEAR (yx,yz,0) ;
+		    CLEAR (yx,yz,1) ;
+		    CLEAR (yx,yz,2) ;
+		    CLEAR (yx,yz,3) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			/* aij = conj(Ax [p]) ; */
+			ASSIGN_CONJ (ax,az,0, Ax,Az,p) ;
+
+			/* yj0 += aij * x [i     ] ; */
+			/* yj1 += aij * x [i+  dx] ; */
+			/* yj2 += aij * x [i+2*dx] ; */
+			/* yj3 += aij * x [i+3*dx] ; */
+			MULTADD (yx,yz,0, ax,az,0, Xx,Xz,i) ;
+			MULTADD (yx,yz,1, ax,az,0, Xx,Xz,i+dx) ;
+			MULTADD (yx,yz,2, ax,az,0, Xx,Xz,i+2*dx) ;
+			MULTADD (yx,yz,3, ax,az,0, Xx,Xz,i+3*dx) ;
+
+		    }
+		    /* y [j     ] += alpha [0] * yj0 ; */
+		    /* y [j+  dy] += alpha [0] * yj1 ; */
+		    /* y [j+2*dy] += alpha [0] * yj2 ; */
+		    /* y [j+3*dy] += alpha [0] * yj3 ; */
+		    MULTADD (Yx,Yz,j,      alpha,alphaz,0, yx,yz,0) ;
+		    MULTADD (Yx,Yz,j+dy,   alpha,alphaz,0, yx,yz,1) ;
+		    MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ;
+		    MULTADD (Yx,Yz,j+3*dy, alpha,alphaz,0, yx,yz,3) ;
+		}
+		/* y += 4*dy ; */
+		/* x += 4*dx ; */
+		ADVANCE (Yx,Yz,4*dy) ;
+		ADVANCE (Xx,Xz,4*dx) ;
+	    }
+
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* Y += alpha * A * x, unsymmetric case */
+	    /* -------------------------------------------------------------- */
+
+	    if (kcol % 4 == 1)
+	    {
+
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /*  xj = alpha [0] * x [j] ; */
+		    MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			/* y [Ai [p]] += Ax [p] * xj ; */
+			i = Ai [p] ;
+			MULTADD (Yx,Yz,i, Ax,Az,p, xx,xz,0) ;
+		    }
+		}
+		/* y += dy ; */
+		/* x += dx ; */
+		ADVANCE (Yx,Yz,dy) ;
+		ADVANCE (Xx,Xz,dx) ;
+		k++ ;
+
+	    }
+	    else if (kcol % 4 == 2)
+	    {
+
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* xj0 = alpha [0] * x [j   ] ; */
+		    /* xj1 = alpha [0] * x [j+dx] ; */
+		    MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+		    MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i   ] += aij * xj0 ; */
+			/* y [i+dy] += aij * xj1 ; */
+			MULTADD (Yx,Yz,i,    ax,az,0, xx,xz,0) ;
+			MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ;
+		    }
+		}
+		/* y += 2*dy ; */
+		/* x += 2*dx ; */
+		ADVANCE (Yx,Yz,2*dy) ;
+		ADVANCE (Xx,Xz,2*dx) ;
+		k += 2 ;
+
+	    }
+	    else if (kcol % 4 == 3)
+	    {
+
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* xj0 = alpha [0] * x [j     ] ; */
+		    /* xj1 = alpha [0] * x [j+  dx] ; */
+		    /* xj2 = alpha [0] * x [j+2*dx] ; */
+		    MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+		    MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ;
+		    MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i     ] += aij * xj0 ; */
+			/* y [i+  dy] += aij * xj1 ; */
+			/* y [i+2*dy] += aij * xj2 ; */
+			MULTADD (Yx,Yz,i,      ax,az,0, xx,xz,0) ;
+			MULTADD (Yx,Yz,i+dy,   ax,az,0, xx,xz,1) ;
+			MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ;
+		    }
+		}
+		/* y += 3*dy ; */
+		/* x += 3*dx ; */
+		ADVANCE (Yx,Yz,3*dy) ;
+		ADVANCE (Xx,Xz,3*dx) ;
+		k += 3 ;
+	    }
+
+	    for ( ; k < kcol ; k += 4)
+	    {
+		for (j = 0 ; j < ncol ; j++)
+		{
+		    /* xj0 = alpha [0] * x [j     ] ; */
+		    /* xj1 = alpha [0] * x [j+  dx] ; */
+		    /* xj2 = alpha [0] * x [j+2*dx] ; */
+		    /* xj3 = alpha [0] * x [j+3*dx] ; */
+		    MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+		    MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ;
+		    MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ;
+		    MULT (xx,xz,3, alpha,alphaz,0, Xx,Xz,j+3*dx) ;
+
+		    p = Ap [j] ;
+		    pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i     ] += aij * xj0 ; */
+			/* y [i+  dy] += aij * xj1 ; */
+			/* y [i+2*dy] += aij * xj2 ; */
+			/* y [i+3*dy] += aij * xj3 ; */
+			MULTADD (Yx,Yz,i,      ax,az,0, xx,xz,0) ;
+			MULTADD (Yx,Yz,i+dy,   ax,az,0, xx,xz,1) ;
+			MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ;
+			MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ;
+		    }
+		}
+		/* y += 4*dy ; */
+		/* x += 4*dx ; */
+		ADVANCE (Yx,Yz,4*dy) ;
+		ADVANCE (Xx,Xz,4*dx) ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* Y += alpha * (A or A') * x, symmetric case (upper/lower) */
+	/* ------------------------------------------------------------------ */
+
+	/* Only the upper/lower triangular part and the diagonal of A is used.
+	 * Since both x and y are written to in the innermost loop, this
+	 * code can experience cache bank conflicts if x is used directly.
+	 * Thus, a copy is made of x, four columns at a time, if x has
+	 * four or more columns.
+	 */
+
+	if (kcol % 4 == 1)
+	{
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		/* yj = 0. ; */
+		CLEAR (yx,yz,0) ;
+
+		/* xj = alpha [0] * x [j] ; */
+		MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i == j)
+		    {
+			/* y [i] += Ax [p] * xj ; */
+			MULTADD (Yx,Yz,i, Ax,Az,p, xx,xz,0) ;
+		    }
+		    else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j))
+		    {
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i] += aij * xj ; */
+			/* yj    += aij * x [i] ; */
+			MULTADD     (Yx,Yz,i, ax,az,0, xx,xz,0) ;
+			MULTADDCONJ (yx,yz,0, ax,az,0, Xx,Xz,i) ;
+
+
+		    }
+		}
+		/* y [j] += alpha [0] * yj ; */
+		MULTADD (Yx,Yz,j, alpha,alphaz,0, yx,yz,0) ;
+
+	    }
+	    /* y += dy ; */
+	    /* x += dx ; */
+	    ADVANCE (Yx,Yz,dy) ;
+	    ADVANCE (Xx,Xz,dx) ;
+	    k++ ;
+
+	}
+	else if (kcol % 4 == 2)
+	{
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		/* yj0 = 0. ; */
+		/* yj1 = 0. ; */
+		CLEAR (yx,yz,0) ;
+		CLEAR (yx,yz,1) ;
+
+		/* xj0 = alpha [0] * x [j   ] ; */
+		/* xj1 = alpha [0] * x [j+dx] ; */
+		MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+		MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ;
+
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i == j)
+		    {
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i   ] += aij * xj0 ; */
+			/* y [i+dy] += aij * xj1 ; */
+			MULTADD (Yx,Yz,i,    ax,az,0, xx,xz,0) ;
+			MULTADD (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ;
+
+		    }
+		    else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j))
+		    {
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i   ] += aij * xj0 ; */
+			/* y [i+dy] += aij * xj1 ; */
+			/* yj0 += aij * x [i   ] ; */
+			/* yj1 += aij * x [i+dx] ; */
+			MULTADD     (Yx,Yz,i,    ax,az,0, xx,xz,0) ;
+			MULTADD     (Yx,Yz,i+dy, ax,az,0, xx,xz,1) ;
+			MULTADDCONJ (yx,yz,0,    ax,az,0, Xx,Xz,i) ;
+			MULTADDCONJ (yx,yz,1,    ax,az,0, Xx,Xz,i+dx) ;
+
+		    }
+		}
+		/* y [j   ] += alpha [0] * yj0 ; */
+		/* y [j+dy] += alpha [0] * yj1 ; */
+		MULTADD (Yx,Yz,j,    alpha,alphaz,0, yx,yz,0) ;
+		MULTADD (Yx,Yz,j+dy, alpha,alphaz,0, yx,yz,1) ;
+
+	    }
+	    /* y += 2*dy ; */
+	    /* x += 2*dx ; */
+	    ADVANCE (Yx,Yz,2*dy) ;
+	    ADVANCE (Xx,Xz,2*dx) ;
+	    k += 2 ;
+
+	}
+	else if (kcol % 4 == 3)
+	{
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		/* yj0 = 0. ; */
+		/* yj1 = 0. ; */
+		/* yj2 = 0. ; */
+		CLEAR (yx,yz,0) ;
+		CLEAR (yx,yz,1) ;
+		CLEAR (yx,yz,2) ;
+
+		/* xj0 = alpha [0] * x [j     ] ; */
+		/* xj1 = alpha [0] * x [j+  dx] ; */
+		/* xj2 = alpha [0] * x [j+2*dx] ; */
+		MULT (xx,xz,0, alpha,alphaz,0, Xx,Xz,j) ;
+		MULT (xx,xz,1, alpha,alphaz,0, Xx,Xz,j+dx) ;
+		MULT (xx,xz,2, alpha,alphaz,0, Xx,Xz,j+2*dx) ;
+
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i == j)
+		    {
+
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i     ] += aij * xj0 ; */
+			/* y [i+  dy] += aij * xj1 ; */
+			/* y [i+2*dy] += aij * xj2 ; */
+			MULTADD (Yx,Yz,i,      ax,az,0, xx,xz,0) ;
+			MULTADD (Yx,Yz,i+dy,   ax,az,0, xx,xz,1) ;
+			MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ;
+
+		    }
+		    else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j))
+		    {
+
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i     ] += aij * xj0 ; */
+			/* y [i+  dy] += aij * xj1 ; */
+			/* y [i+2*dy] += aij * xj2 ; */
+			/* yj0 += aij * x [i     ] ; */
+			/* yj1 += aij * x [i+  dx] ; */
+			/* yj2 += aij * x [i+2*dx] ; */
+			MULTADD     (Yx,Yz,i,      ax,az,0, xx,xz,0) ;
+			MULTADD     (Yx,Yz,i+dy,   ax,az,0, xx,xz,1) ;
+			MULTADD     (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ;
+			MULTADDCONJ (yx,yz,0,      ax,az,0, Xx,Xz,i) ;
+			MULTADDCONJ (yx,yz,1,      ax,az,0, Xx,Xz,i+dx) ;
+			MULTADDCONJ (yx,yz,2,      ax,az,0, Xx,Xz,i+2*dx) ;
+
+		    }
+		}
+		/* y [j     ] += alpha [0] * yj0 ; */
+		/* y [j+  dy] += alpha [0] * yj1 ; */
+		/* y [j+2*dy] += alpha [0] * yj2 ; */
+		MULTADD (Yx,Yz,j,      alpha,alphaz,0, yx,yz,0) ;
+		MULTADD (Yx,Yz,j+dy,   alpha,alphaz,0, yx,yz,1) ;
+		MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ;
+
+	    }
+	    /* y += 3*dy ; */
+	    /* x += 3*dx ; */
+	    ADVANCE (Yx,Yz,3*dy) ;
+	    ADVANCE (Xx,Xz,3*dx) ;
+
+	    k += 3 ;
+	}
+
+	/* copy four columns of X into W, and put in row form */
+	for ( ; k < kcol ; k += 4)
+	{
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		/* w [4*j  ] = x [j     ] ; */
+		/* w [4*j+1] = x [j+  dx] ; */
+		/* w [4*j+2] = x [j+2*dx] ; */
+		/* w [4*j+3] = x [j+3*dx] ; */
+		ASSIGN (w,Wz,4*j  , Xx,Xz,j     ) ;
+		ASSIGN (w,Wz,4*j+1, Xx,Xz,j+dx  ) ;
+		ASSIGN (w,Wz,4*j+2, Xx,Xz,j+2*dx) ;
+		ASSIGN (w,Wz,4*j+3, Xx,Xz,j+3*dx) ;
+	    }
+
+	    for (j = 0 ; j < ncol ; j++)
+	    {
+		/* yj0 = 0. ; */
+		/* yj1 = 0. ; */
+		/* yj2 = 0. ; */
+		/* yj3 = 0. ; */
+		CLEAR (yx,yz,0) ;
+		CLEAR (yx,yz,1) ;
+		CLEAR (yx,yz,2) ;
+		CLEAR (yx,yz,3) ;
+
+		/* xj0 = alpha [0] * w [4*j  ] ; */
+		/* xj1 = alpha [0] * w [4*j+1] ; */
+		/* xj2 = alpha [0] * w [4*j+2] ; */
+		/* xj3 = alpha [0] * w [4*j+3] ; */
+		MULT (xx,xz,0, alpha,alphaz,0, w,Wz,4*j) ;
+		MULT (xx,xz,1, alpha,alphaz,0, w,Wz,4*j+1) ;
+		MULT (xx,xz,2, alpha,alphaz,0, w,Wz,4*j+2) ;
+		MULT (xx,xz,3, alpha,alphaz,0, w,Wz,4*j+3) ;
+
+		p = Ap [j] ;
+		pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ;
+		for ( ; p < pend ; p++)
+		{
+		    i = Ai [p] ;
+		    if (i == j)
+		    {
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i     ] += aij * xj0 ; */
+			/* y [i+  dy] += aij * xj1 ; */
+			/* y [i+2*dy] += aij * xj2 ; */
+			/* y [i+3*dy] += aij * xj3 ; */
+			MULTADD (Yx,Yz,i     , ax,az,0, xx,xz,0) ;
+			MULTADD (Yx,Yz,i+dy  , ax,az,0, xx,xz,1) ;
+			MULTADD (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ;
+			MULTADD (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ;
+
+		    }
+		    else if ((A->stype > 0 && i < j) || (A->stype < 0 && i > j))
+		    {
+			/* aij = Ax [p] ; */
+			ASSIGN (ax,az,0, Ax,Az,p) ;
+
+			/* y [i     ] += aij * xj0 ; */
+			/* y [i+  dy] += aij * xj1 ; */
+			/* y [i+2*dy] += aij * xj2 ; */
+			/* y [i+3*dy] += aij * xj3 ; */
+			/* yj0 += aij * w [4*i  ] ; */
+			/* yj1 += aij * w [4*i+1] ; */
+			/* yj2 += aij * w [4*i+2] ; */
+			/* yj3 += aij * w [4*i+3] ; */
+			MULTADD     (Yx,Yz,i,      ax,az,0, xx,xz,0) ;
+			MULTADD     (Yx,Yz,i+dy,   ax,az,0, xx,xz,1) ;
+			MULTADD     (Yx,Yz,i+2*dy, ax,az,0, xx,xz,2) ;
+			MULTADD     (Yx,Yz,i+3*dy, ax,az,0, xx,xz,3) ;
+			MULTADDCONJ (yx,yz,0,     ax,az,0, w,Wz,4*i) ;
+			MULTADDCONJ (yx,yz,1,     ax,az,0, w,Wz,4*i+1) ;
+			MULTADDCONJ (yx,yz,2,     ax,az,0, w,Wz,4*i+2) ;
+			MULTADDCONJ (yx,yz,3,     ax,az,0, w,Wz,4*i+3) ;
+
+		    }
+		}
+		/* y [j     ] += alpha [0] * yj0 ; */
+		/* y [j+  dy] += alpha [0] * yj1 ; */
+		/* y [j+2*dy] += alpha [0] * yj2 ; */
+		/* y [j+3*dy] += alpha [0] * yj3 ; */
+		MULTADD (Yx,Yz,j     , alpha,alphaz,0, yx,yz,0) ;
+		MULTADD (Yx,Yz,j+dy  , alpha,alphaz,0, yx,yz,1) ;
+		MULTADD (Yx,Yz,j+2*dy, alpha,alphaz,0, yx,yz,2) ;
+		MULTADD (Yx,Yz,j+3*dy, alpha,alphaz,0, yx,yz,3) ;
+
+	    }
+	    /* y += 4*dy ; */
+	    /* x += 4*dx ; */
+	    ADVANCE (Yx,Yz,4*dy) ;
+	    ADVANCE (Xx,Xz,4*dx) ;
+
+	}
+    }
+}
+
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Modify/License.txt b/src/CHOLMOD/Modify/License.txt
new file mode 100644
index 0000000..6e35274
--- /dev/null
+++ b/src/CHOLMOD/Modify/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/Modify Module.
+Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/Modify module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module 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 Module 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 Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff --git a/src/CHOLMOD/Modify/cholmod_rowadd.c b/src/CHOLMOD/Modify/cholmod_rowadd.c
new file mode 100644
index 0000000..dd7ecf0
--- /dev/null
+++ b/src/CHOLMOD/Modify/cholmod_rowadd.c
@@ -0,0 +1,678 @@
+/* ========================================================================== */
+/* === Modify/cholmod_rowadd ================================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Modify Module.
+ * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager.
+ * The CHOLMOD/Modify Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Adds a row and column to an LDL' factorization, and optionally updates the
+ * solution to Lx=b.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), W (2*nrow), Iwork (2*nrow)
+ *
+ * Only real matrices are supported.  A symbolic L is converted into a
+ * numeric identity matrix before the row is added.
+ */
+
+#ifndef NMODIFY
+
+#include "cholmod_internal.h"
+#include "cholmod_modify.h"
+
+
+/* ========================================================================== */
+/* === cholmod_rowadd ======================================================= */
+/* ========================================================================== */
+
+/* cholmod_rowadd adds a row to the LDL' factorization.  It computes the kth
+ * row and kth column of L, and then updates the submatrix L (k+1:n,k+1:n)
+ * accordingly.  The kth row and column of L should originally be equal to the
+ * kth row and column of the identity matrix (they are treated as such, if they
+ * are not).  The kth row/column of L is computed as the factorization of the
+ * kth row/column of the matrix to factorize, which is provided as a single
+ * n-by-1 sparse matrix R.  The sparse vector R need not be sorted.
+ */
+
+int CHOLMOD(rowadd)
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double bk [2] ;
+    bk [0] = 0. ;
+    bk [1] = 0. ;
+    return (CHOLMOD(rowadd_mark) (k, R, bk, NULL, L, NULL, NULL, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowadd_solve ================================================= */
+/* ========================================================================== */
+
+/* Does the same as cholmod_rowadd, and also updates the solution to Lx=b
+ * See cholmod_updown for a description of how Lx=b is updated.  There is on
+ * additional parameter:  bk specifies the new kth entry of b.
+ */
+
+int CHOLMOD(rowadd_solve)
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    double bk [2],	/* kth entry of the right-hand-side b */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(rowadd_mark) (k, R, bk, NULL, L, X, DeltaB, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === icomp ================================================================ */
+/* ========================================================================== */
+
+/* for sorting by qsort */
+static int icomp (Int *i, Int *j)
+{
+    if (*i < *j)
+    {
+	return (-1) ;
+    }
+    else
+    {
+	return (1) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowadd_mark ================================================== */
+/* ========================================================================== */
+
+/* Does the same as cholmod_rowadd_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.  */
+
+int CHOLMOD(rowadd_mark)
+(
+    /* ---- input ---- */
+    size_t kadd,	/* row/column index to add */
+    cholmod_sparse *R,	/* row/column of matrix to factorize (n-by-1) */
+    double bk [2],	/* kth entry of the right hand side, b */
+    Int *colmark,	/* Int array of size 1.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double dk, yj, l_kj, lx, l_ij, sqrt_dk, dj, xk, rnz, fl ;
+    double *Lx, *W, *Cx, *Rx, *Xx, *Nx ;
+    Int *Li, *Lp, *Lnz, *Flag, *Stack, *Ci, *Rj, *Rp, *Lnext, *Iwork, *Rnz ;
+    cholmod_sparse *C, Cmatrix ;
+    Int i, j, p, pend, top, len, kk, li, lnz, mark, k, n, parent, Cp [2],
+	do_solve, do_update ;
+    size_t s ;
+    int ok = TRUE ;
+    DEBUG (Int lastrow) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (R, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (R, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+    n = L->n ;
+    k = kadd ;
+    if (kadd >= L->n || k < 0)
+    {
+	ERROR (CHOLMOD_INVALID, "k invalid") ;
+	return (FALSE) ;
+    }
+    if (R->ncol != 1 || R->nrow != L->n)
+    {
+	ERROR (CHOLMOD_INVALID, "R invalid") ;
+	return (FALSE) ;
+    }
+    Rj = R->i ;
+    Rx = R->x ;
+    Rp = R->p ;
+    Rnz = R->nz ;
+    rnz = (R->packed) ? (Rp [1]) : (Rnz [0]) ;
+    do_solve = (X != NULL) && (DeltaB != NULL) ;
+    if (do_solve)
+    {
+	RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+	Xx = X->x ;
+	Nx = DeltaB->x ;
+	if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n ||
+		DeltaB->ncol != 1 || Xx == NULL || Nx == NULL)
+	{
+	    ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ;
+	    return (FALSE) ;
+	}
+    }
+    else
+    {
+	Xx = NULL ;
+	Nx = NULL ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 2*n */
+    s = CHOLMOD(mult_size_t) (n, 2, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, s, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, s, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to simplicial numeric LDL' factor, if not already */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) 
+    {
+	/* can only update/downdate a simplicial LDL' factorization */
+	CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L,
+		Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory, L is returned unchanged */
+	    return (FALSE) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* inputs, not modified on output: */
+    Lp = L->p ;		/* size n+1.  input, not modified on output */
+
+    /* outputs, contents defined on input for incremental case only: */
+    Lnz = L->nz ;	/* size n */
+    Li = L->i ;		/* size L->nzmax.  Can change in size. */
+    Lx = L->x ;		/* size L->nzmax.  Can change in size. */
+    Lnext = L->next ;	/* size n+2 */
+
+    ASSERT (L->nz != NULL) ;
+
+    PRINT1 (("rowadd:\n")) ;
+    fl = 0 ;
+
+#if 0
+#ifndef NDEBUG
+    /* column k of L should be zero, except for the diagonal.  This test is
+     * overly cautious. */
+    for (p = Lp [k] + 1 ; p < Lp [k] + Lnz [k] ; p++) ASSERT (Lx [p] == 0) ;
+#endif
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;   /* size n */
+    W = Common->Xwork ;     /* size n */
+    Cx = W + n ;	    /* size n (use 2nd column of Xwork for C) */
+    Iwork = Common->Iwork ;
+    Stack = Iwork ;	    /* size n (i/i/l), also in cholmod_updown */
+    Ci = Iwork + n ;	    /* size n (i/i/l) */
+    /* NOTE: cholmod_updown uses Iwork [0..n-1] (i/i/l) as Stack as well */
+
+    mark = Common->mark ;
+
+    /* copy Rj/Rx into W/Ci */
+    for (p = 0 ; p < rnz ; p++)
+    {
+	i = Rj [p] ;
+	ASSERT (i >= 0 && i < n) ;
+	W [i] = Rx [p] ;
+	Ci [p] = i ;
+    }
+
+    /* At this point, W [Ci [0..rnz-1]] holds the sparse vector to add */
+    /* The nonzero pattern of column W is held in Ci (it may be unsorted). */
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic factorization to get pattern of kth row of L */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (for (p = 0 ; p < rnz ; p++)
+	    PRINT1 (("C ("ID",%g)\n", Ci [p], W [Ci [p]]))) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* flag the diagonal */
+    Flag [k] = mark ;
+
+    /* find the union of all the paths */
+    top = n ;
+    lnz = 0 ;	/* # of nonzeros in column k of L, excluding diagonal */
+    for (p = 0 ; p < rnz ; p++)
+    {
+	i = Ci [p] ;
+
+	if (i < k)
+	{
+
+	    /* walk from i = entry in Ci to root (and stop if i marked)*/
+	    PRINT2 (("\nwalk from i = "ID" towards k = "ID"\n", i, k)) ;
+	    len = 0 ;
+
+	    /* walk up tree, but stop if we go below the diagonal */
+	    while (i < k && i != EMPTY && Flag [i] < mark)
+	    {
+		PRINT2 (("   Add "ID" to path\n", i)) ;
+		ASSERT (i >= 0 && i < k) ;
+		Stack [len++] = i ;	/* place i on the stack */
+		Flag [i] = mark ;		/* mark i as visited */
+		/* parent is the first entry in the column after the diagonal */
+		ASSERT (Lnz [i] > 0) ;
+		parent = (Lnz [i] > 1) ? (Li [Lp [i] + 1]) : EMPTY ;
+		PRINT2 (("                      parent: "ID"\n", parent)) ;
+		i = parent ;	/* go up the tree */
+	    }
+	    ASSERT (len <= top) ;
+
+	    /* move the path down to the bottom of the stack */
+	    /* this shifts Stack [0..len-1] down to [ ... oldtop-1] */
+	    while (len > 0)
+	    {
+		Stack [--top] = Stack [--len] ;
+	    }
+	}
+	else if (i > k)
+	{
+	    /* prune the diagonal and upper triangular entries from Ci */
+	    Ci [lnz++] = i ;
+	    Flag [i] = mark ;
+	}
+    }
+
+#ifndef NDEBUG
+    PRINT1 (("length of S after prune: "ID"\n", lnz)) ;
+    for (p = 0 ; p < lnz ; p++)
+    {
+	PRINT1 (("After prune Ci ["ID"] = "ID"\n", p, Ci [p])) ;
+	ASSERT (Ci [p] > k) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* ensure each column of L has enough space to grow */
+    /* ---------------------------------------------------------------------- */
+
+    for (kk = top ; kk < n ; kk++)
+    {
+	/* could skip this if we knew column j already included row k */
+	j = Stack [kk] ;
+	if (Lp [j] + Lnz [j] >= Lp [Lnext [j]])
+	{
+	    PRINT1 (("Col "ID" realloc, old Lnz "ID"\n", j, Lnz [j])) ;
+	    if (!CHOLMOD(reallocate_column) (j, Lnz [j] + 1, L, Common))
+	    {
+		/* out of memory, L is now simplicial symbolic */
+		/* CHOLMOD(clear_flag) (Common) ; */
+		CHOLMOD_CLEAR_FLAG (Common) ;
+		for (i = 0 ; i < n ; i++)
+		{
+		    W [i] = 0 ;
+		}
+		return (FALSE) ;
+	    }
+	    /* L->i and L->x may have moved */
+	    Li = L->i ;
+	    Lx = L->x ;
+	}
+	ASSERT (Lp [j] + Lnz [j] < Lp [Lnext [j]]
+	    || (Lp [Lnext [j]] - Lp [j] == n-j)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute kth row of L and store in column form */
+    /* ---------------------------------------------------------------------- */
+
+    /* solve L (1:k-1, 1:k-1) * y (1:k-1) = b (1:k-1) */
+    /* where b (1:k) is in W and Ci */
+
+    /* L (k, 1:k-1) = y (1:k-1) ./ D (1:k-1) */
+    /* D (k) = B (k,k) - L (k, 1:k-1) * y (1:k-1) */
+
+    PRINT2 (("\nForward solve: "ID" to "ID"\n", top, n)) ;
+    ASSERT (Lnz [k] >= 1 && Li [Lp [k]] == k) ;
+    DEBUG (for (i = top ; i < n ; i++) PRINT2 ((" Path: "ID"\n", Stack [i]))) ;
+
+    dk = W [k] ;
+    W [k] = 0.0 ;
+
+    /* if do_solve: compute x (k) = b (k) - L (k, 1:k-1) * x (1:k-1) */
+    xk = bk [0] ;
+    PRINT2 (("B [k] = %g\n", xk)) ;
+
+    for (kk = top ; kk < n ; kk++)
+    {
+	j = Stack [kk] ;
+	i = j ;
+	PRINT2 (("Forward solve col j = "ID":\n", j)) ;
+	ASSERT (j >= 0 && j < k) ;
+
+	/* forward solve using L (j+1:k-1,j) */
+	yj = W [j] ;
+	W [j] = 0.0 ;
+	p = Lp [j] ;
+	pend = p + Lnz [j] ;
+	ASSERT (Lnz [j] > 0) ;
+	dj = Lx [p++] ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Li [p] ;
+	    PRINT2 (("    row "ID"\n", i)) ;
+	    ASSERT (i > j) ;
+	    ASSERT (i < n) ;
+	    /* stop at row k */
+	    if (i >= k)
+	    {
+		break ;
+	    }
+	    W [i] -= Lx [p] * yj ;
+	}
+
+	/* each iteration of the above for loop did 2 flops, and 3 flops
+	 * are done below.  so: fl += 2 * (Lp [j] - p - 1) + 3 becomes: */
+	fl += 2 * (Lp [j] - p) + 1 ;
+
+	/* scale L (k,1:k-1) and compute dot product for D (k,k) */
+	l_kj = yj / dj ;
+	dk -= l_kj * yj ;
+
+	/* compute dot product for X(k) */
+	if (do_solve)
+	{
+	    xk -= l_kj * Xx [j] ;
+	}
+
+	/* store l_kj in the jth column of L */
+	/* and shift the rest of the column down */
+
+	li = k ;
+	lx = l_kj ;
+
+	if (i == k)
+	{
+	    /* no need to modify the nonzero pattern of L, since it already
+	     * contains row index k. */
+	    ASSERT (Li [p] == k) ;
+	    Lx [p] = l_kj ;
+
+	    for (p++ ; p < pend ; p++)
+	    {
+		i    = Li [p] ;
+		l_ij = Lx [p] ;
+		ASSERT (i > k && i < n) ;
+		PRINT2 (("   apply to row "ID" of column k of L\n", i)) ;
+
+		/* add to the pattern of the kth column of L */
+		if (Flag [i] < mark)
+		{
+		    PRINT2 (("   add Ci["ID"] = "ID"\n", lnz, i)) ;
+		    ASSERT (i > k) ;
+		    Ci [lnz++] = i ;
+		    Flag [i] = mark ;
+		}
+
+		/* apply the update to the kth column of L */
+		/* yj is equal to l_kj * d_j */
+
+		W [i] -= l_ij * yj ;
+	    }
+
+	}
+	else
+	{
+
+	    PRINT2 (("Shift col j = "ID", apply saxpy to col k of L\n", j)) ;
+	    for ( ; p < pend ; p++)
+	    {
+		/* swap (Li [p],Lx [p]) with (li,lx) */
+		i    = Li [p] ;
+		l_ij = Lx [p] ;
+		Li [p] = li ;
+		Lx [p] = lx ;
+		li = i ;
+		lx = l_ij ;
+		ASSERT (i > k && i < n) ;
+		PRINT2 (("   apply to row "ID" of column k of L\n", i)) ;
+
+		/* add to the pattern of the kth column of L */
+		if (Flag [i] < mark)
+		{
+		    PRINT2 (("   add Ci["ID"] = "ID"\n", lnz, i)) ;
+		    ASSERT (i > k) ;
+		    Ci [lnz++] = i ;
+		    Flag [i] = mark ;
+		}
+
+		/* apply the update to the kth column of L */
+		/* yj is equal to l_kj * d_j */
+
+		W [i] -= l_ij * yj ;
+	    }
+
+	    /* store the last value in the jth column of L */
+	    Li [p] = li ;
+	    Lx [p] = lx ;
+	    Lnz [j]++ ;
+
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* merge C with the pattern of the existing column of L */
+    /* ---------------------------------------------------------------------- */
+
+    /* This column should be zero, but it may contain explicit zero entries.
+     * These entries should be kept, not dropped. */
+    p = Lp [k] ;
+    pend = p + Lnz [k] ;
+    for (p++ ; p < pend ; p++)
+    {
+	i = Li [p] ;
+	/* add to the pattern of the kth column of L */
+	if (Flag [i] < mark)
+	{
+	    PRINT2 (("   add Ci["ID"] = "ID" from existing col k\n", lnz, i)) ;
+	    ASSERT (i > k) ;
+	    Ci [lnz++] = i ;
+	    Flag [i] = mark ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+
+    if (do_solve)
+    {
+	Xx [k] = xk ;
+	PRINT2 (("Xx [k] = %g\n", Xx [k])) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* ensure abs (dk) >= dbound, if dbound is given */
+    /* ---------------------------------------------------------------------- */
+
+    dk = (IS_GT_ZERO (Common->dbound)) ? (CHOLMOD(dbound) (dk, Common)) : dk ;
+
+    PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* store the kth column of L */
+    /* ---------------------------------------------------------------------- */
+
+    /* ensure the new column of L has enough space */
+    if (Lp [k] + lnz + 1 > Lp [Lnext [k]])
+    {
+	PRINT1 (("New Col "ID" realloc, old Lnz "ID"\n", k, Lnz [k])) ;
+	if (!CHOLMOD(reallocate_column) (k, lnz + 1, L, Common))
+	{
+	    /* out of memory, L is now simplicial symbolic */
+	    CHOLMOD(clear_flag) (Common) ;
+	    for (i = 0 ; i < n ; i++)
+	    {
+		W [i] = 0 ;
+	    }
+	    return (FALSE) ;
+	}
+	/* L->i and L->x may have moved */
+	Li = L->i ;
+	Lx = L->x ;
+    }
+    ASSERT (Lp [k] + lnz + 1 <= Lp [Lnext [k]]) ;
+
+#ifndef NDEBUG
+    PRINT2 (("\nPrior to sort: lnz "ID" (excluding diagonal)\n", lnz)) ;
+    for (kk = 0 ; kk < lnz ; kk++)
+    {
+	i = Ci [kk] ;
+	PRINT2 (("L ["ID"] kept: "ID" %e\n", kk, i, W [i] / dk)) ;
+    }
+#endif
+
+    /* sort Ci */
+    qsort (Ci, lnz, sizeof (Int), (int (*) (const void *, const void *)) icomp);
+
+    /* store the kth column of L */
+    DEBUG (lastrow = k) ;
+    p = Lp [k] ;
+    Lx [p++] = dk ;
+    Lnz [k] = lnz + 1 ;
+    fl += lnz ;
+    for (kk = 0 ; kk < lnz ; kk++, p++)
+    {
+	i = Ci [kk] ;
+	PRINT2 (("L ["ID"] after sort: "ID", %e\n", kk, i, W [i] / dk)) ;
+	ASSERT (i > lastrow) ;
+	Li [p] = i ;
+	Lx [p] = W [i] / dk ;
+	W [i] = 0.0 ;
+	DEBUG (lastrow = i) ;
+    }
+
+    /* compute DeltaB for updown (in DeltaB) */
+    if (do_solve)
+    {
+	p = Lp [k] ;
+	pend = p + Lnz [k] ;
+	for (p++ ; p < pend ; p++)
+	{
+	    ASSERT (Li [p] > k) ;
+	    Nx [Li [p]] -= Lx [p] * xk ;
+	}
+    }
+
+    /* clear the flag for the update */
+    mark = CHOLMOD(clear_flag) (Common) ;
+
+    /* workspaces are now cleared */
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* update/downdate */
+    /* ---------------------------------------------------------------------- */
+
+    /* update or downdate L (k+1:n, k+1:n) with the vector
+     * C = L (:,k) * sqrt (abs (D [k])).
+     * Do a numeric update if D[k] < 0, numeric downdate otherwise.
+     */
+
+    ok = TRUE ;
+    Common->modfl = 0 ;
+
+    PRINT1 (("rowadd update lnz = "ID"\n", lnz)) ;
+    if (lnz > 0)
+    {
+	do_update = IS_LT_ZERO (dk) ;
+	if (do_update)
+	{
+	    dk = -dk ;
+	}
+	sqrt_dk = sqrt (dk) ;
+	p = Lp [k] + 1 ;
+	for (kk = 0 ; kk < lnz ; kk++, p++)
+	{
+	    Cx [kk] = Lx [p] * sqrt_dk ;
+	}
+	fl += lnz + 1 ;
+
+	/* create a n-by-1 sparse matrix to hold the single column */
+	C = &Cmatrix ;
+	C->nrow = n ;
+	C->ncol = 1 ;
+	C->nzmax = lnz ;
+	C->sorted = TRUE ;
+	C->packed = TRUE ;
+	C->p = Cp ;
+	C->i = Ci ;
+	C->x = Cx ;
+	C->nz = NULL ;
+	C->itype = L->itype ;
+	C->xtype = L->xtype ;
+	C->dtype = L->dtype ;
+	C->z = NULL ;
+	C->stype = 0 ;
+
+	Cp [0] = 0 ;
+	Cp [1] = lnz ;
+
+	/* numeric downdate if dk > 0, and optional Lx=b change */
+	/* workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) */
+	ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark,
+		L, X, DeltaB, Common) ;
+
+	/* clear workspace */
+	for (kk = 0 ; kk < lnz ; kk++)
+	{
+	    Cx [kk] = 0 ;
+	}
+    }
+
+    Common->modfl += fl ;
+
+    DEBUG (CHOLMOD(dump_factor) (L, "LDL factorization, L:", Common)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Modify/cholmod_rowdel.c b/src/CHOLMOD/Modify/cholmod_rowdel.c
new file mode 100644
index 0000000..ccf1ce7
--- /dev/null
+++ b/src/CHOLMOD/Modify/cholmod_rowdel.c
@@ -0,0 +1,461 @@
+/* ========================================================================== */
+/* === Modify/cholmod_rowdel ================================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Modify Module.
+ * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager.
+ * The CHOLMOD/Modify Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Deletes a row and column from an LDL' factorization.  The row and column k
+ * is set to the kth row and column of the identity matrix.  Optionally
+ * downdates the solution to Lx=b.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), W (nrow*2), Iwork (2*nrow)
+ *
+ * Only real matrices are supported (exception: since only the pattern of R
+ * is used, it can have any valid xtype).
+ */
+
+#ifndef NMODIFY
+
+#include "cholmod_internal.h"
+#include "cholmod_modify.h"
+
+
+/* ========================================================================== */
+/* === cholmod_rowdel ======================================================= */
+/* ========================================================================== */
+
+/* Sets the kth row and column of L to be the kth row and column of the identity
+ * matrix, and updates L(k+1:n,k+1:n) accordingly.   To reduce the running time,
+ * the caller can optionally provide the nonzero pattern (or an upper bound) of
+ * kth row of L, as the sparse n-by-1 vector R.  Provide R as NULL if you want
+ * CHOLMOD to determine this itself, which is easier for the caller, but takes
+ * a little more time.
+ */
+
+int CHOLMOD(rowdel)
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double yk [2] ;
+    yk [0] = 0. ;
+    yk [1] = 0. ;
+    return (CHOLMOD(rowdel_mark) (k, R, yk, NULL, L, NULL, NULL, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowdel_solve ================================================= */
+/* ========================================================================== */
+
+/* Does the same as cholmod_rowdel, but also downdates the solution to Lx=b.
+ * When row/column k of A is "deleted" from the system A*y=b, this can induce
+ * a change to x, in addition to changes arising when L and b are modified.
+ * If this is the case, the kth entry of y is required as input (yk) */
+
+int CHOLMOD(rowdel_solve)
+(
+    /* ---- input ---- */
+    size_t k,		/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    double yk [2],	/* kth entry in the solution to A*y=b */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(rowdel_mark) (k, R, yk, NULL, L, X, DeltaB, Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_rowdel_mark ================================================== */
+/* ========================================================================== */
+
+/* Does the same as cholmod_rowdel_solve, except only part of L is used in
+ * the update/downdate of the solution to Lx=b.  This routine is an "expert"
+ * routine.  It is meant for use in LPDASA only.
+ *
+ * if R == NULL then columns 0:k-1 of L are searched for row k.  Otherwise, it
+ * searches columns in the set defined by the pattern of the first column of R.
+ * This is meant to be the pattern of row k of L (a superset of that pattern is
+ * OK too).  R must be a permutation of a subset of 0:k-1.
+ */
+
+int CHOLMOD(rowdel_mark)
+(
+    /* ---- input ---- */
+    size_t kdel,	/* row/column index to delete */
+    cholmod_sparse *R,	/* NULL, or the nonzero pattern of kth row of L */
+    double yk [2],	/* kth entry in the solution to A*y=b */
+    Int *colmark,	/* Int array of size 1.  See cholmod_updown.c */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double dk, sqrt_dk, xk, dj, fl ;
+    double *Lx, *Cx, *W, *Xx, *Nx ;
+    Int *Li, *Lp, *Lnz, *Ci, *Rj, *Rp, *Iwork ;
+    cholmod_sparse *C, Cmatrix ;
+    Int j, p, pend, kk, lnz, n, Cp [2], do_solve, do_update, left, k,
+	right, middle, i, klast, given_row, rnz ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ;
+    n = L->n ;
+    k = kdel ;
+    if (kdel >= L->n || k < 0)
+    {
+	ERROR (CHOLMOD_INVALID, "k invalid") ;
+	return (FALSE) ;
+    }
+    if (R == NULL)
+    {
+	Rj = NULL ;
+	rnz = EMPTY ;
+    }
+    else
+    {
+	RETURN_IF_XTYPE_INVALID (R, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+	if (R->ncol != 1 || R->nrow != L->n)
+	{
+	    ERROR (CHOLMOD_INVALID, "R invalid") ;
+	    return (FALSE) ;
+	}
+	Rj = R->i ;
+	Rp = R->p ;
+	rnz = Rp [1] ;
+    }
+    do_solve = (X != NULL) && (DeltaB != NULL) ;
+    if (do_solve)
+    {
+	RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+	Xx = X->x ;
+	Nx = DeltaB->x ;
+	if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n ||
+		DeltaB->ncol != 1 || Xx == NULL || Nx == NULL)
+	{
+	    ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ;
+	    return (FALSE) ;
+	}
+    }
+    else
+    {
+	Xx = NULL ;
+	Nx = NULL ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 2*n */
+    s = CHOLMOD(mult_size_t) (n, 2, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, s, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to simplicial numeric LDL' factor, if not already */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) 
+    {
+	/* can only update/downdate a simplicial LDL' factorization */
+	CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L,
+		Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory, L is returned unchanged */
+	    return (FALSE) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* inputs, not modified on output: */
+    Lp = L->p ;		/* size n+1 */
+
+    /* outputs, contents defined on input for incremental case only: */
+    Lnz = L->nz ;	/* size n */
+    Li = L->i ;		/* size L->nzmax.  Can change in size. */
+    Lx = L->x ;		/* size L->nzmax.  Can change in size. */
+
+    ASSERT (L->nz != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    W = Common->Xwork ; 	/* size n, used only in cholmod_updown */
+    Cx = W + n ;		/* use 2nd column of Xwork for C (size n) */
+    Iwork = Common->Iwork ;
+    Ci = Iwork + n ;		/* size n (i/i/l) */
+    /* NOTE: cholmod_updown uses Iwork [0..n-1] (i/i/l) as Stack */
+
+    /* ---------------------------------------------------------------------- */
+    /* prune row k from all columns of L */
+    /* ---------------------------------------------------------------------- */
+
+    given_row = (rnz >= 0) ;
+    klast = given_row ? rnz : k ;
+    PRINT2 (("given_row "ID"\n", given_row)) ;
+
+    for (kk = 0 ; kk < klast ; kk++)
+    {
+	/* either search j = 0:k-1 or j = Rj [0:rnz-1] */
+	j = given_row ? (Rj [kk]) : (kk) ;
+
+	if (j < 0 || j >= k)
+	{
+	    ERROR (CHOLMOD_INVALID, "R invalid") ;
+	    return (FALSE) ;
+	}
+
+	PRINT2 (("Prune col j = "ID":\n", j)) ;
+
+	lnz = Lnz [j] ;
+	dj = Lx [Lp [j]] ;
+	ASSERT (Lnz [j] > 0 && Li [Lp [j]] == j) ;
+
+	if (lnz > 1)
+	{
+	    left = Lp [j] ;
+	    pend = left + lnz ;
+	    right = pend - 1 ;
+
+	    i = Li [right] ;
+
+	    if (i < k)
+	    {
+		/* row k is not in column j */
+		continue ;
+	    }
+	    else if (i == k)
+	    {
+		/* k is the last row index in this column (quick delete) */
+		if (do_solve)
+		{
+		    Xx [j] -= yk [0] * dj * Lx [right] ;
+		}
+		Lx [right] = 0 ;
+	    }
+	    else
+	    {
+		/* binary search for row k in column j */
+		PRINT2 (("\nBinary search: lnz "ID" k = "ID"\n", lnz, k)) ;
+		while (left < right)
+		{
+		    middle = (left + right) / 2 ;
+		    PRINT2 (("left "ID" right "ID" middle "ID": ["ID" "ID""
+			""ID"]\n", left, right, middle,
+			Li [left], Li [middle], Li [right])) ;
+		    if (k > Li [middle])
+		    {
+			left = middle + 1 ;
+		    }
+		    else
+		    {
+			right = middle ;
+		    }
+		}
+		ASSERT (left >= Lp [j] && left < pend) ;
+
+#ifndef NDEBUG
+		/* brute force, linear-time search */
+		{
+		    Int p3 = Lp [j] ;
+		    i = EMPTY ;
+		    PRINT2 (("Brute force:\n")) ;
+		    for ( ; p3 < pend ; p3++)
+		    {
+			i = Li [p3] ;
+			PRINT2 (("p "ID" ["ID"]\n", p3, i)) ;
+			if (i >= k)
+			{
+			    break ;
+			}
+		    }
+		    if (i == k)
+		    {
+			ASSERT (k == Li [p3]) ;
+			ASSERT (p3 == left) ;
+		    }
+		}
+#endif
+
+		if (k == Li [left])
+		{
+		    if (do_solve)
+		    {
+			Xx [j] -= yk [0] * dj * Lx [left] ;
+		    }
+		    /* found row k in column j.  Prune it from the column.*/
+		    Lx [left] = 0 ;
+		}
+	    }
+	}
+    }
+
+#ifndef NDEBUG
+    /* ensure that row k has been deleted from the matrix L */
+    for (j = 0 ; j < k ; j++)
+    {
+	Int lasti ;
+	lasti = EMPTY ;
+	p = Lp [j] ;
+	pend = p + Lnz [j] ;
+	/* look for row k in column j */
+	PRINT1 (("Pruned column "ID"\n", j)) ;
+	for ( ; p < pend ; p++)
+	{
+	    i = Li [p] ;
+	    PRINT2 ((" "ID"", i)) ;
+	    PRINT2 ((" %g\n", Lx [p])) ;
+	    ASSERT (IMPLIES (i == k, Lx [p] == 0)) ;
+	    ASSERT (i > lasti) ;
+	    lasti = i ;
+	}
+	PRINT1 (("\n")) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* set diagonal and clear column k of L */
+    /* ---------------------------------------------------------------------- */
+
+    lnz = Lnz [k] - 1 ;
+    ASSERT (Lnz [k] > 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* update/downdate */
+    /* ---------------------------------------------------------------------- */
+
+    /* update or downdate L (k+1:n, k+1:n) with the vector
+     * C = L (:,k) * sqrt (abs (D [k]))
+     * Do a numeric update if D[k] > 0, numeric downdate otherwise.
+     */
+
+    PRINT1 (("rowdel downdate lnz = "ID"\n", lnz)) ;
+
+    /* store the new unit diagonal */
+    p = Lp [k] ;
+    pend = p + lnz + 1 ;
+    dk = Lx [p] ;
+    Lx [p++] = 1 ;
+    PRINT2 (("D [k = "ID"] = %g\n", k, dk)) ;
+    ok = TRUE ;
+    fl = 0 ;
+
+    if (lnz > 0)
+    {
+	/* compute DeltaB for updown (in DeltaB) */
+	if (do_solve)
+	{
+	    xk = Xx [k] - yk [0] * dk ;
+	    for ( ; p < pend ; p++)
+	    {
+		Nx [Li [p]] += Lx [p] * xk ;
+	    }
+	}
+
+	do_update = IS_GT_ZERO (dk) ;
+	if (!do_update)
+	{
+	    dk = -dk ;
+	}
+	sqrt_dk = sqrt (dk) ;
+	p = Lp [k] + 1 ;
+	for (kk = 0 ; kk < lnz ; kk++, p++)
+	{
+	    Ci [kk] = Li [p] ;
+	    Cx [kk] = Lx [p] * sqrt_dk ;
+	    Lx [p] = 0 ;		/* clear column k */
+	}
+	fl = lnz + 1 ;
+
+	/* create a n-by-1 sparse matrix to hold the single column */
+	C = &Cmatrix ;
+	C->nrow = n ;
+	C->ncol = 1 ;
+	C->nzmax = lnz ;
+	C->sorted = TRUE ;
+	C->packed = TRUE ;
+	C->p = Cp ;
+	C->i = Ci ;
+	C->x = Cx ;
+	C->nz = NULL ;
+	C->itype = L->itype ;
+	C->xtype = L->xtype ;
+	C->dtype = L->dtype ;
+	C->z = NULL ;
+	C->stype = 0 ;
+
+	Cp [0] = 0 ;
+	Cp [1] = lnz ;
+
+	/* numeric update if dk > 0, and with Lx=b change */
+	/* workspace: Flag (nrow), Head (nrow+1), W (nrow), Iwork (2*nrow) */
+	ok = CHOLMOD(updown_mark) (do_update ? (1) : (0), C, colmark,
+		L, X, DeltaB, Common) ;
+
+	/* clear workspace */
+	for (kk = 0 ; kk < lnz ; kk++)
+	{
+	    Cx [kk] = 0 ;
+	}
+    }
+
+    Common->modfl += fl ;
+
+    if (do_solve)
+    {
+	/* kth equation becomes identity, so X(k) is now Y(k) */
+	Xx [k] = yk [0] ;
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "LDL factorization, L:", Common)) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 2*n, Common)) ;
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Modify/cholmod_updown.c b/src/CHOLMOD/Modify/cholmod_updown.c
new file mode 100644
index 0000000..e0ed9cb
--- /dev/null
+++ b/src/CHOLMOD/Modify/cholmod_updown.c
@@ -0,0 +1,1570 @@
+/* ========================================================================== */
+/* === Modify/cholmod_updown ================================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Modify Module.
+ * Copyright (C) 2005-2006, Timothy A. Davis and William W. Hager.
+ * The CHOLMOD/Modify Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Updates/downdates the LDL' factorization (symbolic, then numeric), by
+ * computing a new factorization of
+ *
+ *  	Lnew * Dnew * Lnew' = Lold * Dold * Lold' +/- C*C'
+ *
+ * C must be sorted.  It can be either packed or unpacked.  As in all CHOLMOD
+ * routines, the columns of L are sorted on input, and also on output.
+ *
+ * If the factor is not an unpacked LDL' or dynamic LDL', it is converted
+ * to an LDL' dynamic factor.  An unpacked LDL' factor may be updated, but if
+ * any one column runs out of space, the factor is converted to an LDL'
+ * dynamic one.  If the initial conversion fails, the factor is returned
+ * unchanged.
+ *
+ * If memory runs out during the update, the factor is returned as a simplicial
+ * symbolic factor.  That is, everything is freed except for the fill-reducing
+ * ordering and its corresponding column counts (typically computed by
+ * cholmod_analyze).
+ *
+ * Note that the fill-reducing permutation L->Perm is NOT used.  The row
+ * indices of C refer to the rows of L, not A.  If your original system is
+ * LDL' = PAP' (where P = L->Perm), and you want to compute the LDL'
+ * factorization of A+CC', then you must permute C first.  That is:
+ *
+ *	PAP' = LDL'
+ *	P(A+CC')P' = PAP'+PCC'P' = LDL' + (PC)(PC)' = LDL' + Cnew*Cnew'
+ *	where Cnew = P*C.
+ *
+ * You can use the cholmod_submatrix routine in the MatrixOps module
+ * to permute C, with:
+ *
+ * Cnew = cholmod_submatrix (C, L->Perm, L->n, NULL, -1, TRUE, TRUE, Common) ;
+ *
+ * Note that the sorted input parameter to cholmod_submatrix must be TRUE,
+ * because cholmod_updown requires C with sorted columns.
+ *
+ * The system Lx=b can also be updated/downdated.  The old system was Lold*x=b.
+ * The new system is Lnew*xnew = b + deltab.  The old solution x is overwritten
+ * with xnew.  Note that as in the update/downdate of L itself, the fill-
+ * reducing permutation L->Perm is not used.  x and b are in the permuted
+ * ordering, not your original ordering.  x and b are n-by-1; this routine
+ * does not handle multiple right-hand-sides.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), W (maxrank*nrow), Iwork (nrow),
+ * where maxrank is 2, 4, or 8.
+ *
+ * Only real matrices are supported.  A symbolic L is converted into a
+ * numeric identity matrix.
+ */
+
+#ifndef NMODIFY
+
+#include "cholmod_internal.h"
+#include "cholmod_modify.h"
+
+
+/* ========================================================================== */
+/* === cholmod_updown ======================================================= */
+/* ========================================================================== */
+
+/* Compute the new LDL' factorization of LDL'+CC' (an update) or LDL'-CC'
+ * (a downdate).  The factor object L need not be an LDL' factorization; it
+ * is converted to one if it isn't. */
+
+int CHOLMOD(updown)
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(updown_mask) (update, C, NULL, NULL, L, NULL, NULL,
+	Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_updown_solve ================================================= */
+/* ========================================================================== */
+
+/* Does the same as cholmod_updown, except that it also updates/downdates the
+ * solution to Lx=b+DeltaB.  x and b must be n-by-1 dense matrices.  b is not
+ * need as input to this routine, but a sparse change to b is (DeltaB).  Only
+ * entries in DeltaB corresponding to columns modified in L are accessed; the
+ * rest are ignored.
+ */
+
+int CHOLMOD(updown_solve)
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(updown_mask) (update, C, NULL, NULL, L, X, DeltaB,
+	Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === Power2 =============================================================== */
+/* ========================================================================== */
+
+/* Power2 [i] is smallest power of 2 that is >= i (for i in range 0 to 8) */
+
+static Int Power2 [ ] =
+{
+/*  0  1  2  3  4  5  6  7  8 */
+    0, 1, 2, 4, 4, 8, 8, 8, 8
+} ;
+
+/* ========================================================================== */
+/* === debug routines ======================================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+static void dump_set (Int s, Int **Set_ps1, Int **Set_ps2, Int j, Int n,
+	cholmod_common *Common)
+{
+    Int *p, len, i, ilast ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return ;
+    }
+
+    len = Set_ps2 [s] - Set_ps1 [s] ;
+    PRINT2 (("Set s: "ID" len: "ID":", s, len)) ;
+    ASSERT (len > 0) ;
+    ilast = j ;
+    for (p = Set_ps1 [s] ; p < Set_ps2 [s] ; p++)
+    {
+	i = *p ;
+	PRINT3 ((" "ID"", i)) ;
+	ASSERT (i > ilast && i < n) ;
+	ilast = i ;
+    }
+    PRINT3 (("\n")) ;
+}
+
+static void dump_col
+(
+    char *w, Int j, Int p1, Int p2, Int *Li, double *Lx, Int n,
+    cholmod_common *Common
+)
+{
+    Int p, row, lastrow ;
+
+    if (CHOLMOD(dump) < -1)
+    {
+	/* no checks if debug level is -2 or less */
+	return ;
+    }
+
+    PRINT3 (("\n\nDUMP COL==== j = "ID"  %s: p1="ID" p2="ID" \n", j, w, p1,p2));
+    lastrow = -1 ;
+    for (p = p1 ; p < p2 ; p++)
+    {
+	PRINT3 (("   "ID": ", p)) ;
+	row = Li [p] ;
+	PRINT3 ((""ID"  ", Li [p])) ;
+	PRINT3 (("%g ", Lx [p])) ;
+	PRINT3 (("\n")) ;
+	ASSERT (row > lastrow && row < n) ;
+	lastrow = row ;
+    }
+    ASSERT (p1 < p2) ;
+    ASSERT (Li [p1] == j) ;
+    PRINT3 (("\n")) ;
+}
+#endif
+
+
+/* ========================================================================== */
+/* === a path =============================================================== */
+/* ========================================================================== */
+
+/* A path is a set of nodes of the etree which are all affected by the same
+ * columns of C. */
+
+typedef struct Path_struct
+{
+    Int start ;		/* column at which to start, or EMPTY if initial */
+    Int end ;		/* column at which to end, or EMPTY if initial */
+    Int ccol ;		/* column of C to which path refers */
+    Int parent ;	/* parent path */
+    Int c ;		/* child of j along this path */
+    Int next ;		/* next path in link list */
+    Int rank ;		/* number of rank-1 paths merged onto this path */
+    Int order ;		/* dfs order of this path */
+    Int wfirst ;	/* first column of W to affect this path */
+    Int pending ;	/* column at which the path is pending */
+    Int botrow ;	/* for partial update/downdate of solution to Lx=b */ 
+
+} Path_type ;
+
+
+/* ========================================================================== */
+/* === dfs ================================================================== */
+/* ========================================================================== */
+
+/* Compute the DFS order of the set of paths.  This can be recursive because
+ * there are at most 23 paths to sort: one for each column of C (8 at most),
+ * and one for each node in a balanced binary tree with 8 leaves (15).
+ * Stack overflow is thus not a problem.  */
+
+static void dfs
+(
+    Path_type *Path,	/* the set of Paths */
+    Int k,		/* the rank of the update/downdate */
+    Int path,		/* which path to work on */
+    Int *path_order,	/* the current path order */
+    Int *w_order,	/* the current order of the columns of W */
+    Int depth,
+    Int npaths		/* total number of paths */
+)
+{
+    Int c ;		/* child path */
+
+    ASSERT (path >= 0 && path < npaths) ;
+    if (path < k)
+    {
+	/* this is a leaf node, corresponding to column W (:,path) */
+	/* and column C (:, Path [path].ccol) */
+	ASSERT (Path [path].ccol >= 0) ;
+	Path [path].wfirst = *w_order ;
+	Path [path].order = *w_order ;
+	(*w_order)++ ;
+    }
+    else
+    {
+	/* this is a non-leaf path, within the tree */
+	ASSERT (Path [path].c != EMPTY) ;
+	ASSERT (Path [path].ccol == EMPTY) ;
+	/* order each child path */
+	for (c = Path [path].c ; c != EMPTY ; c = Path [c].next)
+	{
+	    dfs (Path, k, c, path_order, w_order, depth+1, npaths) ;
+	    if (Path [path].wfirst == EMPTY)
+	    {
+		Path [path].wfirst = Path [c].wfirst ;
+	    }
+	}
+	/* order this path next */
+	Path [path].order = (*path_order)++ ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === numeric update/downdate routines ===================================== */
+/* ========================================================================== */
+
+#define WDIM 1
+#include "t_cholmod_updown.c"
+#define WDIM 2
+#include "t_cholmod_updown.c"
+#define WDIM 4
+#include "t_cholmod_updown.c"
+#define WDIM 8
+#include "t_cholmod_updown.c"
+
+
+/* ========================================================================== */
+/* === cholmod_updown_mark ================================================== */
+/* ========================================================================== */
+
+/* Update/downdate LDL' +/- C*C', and update/downdate selected portions of the
+ * solution to Lx=b.
+ *
+ * The original system is L*x = b.  The new system is Lnew*xnew = b + deltab.
+ * deltab(i) can be nonzero only if column i of L is modified by the update/
+ * downdate.  If column i is not modified, the deltab(i) is not accessed.
+ *
+ * The solution to Lx=b is not modified if either X or DeltaB are NULL.
+ *
+ * Rowmark and colmark:
+ * --------------------
+ *
+ * rowmark and colmark affect which portions of L take part in the update/
+ * downdate of the solution to Lx=b.  They do not affect how L itself is
+ * updated/downdated.  They are both ignored if X or DeltaB are NULL.
+ *
+ * If not NULL, rowmark is an integer array of size n where L is n-by-n.
+ * rowmark [j] defines the part of column j of L that takes part in the update/
+ * downdate of the forward solve, Lx=b.  Specifically, if i = rowmark [j],
+ * then L(j:i-1,j) is used, and L(i:end,j) is ignored.
+ *
+ * If not NULL, colmark is an integer array of size C->ncol.  colmark [ccol]
+ * for a column C(:,ccol) redefines those parts of L that take part in the
+ * update/downdate of Lx=b.  Each column of C affects a set of columns of L.
+ * If column ccol of C affects column j of L, then the new rowmark [j] of
+ * column j of L is defined as colmark [ccol].  In a multiple-rank update/
+ * downdate, if two or more columns of C affect column j, its new rowmark [j]
+ * is the colmark of the least-numbered column of C.  colmark is ignored if
+ * it is NULL, in which case rowmark is not modified.  If colmark [ccol] is
+ * EMPTY (-1), then rowmark is not modified for that particular column of C.
+ * colmark is ignored if it is NULL, or rowmark, X, or DeltaB are NULL.
+ *
+ * The algorithm for modifying the solution to Lx=b when rowmark and colmark
+ * are NULL is as follows:
+ *
+ *	for each column j of L that is modified:
+ *	    deltab (j:end) += L (j:end,j) * x(j)
+ *	modify L
+ *	for each column j of L that is modified:
+ *	    x (j) = deltab (j)
+ *	    deltab (j) = 0
+ *	    deltab (j+1:end) -= L (j+1:end,j) * x(j)
+ *
+ * If rowmark is non-NULL but colmark is NULL:
+ *
+ *	for each column j of L that is modified:
+ *	    deltab (j:rowmark(j)-1) += L (j:rowmark(j)-1,j) * x(j)
+ *	modify L
+ *	for each column j of L that is modified:
+ *	    x (j) = deltab (j)
+ *	    deltab (j) = 0
+ *	    deltab (j+1:rowmark(j)-1) -= L (j+1:rowmark(j)-1,j) * x(j)
+ *
+ * If both rowmark and colmark are non-NULL:
+ *
+ *	for each column j of L that is modified:
+ *	    deltab (j:rowmark(j)-1) += L (j:rowmark(j)-1,j) * x(j)
+ *	modify L
+ *	for each column j of L that is modified:
+ *	    modify rowmark (j) according to colmark
+ *	for each column j of L that is modified:
+ *	    x (j) = deltab (j)
+ *	    deltab (j) = 0
+ *	    deltab (j+1:rowmark(j)-1) -= L (j+1:rowmark(j)-1,j) * x(j)
+ *
+ * Note that if the rank of C exceeds k = Common->maxrank (which is 2, 4, or 8),
+ * then the update/downdate is done as a series of rank-k updates.  In this
+ * case, the above algorithm is repeated for each block of k columns of C.
+ *
+ * Unless it leads to no changes in rowmark, colmark should be used only if
+ * C->ncol <= Common->maxrank, because the update/downdate is done with maxrank
+ * columns at a time.  Otherwise, the results are undefined.
+ *
+ * This routine is an "expert" routine.  It is meant for use in LPDASA only.
+ */
+
+int CHOLMOD(updown_mark)
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    Int *colmark,	/* Int array of size n. */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(updown_mask) (update, C, colmark, NULL, L, X, DeltaB,
+	Common)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_updown_mask ================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(updown_mask)
+(
+    /* ---- input ---- */
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* the incoming sparse update */
+    Int *colmark,	/* Int array of size n.  See cholmod_updown.c */
+    Int *mask,		/* size n */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factor to modify */
+    cholmod_dense *X,	/* solution to Lx=b (size n-by-1) */
+    cholmod_dense *DeltaB,  /* change in b, zero on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double xj, fl ;
+    double *Lx, *W, *Xx, *Nx ;
+    Int *Li, *Lp, *Lnz, *Cp, *Ci, *Cnz, *Head, *Flag, *Stack, *Lnext, *Iwork,
+	*Set_ps1 [32], *Set_ps2 [32], *ps1, *ps2 ;
+    size_t maxrank ;
+    Path_type OrderedPath [32], Path [32] ;
+    Int n, wdim, k1, k2, npaths, i, j, row, packed, ccol, p, cncol, do_solve,
+	mark, jj, j2, kk, nextj, p1, p2, c, use_colmark, newlnz,
+	k, newpath, path_order, w_order, scattered, path, newparent, pp1, pp2,
+	smax, maxrow, row1, nsets, s, p3, newlnz1, Set [32], top, len, lnz, m,
+	botrow ;
+    size_t w ;
+    int ok = TRUE ;
+    DEBUG (Int oldparent) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (C, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_REAL, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (C, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+    n = L->n ;
+    cncol = C->ncol ;
+    if (!(C->sorted))
+    {
+	ERROR (CHOLMOD_INVALID, "C must have sorted columns") ;
+	return (FALSE) ;
+    }
+    if (n != (Int) (C->nrow))
+    {
+	ERROR (CHOLMOD_INVALID, "C and L dimensions do not match") ;
+	return (FALSE) ;
+    }
+    do_solve = (X != NULL) && (DeltaB != NULL) ;
+    if (do_solve)
+    {
+	RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (DeltaB, CHOLMOD_REAL, CHOLMOD_REAL, FALSE) ;
+	Xx = X->x ;
+	Nx = DeltaB->x ;
+	if (X->nrow != L->n || X->ncol != 1 || DeltaB->nrow != L->n ||
+		DeltaB->ncol != 1 || Xx == NULL || Nx == NULL)
+	{
+	    ERROR (CHOLMOD_INVALID, "X and/or DeltaB invalid") ;
+	    return (FALSE) ;
+	}
+    }
+    else
+    {
+	Xx = NULL ;
+	Nx = NULL ;
+    }
+    Common->status = CHOLMOD_OK ;
+    Common->modfl = 0 ;
+
+    fl = 0 ;
+    use_colmark = (colmark != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Note: cholmod_rowadd and cholmod_rowdel use the second n doubles in
+     * Common->Xwork for Cx, and then perform a rank-1 update here, which uses
+     * the first n doubles in Common->Xwork.   Both the rowadd and rowdel
+     * routines allocate enough workspace so that Common->Xwork isn't destroyed
+     * below.  Also, both cholmod_rowadd and cholmod_rowdel use the second n
+     * ints in Common->Iwork for Ci.
+     */
+
+    /* make sure maxrank is in the proper range */
+    maxrank = CHOLMOD(maxrank) (n, Common) ;
+    k = MIN (cncol, (Int) maxrank) ;	/* maximum k is wdim */
+    wdim = Power2 [k] ;		/* number of columns needed in W */
+    ASSERT (wdim <= (Int) maxrank) ;
+    PRINT1 (("updown wdim final "ID" k "ID"\n", wdim, k)) ;
+
+    /* w = wdim * n */
+    w = CHOLMOD(mult_size_t) (n, wdim, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, n, w, Common) ;
+    if (Common->status < CHOLMOD_OK || maxrank == 0)
+    {
+	/* out of memory, L is returned unchanged */
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert to simplicial numeric LDL' factor, if not already */
+    /* ---------------------------------------------------------------------- */
+
+    if (L->xtype == CHOLMOD_PATTERN || L->is_super || L->is_ll) 
+    {
+	/* can only update/downdate a simplicial LDL' factorization */
+	CHOLMOD(change_factor) (CHOLMOD_REAL, FALSE, FALSE, FALSE, FALSE, L,
+		Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory, L is returned unchanged */
+	    return (FALSE) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* mark = CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    mark = Common->mark ;
+
+    PRINT1 (("updown, rank %g update %d\n", (double) C->ncol, update)) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "input L for updown", Common)) ;
+    ASSERT (CHOLMOD(dump_sparse) (C, "input C for updown", Common) >= 0) ;
+
+    Ci = C->i ;
+    Cp = C->p ;
+    Cnz = C->nz ;
+    packed = C->packed ;
+    ASSERT (IMPLIES (!packed, Cnz != NULL)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return */
+    /* ---------------------------------------------------------------------- */
+
+    if (cncol <= 0 || n == 0)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get L */
+    /* ---------------------------------------------------------------------- */
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+    Lnext = L->next ;
+    ASSERT (Lnz != NULL) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;	/* size n, Flag [i] <= mark must hold */
+    Head = Common->Head ;	/* size n, Head [i] == EMPTY must hold */
+    W = Common->Xwork ;		/* size n-by-wdim, zero on input and output*/
+
+    /* note that Iwork [n .. 2*n-1] (i/i/l) may be in use in rowadd/rowdel: */
+    Iwork = Common->Iwork ;
+    Stack = Iwork ;		/* size n, uninitialized (i/i/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* entire rank-cncol update, done as a sequence of rank-k updates */
+    /* ---------------------------------------------------------------------- */
+
+    ps1 = NULL ;
+    ps2 = NULL ;
+
+    for (k1 = 0 ; k1 < cncol ; k1 += k)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the next k columns of C for the update/downdate */
+	/* ------------------------------------------------------------------ */
+
+	/* the last update/downdate might be less than rank-k */
+	if (k > cncol - k1)
+	{
+	    k = cncol - k1 ;
+	    wdim = Power2 [k] ;
+	}
+	k2 = k1 + k - 1 ;
+
+	/* workspaces are in the following state, on input and output */
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* create a zero-length path for each column of W */
+	/* ------------------------------------------------------------------ */
+
+	nextj = n ;
+	path = 0 ;
+	for (ccol = k1 ; ccol <= k2 ; ccol++)
+	{
+	    PRINT1 (("Column ["ID"]: "ID"\n", path, ccol)) ;
+	    ASSERT (ccol >= 0 && ccol <= cncol) ;
+	    pp1 = Cp [ccol] ;
+	    pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ;
+	    /* get the row index j of the first entry in C (:,ccol) */
+	    if (pp2 > pp1)
+	    {
+		/* Column ccol of C has at least one entry. */
+		j = Ci [pp1] ;
+	    }
+	    else
+	    {
+		/* Column ccol of C is empty.  Pretend it has one entry in
+		 * the last column with numerical value of zero. */
+		j = n-1 ;
+	    }
+	    ASSERT (j >= 0 && j < n) ;
+
+	    /* find first column to work on */
+	    nextj = MIN (nextj, j) ;
+
+	    Path [path].ccol = ccol ;	/* which column of C this path is for */
+	    Path [path].start = EMPTY ;	/* paths for C have zero length */
+	    Path [path].end = EMPTY ;
+	    Path [path].parent = EMPTY ;    /* no parent yet */
+	    Path [path].rank = 1 ;	    /* one column of W */
+	    Path [path].c = EMPTY ;	    /* no child of this path (case A) */
+	    Path [path].next = Head [j] ;   /* this path is pending at col j */
+	    Path [path].pending = j ;	    /* this path is pending at col j */
+	    Head [j] = path ;		    /* this path is pending at col j */
+	    PRINT1(("Path "ID" starts: start "ID" end "ID" parent "ID" c "ID""
+		    "j "ID" ccol "ID"\n", path, Path [path].start,
+		    Path [path].end, Path [path].parent,
+		    Path [path].c, j, ccol)) ;
+
+	    /* initialize botrow for this path */
+	    Path [path].botrow = (use_colmark) ? colmark [ccol] : n ;
+
+	    path++ ;
+	}
+
+	/* we start with paths 0 to k-1.  Next one (now unused) is npaths */
+	npaths = k ;
+
+	j = nextj ;
+	ASSERT (j < n) ;
+	scattered = FALSE ;
+
+	/* ------------------------------------------------------------------ */
+	/* symbolic update of columns of L */
+	/* ------------------------------------------------------------------ */
+
+	while (j < n)
+	{
+	    ASSERT (j >= 0 && j < n && Lnz [j] > 0) ;
+
+	    /* the old column, Li [p1..p2-1].  D (j,j) is stored in Lx [p1] */
+	    p1 = Lp [j] ;
+	    newlnz = Lnz [j] ;
+	    p2 = p1 + newlnz  ;
+
+#ifndef NDEBUG
+	    PRINT1 (("\n=========Column j="ID" p1 "ID" p2 "ID" lnz "ID" \n",
+			j, p1, p2, newlnz)) ;
+	    dump_col ("Old", j, p1, p2, Li, Lx, n, Common) ;
+	    oldparent = (Lnz [j] > 1) ? (Li [p1 + 1]) : EMPTY ;
+	    ASSERT (CHOLMOD(dump_work) (TRUE, FALSE, 0, Common)) ;
+	    ASSERT (!scattered) ;
+	    PRINT1 (("Col "ID": Checking paths, npaths: "ID"\n", j, npaths)) ;
+	    for (kk = 0 ; kk < npaths ; kk++)
+	    {
+		Int kk2, found, j3 = Path [kk].pending ;
+		PRINT2 (("Path "ID" pending at "ID".\n", kk, j3)) ;
+		if (j3 != EMPTY)
+		{
+		    /* Path kk must be somewhere in link list for column j3 */
+		    ASSERT (Head [j3] != EMPTY) ;
+		    PRINT3 (("    List at "ID": ", j3)) ;
+		    found = FALSE ;
+		    for (kk2 = Head [j3] ; kk2 != EMPTY ; kk2 = Path [kk2].next)
+		    {
+			PRINT3 ((""ID" ", kk2)) ;
+			ASSERT (Path [kk2].pending == j3) ;
+			found = found || (kk2 == kk) ;
+		    }
+		    PRINT3 (("\n")) ;
+		    ASSERT (found) ;
+		}
+	    }
+	    PRINT1 (("\nCol "ID": Paths at this column, head "ID"\n",
+			j, Head [j]));
+	    ASSERT (Head [j] != EMPTY) ;
+	    for (kk = Head [j] ; kk != EMPTY ; kk = Path [kk].next)
+	    {
+		PRINT1 (("path "ID": (c="ID" j="ID") npaths "ID"\n",
+			    kk, Path[kk].c, j, npaths)) ;
+		ASSERT (kk >= 0 && kk < npaths) ;
+		ASSERT (Path [kk].pending == j) ;
+	    }
+#endif
+
+	    /* -------------------------------------------------------------- */
+	    /* determine the path we're on */
+	    /* -------------------------------------------------------------- */
+
+	    /* get the first old path at column j */
+	    path = Head [j] ;
+
+	    /* -------------------------------------------------------------- */
+	    /* update/downdate of forward solve, Lx=b */
+	    /* -------------------------------------------------------------- */
+
+	    if (do_solve)
+	    {
+		xj = Xx [j] ;
+		if (IS_NONZERO (xj))
+		{
+		    xj = Xx [j] ;
+		    /* This is first time column j has been seen for entire */
+		    /* rank-k update/downdate. */
+
+		    /* DeltaB += Lold (j:botrow-1,j) * X (j) */
+		    Nx [j] += xj ;			/* diagonal of L */
+
+		    /* find the botrow for this column */
+		    botrow = (use_colmark) ? Path [path].botrow : n ;
+
+		    for (p = p1 + 1 ; p < p2 ; p++)
+		    {
+			i = Li [p] ;
+			if (i >= botrow)
+			{
+			    break ;
+			}
+			Nx [i] += Lx [p] * xj ;
+		    }
+
+		    /* clear X[j] to flag col j of Lold as having been seen.  If
+		     * X (j) was initially zero, then the above code is never
+		     * executed for column j.  This is safe, since if xj=0 the
+		     * code above does not do anything anyway.  */
+		    Xx [j] = 0.0 ;
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* start a new path at this column if two or more paths merge */
+	    /* -------------------------------------------------------------- */
+
+	    newpath =
+		/* start a new path if paths have merged */
+		(Path [path].next != EMPTY)
+		/* or if j is the first node on a path (case A). */
+		|| (Path [path].c == EMPTY) ;
+
+	    if (newpath)
+	    {
+		/* get the botrow of the first path at column j */
+		botrow = (use_colmark) ? Path [path].botrow : n ;
+
+		path = npaths++ ;
+		ASSERT (npaths <= 3*k) ;
+		Path [path].ccol = EMPTY ; /* no single col of C for this path*/
+		Path [path].start = j ;	   /* path starts at this column j */
+		Path [path].end = EMPTY ;  /* don't know yet where it ends */
+		Path [path].parent = EMPTY ;/* don't know parent path yet */
+		Path [path].rank = 0 ;	/* rank is sum of child path ranks */
+		PRINT1 (("Path "ID" starts: start "ID" end "ID" parent "ID"\n",
+		path, Path [path].start, Path [path].end, Path [path].parent)) ;
+
+		/* set the botrow of the new path */
+		Path [path].botrow = (use_colmark) ? botrow : n ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* for each path kk pending at column j */
+	    /* -------------------------------------------------------------- */
+
+	    /* make a list of the sets that need to be merged into column j */
+	    nsets = 0 ;
+
+	    for (kk = Head [j] ; kk != EMPTY ; kk = Path [kk].next)
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* path kk is at (c,j) */
+		/* ---------------------------------------------------------- */
+
+		c = Path [kk].c ;
+		ASSERT (c < j) ;
+		PRINT1 (("TUPLE on path "ID" (c="ID" j="ID")\n", kk, c, j)) ;
+		ASSERT (Path [kk].pending == j) ;
+
+		if (newpath)
+		{
+		    /* finalize path kk and find rank of this path */
+		    Path [kk].end = c ;	/* end of old path is previous node c */
+		    Path [kk].parent = path ;	/* parent is this path */
+		    Path [path].rank += Path [kk].rank ;    /* sum up ranks */
+		    Path [kk].pending = EMPTY ;
+		    PRINT1 (("Path "ID" done:start "ID" end "ID" parent "ID"\n",
+		    kk, Path [kk].start, Path [kk].end, Path [kk].parent)) ;
+		}
+
+		if (c == EMPTY)
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* CASE A: first node in path */
+		    /* ------------------------------------------------------ */
+
+		    /* update:  add pattern of incoming column */
+
+		    /* Column ccol of C is in Ci [pp1 ... pp2-1] */
+		    ccol = Path [kk].ccol ;
+		    pp1 = Cp [ccol] ;
+		    pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ;
+		    PRINT1 (("Case A, ccol = "ID" len "ID"\n", ccol, pp2-pp1)) ;
+		    ASSERT (IMPLIES (pp2 > pp1, Ci [pp1] == j)) ;
+
+		    if (!scattered)
+		    {
+			/* scatter the original pattern of column j of L */
+			for (p = p1 ; p < p2 ; p++)
+			{
+			    Flag [Li [p]] = mark ;
+			}
+			scattered = TRUE ;
+		    }
+
+		    /* scatter column ccol of C (skip first entry, j) */
+		    newlnz1 = newlnz ;
+		    for (p = pp1 + 1 ; p < pp2 ; p++)
+		    {
+			row = Ci [p] ;
+			if (Flag [row] < mark)
+			{
+			    /* this is a new entry in Lj' */
+			    Flag [row] = mark ;
+			    newlnz++ ;
+			}
+		    }
+		    if (newlnz1 != newlnz)
+		    {
+			/* column ccol of C adds something to column j of L */
+			Set [nsets++] = FLIP (ccol) ;
+		    }
+
+		}
+		else if (Head [c] == 1)
+		{
+
+		    /* ------------------------------------------------------ */
+		    /* CASE B: c is old, but changed, child of j */
+		    /* CASE C: new child of j */
+		    /* ------------------------------------------------------ */
+
+		    /* Head [c] is 1 if col c of L has new entries,
+		     * EMPTY otherwise */
+		    Flag [c] = 0 ;
+		    Head [c] = EMPTY ;
+
+		    /* update: add Lc' */
+
+		    /* column c of L is in Li [pp1 .. pp2-1] */
+		    pp1 = Lp [c] ;
+		    pp2 = pp1 + Lnz [c] ;
+		    PRINT1 (("Case B/C: c = "ID"\n", c)) ;
+		    DEBUG (dump_col ("Child", c, pp1, pp2, Li, Lx, n, Common)) ;
+		    ASSERT (j == Li [pp1 + 1]) ; /* j is new parent of c */
+
+		    if (!scattered)
+		    {
+			/* scatter the original pattern of column j of L */
+			for (p = p1 ; p < p2 ; p++)
+			{
+			    Flag [Li [p]] = mark ;
+			}
+			scattered = TRUE ;
+		    }
+
+		    /* scatter column c of L (skip first two entries, c and j)*/
+		    newlnz1 = newlnz ;
+		    for (p = pp1 + 2 ; p < pp2 ; p++)
+		    {
+			row = Li [p] ;
+			if (Flag [row] < mark)
+			{
+			    /* this is a new entry in Lj' */
+			    Flag [row] = mark ;
+			    newlnz++ ;
+			}
+		    }
+		    PRINT2 (("\n")) ;
+
+		    if (newlnz1 != newlnz)
+		    {
+			/* column c of L adds something to column j of L */
+			Set [nsets++] = c ;
+		    }
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* update the pattern of column j of L */
+	    /* -------------------------------------------------------------- */
+
+	    /* Column j of L will be in Li/Lx [p1 .. p3-1] */
+	    p3 = p1 + newlnz ;
+	    ASSERT (IMPLIES (nsets == 0, newlnz == Lnz [j])) ;
+	    PRINT1 (("p1 "ID" p2 "ID" p3 "ID" nsets "ID"\n", p1, p2, p3,nsets));
+
+	    /* -------------------------------------------------------------- */
+	    /* ensure we have enough space for the longer column */
+	    /* -------------------------------------------------------------- */
+
+	    if (nsets > 0 && p3 > Lp [Lnext [j]])
+	    {
+		PRINT1 (("Col realloc: j "ID" newlnz "ID"\n", j, newlnz)) ;
+		if (!CHOLMOD(reallocate_column) (j, newlnz, L, Common))
+		{
+		    /* out of memory, L is now simplicial symbolic */
+		    CHOLMOD(clear_flag) (Common) ;
+		    for (j = 0 ; j <= n ; j++)
+		    {
+			Head [j] = EMPTY ;
+		    }
+		    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ;
+		    return (FALSE) ;
+		}
+		/* L->i and L->x may have moved.  Column j has moved too */
+		Li = L->i ;
+		Lx = L->x ;
+		p1 = Lp [j] ;
+		p2 = p1 + Lnz [j] ;
+		p3 = p1 + newlnz ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* create set pointers */
+	    /* -------------------------------------------------------------- */
+
+	    for (s = 0 ; s < nsets ; s++)
+	    {
+		/* Pattern of Set s is *(Set_ps1 [s] ... Set_ps2 [s]-1) */
+		c = Set [s] ;
+		if (c < EMPTY)
+		{
+		    /* column ccol of C, skip first entry (j) */
+		    ccol = FLIP (c) ;
+		    pp1 = Cp [ccol] ;
+		    pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ;
+		    ASSERT (pp2 - pp1 > 1) ;
+		    Set_ps1 [s] = &(Ci [pp1 + 1]) ;
+		    Set_ps2 [s] = &(Ci [pp2]) ;
+		    PRINT1 (("set "ID" is ccol "ID"\n", s, ccol)) ;
+		}
+		else
+		{
+		    /* column c of L, skip first two entries (c and j)  */
+		    pp1 = Lp [c] ;
+		    pp2 = pp1 + Lnz [c]  ;
+		    ASSERT (Lnz [c] > 2) ;
+		    Set_ps1 [s] = &(Li [pp1 + 2]) ;
+		    Set_ps2 [s] = &(Li [pp2]) ;
+		    PRINT1 (("set "ID" is L "ID"\n", s, c)) ;
+		}
+		DEBUG (dump_set (s, Set_ps1, Set_ps2, j, n, Common)) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* multiset merge */
+	    /* -------------------------------------------------------------- */
+
+	    /* Merge the sets into a single sorted set, Lj'.  Before the merge
+	     * starts, column j is located in Li/Lx [p1 ... p2-1] and the
+	     * space Li/Lx [p2 ... p3-1] is empty.  p1 is Lp [j], p2 is
+	     * Lp [j] + Lnz [j] (the old length of the column), and p3 is
+	     * Lp [j] + newlnz (the new and longer length of the column).
+	     *
+	     * The sets 0 to nsets-1 are defined by the Set_ps1 and Set_ps2
+	     * pointers.  Set s is located in *(Set_ps1 [s] ... Set_ps2 [s]-1).
+	     * It may be a column of C, or a column of L.  All row indices i in
+	     * the sets are in the range i > j and i < n.  All sets are sorted.
+	     *
+	     * The merge into column j of L is done in place.
+	     *
+	     * During the merge, p2 and p3 are updated.  Li/Lx [p1..p2-1]
+	     * reflects the indices of the old column j of L that are yet to
+	     * be merged into the new column.  Entries in their proper place in
+	     * the new column j of L are located in Li/Lx [p3 ... p1+newlnz-1].
+	     * The merge finishes when p2 == p3.
+	     *
+	     * During the merge, set s consumed as it is merged into column j of
+	     * L.  Its unconsumed contents are *(Set_ps1 [s] ... Set_ps2 [s]-1).
+	     * When a set is completely consumed, it is removed from the set of
+	     * sets, and nsets is decremented.
+	     *
+	     * The multiset merge and 2-set merge finishes when p2 == p3.
+	     */
+
+	    PRINT1 (("Multiset merge p3 "ID" p2 "ID" nsets "ID"\n",
+			p3, p2, nsets)) ;
+
+	    while (p3 > p2 && nsets > 1)
+	    {
+
+#ifndef NDEBUG
+		PRINT2 (("\nMultiset merge.  nsets = "ID"\n", nsets)) ;
+		PRINT2 (("Source col p1 = "ID", p2 = "ID", p3= "ID"\n",
+			    p1, p2, p3)) ;
+		for (p = p1 + 1 ; p < p2 ; p++)
+		{
+		    PRINT2 (("    p: "ID" source row "ID" %g\n",
+				p, Li[p], Lx[p])) ;
+		    ASSERT (Li [p] > j && Li [p] < n) ;
+		}
+		PRINT2 (("---\n")) ;
+		for (p = p3 ; p < p1 + newlnz ; p++)
+		{
+		    PRINT2 (("    p: "ID" target row "ID" %g\n",
+				p, Li[p], Lx[p])) ;
+		    ASSERT (Li [p] > j && Li [p] <  n) ;
+		}
+		for (s = 0 ; s < nsets ; s++)
+		{
+		    dump_set (s, Set_ps1, Set_ps2, j, n, Common) ;
+		}
+#endif
+
+		/* get the entry at the tail end of source column Lj */
+		row1 = Li [p2 - 1] ;
+		ASSERT (row1 >= j && p2 >= p1) ;
+
+		/* find the largest row in all the sets */
+		maxrow = row1 ;
+		smax = EMPTY ;
+		for (s = nsets-1 ; s >= 0 ; s--)
+		{
+		    ASSERT (Set_ps1 [s] < Set_ps2 [s]) ;
+		    row = *(Set_ps2 [s] - 1) ;
+		    if (row == maxrow)
+		    {
+			/* skip past this entry in set s (it is a duplicate) */
+			Set_ps2 [s]-- ;
+			if (Set_ps1 [s] == Set_ps2 [s])
+			{
+			    /* nothing more in this set */
+			    nsets-- ;
+			    Set_ps1 [s] = Set_ps1 [nsets] ;
+			    Set_ps2 [s] = Set_ps2 [nsets] ;
+			    if (smax == nsets)
+			    {
+				/* Set smax redefined; it is now this set */
+				smax = s ;
+			    }
+			}
+		    }
+		    else if (row > maxrow)
+		    {
+			maxrow = row ;
+			smax = s ;
+		    }
+		}
+		ASSERT (maxrow > j) ;
+
+		/* move the row onto the stack of the target column */
+		if (maxrow == row1)
+		{
+		    /* next entry is in Lj, move to the bottom of Lj' */
+		    ASSERT (smax == EMPTY) ;
+		    p2-- ;
+		    p3-- ;
+		    Li [p3] = maxrow ;
+		    Lx [p3] = Lx [p2] ;
+		}
+		else
+		{
+		    /* new entry in Lj' */
+		    ASSERT (smax >= 0 && smax < nsets) ;
+		    Set_ps2 [smax]-- ;
+		    p3-- ;
+		    Li [p3] = maxrow ;
+		    Lx [p3] = 0.0 ;
+		    if (Set_ps1 [smax] == Set_ps2 [smax])
+		    {
+			/* nothing more in this set */
+			nsets-- ;
+			Set_ps1 [smax] = Set_ps1 [nsets] ;
+			Set_ps2 [smax] = Set_ps2 [nsets] ;
+			PRINT1 (("Set "ID" now empty\n", smax)) ;
+		    }
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* 2-set merge: */
+	    /* -------------------------------------------------------------- */
+
+	    /* This the same as the multi-set merge, except there is only one
+	     * set s = 0 left.  The source column j and the set 0 are being
+	     * merged into the target column j. */
+
+	    if (nsets > 0)
+	    {
+		ps1 = Set_ps1 [0] ;
+		ps2 = Set_ps2 [0] ;
+	    }
+
+	    while (p3 > p2)
+	    {
+
+#ifndef NDEBUG
+		PRINT2 (("\n2-set merge.\n")) ;
+		ASSERT (nsets == 1) ;
+		PRINT2 (("Source col p1 = "ID", p2 = "ID", p3= "ID"\n",
+			    p1, p2, p3)) ;
+		for (p = p1 + 1 ; p < p2 ; p++)
+		{
+		    PRINT2 (("    p: "ID" source row "ID" %g\n",
+				p, Li[p], Lx[p])) ;
+		    ASSERT (Li [p] > j && Li [p] < n) ;
+		}
+		PRINT2 (("---\n")) ;
+		for (p = p3 ; p < p1 + newlnz ; p++)
+		{
+		    PRINT2 (("    p: "ID" target row "ID" %g\n",
+				p, Li[p], Lx[p])) ;
+		    ASSERT (Li [p] > j && Li [p] <  n) ;
+		}
+		dump_set (0, Set_ps1, Set_ps2, j, n, Common) ;
+#endif
+
+		if (p2 == p1 + 1)
+		{
+		    /* the top of Lj is empty; copy the set and quit */
+		    while (p3 > p2)
+		    {
+			/* new entry in Lj' */
+			row = *(--ps2) ;
+			p3-- ;
+			Li [p3] = row ;
+			Lx [p3] = 0.0 ;
+		    }
+		}
+		else
+		{
+		    /* get the entry at the tail end of Lj */
+		    row1 = Li [p2 - 1] ;
+		    ASSERT (row1 > j && row1 < n) ;
+		    /* get the entry at the tail end of the incoming set */
+		    ASSERT (ps1 < ps2) ;
+		    row = *(ps2-1) ;
+		    ASSERT (row > j && row1 < n) ;
+		    /* move the larger of the two entries to the target set */
+		    if (row1 >= row)
+		    {
+			/* next entry is in Lj, move to the bottom */
+			if (row1 == row)
+			{
+			    /* skip past this entry in the set */
+			    ps2-- ;
+			}
+			p2-- ;
+			p3-- ;
+			Li [p3] = row1 ;
+			Lx [p3] = Lx [p2] ;
+		    }
+		    else
+		    {
+			/* new entry in Lj' */
+			ps2-- ;
+			p3-- ;
+			Li [p3] = row ;
+			Lx [p3] = 0.0 ;
+		    }
+		}
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* The new column j of L is now in Li/Lx [p1 ... p2-1] */
+	    /* -------------------------------------------------------------- */
+
+	    p2 = p1 + newlnz ;
+	    DEBUG (dump_col ("After merge: ", j, p1, p2, Li, Lx, n, Common)) ;
+
+	    fl += Path [path].rank * (6 + 4 * (double) newlnz) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* clear Flag; original pattern of column j L no longer marked */
+	    /* -------------------------------------------------------------- */
+
+	    mark = CHOLMOD(clear_flag) (Common) ;
+	    scattered = FALSE ;
+
+	    /* -------------------------------------------------------------- */
+	    /* find the new parent */
+	    /* -------------------------------------------------------------- */
+
+	    newparent = (newlnz > 1) ? (Li [p1 + 1]) : EMPTY ;
+	    PRINT1 (("\nNew parent, Lnz: "ID": "ID" "ID"\n",
+			j, newparent,newlnz));
+	    ASSERT (oldparent == EMPTY || newparent <= oldparent) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* go to the next node in the path */
+	    /* -------------------------------------------------------------- */
+
+	    /* path moves to (j,nextj) unless j is a root */
+	    nextj = (newparent == EMPTY) ? n : newparent ;
+
+	    /* place path at head of list for nextj, or terminate the path */
+	    PRINT1 (("\n j = "ID" nextj = "ID"\n\n", j, nextj)) ;
+	    Path [path].c = j ;
+	    if (nextj < n)
+	    {
+		/* put path on link list of pending paths at column nextj */
+		Path [path].next = Head [nextj] ;
+		Path [path].pending = nextj ;
+		Head [nextj] = path ;
+		PRINT1 (("Path "ID" continues to ("ID","ID").  Rank "ID"\n",
+		    path, Path [path].c, nextj, Path [path].rank)) ;
+	    }
+	    else
+	    {
+		/* path has ended here, at a root */
+		Path [path].next = EMPTY ;
+		Path [path].pending = EMPTY ;
+		Path [path].end = j ;
+		PRINT1 (("Path "ID" ends at root ("ID").  Rank "ID"\n",
+		    path, Path [path].end, Path [path].rank)) ;
+	    }
+
+	    /* The link list Head [j] can now be emptied.  Set Head [j] to 1
+	     * if column j has changed (it is no longer used as a link list). */
+	    PRINT1 (("column "ID", oldlnz = "ID"\n", j, Lnz [j])) ;
+	    Head [j] = (Lnz [j] != newlnz) ? 1 : EMPTY ;
+	    Lnz [j] = newlnz ;
+	    PRINT1 (("column "ID", newlnz = "ID"\n", j, newlnz)) ;
+	    DEBUG (dump_col ("New", j, p1, p2, Li, Lx, n, Common)) ;
+
+	    /* move to the next column */
+	    if (k == Path [path].rank)
+	    {
+		/* only one path left */
+		j = nextj ;
+	    }
+	    else
+	    {
+		/* The current path is moving from column j to column nextj
+		 * (nextj is n if the path has ended).  However, there may be
+		 * other paths pending in columns j+1 to nextj-1.  There are
+		 * two methods for looking for the next column with a pending
+		 * update.  The first one looks at all columns j+1 to nextj-1
+		 * for a non-empty link list.  This can be costly if j and
+		 * nextj differ by a large amount (it can be O(n), but this
+		 * entire routine may take Omega(1) time).  The second method
+		 * looks at all paths and finds the smallest column at which any
+		 * path is pending.  It takes O(# of paths), which is bounded
+		 * by 23: one for each column of C (up to 8), and then 15 for a
+		 * balanced binary tree with 8 leaves.  However, if j and
+		 * nextj differ by a tiny amount (nextj is often j+1 near
+		 * the end of the matrix), looking at columns j+1 to nextj
+		 * would be faster.  Both methods give the same answer. */
+
+		if (nextj - j < npaths)
+		{
+		    /* there are fewer columns to search than paths */
+		    PRINT1 (("check j="ID" to nextj="ID"\n", j, nextj)) ;
+		    for (j2 = j + 1 ; j2 < nextj ; j2++)
+		    {
+			PRINT1 (("check j="ID" "ID"\n", j2, Head [j2])) ;
+			if (Head [j2] != EMPTY)
+			{
+			    PRINT1 (("found, j="ID"\n", j2)) ;
+			    ASSERT (Path [Head [j2]].pending == j2) ;
+			    break ;
+			}
+		    }
+		}
+		else
+		{
+		    /* there are fewer paths than columns to search */
+		    j2 = nextj ;
+		    for (kk = 0 ; kk < npaths ; kk++)
+		    {
+			jj = Path [kk].pending ;
+			PRINT2 (("Path "ID" pending at "ID"\n", kk, jj)) ;
+			if (jj != EMPTY) j2 = MIN (j2, jj) ;
+		    }
+		}
+		j = j2 ;
+	    }
+	}
+
+	/* ensure workspaces are back to the values required on input */
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, TRUE, Common)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* depth-first-search of tree to order the paths */
+	/* ------------------------------------------------------------------ */
+
+	/* create lists of child paths */
+	PRINT1 (("\n\nDFS search:\n\n")) ;
+	for (path = 0 ; path < npaths ; path++)
+	{
+	    Path [path].c = EMPTY ;	    /* first child of path */
+	    Path [path].next = EMPTY ;	    /* next sibling of path */
+	    Path [path].order = EMPTY ;	    /* path is not ordered yet */
+	    Path [path].wfirst = EMPTY ;    /* 1st column of W not found yet */
+
+#ifndef NDEBUG
+	    j = Path [path].start ;
+	    PRINT1 (("Path "ID" : start "ID" end "ID" parent "ID" ccol "ID"\n", 
+	    path, j, Path [path].end, Path [path].parent, Path [path].ccol)) ;
+	    for ( ; ; )
+	    {
+		PRINT1 (("	column "ID"\n", j)) ;
+		ASSERT (j == EMPTY || (j >= 0 && j < n)) ;
+		if (j == Path [path].end)
+		{
+		    break ;
+		}
+		ASSERT (j >= 0 && j < n) ;
+		j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : EMPTY ;
+	    }
+#endif
+	}
+
+	for (path = 0 ; path < npaths ; path++)
+	{
+	    p = Path [path].parent ;	/* add path to child list of parent */
+	    if (p != EMPTY)
+	    {
+		ASSERT (p < npaths) ;
+		Path [path].next = Path [p].c ;
+		Path [p].c = path ;
+	    }
+	}
+
+	path_order = k ;
+	w_order = 0 ;
+	for (path = npaths-1 ; path >= 0 ; path--)
+	{
+	    if (Path [path].order == EMPTY)
+	    {
+		/* this path is the root of a subtree of Tbar */
+		PRINT1 (("Root path "ID"\n", path)) ;
+		ASSERT (path >= k) ;
+		dfs (Path, k, path, &path_order, &w_order, 0, npaths) ;
+	    }
+	}
+	ASSERT (path_order == npaths) ;
+	ASSERT (w_order == k) ;
+
+	/* reorder the paths */
+	for (path = 0 ; path < npaths ; path++)
+	{
+	    /* old order is path, new order is Path [path].order */
+	    OrderedPath [Path [path].order] = Path [path] ;
+	}
+
+#ifndef NDEBUG
+	for (path = 0 ; path < npaths ; path++)
+	{
+	    PRINT1 (("Ordered Path "ID": start "ID" end "ID" wfirst "ID" rank "
+		    ""ID" ccol "ID"\n", path, OrderedPath [path].start,
+		    OrderedPath [path].end, OrderedPath [path].wfirst,
+		    OrderedPath [path].rank, OrderedPath [path].ccol)) ;
+	    if (path < k)
+	    {
+		ASSERT (OrderedPath [path].ccol >= 0) ;
+	    }
+	    else
+	    {
+		ASSERT (OrderedPath [path].ccol == EMPTY) ;
+	    }
+	}
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* numeric update/downdate for all paths */
+	/* ------------------------------------------------------------------ */
+
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ;
+
+	switch (wdim)
+	{
+	    case 1:
+		updown_1_r (update, C, k, L, W, OrderedPath, npaths, mask,
+		    Common) ;
+		break ;
+	    case 2:
+		updown_2_r (update, C, k, L, W, OrderedPath, npaths, mask,
+		    Common) ;
+		break ;
+	    case 4:
+		updown_4_r (update, C, k, L, W, OrderedPath, npaths, mask,
+		    Common) ;
+		break ;
+	    case 8:
+		updown_8_r (update, C, k, L, W, OrderedPath, npaths, mask,
+		    Common) ;
+		break ;
+	}
+
+	ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, wdim, Common)) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* update/downdate the forward solve */
+    /* ---------------------------------------------------------------------- */
+
+    if (do_solve)
+    {
+	/* We now have DeltaB += Lold (:,j) * X (j) for all columns j in union
+	 * of all paths seen during the entire rank-cncol update/downdate. For
+	 * each j in path, do DeltaB -= Lnew (:,j)*DeltaB(j) 
+	 * in topological order. */
+
+#ifndef NDEBUG
+	PRINT1 (("\ndo_solve, DeltaB + Lold(:,Path)*X(Path):\n")) ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    PRINT1 (("do_solve: "ID" %30.20e\n", i, Nx [i])) ;
+	}
+#endif
+
+	/* Note that the downdate, if it deleted entries, would need to compute
+	 * the Stack prior to doing any downdates. */
+
+	/* find the union of all the paths in the new L */
+	top = n ;	/* "top" is stack pointer, not a row or column index */
+	for (ccol = 0 ; ccol < cncol ; ccol++)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* j = first row index of C (:,ccol) */
+	    /* -------------------------------------------------------------- */
+
+	    pp1 = Cp [ccol] ;
+	    pp2 = (packed) ? (Cp [ccol+1]) : (pp1 + Cnz [ccol]) ;
+	    if (pp2 > pp1)
+	    {
+		/* Column ccol of C has at least one entry. */
+		j = Ci [pp1] ;
+	    }
+	    else
+	    {
+		/* Column ccol of C is empty */
+		j = n-1 ;
+	    }
+	    PRINT1 (("\ndo_solve:      ccol= "ID"\n", ccol)) ;
+	    ASSERT (j >= 0 && j < n) ;
+	    len = 0 ;
+
+	    /* -------------------------------------------------------------- */
+	    /* find the new rowmark */
+	    /* -------------------------------------------------------------- */
+
+	    /* Each column of C can redefine the region of L that takes part in
+	     * the update/downdate of the triangular solve Lx=b.  If
+	     * i = colmark [ccol] for column C(:,ccol), then i = rowmark [j] is
+	     * redefined for all columns along the path modified by C(:,ccol).
+	     * If more than one column modifies any given column j of L, then
+	     * the rowmark of j is determined by the colmark of the least-
+	     * numbered column that affects column j.  That is, if both
+	     * C(:,ccol1) and C(:,ccol2) affect column j of L, then
+	     * rowmark [j] = colmark [MIN (ccol1, ccol2)].
+	     *
+	     * rowmark [j] is not modified if rowmark or colmark are NULL,
+	     * or if colmark [ccol] is EMPTY.
+	     */
+
+	    botrow = (use_colmark) ? (colmark [ccol]) : EMPTY ;
+
+	    /* -------------------------------------------------------------- */
+	    /* traverse from j towards root, stopping if node already visited */
+	    /* -------------------------------------------------------------- */
+
+	    while (j != EMPTY && Flag [j] < mark)
+	    {
+		PRINT1 (("do_solve: subpath j= "ID"\n", j)) ;
+		ASSERT (j >= 0 && j < n) ;
+		Stack [len++] = j ;		/* place j on the stack */
+		Flag [j] = mark ;		/* flag j as visited */
+
+		/* if using colmark, mark column j with botrow */
+		ASSERT (Li [Lp [j]] == j) ;	/* diagonal is always present */
+		if (use_colmark)
+		{
+		    Li [Lp [j]] = botrow ;	/* use the space for botrow */
+		}
+
+		/* go up the tree, to the parent of j */
+		j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : EMPTY ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* move the path down to the bottom of the stack */
+	    /* -------------------------------------------------------------- */
+
+	    ASSERT (len <= top) ;
+	    while (len > 0)
+	    {
+		Stack [--top] = Stack [--len] ;
+	    }
+	}
+
+#ifndef NDEBUG
+	/* Union of paths now in Stack [top..n-1] in topological order */
+	PRINT1 (("\nTopological order:\n")) ;
+	for (i = top ; i < n ; i++)
+	{
+	    PRINT1 (("column "ID" in full path\n", Stack [i])) ;
+	}
+#endif
+
+	/* Do the forward solve for the full path part of L */
+	for (m = top ; m < n ; m++)
+	{
+	    j = Stack [m] ;
+	    ASSERT (j >= 0 && j < n) ;
+	    PRINT1 (("do_solve: path j= "ID"\n", j)) ;
+	    p1 = Lp [j] ;
+	    lnz = Lnz [j] ;
+	    p2 = p1 + lnz ;
+	    xj = Nx [j] ;
+
+	    /* copy new solution onto old one, for all cols in full path */
+	    Xx [j] = xj ;
+	    Nx [j] = 0. ;
+
+	    /* DeltaB -= Lnew (j+1:botrow-1,j) * deltab(j) */
+	    if (use_colmark)
+	    {
+		botrow = Li [p1] ;	/* get botrow */
+		Li [p1] = j ;		/* restore diagonal entry */
+		for (p = p1 + 1 ; p < p2 ; p++)
+		{
+		    i = Li [p] ;
+		    if (i >= botrow) break ;
+		    Nx [i] -= Lx [p] * xj ;
+		}
+	    }
+	    else
+	    {
+		for (p = p1 + 1 ; p < p2 ; p++)
+		{
+		    Nx [Li [p]] -= Lx [p] * xj ;
+		}
+	    }
+	}
+
+	/* clear the Flag */
+	mark = CHOLMOD(clear_flag) (Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* successful update/downdate */
+    /* ---------------------------------------------------------------------- */
+
+    Common->modfl = fl ;
+    DEBUG (for (j = 0 ; j < n ; j++) ASSERT (IMPLIES (do_solve, Nx[j] == 0.))) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, TRUE, Common)) ;
+    DEBUG (CHOLMOD(dump_factor) (L, "output L for updown", Common)) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Modify/gpl.txt b/src/CHOLMOD/Modify/gpl.txt
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/src/CHOLMOD/Modify/gpl.txt
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/CHOLMOD/Modify/t_cholmod_updown.c b/src/CHOLMOD/Modify/t_cholmod_updown.c
new file mode 100644
index 0000000..8d63c48
--- /dev/null
+++ b/src/CHOLMOD/Modify/t_cholmod_updown.c
@@ -0,0 +1,214 @@
+/* ========================================================================== */
+/* === Modify/t_cholmod_updown ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Modify Module.  Copyright (C) 2005-2006,
+ * Timothy A. Davis and William W. Hager.
+ * The CHOLMOD/Modify Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Updates/downdates the LDL' factorization, by computing a new factorization of
+ *
+ *   	Lnew * Dnew * Lnew' = Lold * Dold * Lold' +/- C*C'
+ *
+ * This file is not compiled separately.  It is included into
+ * cholmod_updown.c.  There are no user-callable routines in this file.
+ *
+ * The next include statements, below, create the numerical update/downdate
+ * kernels from t_cholmod_updown_numkr.c.  There are 4 compiled versions of this
+ * file, one for each value of WDIM in the set 1, 2, 4, and 8.  Each calls
+ * multiple versions of t_cholmod_updown_numkr; the number of versions of each
+ * is equal to WDIM.  Each t_cholmod_updown_numkr version is included as a
+ * static function within its t_cholmod_updown.c caller routine.  Thus:
+ *
+ *	t*_updown.c	creates these versions of t_cholmod_updown_numkr.c:
+ *	---------	---------------------------------------------------
+ *
+ *	updown_1_r	updown_1_1
+ *
+ *	updown_2_r	updown_2_1     updown_2_2
+ *
+ *	updown_4_r	updown_4_1     updown_4_2     updown_4_3     updown_4_4
+ *
+ *	updown_8_r	updown_8_1     updown_8_2     updown_8_3     updown_8_4
+ *			updown_8_5     updown_8_6     updown_8_7     updown_8_8
+ *
+ * workspace: Xwork (nrow*wdim)
+ */
+
+/* ========================================================================== */
+/* === routines for numeric update/downdate along one path ================== */
+/* ========================================================================== */
+
+#undef FORM_NAME
+#undef NUMERIC
+
+#define FORM_NAME(k,rank) updown_ ## k ## _ ## rank
+#define NUMERIC(k,rank) FORM_NAME(k,rank)
+
+#define RANK 1
+#include "t_cholmod_updown_numkr.c"
+
+#if WDIM >= 2
+#define RANK 2
+#include "t_cholmod_updown_numkr.c"
+#endif
+
+#if WDIM >= 4
+#define RANK 3
+#include "t_cholmod_updown_numkr.c"
+#define RANK 4
+#include "t_cholmod_updown_numkr.c"
+#endif
+
+#if WDIM == 8
+#define RANK 5
+#include "t_cholmod_updown_numkr.c"
+#define RANK 6
+#include "t_cholmod_updown_numkr.c"
+#define RANK 7
+#include "t_cholmod_updown_numkr.c"
+#define RANK 8
+#include "t_cholmod_updown_numkr.c"
+#endif
+
+
+/* ========================================================================== */
+/* === numeric update/downdate for all paths ================================ */
+/* ========================================================================== */
+
+static void NUMERIC (WDIM, r)
+(
+    int update,		/* TRUE for update, FALSE for downdate */
+    cholmod_sparse *C,	/* in packed or unpacked, and sorted form */
+			/* no empty columns */
+    Int rank,		/* rank of the update/downdate */
+    cholmod_factor *L,	/* with unit diagonal (diagonal not stored) */
+			/* temporary workspaces: */
+    double W [ ],	/* n-by-WDIM dense matrix, initially zero */
+    Path_type Path [ ],
+    Int npaths,
+    Int mask [ ],	/* size n */
+    cholmod_common *Common
+)
+{
+    double Alpha [8] ;
+    double *Cx, *Wpath, *W1, *a ;
+    Int i, j, p, ccol, pend, wfirst, e, path, packed ;
+    Int *Ci, *Cp, *Cnz ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ci = C->i ;
+    Cx = C->x ;
+    Cp = C->p ;
+    Cnz = C->nz ;
+    packed = C->packed ;
+    ASSERT (IMPLIES (!packed, Cnz != NULL)) ;
+    ASSERT (L->n == C->nrow) ;
+    DEBUG (CHOLMOD(dump_real) ("num_d: in W:", W, WDIM, L->n, FALSE, 1,Common));
+
+    /* ---------------------------------------------------------------------- */
+    /* scatter C into W */
+    /* ---------------------------------------------------------------------- */
+
+    for (path = 0 ; path < rank ; path++)
+    {
+	/* W (:, path) = C (:, Path [path].col) */
+	ccol = Path [path].ccol ;
+	Wpath = W + path ;
+	PRINT1 (("Ordered Columns [path = "ID"] = "ID"\n", path, ccol)) ;
+	p = Cp [ccol] ;
+	pend = (packed) ? (Cp [ccol+1]) : (p + Cnz [ccol]) ;
+	/* column C can be empty */
+	for ( ; p < pend ; p++)
+	{
+	    i = Ci [p] ;
+	    ASSERT (i >= 0 && i < (Int) (C->nrow)) ;
+	    if (mask == NULL || mask [i] < 0)
+	    {
+		Wpath [WDIM * i] = Cx [p] ;
+	    }
+	    PRINT1 (("    row "ID" : %g mask "ID"\n", i, Cx [p],
+		    (mask) ? mask [i] : 0)) ;
+	}
+	Alpha [path] = 1.0 ;
+    }
+    DEBUG (CHOLMOD(dump_real) ("num_d: W:", W, WDIM, L->n, FALSE, 1,Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* numeric update/downdate of the paths */
+    /* ---------------------------------------------------------------------- */
+
+    /* for each disjoint subpath in Tbar in DFS order do */
+    for (path = rank ; path < npaths ; path++)
+    {
+
+	/* determine which columns of W to use */
+	wfirst = Path [path].wfirst ;
+	e = Path [path].end ;
+	j = Path [path].start ;
+	ASSERT (e >= 0 && e < (Int) (L->n)) ;
+	ASSERT (j >= 0 && j < (Int) (L->n)) ;
+
+	W1 = W + wfirst ;	/* pointer to row 0, column wfirst of W */
+	a = Alpha + wfirst ;	/* pointer to Alpha [wfirst] */
+
+	PRINT1 (("Numerical update/downdate of path "ID"\n", path)) ;
+	PRINT1 (("start "ID" end "ID" wfirst "ID" rank "ID" ccol "ID"\n", j, e,
+		wfirst, Path [path].rank, Path [path].ccol)) ;
+
+#if WDIM == 1
+	NUMERIC (WDIM,1) (update, j, e, a, W1, L, Common) ;
+#else
+
+	switch (Path [path].rank)
+	{
+	    case 1:
+		NUMERIC (WDIM,1) (update, j, e, a, W1, L, Common) ;
+		break ;
+
+#if WDIM >= 2
+	    case 2:
+		NUMERIC (WDIM,2) (update, j, e, a, W1, L, Common) ;
+		break ;
+#endif
+
+#if WDIM >= 4
+	    case 3:
+		NUMERIC (WDIM,3) (update, j, e, a, W1, L, Common) ;
+		break ;
+	    case 4:
+		NUMERIC (WDIM,4) (update, j, e, a, W1, L, Common) ;
+		break ;
+#endif
+
+#if WDIM == 8
+	    case 5:
+		NUMERIC (WDIM,5) (update, j, e, a, W1, L, Common) ;
+		break ;
+	    case 6:
+		NUMERIC (WDIM,6) (update, j, e, a, W1, L, Common) ;
+		break ;
+	    case 7:
+		NUMERIC (WDIM,7) (update, j, e, a, W1, L, Common) ;
+		break ;
+	    case 8:
+		NUMERIC (WDIM,8) (update, j, e, a, W1, L, Common) ;
+		break ;
+#endif
+
+	}
+#endif
+
+    }
+}
+
+/* prepare for the next inclusion of this file in cholmod_updown.c */
+#undef WDIM
diff --git a/src/CHOLMOD/Modify/t_cholmod_updown_numkr.c b/src/CHOLMOD/Modify/t_cholmod_updown_numkr.c
new file mode 100644
index 0000000..df01dc5
--- /dev/null
+++ b/src/CHOLMOD/Modify/t_cholmod_updown_numkr.c
@@ -0,0 +1,746 @@
+/* ========================================================================== */
+/* === Modify/t_cholmod_updown_numkr ======================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Modify Module.  Copyright (C) 2005-2006,
+ * Timothy A. Davis and William W. Hager.
+ * The CHOLMOD/Modify Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Supernodal numerical update/downdate of rank K = RANK, along a single path.
+ * This routine operates on a simplicial factor, but operates on adjacent
+ * columns of L that would fit within a single supernode.  "Adjacent" means
+ * along a single path in the elimination tree; they may or may not be
+ * adjacent in the matrix L.
+ *
+ * external defines:  NUMERIC, WDIM, RANK.
+ *
+ * WDIM is 1, 2, 4, or 8.  RANK can be 1 to WDIM.
+ *
+ * A simple method is included (#define SIMPLE).  The code works, but is slow.
+ * It is meant only to illustrate what this routine is doing.
+ *
+ * A rank-K update proceeds along a single path, using single-column, dual-
+ * column, or quad-column updates of L.  If a column j and the next column
+ * in the path (its parent) do not have the same nonzero pattern, a single-
+ * column update is used.  If they do, but the 3rd and 4th column from j do
+ * not have the same pattern, a dual-column update is used, in which the two
+ * columns are treated as if they were a single supernode of two columns.  If
+ * there are 4 columns in the path that all have the same nonzero pattern, then
+ * a quad-column update is used.  All three kinds of updates can be used along
+ * a single path, in a single call to this function.
+ *
+ * Single-column update:
+ *
+ *	When updating a single column of L, each iteration of the for loop,
+ *	below, processes four rows of W (all columns involved) and one column
+ *	of L.  Suppose we have a rank-5 update, and columns 2 through 6 of W
+ *	are involved.  In this case, W in this routine is a pointer to column
+ *	2 of the matrix W in the caller.  W (in the caller, shown as 'W') is
+ *	held in row-major order, and is 8-by-n (a dense matrix storage format),
+ *	but shown below in column form to match the column of L.  Suppose there
+ *	are 13 nonzero entries in column 27 of L, with row indices 27 (the
+ *	diagonal, D), 28, 30, 31, 42, 43, 44, 50, 51, 67, 81, 83, and 84.  This
+ *	pattern is held in Li [Lp [27] ... Lp [27 + Lnz [27] - 1], where
+ *	Lnz [27] = 13.   The modification of the current column j of L is done
+ *	in the following order.  A dot (.) means the entry of W is not accessed.
+ *
+ *	W0 points to row 27 of W, and G is a 1-by-8 temporary vector.
+ *
+ *		     G[0]        G[4]
+ *	G	      x  x  x  x  x  .  .  .
+ *
+ *		      W0
+ *		      |
+ *		      v
+ *	27      .  .  x  x  x  x  x  .   W0 points to W (27,2)
+ *
+ *
+ *	row    'W'    W                      column j = 27
+ *	|       |     |                      of L
+ *	v       v     v                      |
+ *	first iteration of for loop:         v
+ *
+ *	28      .  .  1  5  9 13 17  .       x
+ *	30      .  .  2  6 10 14 18  .       x
+ *	31      .  .  3  7 11 15 19  .       x
+ *	42      .  .  4  8 12 16 20  .       x
+ *
+ *	second iteration of for loop:
+ *
+ *	43      .  .  1  5  9 13 17  .       x
+ *	44      .  .  2  6 10 14 18  .       x
+ *	50      .  .  3  7 11 15 19  .       x
+ *	51      .  .  4  8 12 16 20  .       x
+ *
+ *	third iteration of for loop:
+ *
+ *	67      .  .  1  5  9 13 17  .       x
+ *	81      .  .  2  6 10 14 18  .       x
+ *	83      .  .  3  7 11 15 19  .       x
+ *	84      .  .  4  8 12 16 20  .       x
+ *
+ *	If the number of offdiagonal nonzeros in column j of L is not divisible
+ *	by 4, then the switch-statement does the work for the first nz % 4 rows.
+ *
+ * Dual-column update:
+ *
+ *	In this case, two columns of L that are adjacent in the path are being
+ *	updated, by 1 to 8 columns of W.  Suppose columns j=27 and j=28 are
+ *	adjacent columns in the path (they need not be j and j+1).  Two rows
+ *	of G and W are used as coefficients during the update: (G0, G1) and
+ *	(W0, W1).
+ *
+ *	G0	      x  x  x  x  x  .  .  .
+ *	G1	      x  x  x  x  x  .  .  .
+ *
+ *	27      .  .  x  x  x  x  x  .   W0 points to W (27,2)
+ *	28      .  .  x  x  x  x  x  .   W1 points to W (28,2)
+ *
+ *
+ *	row    'W'    W0,W1                  column j = 27
+ *	|       |     |                      of L
+ *	v       v     v                      |
+ *					     | |-- column j = 28 of L
+ *					     v v
+ *	update L (j1,j):
+ *
+ *	28      .  .  1  2  3  4  5  .       x -    ("-" is not stored in L)
+ *
+ *	cleanup iteration since length is odd:
+ *
+ *	30      .  .  1  2  3  4  5  .       x x
+ *
+ *	then each iteration does two rows of both columns of L:
+ *
+ *	31      .  .  1  3  5  7  9  .       x x
+ *	42      .  .  2  4  6  8 10  .       x x
+ *
+ *	43      .  .  1  3  5  7  9  .       x x
+ *	44      .  .  2  4  6  8 10  .       x x
+ *
+ *	50      .  .  1  3  5  7  9  .       x x
+ *	51      .  .  2  4  6  8 10  .       x x
+ *
+ *	67      .  .  1  3  5  7  9  .       x x
+ *	81      .  .  2  4  6  8 10  .       x x
+ *
+ *	83      .  .  1  3  5  7  9  .       x x
+ *	84      .  .  2  4  6  8 10  .       x x
+ *
+ *	If the number of offdiagonal nonzeros in column j of L is not even,
+ *	then the cleanup iteration does the work for the first row.
+ *
+ * Quad-column update:
+ *
+ *	In this case, four columns of L that are adjacent in the path are being
+ *	updated, by 1 to 8 columns of W.  Suppose columns j=27, 28, 30, and 31
+ *	are adjacent columns in the path (they need not be j, j+1, ...).  Four
+ *	rows of G and W are used as coefficients during the update: (G0 through
+ *	G3) and (W0 through W3).  j=27, j1=28, j2=30, and j3=31.
+ *
+ *	G0	      x  x  x  x  x  .  .  .
+ *	G1	      x  x  x  x  x  .  .  .
+ *	G3	      x  x  x  x  x  .  .  .
+ *	G4	      x  x  x  x  x  .  .  .
+ *
+ *	27      .  .  x  x  x  x  x  .   W0 points to W (27,2)
+ *	28      .  .  x  x  x  x  x  .   W1 points to W (28,2)
+ *	30      .  .  x  x  x  x  x  .   W2 points to W (30,2)
+ *	31      .  .  x  x  x  x  x  .   W3 points to W (31,2)
+ *
+ *
+ *	row    'W'    W0,W1,..               column j = 27
+ *	|       |     |                      of L
+ *	v       v     v                      |
+ *					     | |-- column j = 28 of L
+ *					     | | |-- column j = 30 of L
+ *					     | | | |-- column j =  31 of L
+ *					     v v v v
+ *	update L (j1,j):
+ *	28      .  .  1  2  3  4  5  .       x - - -
+ *
+ *	update L (j2,j):
+ *	30      .  .  1  2  3  4  5  .       # x - -	 (# denotes modified)
+ *
+ *	update L (j2,j1)
+ *	30      .  .  1  2  3  4  5  .       x # - -
+ *
+ *	update L (j3,j)
+ *	31      .  .  1  2  3  4  5  .       # x x -
+ *
+ *	update L (j3,j1)
+ *	31      .  .  1  2  3  4  5  .       x # x -
+ *
+ *	update L (j3,j2)
+ *	31      .  .  1  2  3  4  5  .       x x # -
+ *
+ *	cleanup iteration since length is odd:
+ *	42      .  .  1  2  3  4  5  .       x x x x
+ *
+ *
+ * ----- CHOLMOD v1.1.1 did the following --------------------------------------
+ *	then each iteration does two rows of all four colummns of L:
+ *
+ *	43      .  .  1  3  5  7  9  .       x x x x
+ *	44      .  .  2  4  6  8 10  .       x x x x
+ *
+ *	50      .  .  1  3  5  7  9  .       x x x x
+ *	51      .  .  2  4  6  8 10  .       x x x x
+ *
+ *	67      .  .  1  3  5  7  9  .       x x x x
+ *	81      .  .  2  4  6  8 10  .       x x x x
+ *
+ *	83      .  .  1  3  5  7  9  .       x x x x
+ *	84      .  .  2  4  6  8 10  .       x x x x
+ *
+ * ----- CHOLMOD v1.2.0 does the following -------------------------------------
+ *	then each iteration does one rows of all four colummns of L:
+ *
+ *	43      .  .  1  2  3  4  5  .       x x x x
+ *	44      .  .  1  2  3  4  5  .       x x x x
+ *	50      .  .  1  3  5  4  5  .       x x x x
+ *	51      .  .  1  2  3  4  5  .       x x x x
+ *	67      .  .  1  3  5  4  5  .       x x x x
+ *	81      .  .  1  2  3  4  5  .       x x x x
+ *	83      .  .  1  3  5  4  5  .       x x x x
+ *	84      .  .  1  2  3  4  5  .       x x x x
+ *
+ * This file is included in t_cholmod_updown.c, only.
+ * It is not compiled separately.  It contains no user-callable routines.
+ *
+ * workspace: Xwork (WDIM*nrow)
+ */
+
+/* ========================================================================== */
+/* === loop unrolling macros ================================================ */
+/* ========================================================================== */
+
+#undef RANK1
+#undef RANK2
+#undef RANK3
+#undef RANK4
+#undef RANK5
+#undef RANK6
+#undef RANK7
+#undef RANK8
+
+#define RANK1(statement) statement
+
+#if RANK < 2
+#define RANK2(statement)
+#else
+#define RANK2(statement) statement
+#endif
+
+#if RANK < 3
+#define RANK3(statement)
+#else
+#define RANK3(statement) statement
+#endif
+
+#if RANK < 4
+#define RANK4(statement)
+#else
+#define RANK4(statement) statement
+#endif
+
+#if RANK < 5
+#define RANK5(statement)
+#else
+#define RANK5(statement) statement
+#endif
+
+#if RANK < 6
+#define RANK6(statement)
+#else
+#define RANK6(statement) statement
+#endif
+
+#if RANK < 7
+#define RANK7(statement)
+#else
+#define RANK7(statement) statement
+#endif
+
+#if RANK < 8
+#define RANK8(statement)
+#else
+#define RANK8(statement) statement
+#endif
+
+#define FOR_ALL_K \
+    RANK1 (DO (0)) \
+    RANK2 (DO (1)) \
+    RANK3 (DO (2)) \
+    RANK4 (DO (3)) \
+    RANK5 (DO (4)) \
+    RANK6 (DO (5)) \
+    RANK7 (DO (6)) \
+    RANK8 (DO (7))
+
+/* ========================================================================== */
+/* === alpha/gamma ========================================================== */
+/* ========================================================================== */
+
+#undef ALPHA_GAMMA
+
+#define ALPHA_GAMMA(Dj,Alpha,Gamma,W) \
+{ \
+    double dj = Dj ; \
+    if (update) \
+    { \
+	for (k = 0 ; k < RANK ; k++) \
+	{ \
+	    double w = W [k] ; \
+	    double alpha = Alpha [k] ; \
+	    double a = alpha + (w * w) / dj ; \
+	    dj *= a ; \
+	    Alpha [k] = a ; \
+	    Gamma [k] = (- w / dj) ; \
+	    dj /= alpha ; \
+	} \
+    } \
+    else \
+    { \
+	for (k = 0 ; k < RANK ; k++) \
+	{ \
+	    double w = W [k] ; \
+	    double alpha = Alpha [k] ; \
+	    double a = alpha - (w * w) / dj ; \
+	    dj *= a ; \
+	    Alpha [k] = a ; \
+	    Gamma [k] = w / dj ; \
+	    dj /= alpha ; \
+	} \
+    } \
+    Dj = ((use_dbound) ? (CHOLMOD(dbound) (dj, Common)) : (dj)) ; \
+}
+
+/* ========================================================================== */
+/* === numeric update/downdate along one path =============================== */
+/* ========================================================================== */
+
+static void NUMERIC (WDIM, RANK)
+(
+    int update,		/* TRUE for update, FALSE for downdate */
+    Int j,		/* first column in the path */
+    Int e,		/* last column in the path */
+    double Alpha [ ],	/* alpha, for each column of W */
+    double W [ ],	/* W is an n-by-WDIM array, stored in row-major order */
+    cholmod_factor *L,	/* with unit diagonal (diagonal not stored) */
+    cholmod_common *Common
+)
+{
+
+#ifdef SIMPLE
+#define w(row,col) W [WDIM*(row) + (col)]
+
+    /* ---------------------------------------------------------------------- */
+    /* concise but slow version for illustration only */
+    /* ---------------------------------------------------------------------- */
+
+    double Gamma [WDIM] ;
+    double *Lx ;
+    Int *Li, *Lp, *Lnz ;
+    Int p, k ;
+    Int use_dbound = IS_GT_ZERO (Common->dbound) ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+
+    /* walk up the etree from node j to its ancestor e */
+    for ( ; j <= e ; j = (Lnz [j] > 1) ? (Li [Lp [j] + 1]) : Int_max)
+    {
+	/* update the diagonal entry D (j,j) with each column of W */
+	ALPHA_GAMMA (Lx [Lp [j]], Alpha, Gamma, (&(w (j,0)))) ;
+	/* update column j of L */
+	for (p = Lp [j] + 1 ; p < Lp [j] + Lnz [j] ; p++)
+	{
+	    /* update row Li [p] of column j of L with each column of W */
+	    Int i = Li [p] ;
+	    for (k = 0 ; k < RANK ; k++)
+	    {
+		w (i,k) -= w (j,k) * Lx [p] ;
+		Lx [p] -= Gamma [k] * w (i,k) ;
+	    }
+	}
+	/* clear workspace W */
+	for (k = 0 ; k < RANK ; k++)
+	{
+	    w (j,k) = 0 ;
+	}
+    }
+
+#else
+
+    /* ---------------------------------------------------------------------- */
+    /* dynamic supernodal version: supernodes detected dynamically */
+    /* ---------------------------------------------------------------------- */
+
+    double G0 [RANK], G1 [RANK], G2 [RANK], G3 [RANK] ;
+    double Z0 [RANK], Z1 [RANK], Z2 [RANK], Z3 [RANK] ;
+    double *W0, *W1, *W2, *W3, *Lx ;
+    Int *Li, *Lp, *Lnz ;
+    Int j1, j2, j3, p0, p1, p2, p3, parent, lnz, pend, k ;
+    Int use_dbound = IS_GT_ZERO (Common->dbound) ;
+
+    Li = L->i ;
+    Lx = L->x ;
+    Lp = L->p ;
+    Lnz = L->nz ;
+
+    /* walk up the etree from node j to its ancestor e */
+    for ( ; j <= e ; j = parent)
+    {
+
+	p0 = Lp [j] ;		/* col j is Li,Lx [p0 ... p0+lnz-1] */
+	lnz = Lnz [j] ;
+
+	W0 = W + WDIM * j ;	/* pointer to row j of W */
+	pend = p0 + lnz ;
+
+	/* for k = 0 to RANK-1 do: */
+	#define DO(k) Z0 [k] = W0 [k] ;
+	FOR_ALL_K
+	#undef DO
+
+	/* for k = 0 to RANK-1 do: */
+	#define DO(k) W0 [k] = 0 ;
+	FOR_ALL_K
+	#undef DO
+
+	/* update D (j,j) */
+	ALPHA_GAMMA (Lx [p0], Alpha, G0, Z0) ;
+	p0++ ;
+
+	/* determine how many columns of L to update at the same time */
+	parent = (lnz > 1) ? (Li [p0]) : Int_max ;
+	if (parent <= e && lnz == Lnz [parent] + 1)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* node j and its parent j1 can be updated at the same time */
+	    /* -------------------------------------------------------------- */
+
+	    j1 = parent ;
+	    j2 = (lnz > 2) ? (Li [p0+1]) : Int_max ;
+	    j3 = (lnz > 3) ? (Li [p0+2]) : Int_max ;
+	    W1 = W + WDIM * j1 ;	/* pointer to row j1 of W */
+	    p1 = Lp [j1] ;
+
+	    /* for k = 0 to RANK-1 do: */
+	    #define DO(k) Z1 [k] = W1 [k] ;
+	    FOR_ALL_K
+	    #undef DO
+
+	    /* for k = 0 to RANK-1 do: */
+	    #define DO(k) W1 [k] = 0 ;
+	    FOR_ALL_K
+	    #undef DO
+
+	    /* update L (j1,j) */
+	    {
+		double lx = Lx [p0] ;
+
+		/* for k = 0 to RANK-1 do: */
+		#define DO(k) \
+		    Z1 [k] -= Z0 [k] * lx ; \
+		    lx -= G0 [k] * Z1 [k] ;
+		FOR_ALL_K
+		#undef DO
+
+		Lx [p0++] = lx ;
+	    }
+
+	    /* update D (j1,j1) */
+	    ALPHA_GAMMA (Lx [p1], Alpha, G1, Z1) ;
+	    p1++ ;
+
+	    /* -------------------------------------------------------------- */
+	    /* update 2 or 4 columns of L */
+	    /* -------------------------------------------------------------- */
+
+	    if ((j2 <= e) &&			/* j2 in the current path */
+		(j3 <= e) &&			/* j3 in the current path */
+		(lnz == Lnz [j2] + 2) &&	/* column j2 matches */
+		(lnz == Lnz [j3] + 3))		/* column j3 matches */
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* update 4 columns of L */
+		/* ---------------------------------------------------------- */
+
+		/* p0 and p1 currently point to row j2 in cols j and j1 of L */
+
+		parent = (lnz > 4) ? (Li [p0+2]) : Int_max ;
+		W2 = W + WDIM * j2 ;	    /* pointer to row j2 of W */
+		W3 = W + WDIM * j3 ;	    /* pointer to row j3 of W */
+		p2 = Lp [j2] ;
+		p3 = Lp [j3] ;
+
+		/* for k = 0 to RANK-1 do: */
+		#define DO(k) Z2 [k] = W2 [k] ;
+		FOR_ALL_K
+		#undef DO
+
+		/* for k = 0 to RANK-1 do: */
+		#define DO(k) Z3 [k] = W3 [k] ;
+		FOR_ALL_K
+		#undef DO
+
+		/* for k = 0 to RANK-1 do: */
+		#define DO(k) W2 [k] = 0 ;
+		FOR_ALL_K
+		#undef DO
+
+		/* for k = 0 to RANK-1 do: */
+		#define DO(k) W3 [k] = 0 ;
+		FOR_ALL_K
+		#undef DO
+
+		/* update L (j2,j) and update L (j2,j1) */
+		{
+		    double lx [2] ;
+		    lx [0] = Lx [p0] ;
+		    lx [1] = Lx [p1] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    Z2 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * Z2 [k] ; \
+		    Z2 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * Z2 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0++] = lx [0] ;
+		    Lx [p1++] = lx [1] ;
+		}
+
+		/* update D (j2,j2) */
+		ALPHA_GAMMA (Lx [p2], Alpha, G2, Z2) ;
+		p2++ ;
+
+		/* update L (j3,j), L (j3,j1), and L (j3,j2) */
+		{
+		    double lx [3] ;
+		    lx [0] = Lx [p0] ;
+		    lx [1] = Lx [p1] ;
+		    lx [2] = Lx [p2] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    Z3 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * Z3 [k] ; \
+		    Z3 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * Z3 [k] ; \
+		    Z3 [k] -= Z2 [k] * lx [2] ; lx [2] -= G2 [k] * Z3 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0++] = lx [0] ;
+		    Lx [p1++] = lx [1] ;
+		    Lx [p2++] = lx [2] ;
+		}
+
+		/* update D (j3,j3) */
+		ALPHA_GAMMA (Lx [p3], Alpha, G3, Z3) ;
+		p3++ ;
+
+		/* each iteration updates L (i, [j j1 j2 j3]) */
+		for ( ; p0 < pend ; p0++, p1++, p2++, p3++)
+		{
+		    double lx [4], *w0 ;
+		    lx [0] = Lx [p0] ;
+		    lx [1] = Lx [p1] ;
+		    lx [2] = Lx [p2] ;
+		    lx [3] = Lx [p3] ;
+		    w0 = W + WDIM * Li [p0] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    w0 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * w0 [k] ; \
+		    w0 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * w0 [k] ; \
+		    w0 [k] -= Z2 [k] * lx [2] ; lx [2] -= G2 [k] * w0 [k] ; \
+		    w0 [k] -= Z3 [k] * lx [3] ; lx [3] -= G3 [k] * w0 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0] = lx [0] ;
+		    Lx [p1] = lx [1] ;
+		    Lx [p2] = lx [2] ;
+		    Lx [p3] = lx [3] ;
+		}
+	    }
+	    else
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* update 2 columns of L */
+		/* ---------------------------------------------------------- */
+
+		parent = j2 ;
+
+		/* cleanup iteration if length is odd */
+		if ((lnz - 2) % 2)
+		{
+		    double lx [2] , *w0 ;
+		    lx [0] = Lx [p0] ;
+		    lx [1] = Lx [p1] ;
+		    w0 = W + WDIM * Li [p0] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    w0 [k] -= Z0 [k] * lx [0] ; lx [0] -= G0 [k] * w0 [k] ; \
+		    w0 [k] -= Z1 [k] * lx [1] ; lx [1] -= G1 [k] * w0 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0++] = lx [0] ;
+		    Lx [p1++] = lx [1] ;
+		}
+
+		for ( ; p0 < pend ; p0 += 2, p1 += 2)
+		{
+		    double lx [2][2], w [2], *w0, *w1 ;
+		    lx [0][0] = Lx [p0  ] ;
+		    lx [1][0] = Lx [p0+1] ;
+		    lx [0][1] = Lx [p1  ] ;
+		    lx [1][1] = Lx [p1+1] ;
+		    w0 = W + WDIM * Li [p0  ] ;
+		    w1 = W + WDIM * Li [p0+1] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    w [0] = w0 [k] - Z0 [k] * lx [0][0] ; \
+		    w [1] = w1 [k] - Z0 [k] * lx [1][0] ; \
+		    lx [0][0] -= G0 [k] * w [0] ; \
+		    lx [1][0] -= G0 [k] * w [1] ; \
+		    w0 [k] = w [0] -= Z1 [k] * lx [0][1] ; \
+		    w1 [k] = w [1] -= Z1 [k] * lx [1][1] ; \
+		    lx [0][1] -= G1 [k] * w [0] ; \
+		    lx [1][1] -= G1 [k] * w [1] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0  ] = lx [0][0] ;
+		    Lx [p0+1] = lx [1][0] ;
+		    Lx [p1  ] = lx [0][1] ;
+		    Lx [p1+1] = lx [1][1] ;
+		}
+	    }
+	}
+	else
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* update one column of L */
+	    /* -------------------------------------------------------------- */
+
+	    /* cleanup iteration if length is not a multiple of 4 */
+	    switch ((lnz - 1) % 4)
+	    {
+		case 1:
+		{
+		    double lx , *w0 ;
+		    lx = Lx [p0] ;
+		    w0 = W + WDIM * Li [p0] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    w0 [k] -= Z0 [k] * lx ; lx -= G0 [k] * w0 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0++] = lx ;
+		}
+		break ;
+
+		case 2:
+		{
+		    double lx [2], *w0, *w1 ;
+		    lx [0] = Lx [p0  ] ;
+		    lx [1] = Lx [p0+1] ;
+		    w0 = W + WDIM * Li [p0  ] ;
+		    w1 = W + WDIM * Li [p0+1] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    w0 [k] -= Z0 [k] * lx [0] ; \
+		    w1 [k] -= Z0 [k] * lx [1] ; \
+		    lx [0] -= G0 [k] * w0 [k] ; \
+		    lx [1] -= G0 [k] * w1 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0++] = lx [0] ;
+		    Lx [p0++] = lx [1] ;
+		}
+		break ;
+
+		case 3:
+		{
+		    double lx [3], *w0, *w1, *w2 ;
+		    lx [0] = Lx [p0  ] ;
+		    lx [1] = Lx [p0+1] ;
+		    lx [2] = Lx [p0+2] ;
+		    w0 = W + WDIM * Li [p0  ] ;
+		    w1 = W + WDIM * Li [p0+1] ;
+		    w2 = W + WDIM * Li [p0+2] ;
+
+		    /* for k = 0 to RANK-1 do: */
+		    #define DO(k) \
+		    w0 [k] -= Z0 [k] * lx [0] ; \
+		    w1 [k] -= Z0 [k] * lx [1] ; \
+		    w2 [k] -= Z0 [k] * lx [2] ; \
+		    lx [0] -= G0 [k] * w0 [k] ; \
+		    lx [1] -= G0 [k] * w1 [k] ; \
+		    lx [2] -= G0 [k] * w2 [k] ;
+		    FOR_ALL_K
+		    #undef DO
+
+		    Lx [p0++] = lx [0] ;
+		    Lx [p0++] = lx [1] ;
+		    Lx [p0++] = lx [2] ;
+		}
+	    }
+
+	    for ( ; p0 < pend ; p0 += 4)
+	    {
+		double lx [4], *w0, *w1, *w2, *w3 ;
+		lx [0] = Lx [p0  ] ;
+		lx [1] = Lx [p0+1] ;
+		lx [2] = Lx [p0+2] ;
+		lx [3] = Lx [p0+3] ;
+		w0 = W + WDIM * Li [p0  ] ;
+		w1 = W + WDIM * Li [p0+1] ;
+		w2 = W + WDIM * Li [p0+2] ;
+		w3 = W + WDIM * Li [p0+3] ;
+
+		/* for k = 0 to RANK-1 do: */
+		#define DO(k) \
+		w0 [k] -= Z0 [k] * lx [0] ; \
+		w1 [k] -= Z0 [k] * lx [1] ; \
+		w2 [k] -= Z0 [k] * lx [2] ; \
+		w3 [k] -= Z0 [k] * lx [3] ; \
+		lx [0] -= G0 [k] * w0 [k] ; \
+		lx [1] -= G0 [k] * w1 [k] ; \
+		lx [2] -= G0 [k] * w2 [k] ; \
+		lx [3] -= G0 [k] * w3 [k] ;
+		FOR_ALL_K
+		#undef DO
+
+		Lx [p0  ] = lx [0] ;
+		Lx [p0+1] = lx [1] ;
+		Lx [p0+2] = lx [2] ;
+		Lx [p0+3] = lx [3] ;
+	    }
+	}
+    }
+#endif
+}
+/* prepare this file for another inclusion in t_cholmod_updown.c: */
+#undef RANK
diff --git a/src/CHOLMOD/Partition/License.txt b/src/CHOLMOD/Partition/License.txt
new file mode 100644
index 0000000..4beeb59
--- /dev/null
+++ b/src/CHOLMOD/Partition/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/Partition Module.
+Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/Partition module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This Module 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
diff --git a/src/CHOLMOD/Partition/cholmod_camd.c b/src/CHOLMOD/Partition/cholmod_camd.c
new file mode 100644
index 0000000..47b0368
--- /dev/null
+++ b/src/CHOLMOD/Partition/cholmod_camd.c
@@ -0,0 +1,231 @@
+/* ========================================================================== */
+/* === Partition/cholmod_camd =============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Partition Module.  Copyright (C) 2005-2013, Timothy A. Davis
+ * The CHOLMOD/Partition Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the CAMD ordering routine.  Orders A if the matrix is
+ * symmetric.  On output, Perm [k] = i if row/column i of A is the kth
+ * row/column of P*A*P'.  This corresponds to A(p,p) in MATLAB notation.
+ *
+ * If A is unsymmetric, cholmod_camd orders A*A'.  On output, Perm [k] = i if
+ * row/column i of A*A' is the kth row/column of P*A*A'*P'.  This corresponds to
+ * A(p,:)*A(p,:)' in MATLAB notation.  If f is present, A(p,f)*A(p,f)' is
+ * ordered.
+ *
+ * Computes the flop count for a subsequent LL' factorization, the number
+ * of nonzeros in L, and the number of nonzeros in the matrix ordered (A,
+ * A*A' or A(:,f)*A(:,f)').
+ *
+ * workspace: Iwork (4*nrow). Head (nrow).
+ *
+ * Allocates a temporary copy of A+A' or A*A' (with
+ * both upper and lower triangular parts) as input to CAMD.
+ * Also allocates 3*(n+1) additional integer workspace (not in Common).
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex)
+ */
+
+static int igraph_stfu2();
+static int igraph_stfu1() { return igraph_stfu2(); }
+static int igraph_stfu2() { return igraph_stfu1(); }
+
+#ifndef NCAMD
+
+#include "cholmod_internal.h"
+#include "camd.h"
+#include "cholmod_camd.h"
+
+#if (CAMD_VERSION < CAMD_VERSION_CODE (2,0))
+#error "CAMD v2.0 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === cholmod_camd ========================================================= */
+/* ========================================================================== */
+
+int CHOLMOD(camd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    Int *Cmember,	/* size nrow.  see cholmod_ccolamd.c for description.*/
+    /* ---- output ---- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double Info [CAMD_INFO], Control2 [CAMD_CONTROL], *Control ;
+    Int *Cp, *Len, *Nv, *Head, *Elen, *Degree, *Wi, *Next, *BucketSet,
+	*Work3n, *p ;
+    cholmod_sparse *C ;
+    Int j, n, cnz ;
+    size_t s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    n = A->nrow ;
+
+    /* s = 4*n */
+    s = CHOLMOD(mult_size_t) (n, 4, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+    if (n == 0)
+    {
+	/* nothing to do */
+	Common->fl = 0 ;
+	Common->lnz = 0 ;
+	Common->anz = 0 ;
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* cholmod_analyze has allocated Cmember at Common->Iwork + 5*n+uncol, and
+     * CParent at Common->Iwork + 4*n+uncol, where uncol is 0 if A is symmetric
+     * or A->ncol otherwise.  Thus, only the first 4n integers in Common->Iwork
+     * can be used here. */
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    p = Common->Iwork ;
+    Degree = p ; p += n ;	/* size n */
+    Elen   = p ; p += n ;	/* size n */
+    Len    = p ; p += n ;	/* size n */
+    Nv     = p ; p += n ;	/* size n */
+
+    Work3n = CHOLMOD(malloc) (n+1, 3*sizeof (Int), Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    p = Work3n ;
+    Next = p ; p += n ;		/* size n */
+    Wi   = p ; p += (n+1) ;	/* size n+1 */
+    BucketSet = p ;		/* size n */
+
+    Head = Common->Head ;	/* size n+1 */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the input matrix for CAMD */
+    /* ---------------------------------------------------------------------- */
+
+    if (A->stype == 0)
+    {
+	/* C = A*A' or A(:,f)*A(:,f)', add extra space of nnz(C)/2+n to C */
+	C = CHOLMOD(aat) (A, fset, fsize, -2, Common) ;
+    }
+    else
+    {
+	/* C = A+A', but use only the upper triangular part of A if A->stype = 1
+	 * and only the lower part of A if A->stype = -1.  Add extra space of
+	 * nnz(C)/2+n to C. */
+	C = CHOLMOD(copy) (A, 0, -2, Common) ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory, fset invalid, or other error */
+	CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ;
+	return (FALSE) ;
+    }
+
+    Cp = C->p ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Len [j] = Cp [j+1] - Cp [j] ;
+    }
+
+    /* C does not include the diagonal, and both upper and lower parts.
+     * Common->anz includes the diagonal, and just the lower part of C */
+    cnz = Cp [n] ;
+    Common->anz = cnz / 2 + n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order C using CAMD */
+    /* ---------------------------------------------------------------------- */
+
+    /* get parameters */
+    if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
+    {
+	/* use CAMD defaults */
+	Control = NULL ;
+    }
+    else
+    {
+	Control = Control2 ;
+	Control [CAMD_DENSE] = Common->method [Common->current].prune_dense ;
+	Control [CAMD_AGGRESSIVE] = Common->method [Common->current].aggressive;
+    }
+
+    /* CAMD_2 does not use camd_malloc and camd_free, but set these pointers
+     * just be safe. */
+    camd_malloc = Common->malloc_memory ;
+    camd_free = Common->free_memory ;
+    camd_calloc = Common->calloc_memory ;
+    camd_realloc = Common->realloc_memory ;
+
+    /* CAMD_2 doesn't print anything either, but future versions might,
+     * so set the camd_printf pointer too. */
+    camd_printf = Common->print_function ;
+
+#ifdef LONG
+    /* DEBUG (camd_l_debug_init ("cholmod_l_camd")) ; */
+    camd_l2 (n, C->p,  C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
+	    Degree, Wi, Control, Info, Cmember, BucketSet) ;
+#else
+    /* DEBUG (camd_debug_init ("cholmod_camd")) ; */
+    camd_2 (n, C->p,  C->i, Len, C->nzmax, cnz, Nv, Next, Perm, Head, Elen,
+	    Degree, Wi, Control, Info, Cmember, BucketSet) ;
+#endif
+
+    /* LL' flop count.  Need to subtract n for LL' flop count.  Note that this
+     * is a slight upper bound which is often exact (see CAMD/Source/camd_2.c
+     * for details).  cholmod_analyze computes an exact flop count and
+     * fill-in. */
+    Common->fl = Info [CAMD_NDIV] + 2 * Info [CAMD_NMULTSUBS_LDL] + n ;
+
+    /* Info [CAMD_LNZ] excludes the diagonal */
+    Common->lnz = n + Info [CAMD_LNZ] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the CAMD workspace and clear the persistent workspace in Common */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (IMPLIES (Common->status == CHOLMOD_OK,
+		CHOLMOD(dump_perm) (Perm, n, n, "CAMD2 perm", Common))) ;
+    CHOLMOD(free_sparse) (&C, Common) ;
+    for (j = 0 ; j <= n ; j++)
+    {
+	Head [j] = EMPTY ;
+    }
+    CHOLMOD(free) (n+1, 3*sizeof (Int), Work3n, Common) ;
+    return (TRUE) ;
+}
+#endif
diff --git a/src/CHOLMOD/Partition/cholmod_ccolamd.c b/src/CHOLMOD/Partition/cholmod_ccolamd.c
new file mode 100644
index 0000000..284a3a8
--- /dev/null
+++ b/src/CHOLMOD/Partition/cholmod_ccolamd.c
@@ -0,0 +1,208 @@
+/* ========================================================================== */
+/* === Partition/cholmod_ccolamd ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Partition Module. 
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Partition Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the CCOLAMD ordering routine.  Finds a permutation
+ * p such that the Cholesky factorization of PAA'P' is sparser than AA'.
+ * The column etree is found and postordered, and the ccolamd ordering is then
+ * combined with its postordering.  A must be unsymmetric.
+ *
+ * workspace: Iwork (MAX (nrow,ncol))
+ *	Allocates a copy of its input matrix, which is
+ *	then used as CCOLAMD's workspace.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+static int igraph_stfu2();
+static int igraph_stfu1() { return igraph_stfu2(); }
+static int igraph_stfu2() { return igraph_stfu1(); }
+
+#ifndef NCAMD
+
+#include "cholmod_internal.h"
+#include "ccolamd.h"
+#include "cholmod_camd.h"
+
+#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (2,5))
+#error "CCOLAMD v2.0 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === ccolamd_interface ==================================================== */
+/* ========================================================================== */
+
+/* Order with ccolamd */
+
+static int ccolamd_interface
+(
+    cholmod_sparse *A,
+    size_t alen,
+    Int *Perm,
+    Int *Cmember,
+    Int *fset,
+    Int fsize,
+    cholmod_sparse *C,
+    cholmod_common *Common
+)
+{
+    double knobs [CCOLAMD_KNOBS] ;
+    Int *Cp = NULL ;
+    Int ok, k, nrow, ncol, stats [CCOLAMD_STATS] ;
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy (and transpose) the input matrix A into the ccolamd workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* C = A (:,f)', which also packs A if needed. */
+    /* workspace: Iwork (nrow if no fset; MAX (nrow,ncol) if fset non-NULL) */
+    ok = CHOLMOD(transpose_unsym) (A, 0, NULL, fset, fsize, C, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order the matrix (destroys the contents of C->i and C->p) */
+    /* ---------------------------------------------------------------------- */
+
+    /* get parameters */
+#ifdef LONG
+    ccolamd_l_set_defaults (knobs) ;
+#else
+    ccolamd_set_defaults (knobs) ;
+#endif
+
+    if (Common->current < 0 || Common->current >= CHOLMOD_MAXMETHODS)
+    {
+	/* this is the CHOLMOD default, not the CCOLAMD default */
+	knobs [CCOLAMD_DENSE_ROW] = -1 ;
+    }
+    else
+    {
+	/* get the knobs from the Common parameters */
+	knobs [CCOLAMD_DENSE_COL] =Common->method[Common->current].prune_dense ;
+	knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense2;
+	knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ;
+	knobs [CCOLAMD_LU]        =Common->method[Common->current].order_for_lu;
+    }
+
+    if (ok)
+    {
+
+#ifdef LONG
+	ccolamd_l (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ;
+#else
+	ccolamd (ncol, nrow, alen, C->i, C->p, knobs, stats, Cmember) ;
+#endif
+
+	ok = stats [CCOLAMD_STATUS] ;
+
+	ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ;
+	/* permutation returned in C->p, if the ordering succeeded */
+	Cp = C->p ;
+	for (k = 0 ; k < nrow ; k++)
+	{
+	    Perm [k] = Cp [k] ;
+	}
+    }
+
+    return (ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_ccolamd ====================================================== */
+/* ========================================================================== */
+
+/* Order AA' or A(:,f)*A(:,f)' using CCOLAMD. */
+
+int CHOLMOD(ccolamd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    Int *Cmember,	/* size A->nrow.  Cmember [i] = c if row i is in the
+			 * constraint set c.  c must be >= 0.  The # of
+			 * constraint sets is max (Cmember) + 1.  If Cmember is
+			 * NULL, then it is interpretted as Cmember [i] = 0 for
+			 * all i */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_sparse *C ;
+    Int ok, nrow, ncol ;
+    size_t alen ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    if (A->stype != 0)
+    {
+	ERROR (CHOLMOD_INVALID, "matrix must be unsymmetric") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+    ncol = A->ncol ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef LONG
+    alen = ccolamd_l_recommended (A->nzmax, ncol, nrow) ;
+#else
+    alen = ccolamd_recommended (A->nzmax, ncol, nrow) ;
+#endif
+
+    if (alen == 0)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "matrix invalid or too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (0, MAX (nrow,ncol), 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    C = CHOLMOD(allocate_sparse) (ncol, nrow, alen, TRUE, TRUE, 0,
+	    CHOLMOD_PATTERN, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* order with ccolamd */
+    /* ---------------------------------------------------------------------- */
+
+    ok = ccolamd_interface (A, alen, Perm, Cmember, fset, fsize, C, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace and return result */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(free_sparse) (&C, Common) ;
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Partition/cholmod_csymamd.c b/src/CHOLMOD/Partition/cholmod_csymamd.c
new file mode 100644
index 0000000..b3f1303
--- /dev/null
+++ b/src/CHOLMOD/Partition/cholmod_csymamd.c
@@ -0,0 +1,144 @@
+/* ========================================================================== */
+/* === Partition/cholmod_csymamd ============================================ */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Partition Module.
+ * Copyright (C) 2005-2013, Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Partition Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the CSYMAMD ordering routine.  Finds a permutation
+ * p such that the Cholesky factorization of PAP' is sparser than A.
+ * The column etree is found and postordered, and the CSYMAMD
+ * ordering is then combined with its postordering.  If A is unsymmetric,
+ * A+A' is ordered (A must be square).
+ *
+ * workspace: Head (nrow+1)
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+static int igraph_stfu2();
+static int igraph_stfu1() { return igraph_stfu2(); }
+static int igraph_stfu2() { return igraph_stfu1(); }
+
+#ifndef NCAMD
+
+#include "cholmod_internal.h"
+#include "ccolamd.h"
+#include "cholmod_camd.h"
+
+#if (CCOLAMD_VERSION < CCOLAMD_VERSION_CODE (2,5))
+#error "CCOLAMD v2.0 or later is required"
+#endif
+
+/* ========================================================================== */
+/* === cholmod_csymamd ====================================================== */
+/* ========================================================================== */
+
+int CHOLMOD(csymamd)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    /* ---- output --- */
+    Int *Cmember,	/* size nrow.  see cholmod_ccolamd.c for description */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double knobs [CCOLAMD_KNOBS] ;
+    Int *perm, *Head ;
+    Int ok, i, nrow, stats [CCOLAMD_STATS] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    if (A->nrow != A->ncol || !(A->packed))
+    {
+	ERROR (CHOLMOD_INVALID, "matrix must be square and packed") ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrow = A->nrow ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    CHOLMOD(allocate_work) (nrow, 0, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* order the matrix (does not affect A->p or A->i) */
+    /* ---------------------------------------------------------------------- */
+
+    perm = Common->Head ;	/* size nrow+1 (i/l/l) */
+
+    /* get parameters */
+#ifdef LONG
+    ccolamd_l_set_defaults (knobs) ;
+#else
+    ccolamd_set_defaults (knobs) ;
+#endif
+    if (Common->current >= 0 && Common->current < CHOLMOD_MAXMETHODS)
+    {
+	/* get the knobs from the Common parameters */
+	knobs [CCOLAMD_DENSE_ROW] =Common->method[Common->current].prune_dense ;
+	knobs [CCOLAMD_AGGRESSIVE]=Common->method[Common->current].aggressive ;
+    }
+
+    {
+#ifdef LONG
+	csymamd_l (nrow, A->i, A->p, perm, knobs, stats, Common->calloc_memory,
+		Common->free_memory, Cmember, A->stype) ;
+#else
+	csymamd (nrow, A->i, A->p, perm, knobs, stats, Common->calloc_memory,
+		Common->free_memory, Cmember, A->stype) ;
+#endif
+	ok = stats [CCOLAMD_STATUS] ;
+    }
+
+    if (ok == CCOLAMD_ERROR_out_of_memory)
+    {
+	ERROR (CHOLMOD_OUT_OF_MEMORY, "out of memory") ; 
+    }
+    ok = (ok == CCOLAMD_OK || ok == CCOLAMD_OK_BUT_JUMBLED) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the workspace and return result */
+    /* ---------------------------------------------------------------------- */
+
+    /* permutation returned in perm [0..n-1] */
+    for (i = 0 ; i < nrow ; i++)
+    {
+	Perm [i] = perm [i] ;
+    }
+
+    /* clear Head workspace (used for perm, in csymamd): */
+    Head = Common->Head ;
+    for (i = 0 ; i <= nrow ; i++)
+    {
+	Head [i] = EMPTY ;
+    }
+
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Partition/cholmod_metis.c b/src/CHOLMOD/Partition/cholmod_metis.c
new file mode 100644
index 0000000..a4a0524
--- /dev/null
+++ b/src/CHOLMOD/Partition/cholmod_metis.c
@@ -0,0 +1,795 @@
+/* ========================================================================== */
+/* === Partition/cholmod_metis ============================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Partition Module.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Partition Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD interface to the METIS package (Version 4.0.1):
+ *
+ * cholmod_metis_bisector:
+ *
+ *	Wrapper for METIS_NodeComputeSeparator.  Finds a set of nodes that
+ *	partitions the graph into two parts.
+ *
+ * cholmod_metis:
+ *
+ *	Wrapper for METIS_NodeND, METIS's own nested dissection algorithm.
+ *	Typically faster than cholmod_nested_dissection, mostly because it
+ *	uses minimum degree on just the leaves of the separator tree, rather
+ *	than the whole matrix.
+ *
+ * Note that METIS does not return an error if it runs out of memory.  Instead,
+ * it terminates the program.  This interface attempts to avoid that problem
+ * by preallocating space that should be large enough for any memory allocations
+ * within METIS, and then freeing that space, just before the call to METIS.
+ * While this is not guaranteed to work, it is very unlikely to fail.  If you
+ * encounter this problem, increase Common->metis_memory.  If you don't mind
+ * having your program terminated, set Common->metis_memory to zero (a value of
+ * 2.0 is usually safe).  Several other METIS workarounds are made in the
+ * routines in this file.  See the description of metis_memory_ok, just below,
+ * for more details.
+ *
+ * FUTURE WORK: interfaces to other partitioners (CHACO, SCOTCH, JOSTLE, ... )
+ *
+ * workspace: several size-nz and size-n temporary arrays.  Uses no workspace
+ * in Common.
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+static int igraph_stfu2();
+static int igraph_stfu1() { return igraph_stfu2(); }
+static int igraph_stfu2() { return igraph_stfu1(); }
+
+#ifndef NPARTITION
+
+#include "cholmod_internal.h"
+#undef ASSERT
+
+#include "metis.h"
+/* METIS has its own ASSERT that it reveals to the user, so remove it here: */
+#undef ASSERT
+
+/* and redefine it back again */
+#ifndef NDEBUG
+#define ASSERT(expression) (assert (expression))
+#else
+#define ASSERT(expression)
+#endif
+
+#include "cholmod_partition.h"
+#include "cholmod_cholesky.h"
+
+
+/* ========================================================================== */
+/* === dumpgraph ============================================================ */
+/* ========================================================================== */
+
+/* For dumping the input graph to METIS_NodeND, to check with METIS's onmetis
+ * and graphchk programs.  For debugging only.  To use, uncomment this #define:
+#define DUMP_GRAPH
+ */
+
+#ifdef DUMP_GRAPH
+#include <stdio.h>
+/* After dumping the graph with this routine, run "onmetis metisgraph" */
+static void dumpgraph (idxtype *Mp, idxtype *Mi, SuiteSparse_long n,
+    cholmod_common *Common)
+{
+    SuiteSparse_long i, j, p, nz ;
+    FILE *f ;
+    nz = Mp [n] ;
+    printf ("Dumping METIS graph n %ld nz %ld\n", n, nz) ;    /* DUMP_GRAPH */
+    f = fopen ("metisgraph", "w") ;
+    if (f == NULL)
+    {
+	ERROR (-99, "cannot open metisgraph") ;
+	return ;
+    }
+    fprintf (f, "%ld %ld\n", n, nz/2) ;			    /* DUMP_GRAPH */
+    for (j = 0 ; j < n ; j++)
+    {
+	for (p = Mp [j] ; p < Mp [j+1] ; p++)
+	{
+	    i = Mi [p] ;
+	    fprintf (f, " %ld", i+1) ;			    /* DUMP_GRAPH */
+	}
+	fprintf (f, "\n") ;				    /* DUMP_GRAPH */
+    }
+    fclose (f) ;
+}
+#endif
+
+
+/* ========================================================================== */
+/* === metis_memory_ok ====================================================== */
+/* ========================================================================== */
+
+/* METIS_NodeND and METIS_NodeComputeSeparator will terminate your program it
+ * they run out of memory.  In an attempt to workaround METIS' behavior, this
+ * routine allocates a single block of memory of size equal to an observed
+ * upper bound on METIS' memory usage.  It then immediately deallocates the
+ * block.  If the allocation fails, METIS is not called.
+ *
+ * Median memory usage for a graph with n nodes and nz edges (counting each
+ * edge twice, or both upper and lower triangular parts of a matrix) is
+ * 4*nz + 40*n + 4096 integers.  A "typical" upper bound is 10*nz + 50*n + 4096
+ * integers.  Nearly all matrices tested fit within that upper bound, with the
+ * exception two in the UF sparse matrix collection: Schenk_IBMNA/c-64 and
+ * Gupta/gupta2.  The latter exceeds the "upper bound" by a factor of just less
+ * than 2.
+ *
+ * If you do not mind having your program terminated if it runs out of memory,
+ * set Common->metis_memory to zero.  Its default value is 2, which allows for
+ * some memory fragmentation, and also accounts for the Gupta/gupta2 matrix.
+ *
+ * An alternative, if CHOLMOD is used in MATLAB, is to use a version of METIS
+ * (4.0.2, perhaps) proposed to George Karypis.  This version uses function
+ * pointer for malloc and free.  They can be set to mxMalloc and mxFree
+ * (see sputil_config in MATLAB/sputil.c).  On Linux, with gcc, you must also
+ * compile CHOLMOD, METIS, AMD, COLAMD, and CCOLAMD with the -fexceptions
+ * compiler flag.  With this configuration, mxMalloc safely aborts the
+ * mexFunction, frees all memory allocted by METIS, and safely returns to
+ * MATLAB.  You may then set Common->metis_memory = 0.
+ */
+
+#define GUESS(nz,n) (10 * (nz) + 50 * (n) + 4096)
+
+static int metis_memory_ok
+(
+    Int n,
+    Int nz,
+    cholmod_common *Common
+)
+{
+    double s ;
+    void *p ;
+    size_t metis_guard ;
+
+    if (Common->metis_memory <= 0)
+    {
+	/* do not prevent METIS from running out of memory */
+	return (TRUE) ;
+    }
+
+    n  = MAX (1, n) ;
+    nz = MAX (0, nz) ;
+
+    /* compute in double, to avoid integer overflow */
+    s = GUESS ((double) nz, (double) n) ;
+    s *= Common->metis_memory ;
+
+    if (s * sizeof (idxtype) >= ((double) Size_max))
+    {
+	/* don't even attempt to malloc such a large block */
+	return (FALSE) ;
+    }
+
+    /* recompute in size_t */
+    metis_guard = GUESS ((size_t) nz, (size_t) n) ;
+    metis_guard *= Common->metis_memory ;
+
+    /* attempt to malloc the block */
+    p = CHOLMOD(malloc) (metis_guard, sizeof (idxtype), Common) ;
+    if (p == NULL)
+    {
+	/* failure - return out-of-memory condition */
+	return (FALSE) ;
+    }
+
+    /* success - free the block */
+    CHOLMOD(free) (metis_guard, sizeof (idxtype), p, Common) ;
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_metis_bisector =============================================== */
+/* ========================================================================== */
+
+/* Finds a set of nodes that bisects the graph of A or AA' (direct interface
+ * to METIS_NodeComputeSeparator).
+ *
+ * The input matrix A must be square, symmetric (with both upper and lower
+ * parts present) and with no diagonal entries.  These conditions are NOT
+ * checked.
+ */
+
+SuiteSparse_long CHOLMOD(metis_bisector)	/* returns separator size */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to bisect */
+    Int *Anw,		/* size A->nrow, node weights */
+    Int *Aew,		/* size nz, edge weights */
+    /* ---- output --- */
+    Int *Partition,	/* size A->nrow */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Ap, *Ai ;
+    idxtype *Mp, *Mi, *Mnw, *Mew, *Mpart ;
+    Int n, nleft, nright, j, p, csep, total_weight, lightest, nz ;
+    int Opt [8], nn, csp ;
+    size_t n1 ;
+    DEBUG (Int nsep) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_NULL (Anw, EMPTY) ;
+    RETURN_IF_NULL (Aew, EMPTY) ;
+    RETURN_IF_NULL (Partition, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    if (A->stype || A->nrow != A->ncol)
+    {
+	/* A must be square, with both upper and lower parts present */
+	ERROR (CHOLMOD_INVALID, "matrix must be square, symmetric,"
+		" and with both upper/lower parts present") ;
+	return (EMPTY) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+    if (n == 0)
+    {
+	return (0) ;
+    }
+    n1 = ((size_t) n) + 1 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    nz = Ap [n] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* METIS does not have a 64-bit integer version */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef LONG
+    if (sizeof (Int) > sizeof (idxtype) && MAX (n,nz) > INT_MAX / sizeof (int))
+    {
+	/* CHOLMOD's matrix is too large for METIS */
+	return (EMPTY) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* set default options */
+    /* ---------------------------------------------------------------------- */
+
+    Opt [0] = 0 ;	/* use defaults */
+    Opt [1] = 3 ;	/* matching type */
+    Opt [2] = 1 ;	/* init. partitioning algo*/
+    Opt [3] = 2 ;	/* refinement algorithm */
+    Opt [4] = 0 ;	/* no debug */
+    Opt [5] = 0 ;	/* unused */
+    Opt [6] = 0 ;	/* unused */
+    Opt [7] = -1 ;	/* random seed */
+
+    DEBUG (for (j = 0 ; j < n ; j++) ASSERT (Anw [j] > 0)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy Int to METIS idxtype, if necessary */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (for (j = 0 ; j < nz ; j++) ASSERT (Aew [j] > 0)) ;
+    if (sizeof (Int) == sizeof (idxtype))
+    {
+	/* this is the typical case */
+	Mi    = (idxtype *) Ai ;
+	Mew   = (idxtype *) Aew ;
+	Mp    = (idxtype *) Ap ;
+	Mnw   = (idxtype *) Anw ;
+	Mpart = (idxtype *) Partition ;
+    }
+    else
+    {
+	/* idxtype and Int differ; copy the graph into the METIS idxtype */
+	Mi    = CHOLMOD(malloc) (nz, sizeof (idxtype), Common) ;
+	Mew   = CHOLMOD(malloc) (nz, sizeof (idxtype), Common) ;
+	Mp    = CHOLMOD(malloc) (n1, sizeof (idxtype), Common) ;
+	Mnw   = CHOLMOD(malloc) (n,  sizeof (idxtype), Common) ;
+	Mpart = CHOLMOD(malloc) (n,  sizeof (idxtype), Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    CHOLMOD(free) (nz, sizeof (idxtype), Mi,    Common) ;
+	    CHOLMOD(free) (nz, sizeof (idxtype), Mew,   Common) ;
+	    CHOLMOD(free) (n1, sizeof (idxtype), Mp,    Common) ;
+	    CHOLMOD(free) (n,  sizeof (idxtype), Mnw,   Common) ;
+	    CHOLMOD(free) (n,  sizeof (idxtype), Mpart, Common) ;
+	    return (EMPTY) ;
+	}
+	for (p = 0 ; p < nz ; p++)
+	{
+	    Mi [p] = Ai [p] ;
+	}
+	for (p = 0 ; p < nz ; p++)
+	{
+	    Mew [p] = Aew [p] ;
+	}
+	for (j = 0 ; j <= n ; j++)
+	{
+	    Mp [j] = Ap [j] ;
+	}
+	for (j = 0 ; j <  n ; j++)
+	{
+	    Mnw [j] = Anw [j] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* METIS workaround: try to ensure METIS doesn't run out of memory */
+    /* ---------------------------------------------------------------------- */
+
+    if (!metis_memory_ok (n, nz, Common))
+    {
+	/* METIS might ask for too much memory and thus terminate the program */
+	if (sizeof (Int) != sizeof (idxtype))
+	{
+	    CHOLMOD(free) (nz, sizeof (idxtype), Mi,    Common) ;
+	    CHOLMOD(free) (nz, sizeof (idxtype), Mew,   Common) ;
+	    CHOLMOD(free) (n1, sizeof (idxtype), Mp,    Common) ;
+	    CHOLMOD(free) (n,  sizeof (idxtype), Mnw,   Common) ;
+	    CHOLMOD(free) (n,  sizeof (idxtype), Mpart, Common) ;
+	}
+	return (EMPTY) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* partition the graph */
+    /* ---------------------------------------------------------------------- */
+
+#ifndef NDEBUG
+    PRINT1 (("Metis graph, n = "ID"\n", n)) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	Int ppp ;
+	PRINT2 (("M(:,"ID") node weight "ID"\n", j, (Int) Mnw [j])) ;
+	ASSERT (Mnw [j] > 0) ;
+	for (ppp = Mp [j] ; ppp < Mp [j+1] ; ppp++)
+	{
+	    PRINT3 ((" "ID" : "ID"\n", (Int) Mi [ppp], (Int) Mew [ppp])) ;
+	    ASSERT (Mi [ppp] != j) ;
+	    ASSERT (Mew [ppp] > 0) ;
+	}
+    }
+#endif
+
+    nn = n ;
+    METIS_NodeComputeSeparator (&nn, Mp, Mi, Mnw, Mew, Opt, &csp, Mpart) ;
+    n = nn ;
+    csep = csp ;
+
+    PRINT1 (("METIS csep "ID"\n", csep)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy the results back from idxtype, if required */
+    /* ---------------------------------------------------------------------- */
+
+    if (sizeof (Int) != sizeof (idxtype))
+    {
+	for (j = 0 ; j < n ; j++)
+	{
+	    Partition [j] = Mpart [j] ;
+	}
+	CHOLMOD(free) (nz, sizeof (idxtype), Mi,    Common) ;
+	CHOLMOD(free) (nz, sizeof (idxtype), Mew,   Common) ;
+	CHOLMOD(free) (n1, sizeof (idxtype), Mp,    Common) ;
+	CHOLMOD(free) (n,  sizeof (idxtype), Mnw,   Common) ;
+	CHOLMOD(free) (n,  sizeof (idxtype), Mpart, Common) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* ensure a reasonable separator */
+    /* ---------------------------------------------------------------------- */
+
+    /* METIS can return a valid separator with no nodes in (for example) the
+     * left part.  In this case, there really is no separator.  CHOLMOD
+     * prefers, in this case, for all nodes to be in the separator (and both
+     * left and right parts to be empty).  Also, if the graph is unconnected,
+     * METIS can return a valid empty separator.  CHOLMOD prefers at least one
+     * node in the separator.  Note that cholmod_nested_dissection only calls
+     * this routine on connected components, but cholmod_bisect can call this
+     * routine for any graph. */
+
+    if (csep == 0)
+    {
+	/* The separator is empty, select lightest node as separator.  If
+	 * ties, select the highest numbered node. */
+	lightest = 0 ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    if (Anw [j] <= Anw [lightest])
+	    {
+		lightest = j ;
+	    }
+	}
+	PRINT1 (("Force "ID" as sep\n", lightest)) ;
+	Partition [lightest] = 2 ;
+	csep = Anw [lightest] ;
+    }
+
+    /* determine the node weights in the left and right part of the graph */
+    nleft = 0 ;
+    nright = 0 ;
+    DEBUG (nsep = 0) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT1 (("Partition ["ID"] = "ID"\n", j, Partition [j])) ;
+	if (Partition [j] == 0)
+	{
+	    nleft += Anw [j] ;
+	}
+	else if (Partition [j] == 1)
+	{
+	    nright += Anw [j] ;
+	}
+#ifndef NDEBUG
+	else
+	{
+	    ASSERT (Partition [j] == 2) ;
+	    nsep += Anw [j] ;
+	}
+#endif
+    }
+    ASSERT (csep == nsep) ;
+
+    total_weight = nleft + nright + csep ;
+
+    if (csep < total_weight)
+    {
+	/* The separator is less than the whole graph.  Make sure the left and
+	 * right parts are either both empty or both non-empty. */
+	PRINT1 (("nleft "ID" nright "ID" csep "ID" tot "ID"\n",
+		nleft, nright, csep, total_weight)) ;
+	ASSERT (nleft + nright + csep == total_weight) ;
+	ASSERT (nleft > 0 || nright > 0) ;
+	if ((nleft == 0 && nright > 0) || (nleft > 0 && nright == 0))
+	{
+	    /* left or right is empty; put all nodes in the separator */
+	    PRINT1 (("Force all in sep\n")) ;
+	    csep = total_weight ;
+	    for (j = 0 ; j < n ; j++)
+	    {
+		Partition [j] = 2 ;
+	    }
+	}
+    }
+
+    ASSERT (CHOLMOD(dump_partition) (n, Ap, Ai, Anw, Partition, csep, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* return the sum of the weights of nodes in the separator */
+    /* ---------------------------------------------------------------------- */
+
+    return (csep) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_metis ======================================================== */
+/* ========================================================================== */
+
+/* CHOLMOD wrapper for the METIS_NodeND ordering routine.  Creates A+A',
+ * A*A' or A(:,f)*A(:,f)' and then calls METIS_NodeND on the resulting graph.
+ * This routine is comparable to cholmod_nested_dissection, except that it
+ * calls METIS_NodeND directly, and it does not return the separator tree.
+ *
+ * workspace:  Flag (nrow), Iwork (4*n+uncol)
+ *	Allocates a temporary matrix B=A*A' or B=A.
+ */
+
+int CHOLMOD(metis)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int postorder,	/* if TRUE, follow with etree or coletree postorder */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double d ;
+    Int *Iperm, *Iwork, *Bp, *Bi ;
+    idxtype *Mp, *Mi, *Mperm, *Miperm ;
+    cholmod_sparse *B ;
+    Int i, j, n, nz, p, identity, uncol ;
+    int Opt [8], nn, zero = 0 ;
+    size_t n1, s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (Perm, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+    if (n == 0)
+    {
+	return (TRUE) ;
+    }
+    n1 = ((size_t) n) + 1 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 4*n + uncol */
+    uncol = (A->stype == 0) ? A->ncol : 0 ;
+    s = CHOLMOD(mult_size_t) (n, 4, &ok) ;
+    s = CHOLMOD(add_size_t) (s, uncol, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the matrix to adjacency list form */
+    /* ---------------------------------------------------------------------- */
+
+    /* The input graph for METIS must be symmetric, with both upper and lower
+     * parts present, and with no diagonal entries.  The columns need not be
+     * sorted.
+     * B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present */
+    if (A->stype)
+    {
+	/* Add the upper/lower part to a symmetric lower/upper matrix by
+	 * converting to unsymmetric mode */
+	/* workspace: Iwork (nrow) */
+	B = CHOLMOD(copy) (A, 0, -1, Common) ;
+    }
+    else
+    {
+	/* B = A*A' or A(:,f)*A(:,f)', no diagonal */
+	/* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */
+	B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ;
+    }
+    ASSERT (CHOLMOD(dump_sparse) (B, "B for NodeND", Common) >= 0) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (B->nrow == A->nrow) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    Iwork = Common->Iwork ;
+    Iperm = Iwork ;		/* size n (i/i/l) */
+
+    Bp = B->p ;
+    Bi = B->i ;
+    nz = Bp [n] ;
+
+    /* ---------------------------------------------------------------------- */
+    /* METIS does not have a SuiteSparse_long integer version */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef LONG
+    if (sizeof (Int) > sizeof (idxtype) && MAX (n,nz) > INT_MAX / sizeof (int))
+    {
+	/* CHOLMOD's matrix is too large for METIS */
+	CHOLMOD(free_sparse) (&B, Common) ;
+	return (FALSE) ;
+    }
+#endif
+
+    /* B does not include the diagonal, and both upper and lower parts.
+     * Common->anz includes the diagonal, and just the lower part of B */
+    Common->anz = nz / 2 + n ;
+
+    /* ---------------------------------------------------------------------- */
+    /* set control parameters for METIS_NodeND */
+    /* ---------------------------------------------------------------------- */
+
+    Opt [0] = 0 ;	/* use defaults */
+    Opt [1] = 3 ;	/* matching type */
+    Opt [2] = 1 ;	/* init. partitioning algo*/
+    Opt [3] = 2 ;	/* refinement algorithm */
+    Opt [4] = 0 ;	/* no debug */
+    Opt [5] = 1 ;	/* initial compression */
+    Opt [6] = 0 ;	/* no dense node removal */
+    Opt [7] = 1 ;	/* number of separators @ each step */
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate the METIS input arrays, if needed */
+    /* ---------------------------------------------------------------------- */
+
+    if (sizeof (Int) == sizeof (idxtype))
+    {
+	/* This is the typical case. */
+	Miperm = (idxtype *) Iperm ;
+	Mperm  = (idxtype *) Perm ;
+	Mp     = (idxtype *) Bp ;
+	Mi     = (idxtype *) Bi ;
+    }
+    else
+    {
+	/* allocate graph for METIS only if Int and idxtype differ */
+	Miperm = CHOLMOD(malloc) (n,  sizeof (idxtype), Common) ;
+	Mperm  = CHOLMOD(malloc) (n,  sizeof (idxtype), Common) ;
+	Mp     = CHOLMOD(malloc) (n1, sizeof (idxtype), Common) ;
+	Mi     = CHOLMOD(malloc) (nz, sizeof (idxtype), Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* out of memory */
+	    CHOLMOD(free_sparse) (&B, Common) ;
+	    CHOLMOD(free) (n,  sizeof (idxtype), Miperm, Common) ;
+	    CHOLMOD(free) (n,  sizeof (idxtype), Mperm, Common) ;
+	    CHOLMOD(free) (n1, sizeof (idxtype), Mp, Common) ;
+	    CHOLMOD(free) (nz, sizeof (idxtype), Mi, Common) ;
+	    return (FALSE) ;
+	}
+	for (j = 0 ; j <= n ; j++)
+	{
+	    Mp [j] = Bp [j] ;
+	}
+	for (p = 0 ; p < nz ; p++)
+	{
+	    Mi [p] = Bi [p] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* METIS workarounds */
+    /* ---------------------------------------------------------------------- */
+
+    identity = FALSE ;
+    if (nz == 0)
+    {
+	/* The matrix has no off-diagonal entries.  METIS_NodeND fails in this
+	 * case, so avoid using it.  The best permutation is identity anyway,
+	 * so this is an easy fix. */
+	identity = TRUE ;
+	PRINT1 (("METIS:: no nz\n")) ;
+    }
+    else if (Common->metis_nswitch > 0)
+    {
+	/* METIS_NodeND in METIS 4.0.1 gives a seg fault with one matrix of
+	 * order n = 3005 and nz = 6,036,025, including the diagonal entries.
+	 * The workaround is to return the identity permutation instead of using
+	 * METIS for matrices of dimension 3000 or more and with density of 66%
+	 * or more - admittedly an uncertain fix, but such matrices are so dense
+	 * that any reasonable ordering will do, even identity (n^2 is only 50%
+	 * higher than nz in this case).  CHOLMOD's nested dissection method
+	 * (cholmod_nested_dissection) has no problems with the same matrix,
+	 * even though it too uses METIS_NodeComputeSeparator.  The matrix is
+	 * derived from LPnetlib/lpi_cplex1 in the UF sparse matrix collection.
+	 * If C is the lpi_cplex matrix (of order 3005-by-5224), A = (C*C')^2
+	 * results in the seg fault.  The seg fault also occurs in the stand-
+	 * alone onmetis program that comes with METIS.  If a future version of
+	 * METIS fixes this problem, then set Common->metis_nswitch to zero.
+	 */
+	d = ((double) nz) / (((double) n) * ((double) n)) ;
+	if (n > (Int) (Common->metis_nswitch) && d > Common->metis_dswitch)
+	{
+	    identity = TRUE ;
+	    PRINT1 (("METIS:: nswitch/dswitch activated\n")) ;
+	}
+    }
+
+    if (!identity && !metis_memory_ok (n, nz, Common))
+    {
+	/* METIS might ask for too much memory and thus terminate the program */
+	identity = TRUE ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the permutation */
+    /* ---------------------------------------------------------------------- */
+
+    if (identity)
+    {
+	/* no need to do the postorder */
+	postorder = FALSE ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    Mperm [i] = i ;
+	}
+    }
+    else
+    {
+#ifdef DUMP_GRAPH
+	/* DUMP_GRAPH */ printf ("Calling METIS_NodeND n "ID" nz "ID""
+	"density %g\n", n, nz, ((double) nz) / (((double) n) * ((double) n)));
+	dumpgraph (Mp, Mi, n, Common) ;
+#endif
+
+	nn = n ;
+	METIS_NodeND (&nn, Mp, Mi, &zero, Opt, Mperm, Miperm) ;
+	n = nn ;
+
+	PRINT0 (("METIS_NodeND done\n")) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free the METIS input arrays */
+    /* ---------------------------------------------------------------------- */
+
+    if (sizeof (Int) != sizeof (idxtype))
+    {
+	for (i = 0 ; i < n ; i++)
+	{
+	    Perm [i] = (Int) (Mperm [i]) ;
+	}
+	CHOLMOD(free) (n,   sizeof (idxtype), Miperm, Common) ;
+	CHOLMOD(free) (n,   sizeof (idxtype), Mperm, Common) ;
+	CHOLMOD(free) (n+1, sizeof (idxtype), Mp, Common) ;
+	CHOLMOD(free) (nz,  sizeof (idxtype), Mi, Common) ;
+    }
+
+    CHOLMOD(free_sparse) (&B, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* etree or column-etree postordering, using the Cholesky Module */
+    /* ---------------------------------------------------------------------- */
+
+    if (postorder)
+    {
+	Int *Parent, *Post, *NewPerm ;
+	Int k ;
+
+	Parent = Iwork + 2*((size_t) n) + uncol ;   /* size n = nrow */
+	Post   = Parent + n ;			    /* size n */
+
+	/* workspace: Iwork (2*nrow+uncol), Flag (nrow), Head (nrow+1) */
+	CHOLMOD(analyze_ordering) (A, CHOLMOD_METIS, Perm, fset, fsize,
+		Parent, Post, NULL, NULL, NULL, Common) ;
+	if (Common->status == CHOLMOD_OK)
+	{
+	    /* combine the METIS permutation with its postordering */
+	    NewPerm = Parent ;	    /* use Parent as workspace */
+	    for (k = 0 ; k < n ; k++)
+	    {
+		NewPerm [k] = Perm [Post [k]] ;
+	    }
+	    for (k = 0 ; k < n ; k++)
+	    {
+		Perm [k] = NewPerm [k] ;
+	    }
+	}
+    }
+
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    PRINT1 (("cholmod_metis done\n")) ;
+    return (Common->status == CHOLMOD_OK) ;
+}
+#endif
diff --git a/src/CHOLMOD/Partition/cholmod_nesdis.c b/src/CHOLMOD/Partition/cholmod_nesdis.c
new file mode 100644
index 0000000..2e5434e
--- /dev/null
+++ b/src/CHOLMOD/Partition/cholmod_nesdis.c
@@ -0,0 +1,2168 @@
+/* ========================================================================== */
+/* === Partition/cholmod_nesdis ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Partition Module.
+ * Copyright (C) 2005-2006, Univ. of Florida.  Author: Timothy A. Davis
+ * The CHOLMOD/Partition Module is licensed under Version 2.1 of the GNU
+ * Lesser General Public License.  See lesser.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * -------------------------------------------------------------------------- */
+
+/* CHOLMOD nested dissection and graph partitioning.
+ *
+ * cholmod_bisect:
+ *
+ *	Finds a set of nodes that partitions the graph into two parts.
+ *	Compresses the graph first.  Requires METIS.
+ *
+ * cholmod_nested_dissection:
+ *
+ *	Nested dissection, using its own compression and connected-commponents
+ *	algorithms, an external graph partitioner (METIS), and a constrained
+ *	minimum degree ordering algorithm (CCOLAMD or CSYMAMD).  Typically
+ *	gives better orderings than METIS_NodeND (about 5% to 10% fewer
+ *	nonzeros in L).
+ *
+ * cholmod_collapse_septree:
+ *
+ *	Prune the separator tree returned by cholmod_nested_dissection.
+ *
+ * This file contains several routines private to this file:
+ *
+ *	partition	compress and partition a graph
+ *	clear_flag	clear Common->Flag, but do not modify negative entries
+ *	find_components	find the connected components of a graph
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+static int igraph_stfu2();
+static int igraph_stfu1() { return igraph_stfu2(); }
+static int igraph_stfu2() { return igraph_stfu1(); }
+
+#ifndef NPARTITION
+
+#include "cholmod_internal.h"
+#include "cholmod_partition.h"
+#include "cholmod_cholesky.h"
+
+/* ========================================================================== */
+/* === partition ============================================================ */
+/* ========================================================================== */
+
+/* Find a set of nodes that partition a graph.  The graph must be symmetric
+ * with no diagonal entries.  To compress the graph first, compress is TRUE
+ * and on input Hash [j] holds the hash key for node j, which must be in the
+ * range 0 to csize-1. The input graph (Cp, Ci) is destroyed.  Cew is all 1's
+ * on input and output.  Cnw [j] > 0 is the initial weight of node j.  On
+ * output, Cnw [i] = 0 if node i is absorbed into j and the original weight
+ * Cnw [i] is added to Cnw [j].  If compress is FALSE, the graph is not
+ * compressed and Cnw and Hash are unmodified.  The partition itself is held in
+ * the output array Part of size n.  Part [j] is 0, 1, or 2, depending on
+ * whether node j is in the left part of the graph, the right part, or the
+ * separator, respectively.  Note that the input graph need not be connected,
+ * and the output subgraphs (the three parts) may also be unconnected.
+ *
+ * Returns the size of the separator, in terms of the sum of the weights of
+ * the nodes.  It is guaranteed to be between 1 and the total weight of all
+ * the nodes.  If it is of size less than the total weight, then both the left
+ * and right parts are guaranteed to be non-empty (this guarantee depends on
+ * cholmod_metis_bisector).
+ */
+
+static SuiteSparse_long partition    /* size of separator or -1 if failure */
+(
+    /* inputs, not modified on output */
+#ifndef NDEBUG
+    Int csize,		/* upper bound on # of edges in the graph;
+			 * csize >= MAX (n, nnz(C)) must hold. */
+#endif
+    int compress,	/* if TRUE the compress the graph first */
+
+    /* input/output */
+    Int Hash [ ],	/* Hash [i] = hash >= 0 is the hash function for node
+			 * i on input.  On output, Hash [i] = FLIP (j) if node
+			 * i is absorbed into j.  Hash [i] >= 0 if i has not
+			 * been absorbed. */
+
+    /* input graph, compressed graph of cn nodes on output */
+    cholmod_sparse *C,
+
+    /* input/output */
+    Int Cnw [ ],	/* size n.  Cnw [j] > 0 is the weight of node j on
+			 * input.  On output, if node i is absorbed into
+			 * node j, then Cnw [i] = 0 and the original weight of
+			 * node i is added to Cnw [j].  The sum of Cnw [0..n-1]
+			 * is not modified. */
+
+    /* workspace */
+    Int Cew [ ],	/* size csize, all 1's on input and output */
+
+    /* more workspace, undefined on input and output */
+    Int Cmap [ ],	/* size n (i/i/l) */
+
+    /* output */
+    Int Part [ ],	/* size n, Part [j] = 0, 1, or 2. */
+
+    cholmod_common *Common
+)
+{
+    Int n, hash, head, i, j, k, p, pend, ilen, ilast, pi, piend,
+	jlen, ok, cn, csep, pdest, nodes_pruned, nz, total_weight, jscattered ;
+    Int *Cp, *Ci, *Next, *Hhead ;
+
+#ifndef NDEBUG
+    Int cnt, pruned ;
+    double work = 0, goodwork = 0 ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return for small or empty graphs */
+    /* ---------------------------------------------------------------------- */
+
+    n = C->nrow ;
+    Cp = C->p ;
+    Ci = C->i ;
+    nz = Cp [n] ;
+
+    PRINT2 (("Partition start, n "ID" nz "ID"\n", n, nz)) ;
+
+    total_weight = 0 ;
+    for (j = 0 ; j < n ; j++)
+    {
+	ASSERT (Cnw [j] > 0) ;
+	total_weight += Cnw [j] ;
+    }
+
+    if (n <= 2)
+    {
+	/* very small graph */
+	for (j = 0 ; j < n ; j++)
+	{
+	    Part [j] = 2 ;
+	}
+	return (total_weight) ;
+    }
+    else if (nz <= 0)
+    {
+	/* no edges, this is easy */
+	PRINT2 (("diagonal matrix\n")) ;
+	k = n/2 ;
+	for (j = 0 ; j < k ; j++)
+	{
+	    Part [j] = 0 ;
+	}
+	for ( ; j < n ; j++)
+	{
+	    Part [j] = 1 ;
+	}
+	/* ensure the separator is not empty (required by nested dissection) */
+	Part [n-1] = 2 ;
+	return (Cnw [n-1]) ;
+    }
+
+#ifndef NDEBUG
+    ASSERT (n > 1 && nz > 0) ;
+    PRINT2 (("original graph:\n")) ;
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT2 ((""ID": ", j)) ;
+	for (p = Cp [j] ; p < Cp [j+1] ; p++)
+	{
+	    i = Ci [p] ;
+	    PRINT3 ((""ID" ", i)) ;
+	    ASSERT (i >= 0 && i < n && i != j) ;
+	}
+	PRINT2 (("hash: "ID"\n", Hash [j])) ;
+    }
+    DEBUG (for (p = 0 ; p < csize ; p++) ASSERT (Cew [p] == 1)) ;
+#endif
+
+    nodes_pruned = 0 ;
+
+    if (compress)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get workspace */
+	/* ------------------------------------------------------------------ */
+
+	Next = Part ;	/* use Part as workspace for Next [ */
+	Hhead = Cew ;	/* use Cew as workspace for Hhead [ */
+
+	/* ------------------------------------------------------------------ */
+	/* create the hash buckets */
+	/* ------------------------------------------------------------------ */
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    /* get the hash key for node j */
+	    hash = Hash [j] ;
+	    ASSERT (hash >= 0 && hash < csize) ;
+	    head = Hhead [hash] ;
+	    if (head > EMPTY)
+	    {
+		/* hash bucket for this hash key is empty. */
+		head = EMPTY ;
+	    }
+	    else
+	    {
+		/* hash bucket for this hash key is not empty.  get old head */
+		head = FLIP (head) ;
+		ASSERT (head >= 0 && head < n) ;
+	    }
+	    /* node j becomes the new head of the hash bucket.  FLIP it so that
+	     * we can tell the difference between an empty or non-empty hash
+	     * bucket. */
+	    Hhead [hash] = FLIP (j) ;
+	    Next [j] = head ;
+	    ASSERT (head >= EMPTY && head < n) ;
+	}
+
+#ifndef NDEBUG
+	for (cnt = 0, k = 0 ; k < n ; k++)
+	{
+	    ASSERT (Hash [k] >= 0 && Hash [k] < csize) ;    /* k is alive */
+	    hash = Hash [k] ;
+	    ASSERT (hash >= 0 && hash < csize) ;
+	    head = Hhead [hash] ;
+	    ASSERT (head < EMPTY) ;	/* hash bucket not empty */
+	    j = FLIP (head) ;
+	    ASSERT (j >= 0 && j < n) ;
+	    if (j == k)
+	    {
+		PRINT2 (("hash "ID": ", hash)) ;
+		for ( ; j != EMPTY ; j = Next [j])
+		{
+		    PRINT3 ((" "ID"", j)) ;
+		    ASSERT (j >= 0 && j < n) ;
+		    ASSERT (Hash [j] == hash) ;
+		    cnt++ ;
+		    ASSERT (cnt <= n) ;
+		}
+		PRINT2 (("\n")) ;
+	    }
+	}
+	ASSERT (cnt == n) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* scan the non-empty hash buckets for indistinguishable nodes */
+	/* ------------------------------------------------------------------ */
+
+	/* If there are no hash collisions and no compression occurs, this takes
+	 * O(n) time.  If no hash collisions, but some nodes are removed, this
+	 * takes time O(n+e) where e is the sum of the degress of the nodes
+	 * that are removed.  Even with many hash collisions (a rare case),
+	 * this algorithm has never been observed to perform more than nnz(A)
+	 * useless work.
+	 *
+	 * Cmap is used as workspace to mark nodes of the graph, [
+	 * for comparing the nonzero patterns of two nodes i and j.
+	 */
+
+#define Cmap_MARK(i)   Cmap [i] = j
+#define Cmap_MARKED(i) (Cmap [i] == j)
+
+	for (i = 0 ; i < n ; i++)
+	{
+	    Cmap [i] = EMPTY ;
+	}
+
+	for (k = 0 ; k < n ; k++)
+	{
+	    hash = Hash [k] ;
+	    ASSERT (hash >= FLIP (n-1) && hash < csize) ;
+	    if (hash < 0)
+	    {
+		/* node k has already been absorbed into some other node */
+		ASSERT (FLIP (Hash [k]) >= 0 && FLIP (Hash [k] < n)) ;
+		continue ;
+	    }
+	    head = Hhead [hash] ;
+	    ASSERT (head < EMPTY || head == 1) ;
+	    if (head == 1)
+	    {
+		/* hash bucket is already empty */
+		continue ;
+	    }
+	    PRINT2 (("\n--------------------hash "ID":\n", hash)) ;
+	    for (j = FLIP (head) ; j != EMPTY && Next[j] > EMPTY ; j = Next [j])
+	    {
+		/* compare j with all nodes i following it in hash bucket */
+		ASSERT (j >= 0 && j < n && Hash [j] == hash) ;
+		p = Cp [j] ;
+		pend = Cp [j+1] ;
+		jlen = pend - p ;
+		jscattered = FALSE ;
+		DEBUG (for (i = 0 ; i < n ; i++) ASSERT (!Cmap_MARKED (i))) ;
+		DEBUG (pruned = FALSE) ;
+		ilast = j ;
+		for (i = Next [j] ; i != EMPTY ; i = Next [i])
+		{
+		    ASSERT (i >= 0 && i < n && Hash [i] == hash && i != j) ;
+		    pi = Cp [i] ;
+		    piend = Cp [i+1] ;
+		    ilen = piend - pi ;
+		    DEBUG (work++) ;
+		    if (ilen != jlen)
+		    {
+			/* i and j have different degrees */
+			ilast = i ;
+			continue ;
+		    }
+		    /* scatter the pattern of node j, if not already */
+		    if (!jscattered)
+		    {
+			Cmap_MARK (j) ;
+			for ( ; p < pend ; p++)
+			{
+			    Cmap_MARK (Ci [p]) ;
+			}
+			jscattered = TRUE ;
+			DEBUG (work += jlen) ;
+		    }
+		    for (ok = Cmap_MARKED (i) ; ok && pi < piend ; pi++)
+		    {
+			ok = Cmap_MARKED (Ci [pi]) ;
+			DEBUG (work++) ;
+		    }
+		    if (ok)
+		    {
+			/* found it.  kill node i and merge it into j */
+			PRINT2 (("found "ID" absorbed into "ID"\n", i, j)) ;
+			Hash [i] = FLIP (j) ;
+			Cnw [j] += Cnw [i] ;
+			Cnw [i] = 0 ;
+			ASSERT (ilast != i && ilast >= 0 && ilast < n) ;
+			Next [ilast] = Next [i] ; /* delete i from bucket */
+			nodes_pruned++ ;
+			DEBUG (goodwork += (ilen+1)) ;
+			DEBUG (pruned = TRUE) ;
+		    }
+		    else
+		    {
+			/* i and j are different */
+			ilast = i ;
+		    }
+		}
+		DEBUG (if (pruned) goodwork += jlen) ;
+	    }
+	    /* empty the hash bucket, restoring Cew */
+	    Hhead [hash] = 1 ;
+	}
+
+	DEBUG (if (((work - goodwork) / (double) nz) > 0.20) PRINT0 ((
+	    "work %12g good %12g nz %12g (wasted work/nz: %6.2f )\n",
+	    work, goodwork, (double) nz, (work - goodwork) / ((double) nz)))) ;
+
+	/* All hash buckets now empty.  Cmap no longer needed as workspace. ]
+	 * Cew no longer needed as Hhead; Cew is now restored to all ones. ]
+	 * Part no longer needed as workspace for Next. ] */
+    }
+
+    /* Edge weights are all one, node weights reflect node absorption */
+    DEBUG (for (p = 0 ; p < csize ; p++) ASSERT (Cew [p] == 1)) ;
+    DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) cnt += Cnw [j]) ;
+    ASSERT (cnt == total_weight) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compress and partition the graph */
+    /* ---------------------------------------------------------------------- */
+
+    if (nodes_pruned == 0)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* no pruning done at all.  Do not create the compressed graph */
+	/* ------------------------------------------------------------------ */
+
+	/* FUTURE WORK: could call CHACO, SCOTCH, ... here too */
+	csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Part, Common) ;
+
+    }
+    else if (nodes_pruned == n-1)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* only one node left.  This is a dense graph */
+	/* ------------------------------------------------------------------ */
+
+	PRINT2 (("completely dense graph\n")) ;
+	csep = total_weight ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    Part [j] = 2 ;
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* compress the graph and partition the compressed graph */
+	/* ------------------------------------------------------------------ */
+
+	/* ------------------------------------------------------------------ */
+	/* create the map from the uncompressed graph to the compressed graph */
+	/* ------------------------------------------------------------------ */
+
+	/* Cmap [j] = k if node j is alive and the kth node of compressed graph.
+	 * The mapping is done monotonically (that is, k <= j) to simplify the
+	 * uncompression later on.  Cmap [j] = EMPTY if node j is dead. */
+
+	for (j = 0 ; j < n ; j++)
+	{
+	    Cmap [j] = EMPTY ;
+	}
+	k = 0 ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    if (Cnw [j] > 0)
+	    {
+		ASSERT (k <= j) ;
+		Cmap [j] = k++ ;
+	    }
+	}
+	cn = k ;	    /* # of nodes in compressed graph */
+	PRINT2 (("compressed graph from "ID" to "ID" nodes\n", n, cn)) ;
+	ASSERT (cn > 1 && cn == n - nodes_pruned) ;
+
+	/* ------------------------------------------------------------------ */
+	/* create the compressed graph */
+	/* ------------------------------------------------------------------ */
+
+	k = 0 ;
+	pdest = 0 ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    if (Cnw [j] > 0)
+	    {
+		/* node j in the full graph is node k in the compressed graph */
+		ASSERT (k <= j && Cmap [j] == k) ;
+		p = Cp [j] ;
+		pend = Cp [j+1] ;
+		Cp [k] = pdest ;
+		Cnw [k] = Cnw [j] ;
+		for ( ; p < pend ; p++)
+		{
+		    /* prune dead nodes, and remap to new node numbering */
+		    i = Ci [p] ;
+		    ASSERT (i >= 0 && i < n && i != j) ;
+		    i = Cmap [i] ;
+		    ASSERT (i >= EMPTY && i < cn && i != k) ;
+		    if (i > EMPTY)
+		    {
+			ASSERT (pdest <= p) ;
+			Ci [pdest++] = i ;
+		    }
+		}
+		k++ ;
+	    }
+	}
+	Cp [cn] = pdest ;
+	C->nrow = cn ;
+	C->ncol = cn ;	/* affects mem stats unless restored when C free'd */
+
+#ifndef NDEBUG
+	PRINT2 (("pruned graph ("ID"/"ID") nodes, ("ID"/"ID") edges\n",
+		    cn, n, pdest, nz)) ;
+	PRINT2 (("compressed graph:\n")) ;
+	for (cnt = 0, j = 0 ; j < cn ; j++)
+	{
+	    PRINT2 ((""ID": ", j)) ;
+	    for (p = Cp [j] ; p < Cp [j+1] ; p++)
+	    {
+		i = Ci [p] ;
+		PRINT3 ((""ID" ", i)) ;
+		ASSERT (i >= 0 && i < cn && i != j) ;
+	    }
+	    PRINT2 (("weight: "ID"\n", Cnw [j])) ;
+	    ASSERT (Cnw [j] > 0) ;
+	    cnt += Cnw [j] ;
+	}
+	ASSERT (cnt == total_weight) ;
+	for (j = 0 ; j < n ; j++) PRINT2 (("Cmap ["ID"] = "ID"\n", j, Cmap[j]));
+	ASSERT (k == cn) ;
+#endif
+
+	/* ------------------------------------------------------------------ */
+	/* find the separator of the compressed graph */
+	/* ------------------------------------------------------------------ */
+
+	/* FUTURE WORK: could call CHACO, SCOTCH, ... here too */
+	csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Part, Common) ;
+
+	if (csep < 0)
+	{
+	    /* failed */
+	    return (-1) ;
+	}
+
+	PRINT2 (("Part: ")) ;
+	DEBUG (for (j = 0 ; j < cn ; j++) PRINT2 ((""ID" ", Part [j]))) ;
+	PRINT2 (("\n")) ;
+
+	/* Cp and Ci no longer needed */
+
+	/* ------------------------------------------------------------------ */
+	/* find the separator of the uncompressed graph */
+	/* ------------------------------------------------------------------ */
+
+	/* expand the separator to live nodes in the uncompressed graph */
+	for (j = n-1 ; j >= 0 ; j--)
+	{
+	    /* do this in reverse order so that Cnw can be expanded in place */
+	    k = Cmap [j] ;
+	    ASSERT (k >= EMPTY && k < n) ;
+	    if (k > EMPTY)
+	    {
+		/* node k in compressed graph and is node j in full graph */
+		ASSERT (k <= j) ;
+		ASSERT (Hash [j] >= EMPTY) ;
+		Part [j] = Part [k] ;
+		Cnw [j] = Cnw [k] ;
+	    }
+	    else
+	    {
+		/* node j is a dead node */
+		Cnw [j] = 0 ;
+		DEBUG (Part [j] = EMPTY) ;
+		ASSERT (Hash [j] < EMPTY) ;
+	    }
+	}
+
+	/* find the components for the dead nodes */
+	for (i = 0 ; i < n ; i++)
+	{
+	    if (Hash [i] < EMPTY)
+	    {
+		/* node i has been absorbed into node j */
+		j = FLIP (Hash [i]) ;
+		ASSERT (Part [i] == EMPTY && j >= 0 && j < n && Cnw [i] == 0) ;
+		Part [i] = Part [j] ;
+	    }
+	    ASSERT (Part [i] >= 0 && Part [i] <= 2) ;
+	}
+
+#ifndef NDEBUG
+	PRINT2 (("Part: ")) ;
+	for (cnt = 0, j = 0 ; j < n ; j++)
+	{
+	    ASSERT (Part [j] != EMPTY) ;
+	    PRINT2 ((""ID" ", Part [j])) ;
+	    if (Part [j] == 2) cnt += Cnw [j] ;
+	}
+	PRINT2 (("\n")) ;
+	PRINT2 (("csep "ID" "ID"\n", cnt, csep)) ;
+	ASSERT (cnt == csep) ;
+	for (cnt = 0, j = 0 ; j < n ; j++) cnt += Cnw [j] ;
+	ASSERT (cnt == total_weight) ;
+#endif
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return the separator (or -1 if error) */
+    /* ---------------------------------------------------------------------- */
+
+    PRINT2 (("Partition done, n "ID" csep "ID"\n", n, csep)) ;
+    return (csep) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_flag =========================================================== */
+/* ========================================================================== */
+
+/* A node j has been removed from the graph if Flag [j] < EMPTY.
+ * If Flag [j] >= EMPTY && Flag [j] < mark, then node j is alive but unmarked.
+ * Flag [j] == mark means that node j is alive and marked.  Incrementing mark
+ * means that all nodes are either (still) dead, or live but unmarked.
+ *
+ * If Map is NULL, then on output, Common->mark < Common->Flag [i] for all i
+ * from 0 to Common->nrow.  This is the same output condition as
+ * cholmod_clear_flag, except that this routine maintains the Flag [i] < EMPTY
+ * condition as well, if that condition was true on input.
+ *
+ * If Map is non-NULL, then on output, Common->mark < Common->Flag [i] for all
+ * i in the set Map [0..cn-1].
+ *
+ * workspace: Flag (nrow)
+ */
+
+static SuiteSparse_long clear_flag (Int *Map, Int cn, cholmod_common *Common)
+{
+    Int nrow, i ;
+    Int *Flag ;
+    PRINT2 (("old mark %ld\n", Common->mark)) ;
+    Common->mark++ ;
+    PRINT2 (("new mark %ld\n", Common->mark)) ;
+    if (Common->mark <= 0)
+    {
+	nrow = Common->nrow ;
+	Flag = Common->Flag ;
+        if (Map != NULL)
+        {
+            for (i = 0 ; i < cn ; i++)
+            {
+                /* if Flag [Map [i]] < EMPTY, leave it alone */
+                if (Flag [Map [i]] >= EMPTY)
+                {
+                    Flag [Map [i]] = EMPTY ;
+                }
+            }
+            /* now Flag [Map [i]] <= EMPTY for all i */
+        }
+        else
+        {
+            for (i = 0 ; i < nrow ; i++)
+            {
+                /* if Flag [i] < EMPTY, leave it alone */
+                if (Flag [i] >= EMPTY)
+                {
+                    Flag [i] = EMPTY ;
+                }
+            }
+            /* now Flag [i] <= EMPTY for all i */
+        }
+	Common->mark = 0 ;
+    }
+    return (Common->mark) ;
+}
+
+
+/* ========================================================================== */
+/* === find_components ====================================================== */
+/* ========================================================================== */
+
+/* Find all connected components of the current subgraph C.  The subgraph C
+ * consists of the nodes of B that appear in the set Map [0..cn-1].  If Map
+ * is NULL, then it is assumed to be the identity mapping
+ * (Map [0..cn-1] = 0..cn-1).
+ *
+ * A node j does not appear in B if it has been ordered (Flag [j] < EMPTY,
+ * which means that j has been ordered and is "deleted" from B).
+ *
+ * If the size of a component is large, it is placed on the component stack,
+ * Cstack.  Otherwise, its nodes are ordered and it is not placed on the Cstack.
+ *
+ * A component S is defined by a "representative node" (repnode for short)
+ * called the snode, which is one of the nodes in the subgraph.  Likewise, the
+ * subgraph C is defined by its repnode, called cnode.
+ * 
+ * If Part is not NULL on input, then Part [i] determines how the components
+ * are placed on the stack.  Components containing nodes i with Part [i] == 0
+ * are placed first, followed by components with Part [i] == 1. 
+ *
+ * The first node placed in each of the two parts is flipped when placed in
+ * the Cstack.  This allows the components of the two parts to be found simply
+ * by traversing the Cstack.
+ *
+ * workspace: Flag (nrow)
+ */
+
+static void find_components
+(
+    /* inputs, not modified on output */
+    cholmod_sparse *B,
+    Int Map [ ],	    /* size n, only Map [0..cn-1] used */
+    Int cn,		    /* # of nodes in C */
+    Int cnode,		    /* root node of component C, or EMPTY if C is the
+			     * entire graph B */
+
+    Int Part [ ],	    /* size cn, optional */
+
+    /* input/output */
+    Int Bnz [ ],	    /* size n.  Bnz [j] = # nonzeros in column j of B.
+			     * Reduce since B is pruned of dead nodes. */
+
+    Int CParent [ ],	    /* CParent [i] = j if component with repnode j is
+			     * the parent of the component with repnode i.
+			     * CParent [i] = EMPTY if the component with
+			     * repnode i is a root of the separator tree.
+			     * CParent [i] is -2 if i is not a repnode. */
+    Int Cstack [ ],	    /* component stack for nested dissection */
+    Int *top,		    /* Cstack [0..top] contains root nodes of the
+			     * the components currently in the stack */
+
+    /* workspace, undefined on input and output: */
+    Int Queue [ ],	    /* size n, for breadth-first search */
+
+    cholmod_common *Common
+)
+{
+    Int n, mark, cj, j, sj, sn, p, i, snode, pstart, pdest, pend, nd_components,
+	part, first, save_mark ;
+    Int *Bp, *Bi, *Flag ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    PRINT2 (("find components: cn %d\n", cn)) ;
+    Flag = Common->Flag ;	    /* size n */
+
+    /* force initialization of Flag [Map [0..cn-1]] */
+    save_mark = Common->mark ;      /* save the current mark */
+    Common->mark = EMPTY ;
+
+    /* clear Flag; preserve Flag [Map [i]] if Flag [Map [i]] already < EMPTY */
+    /* this takes O(cn) time */
+    mark = clear_flag (Map, cn, Common) ;
+
+    Bp = B->p ;
+    Bi = B->i ;
+    n = B->nrow ;
+    ASSERT (cnode >= EMPTY && cnode < n) ;
+    ASSERT (IMPLIES (cnode >= 0, Flag [cnode] < EMPTY)) ;
+
+    /* get ordering parameters */
+    nd_components = Common->method [Common->current].nd_components ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the connected components of C via a breadth-first search */
+    /* ---------------------------------------------------------------------- */
+
+    part = (Part == NULL) ? 0 : 1 ;
+
+    /* examine each part (part 1 and then part 0) */
+    for (part = (Part == NULL) ? 0 : 1 ; part >= 0 ; part--)
+    {
+
+	/* first is TRUE for the first connected component in each part */
+	first = TRUE ;
+
+	/* find all connected components in the current part */
+	for (cj = 0 ; cj < cn ; cj++)
+	{
+	    /* get node snode, which is node cj of C.  It might already be in
+	     * the separator of C (and thus ordered, with Flag [snode] < EMPTY)
+	     */
+	    snode = (Map == NULL) ? (cj) : (Map [cj]) ;
+	    ASSERT (snode >= 0 && snode < n) ;
+
+	    if (Flag [snode] >= EMPTY && Flag [snode] < mark
+		    && ((Part == NULL) || Part [cj] == part))
+	    {
+
+		/* ---------------------------------------------------------- */
+		/* find new connected component S */
+		/* ---------------------------------------------------------- */
+
+		/* node snode is the repnode of a connected component S, the
+		 * parent of which is cnode, the repnode of C.  If cnode is
+		 * EMPTY then C is the original graph B. */
+		PRINT2 (("----------:::snode "ID" cnode "ID"\n", snode, cnode));
+
+		ASSERT (CParent [snode] == -2) ;
+		if (first || nd_components)
+		{
+		    /* If this is the first node in this part, then it becomes
+		     * the repnode of all components in this part, and all
+		     * components in this part form a single node in the
+		     * separator tree.  If nd_components is TRUE, then all
+		     * connected components form their own node in the
+		     * separator tree.
+		     */
+		    CParent [snode] = cnode ;
+		}
+
+		/* place j in the queue and mark it */
+		Queue [0] = snode ;
+		Flag [snode] = mark ;
+		sn = 1 ;
+
+		/* breadth-first traversal, starting at node j */
+		for (sj = 0 ; sj < sn ; sj++)
+		{
+		    /* get node j from head of Queue and traverse its edges */
+		    j = Queue [sj] ;
+		    PRINT2 (("    j: "ID"\n", j)) ;
+		    ASSERT (j >= 0 && j < n) ;
+		    ASSERT (Flag [j] == mark) ;
+		    pstart = Bp [j] ;
+		    pdest = pstart ;
+		    pend = pstart + Bnz [j] ;
+		    for (p = pstart ; p < pend ; p++)
+		    {
+			i = Bi [p] ;
+			if (i != j && Flag [i] >= EMPTY)
+			{
+			    /* node is still in the graph */
+			    Bi [pdest++] = i ;
+			    if (Flag [i] < mark)
+			    {
+				/* node i is in this component S, and unflagged
+				 * (first time node i has been seen in this BFS)
+				 * place node i in the queue and mark it */
+				Queue [sn++] = i ;
+				Flag [i] = mark ;
+			    }
+			}
+		    }
+		    /* edges to dead nodes have been removed */
+		    Bnz [j] = pdest - pstart ;
+		}
+
+		/* ---------------------------------------------------------- */
+		/* order S if it is small; place it on Cstack otherwise */
+		/* ---------------------------------------------------------- */
+
+		PRINT2 (("sn "ID"\n", sn)) ;
+
+		/* place the new component on the Cstack.  Flip the node if
+		 * is the first connected component of the current part,
+		 * or if all components are treated as their own node in
+		 * the separator tree. */
+		Cstack [++(*top)] =
+			(first || nd_components) ? FLIP (snode) : snode ;
+		first = FALSE ;
+	    }
+	}
+    }
+
+    /* restore the flag (normally taking O(1) time except for Int overflow) */
+    Common->mark = save_mark++ ;
+    clear_flag (NULL, 0, Common) ;
+    DEBUG (for (i = 0 ; i < n ; i++) ASSERT (Flag [i] < Common->mark)) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_bisect ======================================================= */
+/* ========================================================================== */
+
+/* Finds a node bisector of A, A*A', A(:,f)*A(:,f)'.
+ *
+ * workspace: Flag (nrow),
+ *	Iwork (nrow if symmetric, max (nrow,ncol) if unsymmetric).
+ *	Allocates a temporary matrix B=A*A' or B=A,
+ *	and O(nnz(A)) temporary memory space.
+ */
+
+SuiteSparse_long CHOLMOD(bisect)	/* returns # of nodes in separator */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to bisect */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    int compress,	/* if TRUE, compress the graph first */
+    /* ---- output --- */
+    Int *Partition,	/* size A->nrow.  Node i is in the left graph if
+			 * Partition [i] = 0, the right graph if 1, and in the
+			 * separator if 2. */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *Bp, *Bi, *Hash, *Cmap, *Bnw, *Bew, *Iwork ;
+    cholmod_sparse *B ;
+    unsigned Int hash ;
+    Int j, n, bnz, sepsize, p, pend ;
+    size_t csize, s ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_NULL (Partition, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+    if (n == 0)
+    {
+	return (0) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = n + MAX (n, A->ncol) */
+    s = CHOLMOD(add_size_t) (A->nrow, MAX (A->nrow, A->ncol), &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (EMPTY) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    Iwork = Common->Iwork ;
+    Hash = Iwork ;		/* size n, (i/l/l) */
+    Cmap = Iwork + n ;		/* size n, (i/i/l) */
+
+    /* ---------------------------------------------------------------------- */
+    /* convert the matrix to adjacency list form */
+    /* ---------------------------------------------------------------------- */
+
+    /* The input graph to must be symmetric, with no diagonal entries
+     * present.  The columns need not be sorted. */
+
+    /* B = A, A*A', or A(:,f)*A(:,f)', upper and lower parts present */
+
+    if (A->stype)
+    {
+	/* Add the upper/lower part to a symmetric lower/upper matrix by
+	 * converting to unsymmetric mode */
+	/* workspace: Iwork (nrow) */
+	B = CHOLMOD(copy) (A, 0, -1, Common) ;
+    }
+    else
+    {
+	/* B = A*A' or A(:,f)*A(:,f)', no diagonal */
+	/* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */
+	B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+    Bp = B->p ;
+    Bi = B->i ;
+    bnz = Bp [n] ;
+    ASSERT ((Int) (B->nrow) == n && (Int) (B->ncol) == n) ;
+
+    /* B does not include the diagonal, and both upper and lower parts.
+     * Common->anz includes the diagonal, and just the lower part of B */
+    Common->anz = bnz / 2 + ((double) n) ;
+
+    /* Bew should be at least size n for the hash function to work well */
+    /* this cannot cause overflow, because the matrix is already created */
+    csize = MAX (((size_t) n) + 1, (size_t) bnz) ;
+
+    /* create the graph using Flag as workspace for node weights [ */
+    Bnw = Common->Flag ;    /* size n workspace */
+
+    /* compute hash for each node if compression requested */
+    if (compress)
+    {
+	for (j = 0 ; j < n ; j++)
+	{
+	    hash = j ;
+	    pend = Bp [j+1] ;
+	    for (p = Bp [j] ; p < pend ; p++)
+	    {
+		hash += Bi [p] ;
+		ASSERT (Bi [p] != j) ;
+	    }
+	    /* finalize the hash key for node j */
+	    hash %= csize ;
+	    Hash [j] = (Int) hash ;
+	    ASSERT (Hash [j] >= 0 && Hash [j] < csize) ;
+	}
+    }
+
+    /* allocate edge weights */
+    Bew = CHOLMOD(malloc) (csize, sizeof (Int), Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	CHOLMOD(free_sparse) (&B, Common) ;
+	CHOLMOD(free) (csize, sizeof (Int), Bew, Common) ;
+	return (EMPTY) ;
+    }
+
+    /* graph has unit node and edge weights */
+    for (j = 0 ; j < n ; j++)
+    {
+	Bnw [j] = 1 ;
+    }
+    for (s = 0 ; s < csize ; s++)
+    {
+	Bew [s] = 1 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compress and partition the graph */
+    /* ---------------------------------------------------------------------- */
+
+    sepsize = partition (
+#ifndef NDEBUG
+	    csize,
+#endif
+	    compress, Hash, B, Bnw, Bew, Cmap, Partition, Common) ;
+
+    /* contents of Bp, Bi, Bnw, and Bew no longer needed ] */
+
+    /* If partition fails, free the workspace below and return sepsize < 0 */
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    B->ncol = n ;   /* restore size for memory usage statistics */
+    CHOLMOD(free_sparse) (&B, Common) ;
+    Common->mark = EMPTY ;
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    CHOLMOD(free) (csize, sizeof (Int), Bew, Common) ;
+    return (sepsize) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_nested_dissection ============================================ */
+/* ========================================================================== */
+
+/* This method uses a node bisector, applied recursively (but using a
+ * non-recursive algorithm).  Once the graph is partitioned, it calls a
+ * constrained min degree code (CAMD or CSYMAMD for A+A', and CCOLAMD for A*A')
+ * to order all the nodes in the graph - but obeying the constraints determined
+ * by the separators.  This routine is similar to METIS_NodeND, except for how
+ * it treats the leaf nodes.  METIS_NodeND orders the leaves of the separator
+ * tree with MMD, ignoring the rest of the matrix when ordering a single leaf.
+ * This routine orders the whole matrix with CSYMAMD or CCOLAMD, all at once,
+ * when the graph partitioning is done.
+ *
+ * This function also returns a postorderd separator tree (CParent), and a
+ * mapping of nodes in the graph to nodes in the separator tree (Cmember).
+ *
+ * workspace: Flag (nrow), Head (nrow+1), Iwork (4*nrow + (ncol if unsymmetric))
+ *	Allocates a temporary matrix B=A*A' or B=A,
+ *	and O(nnz(A)) temporary memory space.
+ *	Allocates an additional 3*n*sizeof(Int) temporary workspace
+ */
+
+SuiteSparse_long CHOLMOD(nested_dissection)
+    /* returns # of components, or -1 if error */
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to order */
+    Int *fset,		/* subset of 0:(A->ncol)-1 */
+    size_t fsize,	/* size of fset */
+    /* ---- output --- */
+    Int *Perm,		/* size A->nrow, output permutation */
+    Int *CParent,	/* size A->nrow.  On output, CParent [c] is the parent
+			 * of component c, or EMPTY if c is a root, and where
+			 * c is in the range 0 to # of components minus 1 */
+    Int *Cmember,	/* size A->nrow.  Cmember [j] = c if node j of A is
+			 * in component c */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double prune_dense, nd_oksep ;
+    Int *Bp, *Bi, *Bnz, *Cstack, *Imap, *Map, *Flag, *Head, *Next, *Bnw, *Iwork,
+	*Ipost, *NewParent, *Hash, *Cmap, *Cp, *Ci, *Cew, *Cnw, *Part, *Post,
+	*Work3n ;
+    unsigned Int hash ;
+    Int n, bnz, top, i, j, k, cnode, cdense, p, cj, cn, ci, cnz, mark, c, uncol,
+	sepsize, parent, ncomponents, threshold, ndense, pstart, pdest, pend,
+	nd_compress, nd_camd, csize, jnext, nd_small, total_weight,
+	nchild, child = EMPTY ;
+    cholmod_sparse *B, *C ;
+    size_t s ;
+    int ok = TRUE ;
+    DEBUG (Int cnt) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (A, EMPTY) ;
+    RETURN_IF_NULL (Perm, EMPTY) ;
+    RETURN_IF_NULL (CParent, EMPTY) ;
+    RETURN_IF_NULL (Cmember, EMPTY) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, EMPTY) ;
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* quick return */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+    if (n == 0)
+    {
+	return (1) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* get ordering parameters */
+    prune_dense = Common->method [Common->current].prune_dense ;
+    nd_compress = Common->method [Common->current].nd_compress ;
+    nd_oksep = Common->method [Common->current].nd_oksep ;
+    nd_oksep = MAX (0, nd_oksep) ;
+    nd_oksep = MIN (1, nd_oksep) ;
+    nd_camd = Common->method [Common->current].nd_camd ;
+    nd_small = Common->method [Common->current].nd_small ;
+    nd_small = MAX (4, nd_small) ;
+
+    PRINT0 (("nd_components %d nd_small %d nd_oksep %g\n", 
+	Common->method [Common->current].nd_components,
+	nd_small, nd_oksep)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 4*n + uncol */
+    uncol = (A->stype == 0) ? A->ncol : 0 ;
+    s = CHOLMOD(mult_size_t) (n, 4, &ok) ;
+    s = CHOLMOD(add_size_t) (s, uncol, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (EMPTY) ;
+    }
+
+    CHOLMOD(allocate_work) (n, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    Flag = Common->Flag ;	/* size n */
+    Head = Common->Head ;	/* size n+1, all equal to -1 */
+
+    Iwork = Common->Iwork ;
+    Imap = Iwork ;		/* size n, same as Queue in find_components */
+    Map  = Iwork + n ;		/* size n */
+    Bnz  = Iwork + 2*((size_t) n) ;	/* size n */
+    Hash = Iwork + 3*((size_t) n) ;	/* size n */
+
+    Work3n = CHOLMOD(malloc) (n, 3*sizeof (Int), Common) ;
+    Part = Work3n ;		/* size n */
+    Bnw  = Part + n ;		/* size n */
+    Cnw  = Bnw + n ;		/* size n */
+
+    Cstack = Perm ;		/* size n, use Perm as workspace for Cstack [ */
+    Cmap = Cmember ;		/* size n, use Cmember as workspace [ */
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* convert B to symmetric form with both upper/lower parts present */
+    /* ---------------------------------------------------------------------- */
+
+    /* B = A+A', A*A', or A(:,f)*A(:,f)', upper and lower parts present */
+
+    if (A->stype)
+    {
+	/* Add the upper/lower part to a symmetric lower/upper matrix by
+	 * converting to unsymmetric mode */
+	/* workspace: Iwork (nrow) */
+	B = CHOLMOD(copy) (A, 0, -1, Common) ;
+    }
+    else
+    {
+	/* B = A*A' or A(:,f)*A(:,f)', no diagonal */
+	/* workspace: Flag (nrow), Iwork (max (nrow,ncol)) */
+	B = CHOLMOD(aat) (A, fset, fsize, -1, Common) ;
+    }
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ;
+	return (EMPTY) ;
+    }
+    Bp = B->p ;
+    Bi = B->i ;
+    bnz = CHOLMOD(nnz) (B, Common) ;
+    ASSERT ((Int) (B->nrow) == n && (Int) (B->ncol) == n) ;
+    csize = MAX (n, bnz) ;
+    ASSERT (CHOLMOD(dump_sparse) (B, "B for nd:", Common) >= 0) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* initializations */
+    /* ---------------------------------------------------------------------- */
+
+    /* all nodes start out unmarked and unordered (Type 4, see below) */
+    Common->mark = EMPTY ;
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    ASSERT (Flag == Common->Flag) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	CParent [j] = -2 ;
+    }
+
+    /* prune dense nodes from B */
+    if (IS_NAN (prune_dense) || prune_dense < 0)
+    {
+	/* only remove completely dense nodes */
+	threshold = n-2 ;
+    }
+    else
+    {
+	/* remove nodes with degree more than threshold */
+	threshold = (Int) (MAX (16, prune_dense * sqrt ((double) (n)))) ;
+	threshold = MIN (n, threshold) ;
+    }
+    ndense = 0 ;
+    cnode = EMPTY ;
+    cdense = EMPTY ;
+
+    for (j = 0 ; j < n ; j++)
+    {
+	Bnz [j] = Bp [j+1] - Bp [j] ;
+	if (Bnz [j] > threshold)
+	{
+	    /* node j is dense, prune it from B */
+	    PRINT2 (("j is dense %d\n", j)) ;
+	    ndense++ ;
+	    if (cnode == EMPTY)
+	    {
+		/* first dense node found becomes root of this component,
+		 * which contains all of the dense nodes found here */
+		cdense = j ;
+		cnode = j ;
+		CParent [cnode] = EMPTY ;
+	    }
+	    Flag [j] = FLIP (cnode) ;
+	}
+    }
+    B->packed = FALSE ;
+    ASSERT (B->nz == NULL) ;
+
+    if (ndense == n)
+    {
+	/* all nodes removed: Perm is identity, all nodes in component zero,
+	 * and the separator tree has just one node. */
+	PRINT2 (("all nodes are dense\n")) ;
+	for (k = 0 ; k < n ; k++)
+	{
+	    Perm [k] = k ;
+	    Cmember [k] = 0 ;
+	}
+	CParent [0] = EMPTY ;
+	CHOLMOD(free_sparse) (&B, Common) ;
+	CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ;
+	Common->mark = EMPTY ;
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	return (1) ;
+    }
+
+    /* Cp and Ci are workspace to construct the subgraphs to partition */
+    C = CHOLMOD(allocate_sparse) (n, n, csize, FALSE, TRUE, 0, CHOLMOD_PATTERN,
+	    Common) ;
+    Cew  = CHOLMOD(malloc) (csize, sizeof (Int), Common) ;
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	CHOLMOD(free_sparse) (&C, Common) ;
+	CHOLMOD(free_sparse) (&B, Common) ;
+	CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ;
+	CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ;
+	Common->mark = EMPTY ;
+	CHOLMOD_CLEAR_FLAG (Common) ;
+	PRINT2 (("out of memory for C, etc\n")) ;
+	return (EMPTY) ;
+    }
+
+    Cp = C->p ;
+    Ci = C->i ;
+
+    /* create initial unit node and edge weights */
+    for (j = 0 ; j < n ; j++)
+    {
+	Bnw [j] = 1 ;
+    }
+    for (p = 0 ; p < csize ; p++)
+    {
+	Cew [p] = 1 ;
+    }
+
+    /* push the initial connnected components of B onto the Cstack */
+    top = EMPTY ;	/* Cstack is empty */
+    /* workspace: Flag (nrow), Iwork (nrow); use Imap as workspace for Queue [*/
+    find_components (B, NULL, n, cnode, NULL,
+	    Bnz, CParent, Cstack, &top, Imap, Common) ;
+    /* done using Imap as workspace for Queue ] */
+
+    /* Nodes can now be of Type 0, 1, 2, or 4 (see definition below) */
+
+    /* ---------------------------------------------------------------------- */
+    /* while Cstack is not empty, do: */
+    /* ---------------------------------------------------------------------- */
+
+    while (top >= 0)
+    {
+
+	/* clear the Flag array, but do not modify negative entries in Flag  */
+	mark = clear_flag (NULL, 0, Common) ;
+
+	DEBUG (for (i = 0 ; i < n ; i++) Imap [i] = EMPTY) ;
+
+	/* ------------------------------------------------------------------ */
+	/* get node(s) from the top of the Cstack */
+	/* ------------------------------------------------------------------ */
+
+	/* i is the repnode of its (unordered) connected component.  Get
+	 * all repnodes for all connected components of a single part.  If
+	 * each connected component is to be ordered separately (nd_components
+	 * is TRUE), then this while loop iterates just once. */
+
+	cnode = EMPTY ;
+	cn = 0 ;
+	while (cnode == EMPTY)
+	{
+	    i = Cstack [top--] ;
+
+	    if (i < 0)
+	    {
+		/* this is the last node in this component */
+		i = FLIP (i) ;
+		cnode = i ;
+	    }
+
+	    ASSERT (i >= 0 && i < n && Flag [i] >= EMPTY) ;
+
+	    /* place i in the queue and mark it */
+	    Map [cn] = i ;
+	    Flag [i] = mark ;
+	    Imap [i] = cn ;
+	    cn++ ;
+	}
+
+	ASSERT (cnode != EMPTY) ;
+
+	/* During ordering, there are five kinds of nodes in the graph of B,
+	 * based on Flag [j] and CParent [j] for nodes j = 0 to n-1:
+	 *
+	 * Type 0: If cnode is a repnode of an unordered component, then
+	 * CParent [cnode] is in the range EMPTY to n-1 and
+	 * Flag [cnode] >= EMPTY.  This is a "live" node.
+	 *
+	 * Type 1: If cnode is a repnode of an ordered separator component,
+	 * then Flag [cnode] < EMPTY and FLAG [cnode] = FLIP (cnode).
+	 * CParent [cnode] is in the range EMPTY to n-1.  cnode is a root of
+	 * the separator tree if CParent [cnode] == EMPTY.  This node is dead.
+	 *
+	 * Type 2: If node j isn't a repnode, has not been absorbed via
+	 * graph compression into another node, but is in an ordered separator
+	 * component, then cnode = FLIP (Flag [j]) gives the repnode of the
+	 * component that contains j and CParent [j]  is -2.  This node is dead.
+	 * Note that Flag [j] < EMPTY.
+	 *
+	 * Type 3: If node i has been absorbed via graph compression into some
+	 * other node j = FLIP (Flag [i]) where j is not a repnode.
+	 * CParent [j] is -2.  Node i may or may not be in an ordered
+	 * component.  This node is dead.  Note that Flag [j] < EMPTY.
+	 *
+	 * Type 4: If node j is "live" (not in an ordered component, and not
+	 * absorbed into any other node), then Flag [j] >= EMPTY.
+	 *
+	 * Only "live" nodes (of type 0 or 4) are placed in a subgraph to be
+	 * partitioned.  Node j is alive if Flag [j] >= EMPTY, and dead if
+	 * Flag [j] < EMPTY.
+	 */
+
+	/* ------------------------------------------------------------------ */
+	/* create the subgraph for this connected component C */
+	/* ------------------------------------------------------------------ */
+
+	/* Do a breadth-first search of the graph starting at cnode.
+	 * use Map [0..cn-1] for nodes in the component C [
+	 * use Cnw and Cew for node and edge weights of the resulting subgraph [
+	 * use Cp and Ci for the resulting subgraph [
+	 * use Imap [i] for all nodes i in B that are in the component C [
+	 */
+
+	cnz = 0 ;
+	total_weight = 0 ;
+	for (cj = 0 ; cj < cn ; cj++)
+	{
+	    /* get node j from the head of the queue; it is node cj of C */
+	    j = Map [cj] ;
+	    ASSERT (Flag [j] == mark) ;
+	    Cp [cj] = cnz ;
+	    Cnw [cj] = Bnw [j] ;
+	    ASSERT (Cnw [cj] >= 0) ;
+	    total_weight += Cnw [cj] ;
+	    pstart = Bp [j] ;
+	    pdest = pstart ;
+	    pend = pstart + Bnz [j] ;
+	    hash = cj ;
+	    for (p = pstart ; p < pend ; p++)
+	    {
+		i = Bi [p] ;
+		/* prune diagonal entries and dead edges from B */
+		if (i != j && Flag [i] >= EMPTY)
+		{
+		    /* live node i is in the current component */
+		    Bi [pdest++] = i ;
+		    if (Flag [i] != mark)
+		    {
+			/* First time node i has been seen, it is a new node
+			 * of C.  place node i in the queue and mark it */
+			Map [cn] = i ;
+			Flag [i] = mark ;
+			Imap [i] = cn ;
+			cn++ ;
+		    }
+		    /* place the edge (cj,ci) in the adjacency list of cj */
+		    ci = Imap [i] ;
+		    ASSERT (ci >= 0 && ci < cn && ci != cj && cnz < csize) ;
+		    Ci [cnz++] = ci ;
+		    hash += ci ;
+		}
+	    }
+	    /* edges to dead nodes have been removed */
+	    Bnz [j] = pdest - pstart ;
+	    /* finalize the hash key for column j */
+	    hash %= csize ;
+	    Hash [cj] = (Int) hash ;
+	    ASSERT (Hash [cj] >= 0 && Hash [cj] < csize) ;
+	}
+	Cp [cn] = cnz ;
+	C->nrow = cn ;
+	C->ncol = cn ;	/* affects mem stats unless restored when C free'd */
+
+	/* contents of Imap no longer needed ] */
+
+#ifndef NDEBUG
+	for (cj = 0 ; cj < cn ; cj++)
+	{
+	    j = Map [cj] ;
+	    PRINT2 (("----------------------------C column cj: "ID" j: "ID"\n",
+		cj, j)) ;
+	    ASSERT (j >= 0 && j < n) ;
+	    ASSERT (Flag [j] >= EMPTY) ;
+	    for (p = Cp [cj] ; p < Cp [cj+1] ; p++)
+	    {
+		ci = Ci [p] ;
+		i = Map [ci] ;
+		PRINT3 (("ci: "ID" i: "ID"\n", ci, i)) ;
+		ASSERT (ci != cj && ci >= 0 && ci < cn) ;
+		ASSERT (i != j && i >= 0 && i < n) ;
+		ASSERT (Flag [i] >= EMPTY) ;
+	    }
+	}
+#endif
+
+	PRINT0 (("consider cn %d nd_small %d ", cn, nd_small)) ;
+	if (cn < nd_small)  /* could be 'total_weight < nd_small' instead */
+	{
+	    /* place all nodes in the separator */
+	    PRINT0 ((" too small\n")) ;
+	    sepsize = total_weight ;
+	}
+	else
+	{
+
+	    /* Cp and Ci now contain the component, with cn nodes and cnz
+	     * nonzeros.  The mapping of a node cj into node j the main graph
+	     * B is given by Map [cj] = j */
+	    PRINT0 ((" cut\n")) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* compress and partition the graph C */
+	    /* -------------------------------------------------------------- */
+
+	    /* The edge weights Cew [0..csize-1] are all 1's on input to and
+	     * output from the partition routine. */
+
+	    sepsize = partition (
+#ifndef NDEBUG
+		    csize,
+#endif
+		    nd_compress, Hash, C, Cnw, Cew,
+		    Cmap, Part, Common) ;
+
+	    /* contents of Cp and Ci no longer needed ] */
+
+	    if (sepsize < 0)
+	    {
+		/* failed */
+		C->ncol = n ;   /* restore size for memory usage statistics */
+		CHOLMOD(free_sparse) (&C, Common) ;
+		CHOLMOD(free_sparse) (&B, Common) ;
+		CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ;
+		CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ;
+		Common->mark = EMPTY ;
+		CHOLMOD_CLEAR_FLAG (Common) ;
+		return (EMPTY) ;
+	    }
+
+	    /* -------------------------------------------------------------- */
+	    /* compress B based on how C was compressed */
+	    /* -------------------------------------------------------------- */
+
+	    for (ci = 0 ; ci < cn ; ci++)
+	    {
+		if (Hash [ci] < EMPTY)
+		{
+		    /* ci is dead in C, having been absorbed into cj */
+		    cj = FLIP (Hash [ci]) ;
+		    PRINT2 (("In C, "ID" absorbed into "ID" (wgt now "ID")\n",
+			    ci, cj, Cnw [cj])) ;
+		    /* i is dead in B, having been absorbed into j */
+		    i = Map [ci] ;
+		    j = Map [cj] ;
+		    PRINT2 (("In B, "ID" (wgt "ID") => "ID" (wgt "ID")\n",
+				i, Bnw [i], j, Bnw [j], Cnw [cj])) ;
+		    /* more than one node may be absorbed into j.  This is
+		     * accounted for in Cnw [cj].  Assign it here rather
+		     * than += Bnw [i] */
+		    Bnw [i] = 0 ;
+		    Bnw [j] = Cnw [cj] ;
+		    Flag [i] = FLIP (j) ;
+		}
+	    }
+
+	    DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) cnt += Bnw [j]) ;
+	    ASSERT (cnt == n) ;
+	}
+
+	/* contents of Cnw [0..cn-1] no longer needed ] */
+
+	/* ------------------------------------------------------------------ */
+	/* order the separator, and stack the components when C is split */
+	/* ------------------------------------------------------------------ */
+
+	/* one more component has been found: either the separator of C,
+	 * or all of C */
+
+	ASSERT (sepsize >= 0 && sepsize <= total_weight) ;
+
+	PRINT0 (("sepsize %d tot %d : %8.4f ", sepsize, total_weight,
+	    ((double) sepsize) / ((double) total_weight))) ;
+
+	if (sepsize == total_weight || sepsize == 0 ||
+	    sepsize > nd_oksep * total_weight)
+	{
+	    /* Order the nodes in the component.  The separator is too large,
+	     * or empty.  Note that the partition routine cannot return a
+	     * sepsize of zero, but it can return a separator consisting of the
+	     * whole graph.  The "sepsize == 0" test is kept, above, in case the
+	     * partition routine changes.  In either case, this component
+	     * remains unsplit, and becomes a leaf of the separator tree. */
+	    PRINT2 (("cnode %d sepsize zero or all of graph: "ID"\n",
+		cnode, sepsize)) ;
+	    for (cj = 0 ; cj < cn ; cj++)
+	    {
+		j = Map [cj] ;
+		Flag [j] = FLIP (cnode) ;
+		PRINT2 (("      node cj: "ID" j: "ID" ordered\n", cj, j)) ;
+	    }
+	    ASSERT (Flag [cnode] == FLIP (cnode)) ;
+	    ASSERT (cnode != EMPTY && Flag [cnode] < EMPTY) ;
+	    PRINT0 (("discarded\n")) ;
+
+	}
+	else
+	{
+
+	    /* Order the nodes in the separator of C and find a new repnode
+	     * cnode that is in the separator of C.  This requires the separator
+	     * to be non-empty. */
+	    PRINT0 (("sepsize not tiny: "ID"\n", sepsize)) ;
+	    parent = CParent [cnode] ;
+	    ASSERT (parent >= EMPTY && parent < n) ;
+	    CParent [cnode] = -2 ;
+	    cnode = EMPTY ;
+	    for (cj = 0 ; cj < cn ; cj++)
+	    {
+		j = Map [cj] ;
+		if (Part [cj] == 2)
+		{
+		    /* All nodes in the separator become part of a component
+		     * whose repnode is cnode */
+		    PRINT2 (("node cj: "ID" j: "ID" ordered\n", cj, j)) ;
+		    if (cnode == EMPTY)
+		    {
+			PRINT2(("------------new cnode: cj "ID" j "ID"\n",
+				    cj, j)) ;
+			cnode = j ;
+		    }
+		    Flag [j] = FLIP (cnode) ;
+		}
+		else
+		{
+		    PRINT2 (("      node cj: "ID" j: "ID" not ordered\n",
+				cj, j)) ;
+		}
+	    }
+	    ASSERT (cnode != EMPTY && Flag [cnode] < EMPTY) ;
+	    ASSERT (CParent [cnode] == -2) ;
+	    CParent [cnode] = parent ;
+
+	    /* find the connected components when C is split, and push
+	     * them on the Cstack.  Use Imap as workspace for Queue. [ */
+	    /* workspace: Flag (nrow) */
+	    find_components (B, Map, cn, cnode, Part, Bnz,
+		    CParent, Cstack, &top, Imap, Common) ;
+	    /* done using Imap as workspace for Queue ] */
+	}
+	/* contents of Map [0..cn-1] no longer needed ] */
+    }
+
+    /* done using Cmember as workspace for Cmap ] */
+    /* done using Perm as workspace for Cstack ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* place nodes removed via compression into their proper component */
+    /* ---------------------------------------------------------------------- */
+
+    /* At this point, all nodes are of Type 1, 2, or 3, as defined above. */
+
+    for (i = 0 ; i < n ; i++)
+    {
+	/* find the repnode cnode that contains node i */
+	j = FLIP (Flag [i]) ;
+	PRINT2 (("\nfind component for "ID", in: "ID"\n", i, j)) ;
+	ASSERT (j >= 0 && j < n) ;
+	DEBUG (cnt = 0) ;
+	while (CParent [j] == -2)
+	{
+	    j = FLIP (Flag [j]) ;
+	    PRINT2 (("    walk up to "ID" ", j)) ;
+	    ASSERT (j >= 0 && j < n) ;
+	    PRINT2 ((" CParent "ID"\n", CParent [j])) ;
+	    ASSERT (cnt < n) ;
+	    DEBUG (cnt++) ;
+	}
+	cnode = j ;
+	ASSERT (cnode >= 0 && cnode < n) ;
+	ASSERT (CParent [cnode] >= EMPTY && CParent [cnode] < n) ;
+	PRINT2 (("i "ID" is in component with cnode "ID"\n", i, cnode)) ;
+	ASSERT (Flag [cnode] == FLIP (cnode)) ;
+
+	/* Mark all nodes along the path from i to cnode as being in the
+	 * component whos repnode is cnode.  Perform path compression.  */
+	j = FLIP (Flag [i]) ;
+	Flag [i] = FLIP (cnode) ;
+	DEBUG (cnt = 0) ;
+	while (CParent [j] == -2)
+	{
+	    ASSERT (j >= 0 && j < n) ;
+	    jnext = FLIP (Flag [j]) ;
+	    PRINT2 (("    "ID" walk "ID" set cnode to "ID"\n", i, j, cnode)) ;
+	    ASSERT (cnt < n) ;
+	    DEBUG (cnt++) ;
+	    Flag [j] = FLIP (cnode) ;
+	    j = jnext ;
+	}
+    }
+
+    /* At this point, all nodes fall into Types 1 or 2, as defined above. */
+
+#ifndef NDEBUG
+    for (j = 0 ; j < n ; j++)
+    {
+	PRINT2 (("j %d CParent %d  ", j, CParent [j])) ;
+	if (CParent [j] >= EMPTY && CParent [j] < n)
+	{
+	    /* case 1: j is a repnode of a component */
+	    cnode = j ;
+	    PRINT2 ((" a repnode\n")) ;
+	}
+	else
+	{
+	    /* case 2: j is not a repnode of a component */
+	    cnode = FLIP (Flag [j]) ;
+	    PRINT2 ((" repnode is %d\n", cnode)) ;
+	    ASSERT (cnode >= 0 && cnode < n) ;
+	    ASSERT (CParent [cnode] >= EMPTY && CParent [cnode] < n) ;
+	}
+	ASSERT (Flag [cnode] == FLIP (cnode)) ;
+	/* case 3 no longer holds */
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace */
+    /* ---------------------------------------------------------------------- */
+
+    C->ncol = n ;   /* restore size for memory usage statistics */
+    CHOLMOD(free_sparse) (&C, Common) ;
+    CHOLMOD(free_sparse) (&B, Common) ;
+    CHOLMOD(free) (csize, sizeof (Int), Cew, Common) ;
+    CHOLMOD(free) (3*n, sizeof (Int), Work3n, Common) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* handle dense nodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* The separator tree has nodes with either no children or two or more
+     * children - with one exception.  There may exist a single root node with
+     * exactly one child, which holds the dense rows/columns of the matrix.
+     * Delete this node if it exists. */
+
+    if (ndense > 0)
+    {
+	ASSERT (CParent [cdense] == EMPTY) ;	/* cdense has no parent */
+	/* find the children of cdense */
+	nchild = 0 ;
+	for (j = 0 ; j < n ; j++)
+	{
+	    if (CParent [j] == cdense)
+	    {
+		nchild++ ;
+		child = j ;
+	    }
+	}
+	if (nchild == 1)
+	{
+	    /* the cdense node has just one child; merge the two nodes */
+	    PRINT1 (("root has one child\n")) ;
+	    CParent [cdense] = -2 ;		/* cdense is deleted */
+	    CParent [child] = EMPTY ;		/* child becomes a root */
+	    for (j = 0 ; j < n ; j++)
+	    {
+		if (Flag [j] == FLIP (cdense))
+		{
+		    /* j is a dense node */
+		    PRINT1 (("dense %d\n", j)) ;
+		    Flag [j] = FLIP (child) ;
+		}
+	    }
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* postorder the components */
+    /* ---------------------------------------------------------------------- */
+
+    DEBUG (for (cnt = 0, j = 0 ; j < n ; j++) if (CParent [j] != -2) cnt++) ;
+
+    /* use Cmember as workspace for Post [ */
+    Post = Cmember ;
+
+    /* cholmod_postorder uses Head and Iwork [0..2n].  It does not use Flag,
+     * which here holds the mapping of nodes to repnodes.  It ignores all nodes
+     * for which CParent [j] < -1, so it operates just on the repnodes. */
+    /* workspace: Head (n), Iwork (2*n) */
+    ncomponents = CHOLMOD(postorder) (CParent, n, NULL, Post, Common) ;
+    ASSERT (cnt == ncomponents) ;
+
+    /* use Iwork [0..n-1] as workspace for Ipost ( */
+    Ipost = Iwork ;
+    DEBUG (for (j = 0 ; j < n ; j++) Ipost [j] = EMPTY) ;
+
+    /* compute inverse postorder */
+    for (c = 0 ; c < ncomponents ; c++)
+    {
+	cnode = Post [c] ;
+	ASSERT (cnode >= 0 && cnode < n) ;
+	Ipost [cnode] = c ;
+	ASSERT (Head [c] == EMPTY) ;
+    }
+
+    /* adjust the parent array */
+    /* Iwork [n..2n-1] used for NewParent [ */
+    NewParent = Iwork + n ;
+    for (c = 0 ; c < ncomponents ; c++)
+    {
+	parent = CParent [Post [c]] ;
+	NewParent [c] = (parent == EMPTY) ? EMPTY : (Ipost [parent]) ;
+    }
+    for (c = 0 ; c < ncomponents ; c++)
+    {
+	CParent [c] = NewParent [c] ;
+    }
+    ASSERT (CHOLMOD(dump_parent) (CParent, ncomponents, "CParent", Common)) ;
+
+    /* Iwork [n..2n-1] no longer needed for NewParent ] */
+    /* Cmember no longer needed for Post ] */
+
+#ifndef NDEBUG
+    /* count the number of children of each node */
+    for (c = 0 ; c < ncomponents ; c++)
+    {
+	Cmember [c] = 0 ;
+    }
+    for (c = 0 ; c < ncomponents ; c++)
+    {
+	if (CParent [c] != EMPTY) Cmember [CParent [c]]++ ;
+    }
+    for (c = 0 ; c < ncomponents ; c++)
+    {
+	/* a node is either a leaf, or has 2 or more children */
+	ASSERT (Cmember [c] == 0 || Cmember [c] >= 2) ;
+    }
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* place each node in its component */
+    /* ---------------------------------------------------------------------- */
+
+    for (j = 0 ; j < n ; j++)
+    {
+	/* node j is in the cth component, whose repnode is cnode */
+	cnode = FLIP (Flag [j]) ;
+	PRINT2 (("j "ID"  flag "ID" cnode "ID"\n",
+		    j, Flag [j], FLIP (Flag [j]))) ;
+	ASSERT (cnode >= 0 && cnode < n) ;
+	c = Ipost [cnode] ;
+	ASSERT (c >= 0 && c < ncomponents) ;
+	Cmember [j] = c ;
+    }
+
+    /* Flag no longer needed for the node-to-component mapping */
+
+    /* done using Iwork [0..n-1] as workspace for Ipost ) */
+
+    /* ---------------------------------------------------------------------- */
+    /* clear the Flag array */
+    /* ---------------------------------------------------------------------- */
+
+    Common->mark = EMPTY ;
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* find the permutation */
+    /* ---------------------------------------------------------------------- */
+
+    PRINT1 (("nd_camd: %d A->stype %d\n", nd_camd, A->stype)) ;
+
+    if (nd_camd)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* apply camd, csymamd, or ccolamd using the Cmember constraints */
+	/* ------------------------------------------------------------------ */
+
+	if (A->stype != 0)
+	{
+	    /* ordering A+A', so fset and fsize are ignored.
+	     * Add the upper/lower part to a symmetric lower/upper matrix by
+	     * converting to unsymmetric mode
+	     * workspace: Iwork (nrow) */
+	    B = CHOLMOD(copy) (A, 0, -1, Common) ;
+	    if (Common->status < CHOLMOD_OK)
+	    {
+		PRINT0 (("make symmetric failed\n")) ;
+		return (EMPTY) ;
+	    }
+	    ASSERT ((Int) (B->nrow) == n && (Int) (B->ncol) == n) ;
+	    PRINT2 (("nested dissection (2)\n")) ;
+	    B->stype = -1 ;
+	    if (nd_camd == 2)
+	    {
+		/* workspace:  Head (nrow+1), Iwork (nrow) if symmetric-upper */
+		ok = CHOLMOD(csymamd) (B, Cmember, Perm, Common) ;
+	    }
+	    else
+	    {
+		/* workspace: Head (nrow), Iwork (4*nrow) */
+		ok = CHOLMOD(camd) (B, NULL, 0, Cmember, Perm, Common) ;
+	    }
+	    CHOLMOD(free_sparse) (&B, Common) ;
+	    if (!ok)
+	    {
+		/* failed */
+		PRINT0 (("camd/csymamd failed\n")) ;
+		return (EMPTY) ;
+	    }
+	}
+	else
+	{
+	    /* ordering A*A' or A(:,f)*A(:,f)' */
+	    /* workspace: Iwork (nrow if no fset; MAX(nrow,ncol) if fset) */
+	    if (!CHOLMOD(ccolamd) (A, fset, fsize, Cmember, Perm, Common))
+	    {
+		/* ccolamd failed */
+		PRINT2 (("ccolamd failed\n")) ;
+		return (EMPTY) ;
+	    }
+	}
+
+    }
+    else
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* natural ordering of each component */
+	/* ------------------------------------------------------------------ */
+
+	/* use Iwork [0..n-1] for Next [ */
+	Next = Iwork  ;
+
+	/* ------------------------------------------------------------------ */
+	/* place the nodes in link lists, one list per component */
+	/* ------------------------------------------------------------------ */
+
+	/* do so in reverse order, to preserve original ordering */
+	for (j = n-1 ; j >= 0 ; j--)
+	{
+	    /* node j is in the cth component */
+	    c = Cmember [j] ;
+	    ASSERT (c >= 0 && c < ncomponents) ;
+	    /* place node j in link list for component c */
+	    Next [j] = Head [c] ;
+	    Head [c] = j ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* order each node in each component */
+	/* ------------------------------------------------------------------ */
+
+	k = 0 ;
+	for (c = 0 ; c < ncomponents ; c++)
+	{
+	    for (j = Head [c] ; j != EMPTY ; j = Next [j])
+	    {
+		Perm [k++] = j ;
+	    }
+	    Head [c] = EMPTY ;
+	}
+	ASSERT (k == n) ;
+
+	/* done using Iwork [0..n-1] for Next ] */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear workspace and return number of components */
+    /* ---------------------------------------------------------------------- */
+
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    return (ncomponents) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_collapse_septree ============================================= */
+/* ========================================================================== */
+
+/* cholmod_nested_dissection returns the separator tree that was used in the
+ * constrained minimum degree algorithm.  Parameter settings (nd_small,
+ * nd_oksep, etc) that give a good fill-reducing ordering may give too fine of
+ * a separator tree for other uses (parallelism, multi-level LPDASA, etc).  This
+ * function takes as input the separator tree computed by
+ * cholmod_nested_dissection, and collapses selected subtrees into single
+ * nodes.  A subtree is collapsed if its root node (the separator) is large
+ * compared to the total number of nodes in the subtree, or if the subtree is
+ * small.  Note that the separator tree may actually be a forest.
+ *
+ * nd_oksep and nd_small act just like the ordering parameters in Common.
+ * Returns the new number of nodes in the separator tree.
+ */
+
+SuiteSparse_long CHOLMOD(collapse_septree)
+(
+    /* ---- input ---- */
+    size_t n,		/* # of nodes in the graph */
+    size_t ncomponents,	/* # of nodes in the separator tree (must be <= n) */
+    double nd_oksep,    /* collapse if #sep >= nd_oksep * #nodes in subtree */
+    size_t nd_small,    /* collapse if #nodes in subtree < nd_small */
+    /* ---- in/out --- */
+    Int *CParent,	/* size ncomponents; from cholmod_nested_dissection */
+    Int *Cmember,	/* size n; from cholmod_nested_dissection */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    Int *First, *Count, *Csubtree, *W, *Map ;
+    Int c, j, k, nc, sepsize, total_weight, parent, nc_new, first ;
+    int collapse = FALSE, ok = TRUE ;
+    size_t s ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (EMPTY) ;
+    RETURN_IF_NULL (CParent, EMPTY) ;
+    RETURN_IF_NULL (Cmember, EMPTY) ;
+    if (n < ncomponents)
+    {
+	ERROR (CHOLMOD_INVALID, "invalid separator tree") ;
+	return (EMPTY) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    nc = ncomponents ;
+    if (n <= 1 || ncomponents <= 1)
+    {
+	/* no change; tree is one node already */
+	return (nc) ;
+    }
+
+    nd_oksep = MAX (0, nd_oksep) ;
+    nd_oksep = MIN (1, nd_oksep) ;
+    nd_small = MAX (4, nd_small) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* s = 3*ncomponents */
+    s = CHOLMOD(mult_size_t) (ncomponents, 3, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (EMPTY) ;
+    }
+    CHOLMOD(allocate_work) (0, s, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (EMPTY) ;
+    }
+    W = Common->Iwork ;
+    Count    = W ; W += ncomponents ;	    /* size ncomponents */
+    Csubtree = W ; W += ncomponents ;	    /* size ncomponents */
+    First    = W ; W += ncomponents ;	    /* size ncomponents */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the first descendant of each node of the separator tree */
+    /* ---------------------------------------------------------------------- */
+
+    for (c = 0 ; c < nc ; c++)
+    {
+	First [c] = EMPTY ;
+    }
+    for (k = 0 ; k < nc ; k++)
+    {
+	for (c = k ; c != EMPTY && First [c] == -1 ; c = CParent [c])
+	{
+	    ASSERT (c >= 0 && c < nc) ;
+	    First [c] = k ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the number of nodes of the graph in each node of the tree */
+    /* ---------------------------------------------------------------------- */
+
+    for (c = 0 ; c < nc ; c++)
+    {
+	Count [c] = 0 ;
+    }
+    for (j = 0 ; j < (Int) n ; j++)
+    {
+	ASSERT (Cmember [j] >= 0 && Cmember [j] < nc) ;
+	Count [Cmember [j]]++ ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the number of nodes in each subtree */
+    /* ---------------------------------------------------------------------- */
+
+    for (c = 0 ; c < nc ; c++)
+    {
+	/* each subtree includes its root */
+	Csubtree [c] = Count [c] ;
+	PRINT1 ((ID" size "ID" parent "ID" first "ID"\n",
+	    c, Count [c], CParent [c], First [c])) ;
+    }
+
+    for (c = 0 ; c < nc ; c++)
+    {
+	/* add the subtree of the child, c, into the count of its parent */
+	parent = CParent [c] ;
+	ASSERT (parent >= EMPTY && parent < nc) ;
+	if (parent != EMPTY)
+	{
+	    Csubtree [parent] += Csubtree [c] ;
+	}
+    }
+
+#ifndef NDEBUG
+    /* the sum of the roots should be n */
+    j = 0 ;
+    for (c = 0 ; c < nc ; c++) if (CParent [c] == EMPTY) j += Csubtree [c] ;
+    ASSERT (j == (Int) n) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* find subtrees to collapse */
+    /* ---------------------------------------------------------------------- */
+
+    /* consider all nodes in reverse post-order */
+    for (c = nc-1 ; c >= 0 ; c--)
+    {
+	/* consider the subtree rooted at node c */
+	sepsize = Count [c] ;
+	total_weight = Csubtree [c] ;
+	PRINT1 (("Node "ID" sepsize "ID" subtree "ID" ratio %g\n", c, sepsize,
+	    total_weight, ((double) sepsize)/((double) total_weight))) ;
+	first = First [c] ;
+	if (first < c &&    /* c must not be a leaf */
+	   (sepsize > nd_oksep * total_weight || total_weight < (int) nd_small))
+	{
+	    /* this separator is too large, or the subtree is too small.
+	     * collapse the tree, by converting the entire subtree rooted at
+	     * c into a single node.  The subtree consists of all nodes from
+	     * First[c] to the root c.  Flag all nodes from First[c] to c-1
+	     * as dead.
+	     */
+	    collapse = TRUE ;
+	    for (k = first ; k < c ; k++)
+	    {
+		CParent [k] = -2 ;
+		PRINT1 (("   collapse node "ID"\n", k)) ;
+	    }
+	    /* continue at the next node, first-1 */
+	    c = first ;
+	}
+    }
+
+    PRINT1 (("collapse: %d\n", collapse)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* compress the tree */
+    /* ---------------------------------------------------------------------- */
+
+    Map = Count ;	/* Count no longer needed */
+
+    nc_new = nc ;
+    if (collapse)
+    {
+	nc_new = 0 ;
+	for (c = 0 ; c < nc ; c++)
+	{
+	    Map [c] = nc_new ;
+	    if (CParent [c] >= EMPTY)
+	    {
+		/* node c is alive, and becomes node Map[c] in the new tree.
+		 * Increment nc_new for the next node c. */
+		nc_new++ ;
+	    }
+	}
+	PRINT1 (("Collapse the tree from "ID" to "ID" nodes\n", nc, nc_new)) ;
+	ASSERT (nc_new > 0) ;
+	for (c = 0 ; c < nc ; c++)
+	{
+	    parent = CParent [c] ;
+	    if (parent >= EMPTY)
+	    {
+		/* node c is alive */
+		CParent [Map [c]] = (parent == EMPTY) ? EMPTY : Map [parent] ;
+	    }
+	}
+	for (j = 0 ; j < (Int) n ; j++)
+	{
+	    PRINT1 (("j "ID" Cmember[j] "ID" Map[Cmember[j]] "ID"\n",
+		j, Cmember [j], Map [Cmember [j]])) ;
+	    Cmember [j] = Map [Cmember [j]] ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* return new size of separator tree */
+    /* ---------------------------------------------------------------------- */
+
+    return (nc_new) ;
+}
+#endif
diff --git a/src/CHOLMOD/Partition/lesser.txt b/src/CHOLMOD/Partition/lesser.txt
new file mode 100644
index 0000000..8add30a
--- /dev/null
+++ b/src/CHOLMOD/Partition/lesser.txt
@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+

+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+

+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+

+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+

+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+

+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+

+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+

+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+

+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/CHOLMOD/README.txt b/src/CHOLMOD/README.txt
new file mode 100644
index 0000000..08eb0a2
--- /dev/null
+++ b/src/CHOLMOD/README.txt
@@ -0,0 +1,81 @@
+CHOLMOD: a sparse CHOLesky MODification package, Copyright (c) 2005-2012.
+http://www.suitesparse.com
+-----------------------------------------------
+
+    CHOLMOD is a set of routines for factorizing sparse symmetric positive
+    definite matrices of the form A or AA', updating/downdating a sparse
+    Cholesky factorization, solving linear systems, updating/downdating
+    the solution to the triangular system Lx=b, and many other sparse matrix
+    functions for both symmetric and unsymmetric matrices.  Its supernodal
+    Cholesky factorization relies on LAPACK and the Level-3 BLAS, and obtains
+    a substantial fraction of the peak performance of the BLAS.  Both real and
+    complex matrices are supported.  CHOLMOD is written in ANSI/ISO C, with both
+    C and MATLAB interfaces.  This code works on Microsoft Windows and many
+    versions of Unix and Linux.
+
+
+Some Modules of CHOLMOD are copyrighted by the University of Florida (the
+Core and Partition Modules).  The rest are copyrighted by the authors:
+Timothy A. Davis (all of them), and William W. Hager (the Modify Module).
+
+CHOLMOD relies on several other packages:  AMD, CAMD, COLAMD, CCOLAMD,
+SuiteSparse_config, METIS, the BLAS, and LAPACK.  All but METIS, the BLAS, and
+LAPACK are part of SuiteSparse.
+
+AMD is authored by T. Davis, Iain Duff, and Patrick Amestoy.
+COLAMD is authored by T. Davis and Stefan Larimore, with algorithmic design
+in collaboration with John Gilbert and Esmond Ng.
+CCOLAMD is authored by T. Davis and Siva Rajamanickam.
+CAMD is authored by T. Davis and Y. Chen.
+
+LAPACK and the BLAS are authored by Jack Dongarra and many others.
+LAPACK is available at http://www.netlib.org/lapack
+
+METIS is authored by George Karypis, Univ. of Minnesota.  Its use in CHOLMOD
+is optional.  See http://www-users.cs.umn.edu/~karypis/metis.
+Place a copy of the metis-4.0 directory in the same directory that
+contains the CHOLMOD, AMD, COLAMD, and CCOLAMD directories prior to compiling
+with "make".
+
+If you do not wish to use METIS, you must edit SuiteSparse_config and change
+the line:
+
+    CHOLMOD_CONFIG =
+
+to
+
+    CHOLMOD_CONFIG = -DNPARTITION
+
+The CHOLMOD, AMD, COLAMD, CCOLAMD, and SuiteSparse)config directories must all
+reside in a common parent directory.  To compile all these libraries, edit
+SuiteSparse)config/SuiteSparse)config.mk to reflect your environment (C
+compiler, location of the BLAS, and so on) and then type "make" in either the
+CHOLMOD directory or in the parent directory of CHOLMOD.  See each package for
+more details on how to compile them.
+
+For use in MATLAB (on any system, including Windows):  start MATLAB,
+cd to the CHOLMOD/MATLAB directory, and type cholmod_make in the MATLAB
+Command Window.  This is the best way to compile CHOLMOD for MATLAB; it
+provides a workaround for a METIS design feature, in which METIS terminates
+your program (and thus MATLAB) if it runs out of memory.  Using cholmod_make
+also ensures your mexFunctions are compiled with -fexceptions, so that
+exceptions are handled properly (when hitting control-C in the MATLAB command
+window, for example).
+
+On the Pentium, do NOT use the Intel MKL BLAS prior to MKL Version 8.0 with
+CHOLMOD.  Older versions (prior to 8.0) have a bug in dgemm when computing
+A*B'.  The bug generates a NaN result, when the inputs are well-defined.  Use
+the Goto BLAS or the MKL v8.0 BLAS instead.  The Goto BLAS is faster and more
+reliable.  See http://www.tacc.utexas.edu/~kgoto/ or
+http://www.cs.utexas.edu/users/flame/goto/.
+Sadly, the Intel MKL BLAS 7.x is the default for MATLAB 7.0.4.  See
+http://www.mathworks.com/support/bugreports/details.html?rp=252103 for more
+details.  To workaround this problem on Linux, set environment variable
+BLAS_VERSION to libmkl_p3.so:libguide.so. On Windows, set environment variable
+BLAS_VERSION to mkl_p3.dll.  Better yet, get MATLAB 7sp3 (MATLAB 7.1) or later.
+
+Acknowledgements:  this work was supported in part by the National Science
+Foundation (NFS CCR-0203270 and DMS-9803599), and a grant from Sandia National
+Laboratories (Dept. of Energy) which supported the development of CHOLMOD's
+Partition Module.
+
diff --git a/src/CHOLMOD/Supernodal/License.txt b/src/CHOLMOD/Supernodal/License.txt
new file mode 100644
index 0000000..d6b6abf
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/License.txt
@@ -0,0 +1,25 @@
+CHOLMOD/Supernodal Module.
+Copyright (C) 2005-2006, Timothy A. Davis
+CHOLMOD is also available under other licenses; contact authors for details.
+http://www.suitesparse.com
+
+Note that this license is for the CHOLMOD/Supernodal module only.
+All CHOLMOD modules are licensed separately.
+
+
+--------------------------------------------------------------------------------
+
+
+This Module 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 Module 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 Module; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
diff --git a/src/CHOLMOD/Supernodal/cholmod_super_numeric.c b/src/CHOLMOD/Supernodal/cholmod_super_numeric.c
new file mode 100644
index 0000000..a8ce274
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/cholmod_super_numeric.c
@@ -0,0 +1,307 @@
+/* ========================================================================== */
+/* === Supernodal/cholmod_super_numeric ===================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Computes the Cholesky factorization of A+beta*I or A*F+beta*I.  Only the
+ * the lower triangular part of A+beta*I or A*F+beta*I is accessed.  The
+ * matrices A and F must already be permuted according to the fill-reduction
+ * permutation L->Perm.  cholmod_factorize is an "easy" wrapper for this code
+ * which applies that permutation.  beta is real.
+ *
+ * Symmetric case: A is a symmetric (lower) matrix.  F is not accessed.
+ * With a fill-reducing permutation, A(p,p) should be passed instead, where is
+ * p is L->Perm.
+ *
+ * Unsymmetric case: A is unsymmetric, and F must be present.  Normally, F=A'.
+ * With a fill-reducing permutation, A(p,f) and A(p,f)' should be passed as A
+ * and F, respectively, where f is a list of the subset of the columns of A.
+ *
+ * The input factorization L must be supernodal (L->is_super is TRUE).  It can
+ * either be symbolic or numeric.  In the first case, L has been analyzed by
+ * cholmod_analyze or cholmod_super_symbolic, but the matrix has not yet been
+ * numerically factorized.  The numerical values are allocated here and the
+ * factorization is computed.  In the second case, a prior matrix has been
+ * analyzed and numerically factorized, and a new matrix is being factorized.
+ * The numerical values of L are replaced with the new numerical factorization.
+ *
+ * L->is_ll is ignored, and set to TRUE.  This routine always computes an LL'
+ * factorization.  Supernodal LDL' factorization is not (yet) supported.
+ * FUTURE WORK: perform a supernodal LDL' factorization if L->is_ll is FALSE.
+ *
+ * Uses BLAS routines dsyrk, dgemm, dtrsm, and the LAPACK routine dpotrf.
+ * The supernodal solver uses BLAS routines dtrsv, dgemv, dtrsm, and dgemm.
+ *
+ * If the matrix is not positive definite the routine returns TRUE, but sets
+ * Common->status to CHOLMOD_NOT_POSDEF and L->minor is set to the column at
+ * which the failure occurred.  The supernode containing the non-positive
+ * diagonal entry is set to zero (this includes columns to the left of L->minor
+ * in the same supernode), as are all subsequent supernodes.
+ *
+ * workspace: Flag (nrow), Head (nrow+1), Iwork (2*nrow + 4*nsuper).
+ *	Allocates temporary space of size L->maxcsize * sizeof(double)
+ *	(twice that for the complex/zomplex case).
+ *
+ * If L is supernodal symbolic on input, it is converted to a supernodal numeric
+ * factor on output, with an xtype of real if A is real, or complex if A is
+ * complex or zomplex.  If L is supernodal numeric on input, its xtype must
+ * match A (except that L can be complex and A zomplex).  The xtype of A and F
+ * must match.
+ */
+
+#ifndef NSUPERNODAL
+
+#include "cholmod_internal.h"
+#include "cholmod_supernodal.h"
+#include "igraph_blas_internal.h"
+#include "igraph_lapack_internal.h"
+
+/* ========================================================================== */
+/* === TEMPLATE codes for GPU and regular numeric factorization ============= */
+/* ========================================================================== */
+
+#ifdef GPU_BLAS
+#define REAL
+#include "t_cholmod_gpu.c"
+#define COMPLEX
+#include "t_cholmod_gpu.c"
+#define ZOMPLEX
+#include "t_cholmod_gpu.c"
+#endif
+
+#define REAL
+#include "t_cholmod_super_numeric.c"
+/* #define COMPLEX */
+/* #include "t_cholmod_super_numeric.c" */
+/* #define ZOMPLEX */
+/* #include "t_cholmod_super_numeric.c" */
+
+/* ========================================================================== */
+/* === cholmod_super_numeric ================================================ */
+/* ========================================================================== */
+
+/* Returns TRUE if successful, or if the matrix is not positive definite.
+ * Returns FALSE if out of memory, inputs are invalid, or other fatal error
+ * occurs.
+ */
+
+int CHOLMOD(super_numeric)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    double beta [2],	/* beta*I is added to diagonal of matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    cholmod_dense *C ;
+    Int *Super, *Map, *SuperMap ;
+    size_t maxcsize ;
+    Int nsuper, n, i, k, s, stype, nrow ;
+    int ok = TRUE, symbolic ;
+    size_t t, w ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_COMPLEX, FALSE) ;
+    stype = A->stype ;
+    if (stype < 0)
+    {
+	if (A->nrow != A->ncol || A->nrow != L->n)
+	{
+	    ERROR (CHOLMOD_INVALID, "invalid dimensions") ;
+	    return (FALSE) ;
+	}
+    }
+    else if (stype == 0)
+    {
+	if (A->nrow != L->n)
+	{
+	    ERROR (CHOLMOD_INVALID, "invalid dimensions") ;
+	    return (FALSE) ;
+	}
+	RETURN_IF_NULL (F, FALSE) ;
+	RETURN_IF_XTYPE_INVALID (F, CHOLMOD_REAL, CHOLMOD_ZOMPLEX, FALSE) ;
+	if (A->nrow != F->ncol || A->ncol != F->nrow || F->stype != 0)
+	{
+	    ERROR (CHOLMOD_INVALID, "F invalid") ;
+	    return (FALSE) ;
+	}
+	if (A->xtype != F->xtype)
+	{
+	    ERROR (CHOLMOD_INVALID, "A and F must have same xtype") ;
+	    return (FALSE) ;
+	}
+    }
+    else
+    {
+	/* symmetric upper case not suppored */
+	ERROR (CHOLMOD_INVALID, "symmetric upper case not supported") ;
+	return (FALSE) ;
+    }
+    if (!(L->is_super))
+    {
+	ERROR (CHOLMOD_INVALID, "L not supernodal") ;
+	return (FALSE) ;
+    }
+    if (L->xtype != CHOLMOD_PATTERN)
+    {
+	if (! ((A->xtype == CHOLMOD_REAL    && L->xtype == CHOLMOD_REAL)
+	    || (A->xtype == CHOLMOD_COMPLEX && L->xtype == CHOLMOD_COMPLEX)
+	    || (A->xtype == CHOLMOD_ZOMPLEX && L->xtype == CHOLMOD_COMPLEX)))
+	{
+	    ERROR (CHOLMOD_INVALID, "complex type mismatch") ;
+	    return (FALSE) ;
+	}
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace in Common */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = L->nsuper ;
+    maxcsize = L->maxcsize ;
+    nrow = A->nrow ;
+    n = nrow ;
+
+    PRINT1 (("nsuper "ID" maxcsize %g\n", nsuper, (double) maxcsize)) ;
+    ASSERT (nsuper >= 0 && maxcsize > 0) ;
+
+    /* w = 2*n + 4*nsuper */
+    w = CHOLMOD(mult_size_t) (n, 2, &ok) ;
+    t = CHOLMOD(mult_size_t) (nsuper, 4, &ok) ;
+    w = CHOLMOD(add_size_t) (w, t, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, w, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get the current factor L and allocate numerical part, if needed */
+    /* ---------------------------------------------------------------------- */
+
+    Super = L->super ;
+    symbolic = (L->xtype == CHOLMOD_PATTERN) ;
+    if (symbolic)
+    {
+	/* convert to supernodal numeric by allocating L->x */
+	CHOLMOD(change_factor) (
+		(A->xtype == CHOLMOD_REAL) ? CHOLMOD_REAL : CHOLMOD_COMPLEX,
+		TRUE, TRUE, TRUE, TRUE, L, Common) ;
+	if (Common->status < CHOLMOD_OK)
+	{
+	    /* the factor L remains in symbolic supernodal form */
+	    return (FALSE) ;
+	}
+    }
+    ASSERT (L->dtype == DTYPE) ;
+    ASSERT (L->xtype == CHOLMOD_REAL || L->xtype == CHOLMOD_COMPLEX) ;
+
+    /* supernodal LDL' is not supported */
+    L->is_ll = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get more workspace */
+    /* ---------------------------------------------------------------------- */
+
+    C = CHOLMOD(allocate_dense) (maxcsize, 1, maxcsize, L->xtype, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	int status = Common->status ;
+	if (symbolic)
+	{
+	    /* Change L back to symbolic, since the numeric values are not
+	     * initialized.  This cannot fail. */
+	    CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE,
+		    L, Common) ;
+	}
+	/* the factor L is now back to the form it had on input */
+	Common->status = status ;
+	return (FALSE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    SuperMap = Common->Iwork ;		/* size n (i/i/l) */
+    Map = Common->Flag ;    /* size n, use Flag as workspace for Map array */
+    for (i = 0 ; i < n ; i++)
+    {
+	Map [i] = EMPTY ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* find the mapping of nodes to relaxed supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* SuperMap [k] = s if column k is contained in supernode s */
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	PRINT1 (("Super ["ID"] "ID" ncols "ID"\n",
+		    s, Super[s], Super[s+1]-Super[s]));
+	for (k = Super [s] ; k < Super [s+1] ; k++)
+	{
+	    SuperMap [k] = s ;
+	    PRINT2 (("relaxed SuperMap ["ID"] = "ID"\n", k, SuperMap [k])) ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal numerical factorization, using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (A->xtype)
+    {
+	case CHOLMOD_REAL:
+	    ok = r_cholmod_super_numeric (A, F, beta, L, C, Common) ;
+	    break ;
+
+	/* case CHOLMOD_COMPLEX: */
+	/*     ok = c_cholmod_super_numeric (A, F, beta, L, C, Common) ; */
+	/*     break ; */
+
+	/* case CHOLMOD_ZOMPLEX: */
+	/*     /\* This operates on complex L, not zomplex *\/ */
+	/*     ok = z_cholmod_super_numeric (A, F, beta, L, C, Common) ; */
+	/*     break ; */
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* clear Common workspace, free temp workspace C, and return */
+    /* ---------------------------------------------------------------------- */
+
+    /* Flag array was used as workspace, clear it */
+    Common->mark = EMPTY ;
+    /* CHOLMOD(clear_flag) (Common) ; */
+    CHOLMOD_CLEAR_FLAG (Common) ;
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+    CHOLMOD(free_dense) (&C, Common) ;
+    return (ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Supernodal/cholmod_super_solve.c b/src/CHOLMOD/Supernodal/cholmod_super_solve.c
new file mode 100644
index 0000000..33fffab
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/cholmod_super_solve.c
@@ -0,0 +1,217 @@
+/* ========================================================================== */
+/* === Supernodal/cholmod_super_solve ======================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Solve Lx=b or L'x=b for a supernodal factorization.  These routines do not
+ * apply the permutation L->Perm.  See cholmod_solve for a more general
+ * interface that performs that operation.
+ */
+
+#ifndef NSUPERNODAL
+
+#include "cholmod_internal.h"
+#include "cholmod_supernodal.h"
+#include "igraph_blas_internal.h"
+
+/* ========================================================================== */
+/* === TEMPLATE ============================================================= */
+/* ========================================================================== */
+
+#define REAL
+#include "t_cholmod_super_solve.c"
+/* #define COMPLEX */
+/* #include "t_cholmod_super_solve.c" */
+
+/* ========================================================================== */
+/* === cholmod_super_lsolve ================================================= */
+/* ========================================================================== */
+
+/* Solve Lx=b where x and b are of size n-by-nrhs.  b is overwritten by the
+ * solution x.  On input, b is stored in col-major order with leading dimension
+ * of d, and on output x is stored in the same manner.
+ *
+ * The contents of the workspace E are undefined on both input and output.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(super_lsolve)   /* TRUE if OK, FALSE if BLAS overflow occured */
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (E, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    if (L->xtype != X->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (L->xtype != E->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (X->d < X->nrow || L->n != X->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ;
+	return (FALSE) ;
+    }
+    if (E->nzmax < X->ncol * (L->maxesize))
+    {
+	ERROR (CHOLMOD_INVALID, "workspace E not large enough") ;
+	return (FALSE) ;
+    }
+    if (!(L->is_ll) || !(L->is_super))
+    {
+	ERROR (CHOLMOD_INVALID, "L not supernodal") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ;
+    if (L->n == 0 || X->ncol == 0)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve Lx=b using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_cholmod_super_lsolve (L, X, E, Common) ;
+	    break ;
+
+	/* case CHOLMOD_COMPLEX: */
+	/*     c_cholmod_super_lsolve (L, X, E, Common) ; */
+	/*     break ; */
+    }
+
+    if (CHECK_BLAS_INT && !Common->blas_ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+    }
+    return (Common->blas_ok) ;
+}
+
+
+/* ========================================================================== */
+/* === cholmod_super_ltsolve ================================================ */
+/* ========================================================================== */
+
+/* Solve L'x=b where x and b are of size n-by-nrhs.  b is overwritten by the
+ * solution x.  On input, b is stored in col-major order with leading dimension
+ * of d, and on output x is stored in the same manner.
+ *
+ * The contents of the workspace E are undefined on both input and output.
+ *
+ * workspace: none
+ */
+
+int CHOLMOD(super_ltsolve)  /* TRUE if OK, FALSE if BLAS overflow occured */
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the backsolve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to L'x=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (X, FALSE) ;
+    RETURN_IF_NULL (E, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (X, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (E, CHOLMOD_REAL, CHOLMOD_COMPLEX, FALSE) ;
+    if (L->xtype != X->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and X must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (L->xtype != E->xtype)
+    {
+	ERROR (CHOLMOD_INVALID, "L and E must have the same xtype") ;
+	return (FALSE) ;
+    }
+    if (X->d < X->nrow || L->n != X->nrow)
+    {
+	ERROR (CHOLMOD_INVALID, "X and L dimensions must match") ;
+	return (FALSE) ;
+    }
+    if (E->nzmax < X->ncol * (L->maxesize))
+    {
+	ERROR (CHOLMOD_INVALID, "workspace E not large enough") ;
+	return (FALSE) ;
+    }
+    if (!(L->is_ll) || !(L->is_super))
+    {
+	ERROR (CHOLMOD_INVALID, "L not supernodal") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+    ASSERT (IMPLIES (L->n == 0, L->nsuper == 0)) ;
+    if (L->n == 0 || X->ncol == 0)
+    {
+	/* nothing to do */
+	return (TRUE) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* solve Lx=b using template routine */
+    /* ---------------------------------------------------------------------- */
+
+    switch (L->xtype)
+    {
+
+	case CHOLMOD_REAL:
+	    r_cholmod_super_ltsolve (L, X, E, Common) ;
+	    break ;
+
+	/* case CHOLMOD_COMPLEX: */
+	/*     c_cholmod_super_ltsolve (L, X, E, Common) ; */
+	/*     break ; */
+    }
+
+    if (CHECK_BLAS_INT && !Common->blas_ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+    }
+    return (Common->blas_ok) ;
+}
+#endif
diff --git a/src/CHOLMOD/Supernodal/cholmod_super_symbolic.c b/src/CHOLMOD/Supernodal/cholmod_super_symbolic.c
new file mode 100644
index 0000000..70ea728
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/cholmod_super_symbolic.c
@@ -0,0 +1,862 @@
+/* ========================================================================== */
+/* === Supernodal/cholmod_super_symbolic ==================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module. Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Supernodal symbolic analysis of the LL' factorization of A, A*A',
+ * A(:,f)*A(:,f)'.
+ *
+ * This routine must be preceded by a simplicial symbolic analysis
+ * (cholmod_rowcolcounts).  See cholmod_analyze.c for an example of how to use
+ * this routine.
+ *
+ * The user need not call this directly; cholmod_analyze is a "simple" wrapper
+ * for this routine.
+ *
+ * Symmetric case:
+ *
+ *	A is stored in column form, with entries stored in the upper triangular
+ *	part.  Entries in the lower triangular part are ignored.
+ *
+ * Unsymmetric case:
+ *
+ *	A is stored in column form.  If F is equal to the transpose of A, then
+ *	A*A' is analyzed.  F can include a subset of the columns of A
+ *	(F=A(:,f)'), in which case F*F' is analyzed.
+ *
+ * Requires Parent and L->ColCount to be defined on input; these are the
+ * simplicial Parent and ColCount arrays as computed by cholmod_rowcolcounts.
+ * Does not use L->Perm; the input matrices A and F must already be properly
+ * permuted.  Allocates and computes the supernodal pattern of L (L->super,
+ * L->pi, L->px, and L->s).  Does not allocate the real part (L->x).
+ *
+ * Supports any xtype (pattern, real, complex, or zomplex).
+ */
+
+#ifndef NSUPERNODAL
+
+#include "cholmod_internal.h"
+#include "cholmod_supernodal.h"
+
+
+/* ========================================================================== */
+/* === subtree ============================================================== */
+/* ========================================================================== */
+
+/* In the symmetric case, traverse the kth row subtree from the nonzeros in
+ * A (0:k1-1,k) and add the new entries found to the pattern of the kth row
+ * of L.  The current supernode s contains the diagonal block k1:k2-1, so it
+ * can be skipped.
+ *
+ * In the unsymmetric case, the nonzero pattern of A*F is computed one column
+ * at a time (thus, the total time spent in this function is bounded below by
+ * the time taken to multiply A*F, which can be high if A is tall and thin).
+ * The kth column is A*F(:,k), or the set union of all columns A(:,j) for which
+ * F(j,k) is nonzero.  This routine is called once for each entry j.  Only the
+ * upper triangular part is needed, so only A (0:k1-1,j) is accessed, where
+ * k1:k2-1 are the columns of the current supernode s (k is in the range k1 to
+ * k2-1).
+ *
+ * If A is sorted, then the total time taken by this function is proportional
+ * to the number of nonzeros in the strictly block upper triangular part of A,
+ * plus the number of entries in the strictly block lower triangular part of
+ * the supernodal part of L.  This excludes entries in the diagonal blocks
+ * corresponding to the columns in each supernode.  That is, if k1:k2-1 are
+ * in a single supernode, then only A (0:k1-1,k1:k2-1) are accessed.
+ *
+ * For the unsymmetric case, only the strictly block upper triangular part
+ * of A*F is constructed.
+ *
+ * Only adds column indices corresponding to the leading columns of each
+ * relaxed supernode.
+ */
+
+static void subtree
+(
+    /* inputs, not modified: */
+    Int j,		/* j = k for symmetric case */
+    Int k,
+    Int Ap [ ],
+    Int Ai [ ],
+    Int Anz [ ],
+    Int SuperMap [ ],
+    Int Sparent [ ],
+    Int mark,
+    Int sorted,         /* true if the columns of A are sorted */
+    Int k1,             /* only consider A (0:k1-1,k) */
+
+    /* input/output: */
+    Int Flag [ ],
+    Int Ls [ ],
+    Int Lpi2 [ ]
+)
+{
+    Int p, pend, i, si ;
+    p = Ap [j] ;
+    pend = (Anz == NULL) ? (Ap [j+1]) : (p + Anz [j]) ;
+
+    for ( ; p < pend ; p++)
+    {
+	i = Ai [p] ;
+	if (i < k1)
+	{
+	    /* (i,k) is an entry in the upper triangular part of A or A*F'.
+	     * symmetric case:   A(i,k) is nonzero (j=k).
+	     * unsymmetric case: A(i,j) and F(j,k) are both nonzero.
+	     *
+	     * Column i is in supernode si = SuperMap [i].  Follow path from si
+	     * to root of supernodal etree, stopping at the first flagged
+	     * supernode.  The root of the row subtree is supernode SuperMap[k],
+	     * which is flagged already. This traversal will stop there, or it
+	     * might stop earlier if supernodes have been flagged by previous
+	     * calls to this routine for the same k. */
+	    for (si = SuperMap [i] ; Flag [si] < mark ; si = Sparent [si])
+	    {
+		ASSERT (si <= SuperMap [k]) ;
+		Ls [Lpi2 [si]++] = k ;
+		Flag [si] = mark ;
+	    }
+	}
+        else if (sorted)
+        {
+            break ;
+        }
+    }
+}
+
+
+/* clear workspace used by cholmod_super_symbolic */
+#define FREE_WORKSPACE \
+{ \
+    /* CHOLMOD(clear_flag) (Common) ; */ \
+    CHOLMOD_CLEAR_FLAG (Common) ; \
+    for (k = 0 ; k <= nfsuper ; k++) \
+    { \
+	Head [k] = EMPTY ; \
+    } \
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ; \
+} \
+
+
+/* ========================================================================== */
+/* === cholmod_super_symbolic2 ============================================== */
+/* ========================================================================== */
+
+/* Analyze for supernodal Cholesky or multifrontal QR.  CHOLMOD itself always
+ * analyzes for supernodal Cholesky, of course.  The "for_cholesky = TRUE"
+ * option is used by SuiteSparseQR only. */
+
+int CHOLMOD(super_symbolic2)
+(
+    /* ---- input ---- */
+    int for_cholesky,   /* Cholesky if TRUE, QR if FALSE */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    Int *Parent,	/* elimination tree */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* simplicial symbolic on input,
+			 * supernodal symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double zrelax0, zrelax1, zrelax2, xxsize ;
+    Int *Wi, *Wj, *Super, *Snz, *Ap, *Ai, *Flag, *Head, *Ls, *Lpi, *Lpx, *Fnz,
+	*Sparent, *Anz, *SuperMap, *Merged, *Nscol, *Zeros, *Fp, *Fj,
+	*ColCount, *Lpi2, *Lsuper, *Iwork ;
+    Int nsuper, d, n, j, k, s, mark, parent, p, pend, k1, k2, packed, nscol,
+	nsrow, ndrow1, ndrow2, stype, ssize, xsize, sparent, plast, slast,
+	csize, maxcsize, ss, nscol0, nscol1, ns, nfsuper, newzeros, totzeros,
+	merge, snext, esize, maxesize, nrelax0, nrelax1, nrelax2, Asorted ;
+    size_t w ;
+    int ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* check inputs */
+    /* ---------------------------------------------------------------------- */
+
+    RETURN_IF_NULL_COMMON (FALSE) ;
+    RETURN_IF_NULL (A, FALSE) ;
+    RETURN_IF_NULL (L, FALSE) ;
+    RETURN_IF_NULL (Parent, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (A, CHOLMOD_PATTERN, CHOLMOD_ZOMPLEX, FALSE) ;
+    RETURN_IF_XTYPE_INVALID (L, CHOLMOD_PATTERN, CHOLMOD_PATTERN, FALSE) ;
+    stype = A->stype ;
+    if (stype < 0)
+    {
+	/* invalid symmetry; symmetric lower form not supported */
+	ERROR (CHOLMOD_INVALID, "symmetric lower not supported") ;
+	return (FALSE) ;
+    }
+    if (stype == 0)
+    {
+	/* F must be present in the unsymmetric case */
+	RETURN_IF_NULL (F, FALSE) ;
+    }
+    if (L->is_super)
+    {
+	/* L must be a simplicial symbolic factor */
+	ERROR (CHOLMOD_INVALID, "L must be symbolic on input") ;
+	return (FALSE) ;
+    }
+    Common->status = CHOLMOD_OK ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace */
+    /* ---------------------------------------------------------------------- */
+
+    n = A->nrow ;
+
+    /* w = 5*n */
+    w = CHOLMOD(mult_size_t) (n, 5, &ok) ;
+    if (!ok)
+    {
+	ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	return (FALSE) ;
+    }
+
+    CHOLMOD(allocate_work) (n, w, 0, Common) ;
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory */
+	return (FALSE) ;
+    }
+    ASSERT (CHOLMOD(dump_work) (TRUE, TRUE, 0, Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    /* A is now either A or triu(A(p,p)) for the symmetric case.  It is either
+     * A or A(p,f) for the unsymmetric case (both in column form).  It can be
+     * either packed or unpacked, and either sorted or unsorted.  Entries in
+     * the lower triangular part may be present if A is symmetric, but these
+     * are ignored. */
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Anz = A->nz ;
+
+    if (stype != 0)
+    {
+	/* F not accessed */
+	Fp = NULL ;
+	Fj = NULL ;
+	Fnz = NULL ;
+	packed = TRUE ;
+    }
+    else
+    {
+	/* F = A(:,f) or A(p,f) in packed row form, either sorted or unsorted */
+	Fp = F->p ;
+	Fj = F->i ;
+	Fnz = F->nz ;
+	packed = F->packed ;
+    }
+
+    ColCount = L->ColCount ;
+
+    nrelax0 = Common->nrelax [0] ;
+    nrelax1 = Common->nrelax [1] ;
+    nrelax2 = Common->nrelax [2] ;
+
+    zrelax0 = Common->zrelax [0] ;
+    zrelax1 = Common->zrelax [1] ;
+    zrelax2 = Common->zrelax [2] ;
+
+    zrelax0 = IS_NAN (zrelax0) ? 0 : zrelax0 ;
+    zrelax1 = IS_NAN (zrelax1) ? 0 : zrelax1 ;
+    zrelax2 = IS_NAN (zrelax2) ? 0 : zrelax2 ;
+
+    ASSERT (CHOLMOD(dump_parent) (Parent, n, "Parent", Common)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get workspace */
+    /* ---------------------------------------------------------------------- */
+
+    /* Sparent, Snz, and Merged could be allocated later, of size nfsuper */
+
+    Iwork = Common->Iwork ;
+    Wi      = Iwork ;	    /* size n (i/l/l).  Lpi2 is i/l/l */
+    Wj      = Iwork + n ;   /* size n (i/l/l).  Zeros is i/l/l */
+    Sparent = Iwork + 2*((size_t) n) ; /* size nfsuper <= n [ */
+    Snz     = Iwork + 3*((size_t) n) ; /* size nfsuper <= n [ */
+    Merged  = Iwork + 4*((size_t) n) ; /* size nfsuper <= n [ */
+
+    Flag = Common->Flag ;   /* size n */
+    Head = Common->Head ;   /* size n+1 */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the fundamental supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* count the number of children of each node, using Wi [ */
+    for (j = 0 ; j < n ; j++)
+    {
+	Wi [j] = 0 ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	parent = Parent [j] ;
+	if (parent != EMPTY)
+	{
+	    Wi [parent]++ ;
+	}
+    }
+
+    Super = Head ;  /* use Head [0..nfsuper] as workspace for Super list ( */
+
+    /* column 0 always starts a new supernode */
+    nfsuper = (n == 0) ? 0 : 1 ;	/* number of fundamental supernodes */
+    Super [0] = 0 ;
+
+    for (j = 1 ; j < n ; j++)
+    {
+	/* check if j starts new supernode, or in the same supernode as j-1 */
+	if (Parent [j-1] != j	    /* parent of j-1 is not j */
+	    || (ColCount [j-1] != ColCount [j] + 1) /* j-1 not subset of j*/
+	    || Wi [j] > 1)	    /* j has more than one child */
+	{
+	    /* j is the leading node of a supernode */
+	    Super [nfsuper++] = j ;
+	}
+    }
+    Super [nfsuper] = n ;
+
+    /* contents of Wi no longer needed for child count ] */
+
+    Nscol = Wi ; /* use Wi as size-nfsuper workspace for Nscol [ */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the mapping of fundamental nodes to supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    SuperMap = Wj ;	/* use Wj as workspace for SuperMap [ */
+
+    /* SuperMap [k] = s if column k is contained in supernode s */
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	for (k = Super [s] ; k < Super [s+1] ; k++)
+	{
+	    SuperMap [k] = s ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the fundamental supernodal etree */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	j = Super [s+1] - 1 ;	/* last node in supernode s */
+	parent = Parent [j] ;	/* parent of last node */
+	Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ;
+	PRINT1 (("Sparent ["ID"] = "ID"\n", s, Sparent [s])) ;
+    }
+
+    /* contents of Wj no longer needed as workspace for SuperMap ]
+     * SuperMap will be recomputed below, for the relaxed supernodes. */
+
+    Zeros = Wj ;   /* use Wj for Zeros, workspace of size nfsuper [ */
+
+    /* ---------------------------------------------------------------------- */
+    /* relaxed amalgamation */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	Merged [s] = EMPTY ;			/* s not merged into another */
+	Nscol [s] = Super [s+1] - Super [s] ;	/* # of columns in s */
+	Zeros [s] = 0 ;				/* # of zero entries in s */
+	ASSERT (s <= Super [s]) ;
+	Snz [s] = ColCount [Super [s]] ;  /* # of entries in leading col of s */
+	PRINT2 (("lnz ["ID"] "ID"\n", s, Snz [s])) ;
+    }
+
+    for (s = nfsuper-2 ; s >= 0 ; s--)
+    {
+	/* should supernodes s and s+1 merge into a new node s? */
+	PRINT1 (("\n========= Check relax of s "ID" and s+1 "ID"\n", s, s+1)) ;
+
+	ss = Sparent [s] ;
+	if (ss == EMPTY)
+	{
+	    PRINT1 (("s "ID" is a root, no merge with s+1 = "ID"\n", s, s+1)) ;
+	    continue ;
+	}
+
+	/* find the current parent of s (perform path compression as needed) */
+	for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = Merged [ss]) ;
+	sparent = ss ;
+	PRINT2 (("Current sparent of s "ID" is "ID"\n", s, sparent)) ;
+
+	/* ss is the current parent of s */
+	for (ss = Sparent [s] ; Merged [ss] != EMPTY ; ss = snext)
+	{
+	    snext = Merged [ss] ;
+	    PRINT2 (("ss "ID" is dead, merged into snext "ID"\n", ss, snext)) ;
+	    Merged [ss] = sparent ;
+	}
+
+	/* if s+1 is not the current parent of s, do not merge */
+	if (sparent != s+1)
+	{
+	    continue ;
+	}
+
+	nscol0 = Nscol [s] ;	/* # of columns in s */
+	nscol1 = Nscol [s+1] ;	/* # of columns in s+1 */
+	ns = nscol0 + nscol1 ;
+	PRINT2 (("ns "ID" nscol0 "ID" nscol1 "ID"\n", ns, nscol0, nscol1)) ;
+
+	totzeros = Zeros [s+1] ;	/* current # of zeros in s+1 */
+
+	/* determine if supernodes s and s+1 should merge */
+	if (ns <= nrelax0)
+	{
+	    PRINT2 (("ns is tiny ("ID"), so go ahead and merge\n", ns)) ;
+	    merge = TRUE ;
+	}
+	else
+	{
+	    /* use double to avoid integer overflow */
+	    double lnz0 = Snz [s] ;	/* # entries in leading column of s */
+	    double lnz1 = Snz [s+1] ;	/* # entries in leading column of s+1 */
+	    double xnewzeros = nscol0 * (lnz1 + nscol0 - lnz0) ;
+
+	    /* use Int for the final update of Zeros [s] below */
+	    newzeros = nscol0 * (Snz [s+1] + nscol0 - Snz [s]) ;
+	    ASSERT (newzeros == xnewzeros) ;
+
+	    PRINT2 (("lnz0 %g lnz1 %g xnewzeros %g\n", lnz0, lnz1, xnewzeros)) ;
+	    if (xnewzeros == 0)
+	    {
+		/* no new zeros, so go ahead and merge */
+		PRINT2 (("no new fillin, so go ahead and merge\n")) ;
+		merge = TRUE ;
+	    }
+	    else
+	    {
+		/* # of zeros if merged */
+		double xtotzeros = ((double) totzeros) + xnewzeros ;
+
+		/* xtotsize: total size of merged supernode, if merged: */
+		double xns = (double) ns ;
+		double xtotsize  = (xns * (xns+1) / 2) + xns * (lnz1 - nscol1) ;
+		double z = xtotzeros / xtotsize ;
+
+		Int totsize ;
+		totsize  = (ns * (ns+1) / 2) + ns * (Snz [s+1] - nscol1) ;
+
+		PRINT2 (("oldzeros "ID" newzeros "ID" xtotsize %g z %g\n",
+			    Zeros [s+1], newzeros, xtotsize, z)) ;
+
+		/* use Int for the final update of Zeros [s] below */
+		totzeros += newzeros ;
+
+		/* do not merge if supernode would become too big
+		 * (Int overflow).  Continue computing; not (yet) an error. */
+		/* fl.pt. compare, but no NaN's can occur here */
+		merge = ((ns <= nrelax1 && z < zrelax0) ||
+			 (ns <= nrelax2 && z < zrelax1) ||
+					  (z < zrelax2)) &&
+			(xtotsize < Int_max / sizeof (double)) ;
+
+	    }
+	}
+
+	if (merge)
+	{
+	    PRINT1 (("Merge node s ("ID") and s+1 ("ID")\n", s, s+1)) ;
+	    Zeros [s] = totzeros ;
+	    Merged [s+1] = s ;
+	    Snz [s] = nscol0 + Snz [s+1] ;
+	    Nscol [s] += Nscol [s+1] ;
+	}
+    }
+
+    /* contents of Wj no longer needed for Zeros ] */
+    /* contents of Wi no longer needed for Nscol ] */
+    /* contents of Sparent no longer needed (recomputed below) */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the relaxed supernode list */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = 0 ;
+    for (s = 0 ; s < nfsuper ; s++)
+    {
+	if (Merged [s] == EMPTY)
+	{
+	    PRINT1 (("live supernode: "ID" snz "ID"\n", s, Snz [s])) ;
+	    Super [nsuper] = Super [s] ;
+	    Snz [nsuper] = Snz [s] ;
+	    nsuper++ ;
+	}
+    }
+    Super [nsuper] = n ;
+    PRINT1 (("Fundamental supernodes: "ID"  relaxed "ID"\n", nfsuper, nsuper)) ;
+
+    /* Merged no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* find the mapping of relaxed nodes to supernodes */
+    /* ---------------------------------------------------------------------- */
+
+    /* use Wj as workspace for SuperMap { */
+
+    /* SuperMap [k] = s if column k is contained in supernode s */
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	for (k = Super [s] ; k < Super [s+1] ; k++)
+	{
+	    SuperMap [k] = s ;
+	}
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* construct the relaxed supernodal etree */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	j = Super [s+1] - 1 ;	/* last node in supernode s */
+	parent = Parent [j] ;	/* parent of last node */
+	Sparent [s] = (parent == EMPTY) ? EMPTY : SuperMap [parent] ;
+	PRINT1 (("new Sparent ["ID"] = "ID"\n", s, Sparent [s])) ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the size of L->s and L->x */
+    /* ---------------------------------------------------------------------- */
+
+    ssize = 0 ;
+    xsize = 0 ;
+    xxsize = 0 ;
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	nscol = Super [s+1] - Super [s] ;
+	nsrow = Snz [s] ;
+	ASSERT (nscol > 0) ;
+	ssize += nsrow ;
+        if (for_cholesky)
+        {
+            xsize += nscol * nsrow ;
+            /* also compute xsize in double to guard against Int overflow */
+            xxsize += ((double) nscol) * ((double) nsrow) ;
+        }
+	if (ssize < 0 || (for_cholesky && xxsize > Int_max))
+	{
+	    /* Int overflow, clear workspace and return.
+               QR factorization will not use xxsize, so that error is ignored.
+               For Cholesky factorization, however, memory of space xxsize
+               will be allocated, so this is a failure.  Both QR and Cholesky
+               fail if ssize overflows. */
+	    ERROR (CHOLMOD_TOO_LARGE, "problem too large") ;
+	    FREE_WORKSPACE ;
+	    return (FALSE) ;
+	}
+	ASSERT (ssize > 0) ;
+        ASSERT (IMPLIES (for_cholesky, xsize > 0)) ;
+    }
+    xsize = MAX (1, xsize) ;
+    ssize = MAX (1, ssize) ;
+    PRINT1 (("ix sizes: "ID" "ID" nsuper "ID"\n", ssize, xsize, nsuper)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate L (all except real part L->x) */
+    /* ---------------------------------------------------------------------- */
+
+    L->ssize = ssize ;
+    L->xsize = xsize ;
+    L->nsuper = nsuper ;
+
+    CHOLMOD(change_factor) (CHOLMOD_PATTERN, TRUE, TRUE, TRUE, TRUE, L, Common);
+
+    if (Common->status < CHOLMOD_OK)
+    {
+	/* out of memory; L is still a valid simplicial symbolic factor */
+	FREE_WORKSPACE ;
+	return (FALSE) ;
+    }
+
+    DEBUG (CHOLMOD(dump_factor) (L, "L to symbolic super", Common)) ;
+    ASSERT (L->is_ll && L->xtype == CHOLMOD_PATTERN && L->is_super) ;
+
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Ls [0] = 0 ;    /* flag for cholmod_check_factor; supernodes are defined */
+    Lpx [0] = for_cholesky ? 0 : 123456 ;   /* magic number for sparse QR */
+    Lsuper = L->super ;
+
+    /* copy the list of relaxed supernodes into the final list in L */
+    for (s = 0 ; s <= nsuper ; s++)
+    {
+	Lsuper [s] = Super [s] ;
+    }
+
+    /* Head no longer needed as workspace for fundamental Super list ) */
+
+    Super = Lsuper ;	    /* Super is now the list of relaxed supernodes */
+
+    /* ---------------------------------------------------------------------- */
+    /* construct column pointers of relaxed supernodal pattern (L->pi) */
+    /* ---------------------------------------------------------------------- */
+
+    p = 0 ;
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	Lpi [s] = p ;
+	p += Snz [s] ;
+	PRINT1 (("Snz ["ID"] = "ID", Super ["ID"] = "ID"\n",
+		    s, Snz [s], s, Super[s])) ;
+    }
+    Lpi [nsuper] = p ;
+    ASSERT ((Int) (L->ssize) == MAX (1,p)) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* construct pointers for supernodal values (L->px) */
+    /* ---------------------------------------------------------------------- */
+
+    if (for_cholesky)
+    {
+        /* L->px is not needed for QR factorization (it may lead to Int
+           overflow, anyway, if xsize caused Int overflow above) */
+        p = 0 ;
+        for (s = 0 ; s < nsuper ; s++)
+        {
+            nscol = Super [s+1] - Super [s] ;   /* number of columns in s */
+            nsrow = Snz [s] ;           /* # of rows, incl triangular part*/
+            Lpx [s] = p ;               /* pointer to numerical part of s */
+            p += nscol * nsrow ;
+        }
+        Lpx [s] = p ;
+        ASSERT ((Int) (L->xsize) == MAX (1,p)) ;
+    }
+
+    /* Snz no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* symbolic analysis to construct the relaxed supernodal pattern (L->s) */
+    /* ---------------------------------------------------------------------- */
+
+    Lpi2 = Wi ;	    /* copy Lpi into Lpi2, using Wi as workspace for Lpi2 [ */
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	Lpi2 [s] = Lpi [s] ;
+    }
+
+    Asorted = A->sorted ;
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	/* sth supernode is in columns k1 to k2-1.
+	 * compute nonzero pattern of L (k1:k2-1,:). */
+
+	/* place rows k1 to k2-1 in leading column of supernode s */
+	k1 = Super [s] ;
+	k2 = Super [s+1] ;
+	PRINT1 (("=========>>> Supernode "ID" k1 "ID" k2-1 "ID"\n",
+		    s, k1, k2-1)) ;
+	for (k = k1 ; k < k2 ; k++)
+	{
+	    Ls [Lpi2 [s]++] = k ;
+	}
+
+	/* compute nonzero pattern each row k1 to k2-1 */
+	for (k = k1 ; k < k2 ; k++)
+	{
+	    /* compute row k of L.  In the symmetric case, the pattern of L(k,:)
+	     * is the set of nodes reachable in the supernodal etree from any
+	     * row i in the nonzero pattern of A(0:k,k).  In the unsymmetric
+	     * case, the pattern of the kth column of A*A' is the set union
+	     * of all columns A(0:k,j) for each nonzero F(j,k). */
+
+	    /* clear the Flag array and mark the current supernode */
+	    /* mark = CHOLMOD(clear_flag) (Common) ; */
+	    CHOLMOD_CLEAR_FLAG (Common) ;
+	    mark = Common->mark ;
+	    Flag [s] = mark ;
+	    ASSERT (s == SuperMap [k]) ;
+
+	    /* traverse the row subtree for each nonzero in A or AA' */
+	    if (stype != 0)
+	    {
+		subtree (k, k, Ap, Ai, Anz, SuperMap, Sparent, mark,
+                        Asorted, k1, Flag, Ls, Lpi2) ;
+	    }
+	    else
+	    {
+		/* for each j nonzero in F (:,k) do */
+		p = Fp [k] ;
+		pend = (packed) ? (Fp [k+1]) : (p + Fnz [k]) ;
+		for ( ; p < pend ; p++)
+		{
+		    subtree (Fj [p], k, Ap, Ai, Anz, SuperMap, Sparent, mark,
+			    Asorted, k1, Flag, Ls, Lpi2) ;
+		}
+	    }
+	}
+    }
+#ifndef NDEBUG
+    for (s = 0 ; s < nsuper ; s++)
+    {
+	PRINT1 (("Lpi2[s] "ID" Lpi[s+1] "ID"\n", Lpi2 [s], Lpi [s+1])) ;
+	ASSERT (Lpi2 [s] == Lpi [s+1]) ;
+	CHOLMOD(dump_super) (s, Super, Lpi, Ls, NULL, NULL, 0, Common) ;
+    }
+#endif
+
+    /* contents of Wi no longer needed for Lpi2 ] */
+    /* Sparent no longer needed ] */
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the largest update matrix (L->maxcsize) */
+    /* ---------------------------------------------------------------------- */
+
+    /* maxcsize could be determined before L->s is allocated and defined, which
+     * would mean that all memory requirements for both the symbolic and numeric
+     * factorizations could be computed using O(nnz(A)+O(n)) space.  However, it
+     * would require a lot of extra work.  The analysis phase, above, would need
+     * to be duplicated, but with Ls not kept; instead, the algorithm would keep
+     * track of the current s and slast for each supernode d, and update them
+     * when a new row index appears in supernode d.  An alternative would be to
+     * do this computation only if the allocation of L->s failed, in which case
+     * the following code would be skipped.
+     *
+     * The csize for a supernode is the size of its largest contribution to
+     * a subsequent ancestor supernode.  For example, suppose the rows of #'s
+     * in the figure below correspond to the columns of a subsequent supernode,
+     * and the dots are the entries in that ancestore.
+     *
+     *	    c
+     *	    c c
+     *	    c c c
+     *	    x x x
+     *	    x x x
+     *	    # # #   .
+     *	    # # #   . .
+     *	    * * *   . .
+     *	    * * *   . .
+     *	    * * *   . .
+     *	            . .
+     *
+     * Then for this update, the csize is 3-by-2, or 6, because there are 3
+     * rows of *'s which is the number of rows in the update, and there are
+     * 2 rows of #'s, which is the number columns in the update.  The csize
+     * of a supernode is the largest such contribution for any ancestor
+     * supernode.  maxcsize, for the whole matrix, has a rough upper bound of
+     * the maximum size of any supernode.  This bound is loose, because the
+     * the contribution must be less than the size of the ancestor supernodal
+     * that it's updating.  maxcsize of a completely dense matrix, with one
+     * supernode, is zero.
+     *
+     * maxesize is the column dimension for the workspace E needed for the
+     * solve.  E is of size nrhs-by-maxesize, where the nrhs is the number of
+     * columns in the right-hand-side.  The maxesize is the largest esize of
+     * any supernode.  The esize of a supernode is the number of row indices
+     * it contains, excluding the column indices of the supernode itself.
+     * For the following example, esize is 4:
+     *
+     *	    c
+     *	    c c
+     *	    c c c
+     *	    x x x
+     *	    x x x
+     *	    x x x
+     *	    x x x
+     *
+     * maxesize can be no bigger than n.
+     */
+
+    maxcsize = 1 ;
+    maxesize = 1 ;
+
+    /* Do not need to guard csize against Int overflow since xsize is OK. */
+
+    if (for_cholesky)
+    {
+        /* this is not needed for QR factorization */
+        for (d = 0 ; d < nsuper ; d++)
+        {
+            nscol = Super [d+1] - Super [d] ;
+            p = Lpi [d] + nscol ;
+            plast = p ;
+            pend = Lpi [d+1] ;
+            esize = pend - p ;
+            maxesize = MAX (maxesize, esize) ;
+            slast = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ;
+            for ( ; p <= pend ; p++)
+            {
+                s = (p == pend) ? (EMPTY) : (SuperMap [Ls [p]]) ;
+                if (s != slast)
+                {
+                    /* row i is the start of a new supernode */
+                    ndrow1 = p - plast ;
+                    ndrow2 = pend - plast ;
+                    csize = ndrow2 * ndrow1 ;
+                    PRINT1 (("Supernode "ID" ancestor "ID" C: "ID"-by-"ID
+                        "  csize "ID"\n", d, slast, ndrow1, ndrow2, csize)) ;
+                    maxcsize = MAX (maxcsize, csize) ;
+                    plast = p ;
+                    slast = s ;
+                }
+            }
+        }
+        PRINT1 (("max csize "ID"\n", maxcsize)) ;
+    }
+
+    /* Wj no longer needed for SuperMap } */
+
+    L->maxcsize = maxcsize ;
+    L->maxesize = maxesize ;
+    L->is_super = TRUE ;
+    ASSERT (L->xtype == CHOLMOD_PATTERN && L->is_ll) ;
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal symbolic factorization is complete */
+    /* ---------------------------------------------------------------------- */
+
+    FREE_WORKSPACE ;
+    return (TRUE) ;
+}
+
+/* ========================================================================== */
+/* === cholmod_super_symbolic =============================================== */
+/* ========================================================================== */
+
+/* Analyzes A, AA', or A(:,f)*A(:,f)' in preparation for a supernodal numeric
+ * factorization.  The user need not call this directly; cholmod_analyze is
+ * a "simple" wrapper for this routine.
+ * 
+ * This function does all the analysis for a supernodal Cholesky factorization.
+ *
+ * workspace: Flag (nrow), Head (nrow), Iwork (2*nrow),
+ * and temporary space of size 3*nfsuper*sizeof(Int), where nfsuper <= n
+ * is the number of fundamental supernodes.
+ */
+
+int CHOLMOD(super_symbolic)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to analyze */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    Int *Parent,	/* elimination tree */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* simplicial symbolic on input,
+			 * supernodal symbolic on output */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    return (CHOLMOD(super_symbolic2) (TRUE, A, F, Parent, L, Common)) ;
+}
+#endif
diff --git a/src/CHOLMOD/Supernodal/gpl.txt b/src/CHOLMOD/Supernodal/gpl.txt
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/gpl.txt
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+

+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+

+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+

+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+

+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+

+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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 St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/CHOLMOD/Supernodal/t_cholmod_gpu.c b/src/CHOLMOD/Supernodal/t_cholmod_gpu.c
new file mode 100644
index 0000000..9a4c6a8
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/t_cholmod_gpu.c
@@ -0,0 +1,972 @@
+/* ========================================================================== */
+/* === Supernodal/t_cholmod_gpu ============================================= */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2012, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* GPU BLAS template routine for cholmod_super_numeric. */
+
+/* ========================================================================== */
+/* === include files and definitions ======================================== */
+/* ========================================================================== */
+
+#include "cholmod_template.h"
+
+#undef L_ENTRY
+#ifdef REAL
+#define L_ENTRY 1
+#else
+#define L_ENTRY 2
+#endif
+
+/*
+#define GPU_Printf  printf
+*/
+#define GPU_Printf
+
+#define PAGE_SIZE (4*1024)
+#define OK(cuda_operation) ((cuda_operation) == cudaSuccess)
+
+/* ========================================================================== */
+/* === gpu_init ============================================================= */
+/* ========================================================================== */
+
+void TEMPLATE (CHOLMOD (gpu_init))
+(
+    void *Cwork,
+    Int maxSize,
+    cholmod_common *Common
+)
+{
+    Int i ;
+    cublasStatus_t cublasError ;
+    cudaError_t cudaErr ;
+    size_t maxBytesSize, HostPinnedSize ;
+
+    Common->GemmUsed = 0 ;
+
+    GPU_Printf ("gpu_init : %p\n", (void *) ((size_t) Cwork & ~(PAGE_SIZE-1))) ;
+
+    if (!(Common->cublasHandle))
+    {
+
+        /* ------------------------------------------------------------------ */
+        /* create the CUDA BLAS handle */
+        /* ------------------------------------------------------------------ */
+
+        cublasError = cublasCreate (&(Common->cublasHandle)) ;
+        if (cublasError != CUBLAS_STATUS_SUCCESS)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUBLAS initialization") ;
+            return ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* create each CUDA stream */
+        /* ------------------------------------------------------------------ */
+
+        cudaErr = cudaStreamCreate (&(Common->cudaStreamSyrk)) ;
+        if (cudaErr != cudaSuccess)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUDA stream initialization") ;
+            return ;
+        }
+
+        cudaErr = cudaStreamCreate (&(Common->cudaStreamGemm)) ;
+        if (cudaErr != cudaSuccess)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUDA stream initialization") ;
+            return ;
+        }
+
+        cudaErr = cudaStreamCreate (&(Common->cudaStreamTrsm)) ;
+        if (cudaErr != cudaSuccess)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUDA stream initialization") ;
+            return ;
+        }
+
+        for (i = 0 ; i < 3 ; i++)
+        {
+            cudaErr = cudaStreamCreate (&(Common->cudaStreamPotrf [i])) ;
+            if (cudaErr != cudaSuccess)
+            {
+                ERROR (CHOLMOD_GPU_PROBLEM, "CUDA stream initialization") ;
+                return ;
+            }
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* create each CUDA event */
+        /* ------------------------------------------------------------------ */
+
+        for (i = 0 ; i < 2 ; i++)
+        {
+            cudaErr = cudaEventCreateWithFlags
+                (&(Common->cublasEventPotrf [i]), cudaEventDisableTiming) ;
+            if (cudaErr != cudaSuccess)
+            {
+                ERROR (CHOLMOD_GPU_PROBLEM, "CUDA event") ;
+                return ;
+            }
+        }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* pin the Host memory */
+    /* ---------------------------------------------------------------------- */
+
+    Common->HostPinnedMemory = (void *) ((size_t) Cwork & ~(PAGE_SIZE-1)) ;
+    maxBytesSize = sizeof (double)*L_ENTRY*maxSize ;
+
+    /* Align on a 4K page boundary (it is no more necessary in 4.1 */
+    HostPinnedSize  = 
+        (((size_t) Cwork + maxBytesSize + PAGE_SIZE-1) & ~(PAGE_SIZE-1))
+        - (size_t) (Common->HostPinnedMemory) ;
+
+    GPU_Printf ("gpu HostPinnedSize: %g %p\n", (double) HostPinnedSize,
+        Common->HostPinnedMemory) ;
+    cudaErr = cudaHostRegister (Common->HostPinnedMemory,
+        HostPinnedSize, 0) ;
+
+    if (cudaErr != cudaSuccess)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "CUDA Pinning Memory") ;
+        Common->HostPinnedMemory = NULL ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === gpu_end ============================================================== */
+/* ========================================================================== */
+
+void TEMPLATE (CHOLMOD (gpu_end))
+(
+    cholmod_common *Common
+)
+{
+    int i;
+    /* unpin the Host memory */
+    GPU_Printf ("gpu_end %p\n", Common->HostPinnedMemory) ;
+    cudaError_t cudaErr = cudaHostUnregister (Common->HostPinnedMemory) ;
+    if (cudaErr != cudaSuccess)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "CUDA Unpinning Memory") ;
+        Common->HostPinnedMemory = NULL ;
+    }
+    /* ------------------------------------------------------------------ */
+    /* destroy Cublas Handle */
+    /* ------------------------------------------------------------------ */
+    
+    if (Common->cublasHandle) {
+        cublasDestroy(Common->cublasHandle);
+        Common->cublasHandle = NULL ;
+    }
+    /* ------------------------------------------------------------------ */
+    /* destroy each CUDA stream */
+    /* ------------------------------------------------------------------ */
+    if (Common->cudaStreamSyrk) 
+    {
+        cudaStreamDestroy (Common->cudaStreamSyrk) ;
+        Common->cudaStreamSyrk = NULL ;
+    }
+    if (Common->cudaStreamGemm) 
+    {
+        cudaStreamDestroy (Common->cudaStreamGemm) ;
+    }
+    if (Common->cudaStreamTrsm) 
+    {
+        cudaStreamDestroy (Common->cudaStreamTrsm) ;
+        Common->cudaStreamTrsm = NULL ;
+    }        
+
+    for (i = 0 ; i < 3 ; i++)
+    {
+        if (Common->cudaStreamPotrf [i]) 
+        {
+            cudaStreamDestroy(Common->cudaStreamPotrf [i]) ;
+            Common->cudaStreamPotrf [i] = NULL ;
+        }
+    }
+
+    /* ------------------------------------------------------------------ */
+    /* destroy each CUDA event */
+    /* ------------------------------------------------------------------ */
+
+    for (i = 0 ; i < 2 ; i++)
+    {
+        if (Common->cublasEventPotrf [i]) 
+        {
+            cudaEventDestroy( Common->cublasEventPotrf [i] ) ;
+            Common->cublasEventPotrf [i] = NULL ;
+        }
+    }    
+}
+
+
+/* ========================================================================== */
+/* === gpu_updateC ========================================================== */
+/* ========================================================================== */
+
+/* C = L (k1:n-1, kd1:kd2-1) * L (k1:k2-1, kd1:kd2-1)', except that k1:n-1
+ * refers to all of the rows in L, but many of the rows are all zero.
+ * Supernode d holds columns kd1 to kd2-1 of L.  Nonzero rows in the range
+ * k1:k2-1 are in the list Ls [pdi1 ... pdi2-1], of size ndrow1.  Nonzero rows
+ * in the range k2:n-1 are in the list Ls [pdi2 ... pdend], of size ndrow2.
+ * Let L1 = L (Ls [pdi1 ... pdi2-1], kd1:kd2-1), and let L2 = L (Ls [pdi2 ...
+ * pdend],  kd1:kd2-1).  C is ndrow2-by-ndrow1.  Let C1 be the first ndrow1
+ * rows of C and let C2 be the last ndrow2-ndrow1 rows of C.  Only the lower
+ * triangular part of C1 needs to be computed since C1 is symmetric.
+ */
+
+int TEMPLATE (CHOLMOD (gpu_updateC))
+(
+    Int ndrow1,         /* C is ndrow2-by-ndrow2 */   
+    Int ndrow2,
+    Int ndrow,          /* leading dimension of Lx */
+    Int ndcol,          /* L1 is ndrow1-by-ndcol */
+    Int pdx1,           /* L1 starts at Lx + L_ENTRY*pdx1 */
+                        /* L2 starts at Lx + L_ENTRY*(pdx1 + ndrow1) */
+    double *Lx,
+    double *C,
+    cholmod_common *Common
+)
+{
+    double *devPtrLx, *devPtrC ;
+    double alpha, beta ;
+    cublasStatus_t cublasStatus ;
+    cudaError_t cudaStat [2] ;
+    Int ndrow3 ;
+
+    Common->SyrkUsed = 0 ;
+    Common->GemmUsed = 0 ;
+
+    if ((ndrow2 < 512) || (ndcol <  128))
+    {
+        /* too small for the CUDA BLAS; use the CPU instead */
+        return (0) ;
+    }
+
+    ndrow3 = ndrow2 - ndrow1 ;
+
+#ifndef NTIMER
+    Common->syrkStart = SuiteSparse_time ( ) ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate workspace on the GPU */
+    /* ---------------------------------------------------------------------- */
+
+    cudaStat [0] = cudaMalloc ((void **) &devPtrLx,
+        ndrow2 * ndcol  * L_ENTRY * sizeof (devPtrLx [0])) ;
+    cudaStat [1] = cudaMalloc ((void **) &devPtrC,
+        ndrow2 * ndrow1 * L_ENTRY * sizeof (devPtrC [0])) ;
+    Common->devSyrkGemmPtrLx = devPtrLx ;
+    Common->devSyrkGemmPtrC  = devPtrC ;
+    
+    if (cudaStat [0] || cudaStat [1])
+    {
+        /* one or both cudaMalloc's failed */
+        if (devPtrLx) cudaFree (devPtrLx) ;
+        if (devPtrC)  cudaFree (devPtrC) ;
+        GPU_Printf ("gpu malloc failed =%d,%d ndrow1=%d ndrow2=%d ndcol=%d\n",
+            cudaStat [0], cudaStat [1], (int) ndrow1,
+            (int) ndrow2, (int) ndcol) ;
+        /* cudaMalloc failure is not an error, just bypass the GPU */
+        return (0) ;
+    }
+    Common->SyrkUsed = 1 ;
+#ifndef NTIMER
+    Common->CHOLMOD_GPU_SYRK_CALLS++ ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* copy Lx to the GPU */
+    /* ---------------------------------------------------------------------- */
+
+    /* copy Lx in two steps on different streams.
+     * (ldLx is shortened from ndrow to ndrow2) */
+    cudaStat [0] = cudaMemcpy2DAsync (devPtrLx,
+        ndrow2 * L_ENTRY * sizeof (devPtrLx [0]),
+        Lx + L_ENTRY * pdx1, ndrow * L_ENTRY * sizeof (Lx [0]),
+        ndrow1 * L_ENTRY * sizeof (devPtrLx [0]),
+        ndcol, cudaMemcpyHostToDevice, Common->cudaStreamSyrk) ;
+    if (cudaStat [0])
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+    }
+
+    if (ndrow3 > 0)
+    {
+        Common->GemmUsed = 1 ;
+        cudaStat [1] = cudaMemcpy2DAsync (devPtrLx + L_ENTRY*ndrow1,
+            ndrow2 * L_ENTRY * sizeof (devPtrLx [0]),
+            Lx + L_ENTRY * (pdx1 + ndrow1), ndrow * L_ENTRY * sizeof (Lx [0]),
+            ndrow3 * L_ENTRY * sizeof (devPtrLx [0]),
+            ndcol, cudaMemcpyHostToDevice, Common->cudaStreamGemm) ;
+        if (cudaStat [1])
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+        }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* do the CUDA SYRK */
+    /* ---------------------------------------------------------------------- */
+
+    cublasStatus = cublasSetStream (Common->cublasHandle,
+        Common->cudaStreamSyrk) ;
+    if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS stream") ;
+    }
+
+    alpha  = 1.0 ;
+    beta   = 0.0 ;
+#ifdef REAL
+    cublasStatus = cublasDsyrk (Common->cublasHandle,
+        CUBLAS_FILL_MODE_LOWER, CUBLAS_OP_N,
+        (int) ndrow1, (int) ndcol,          /* N, K: L1 is ndrow1-by-ndcol */
+        &alpha,                             /* ALPHA:  1 */
+        devPtrLx, ndrow2,                   /* A, LDA: L1, ndrow2 */
+        &beta,                              /* BETA:   0 */
+        devPtrC, ndrow2) ;                  /* C, LDC: C1 */
+#else
+    cublasStatus = cublasZherk (Common->cublasHandle,
+        CUBLAS_FILL_MODE_LOWER, CUBLAS_OP_N,
+        (int) ndrow1, (int) ndcol,              /* N, K: L1 is ndrow1-by-ndcol*/
+        &alpha,                                 /* ALPHA:  1 */
+        (const cuDoubleComplex *) devPtrLx, ndrow2, /* A, LDA: L1, ndrow2 */
+        &beta,                                  /* BETA:   0 */
+        (cuDoubleComplex *) devPtrC, ndrow2) ;  /* C, LDC: C1 */
+#endif
+
+    if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* partial copy of C to the GPU */
+    /* ---------------------------------------------------------------------- */
+
+    cudaStat [0] = cudaMemcpy2DAsync (C, ndrow2 * L_ENTRY * sizeof (C [0]),
+        devPtrC, ndrow2 * L_ENTRY * sizeof (devPtrC [0]),
+        ndrow1 * L_ENTRY * sizeof (devPtrC [0]),
+        ndrow1, cudaMemcpyDeviceToHost, Common->cudaStreamSyrk) ;
+    if (cudaStat [0])
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy from device") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* compute remaining (ndrow2-ndrow1)-by-ndrow1 block of C, C2 = L2*L1' */
+    /* ---------------------------------------------------------------------- */
+
+    if (ndrow3 > 0)
+    {
+#ifndef REAL
+        cuDoubleComplex calpha  = {1.0,0.0} ;
+        cuDoubleComplex cbeta   = {0.0,0.0} ;
+#endif
+
+#ifndef NTIMER
+        Common->CHOLMOD_GPU_GEMM_CALLS++ ;
+#endif
+        cublasStatus = cublasSetStream (Common->cublasHandle,
+            Common->cudaStreamGemm) ;
+        if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS stream") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* do the CUDA BLAS dgemm */
+        /* ------------------------------------------------------------------ */
+
+#ifdef REAL
+        alpha  = 1.0 ;
+        beta   = 0.0 ;
+        cublasStatus = cublasDgemm (Common->cublasHandle,
+            CUBLAS_OP_N, CUBLAS_OP_T,
+            ndrow3, ndrow1, ndcol,                  /* M, N, K */
+            &alpha,                                 /* ALPHA:  1 */
+            devPtrLx + L_ENTRY*(ndrow1),            /* A, LDA: L2, ndrow */
+            ndrow2,
+            devPtrLx,                               /* B, LDB: L1, ndrow */
+            ndrow2,
+            &beta,                                  /* BETA:   0 */
+            devPtrC + L_ENTRY*ndrow1,               /* C, LDC: C2 */
+            ndrow2) ;
+#else
+        cublasStatus = cublasZgemm (Common->cublasHandle,
+            CUBLAS_OP_N, CUBLAS_OP_C,
+            ndrow3, ndrow1, ndcol,                  /* M, N, K */
+            &calpha,                                /* ALPHA:  1 */
+            (const cuDoubleComplex *) devPtrLx + ndrow1, /* A, LDA: L2, ndrow */
+            ndrow2,
+            (const cuDoubleComplex *) devPtrLx,     /* B, LDB: L1, ndrow */
+            ndrow2,
+            &cbeta,                                 /* BETA:   0 */
+            (cuDoubleComplex *)devPtrC + ndrow1,    /* C, LDC: C2 */
+            ndrow2) ;
+#endif
+
+        if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* finish copy of C */
+        /* ------------------------------------------------------------------ */
+
+        cudaStat [0] = cudaMemcpy2DAsync (C + L_ENTRY*ndrow1,
+            ndrow2 * L_ENTRY * sizeof (C [0]),
+            devPtrC+ L_ENTRY*ndrow1, ndrow2 * L_ENTRY * sizeof (devPtrC [0]),
+            ndrow3 * L_ENTRY * sizeof (devPtrC [0]),
+            ndrow1, cudaMemcpyDeviceToHost, Common->cudaStreamGemm) ;
+        if (cudaStat [0])
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy from device") ;
+        }
+    }
+
+    return (1) ;
+}
+
+
+/* ========================================================================== */
+/* === gpu_syncSyrk ========================================================= */
+/* ========================================================================== */
+
+/* synchronize with the CUDA BLAS dsyrk stream */
+
+void TEMPLATE (CHOLMOD (gpu_syncSyrk))
+(
+    cholmod_common *Common
+)
+{
+    if (Common->SyrkUsed)
+    {
+        cudaStreamSynchronize (Common->cudaStreamSyrk) ;
+        if (!Common->GemmUsed)
+        {
+            cudaFree (Common->devSyrkGemmPtrLx) ;
+            cudaFree (Common->devSyrkGemmPtrC) ;
+            Common->devSyrkGemmPtrLx = NULL ;
+            Common->devSyrkGemmPtrC = NULL ;
+#ifndef NTIMER
+            /* this actually sums time spend on Syrk and Gemm */
+            Common->CHOLMOD_GPU_SYRK_TIME +=
+                SuiteSparse_time ( ) -  Common->syrkStart ;
+#endif
+        }
+    }
+}
+
+
+/* ========================================================================== */
+/* === gpu_syncGemm ========================================================= */
+/* ========================================================================== */
+
+/* synchronize with the CUDA BLAS dgemm stream */
+
+void TEMPLATE (CHOLMOD (gpu_syncGemm))
+(
+    cholmod_common *Common
+)
+{
+    if (Common->GemmUsed)
+    {
+        cudaStreamSynchronize (Common->cudaStreamGemm) ;
+        cudaFree (Common->devSyrkGemmPtrLx) ;
+        cudaFree (Common->devSyrkGemmPtrC) ;
+        Common->devSyrkGemmPtrLx = NULL ;
+        Common->devSyrkGemmPtrC = NULL ;
+#ifndef NTIMER
+        /* this actually sums time spend on Syrk and Gemm */
+        Common->CHOLMOD_GPU_SYRK_TIME +=
+            SuiteSparse_time ( ) - Common->syrkStart ;
+#endif
+    }
+}
+
+
+/* ========================================================================== */
+/* === gpu_lower_potrf ====================================================== */
+/* ========================================================================== */
+
+/* Cholesky factorzation (dpotrf) of a matrix S, operating on the lower
+ * triangular part only.   S is nscol2-by-nscol2 with leading dimension nsrow.
+ *
+ * S is the top part of the supernode (the lower triangular matrx).
+ * This function also copies the bottom rectangular part of the supernode (B)
+ * onto the GPU, in preparation for gpu_triangular_solve. 
+ */
+
+int TEMPLATE (CHOLMOD (gpu_lower_potrf))
+(
+    Int nscol2,     /* S is nscol2-by-nscol2 */
+    Int nsrow,      /* leading dimension of S */
+    Int psx,        /* S is located at Lx + L_Entry*psx */
+    double *Lx,     /* contains S; overwritten with Cholesky factor */
+    Int *info,      /* BLAS info return value */
+    cholmod_common *Common
+)
+{
+    double *devPtrA, *devPtrB, *A ;
+    double alpha, beta ;
+    cudaError_t cudaStat ;
+    cublasStatus_t cublasStatus ;
+    Int j, nsrow2, nb, n, gpu_lda, lda, gpu_ldb ;
+    int ilda, ijb, iinfo ;
+#ifndef NTIMER
+    double tstart = SuiteSparse_time ( ) ;
+#endif
+
+    if (nscol2 < 256)
+    {
+        /* too small for the CUDA BLAS; use the CPU instead */
+        return (0) ;
+    }
+
+    nsrow2 = nsrow - nscol2 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* heuristic to get the block size depending of the problem size */
+    /* ---------------------------------------------------------------------- */
+
+    nb = 128 ;
+    if (nscol2 > 4096) nb = 256 ;
+    if (nscol2 > 8192) nb = 384 ;
+    n  = nscol2 ;
+    gpu_lda = ((nscol2+31)/32)*32 ;
+    lda = nsrow ;
+    A = Lx + L_ENTRY*psx ;
+
+    /* ---------------------------------------------------------------------- */
+    /* free the dpotrf workspace, if allocated */
+    /* ---------------------------------------------------------------------- */
+
+    if (Common->devPotrfWork)
+    {
+        cudaFree (Common->devPotrfWork) ;
+        Common->devPotrfWork = NULL ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* determine the GPU leading dimension of B */
+    /* ---------------------------------------------------------------------- */
+
+    gpu_ldb = 0 ;
+    if (nsrow2 > 0)
+    {
+        gpu_ldb = ((nsrow2+31)/32)*32 ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* allocate device memory for the factorization and for potential solve */
+    /* ---------------------------------------------------------------------- */
+
+    cudaStat = cudaMalloc ((void **) &devPtrA,
+        gpu_lda * (gpu_lda + gpu_ldb) * L_ENTRY * sizeof (devPtrA [0])) ;
+    if (cudaStat)
+    {
+        GPU_Printf ("@@gpu_lower_potrf cudaMalloc failed =%d gpu_lda=%d\n",
+            cudaStat, (int) (gpu_lda)) ;
+        /* cudaMalloc failure not fatal, GPU bypassed */
+        return (0) ;
+    }
+#ifndef NTIMER
+    Common->CHOLMOD_GPU_POTRF_CALLS++ ;
+#endif
+
+    /* ---------------------------------------------------------------------- */
+    /* remember where device memory is, to be used by triangular solve later */
+    /* ---------------------------------------------------------------------- */
+
+    Common->devPotrfWork = devPtrA ;
+    devPtrB = devPtrA + gpu_lda * gpu_lda * L_ENTRY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* copy B in advance, for gpu_triangular_solve */
+    /* ---------------------------------------------------------------------- */
+
+    if (nsrow2 > 0)
+    {
+        cudaStat = cudaMemcpy2DAsync (devPtrB,
+            gpu_ldb * L_ENTRY * sizeof (devPtrB [0]),
+            Lx + L_ENTRY * (psx + nscol2),
+            nsrow * L_ENTRY * sizeof (Lx [0]),
+            nsrow2 * L_ENTRY * sizeof (devPtrB [0]),
+            nscol2, cudaMemcpyHostToDevice, Common->cudaStreamTrsm) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+        }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* block Cholesky factorization of S */
+    /* ---------------------------------------------------------------------- */
+
+    for (j = 0 ; j < n ; j += nb)
+    {
+        Int jb = nb < (n-j) ? nb : (n-j) ;
+
+        /* ------------------------------------------------------------------ */
+        /* copy jb columns starting at the diagonal to the GPU */
+        /* ------------------------------------------------------------------ */
+
+        cudaStat = cudaMemcpy2DAsync (devPtrA + (j + j*gpu_lda)*L_ENTRY,
+            gpu_lda * L_ENTRY * sizeof (devPtrA [0]),
+            A + L_ENTRY*(j + j*lda),
+            lda * L_ENTRY * sizeof (A [0]),
+            (n-j) * L_ENTRY * sizeof (devPtrA [0]),
+            jb, cudaMemcpyHostToDevice, Common->cudaStreamPotrf [0]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* define the dpotrf stream */
+        /* ------------------------------------------------------------------ */
+
+        cublasStatus = cublasSetStream (Common->cublasHandle,
+            Common->cudaStreamPotrf [0]) ;
+        if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS stream") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* record the end of the copy of block L22 | L32 */
+        /* ------------------------------------------------------------------ */
+
+        cudaStat = cudaEventRecord (Common->cublasEventPotrf [0],
+            Common->cudaStreamPotrf [0]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUDA event failure") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* do the CUDA BLAS dsyrk */
+        /* ------------------------------------------------------------------ */
+
+        alpha = -1.0 ;
+        beta  = 1.0 ;
+#ifdef REAL
+        cublasStatus = cublasDsyrk (Common->cublasHandle,
+            CUBLAS_FILL_MODE_LOWER, CUBLAS_OP_N, jb, j,
+            &alpha, devPtrA + j, gpu_lda,
+            &beta,  devPtrA + j + j*gpu_lda, gpu_lda) ;
+#else
+        cublasStatus = cublasZherk (Common->cublasHandle,
+            CUBLAS_FILL_MODE_LOWER, CUBLAS_OP_N, jb, j,
+            &alpha, (cuDoubleComplex*)devPtrA + j, gpu_lda,
+            &beta,  (cuDoubleComplex*)devPtrA + j + j*gpu_lda, gpu_lda) ;
+#endif
+        if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+
+        cudaStat = cudaEventRecord (Common->cublasEventPotrf [1],
+            Common->cudaStreamPotrf [0]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUDA event failure") ;
+        }
+
+        cudaStat = cudaStreamWaitEvent (Common->cudaStreamPotrf [1],
+            Common->cublasEventPotrf [1], 0) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "CUDA event failure") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* copy back the jb columns on two different streams */
+        /* ------------------------------------------------------------------ */
+
+        cudaStat = cudaMemcpy2DAsync (A + L_ENTRY*(j + j*lda),
+            lda * L_ENTRY * sizeof (double),
+            devPtrA + L_ENTRY*(j + j*gpu_lda),
+            gpu_lda * L_ENTRY * sizeof (double),
+            L_ENTRY * sizeof (double)*jb, jb,
+            cudaMemcpyDeviceToHost, Common->cudaStreamPotrf [1]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy from device") ;
+        }
+
+        cudaStat = cudaMemcpy2DAsync (A + L_ENTRY*j,
+            lda * L_ENTRY * sizeof (double),
+            devPtrA + L_ENTRY*j,
+            gpu_lda * L_ENTRY * sizeof (double),
+            L_ENTRY * sizeof (double)*jb, j,
+            cudaMemcpyDeviceToHost, Common->cudaStreamPotrf [0]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* do the CUDA BLAS dgemm */
+        /* ------------------------------------------------------------------ */
+
+        if ((j+jb) < n)
+        {
+#ifdef REAL
+            alpha = -1.0 ;
+            beta  = 1.0 ;
+            cublasStatus = cublasDgemm (Common->cublasHandle,
+                CUBLAS_OP_N, CUBLAS_OP_T,
+                (n-j-jb), jb, j,
+                &alpha,
+                devPtrA + (j+jb), gpu_lda,
+                devPtrA + (j)  , gpu_lda,
+                &beta,
+                devPtrA + (j+jb + j*gpu_lda), gpu_lda) ;
+#else
+            cuDoubleComplex calpha = {-1.0,0.0} ;
+            cuDoubleComplex cbeta  = { 1.0,0.0} ;
+            cublasStatus = cublasZgemm (Common->cublasHandle,
+                CUBLAS_OP_N, CUBLAS_OP_C,
+                (n-j-jb), jb, j,
+                &calpha,
+                (cuDoubleComplex*)devPtrA + (j+jb), gpu_lda,
+                (cuDoubleComplex*)devPtrA + (j)  , gpu_lda,
+                &cbeta,
+                (cuDoubleComplex*)devPtrA + (j+jb + j*gpu_lda), gpu_lda) ;
+#endif
+            if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+            {
+                ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ;
+            }
+        }
+
+        cudaStat = cudaStreamSynchronize (Common->cudaStreamPotrf [1]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* compute the Cholesky factorization of the jbxjb block on the CPU */
+        /* ------------------------------------------------------------------ */
+
+        ilda = (int) lda ;
+        ijb  = jb ;
+#ifdef REAL
+        LAPACK_DPOTRF ("L", &ijb, A + L_ENTRY * (j + j*lda), &ilda, &iinfo) ;
+#else
+        LAPACK_ZPOTRF ("L", &ijb, A + L_ENTRY * (j + j*lda), &ilda, &iinfo) ;
+#endif
+        *info = iinfo ;
+
+        if (*info != 0)
+        {
+            *info = *info + j ;
+            break ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* copy the result back to the GPU */
+        /* ------------------------------------------------------------------ */
+
+        cudaStat = cudaMemcpy2DAsync (devPtrA + L_ENTRY*(j + j*gpu_lda),
+            gpu_lda * L_ENTRY * sizeof (double),
+            A + L_ENTRY * (j + j*lda),
+            lda * L_ENTRY * sizeof (double),
+            L_ENTRY * sizeof (double) * jb, jb,
+            cudaMemcpyHostToDevice, Common->cudaStreamPotrf [0]) ;
+        if (cudaStat)
+        {
+            ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy to device") ;
+        }
+
+        /* ------------------------------------------------------------------ */
+        /* do the CUDA BLAS dtrsm */
+        /* ------------------------------------------------------------------ */
+
+        if ((j+jb) < n)
+        {
+#ifdef REAL
+             alpha  = 1.0 ;
+             cublasStatus = cublasDtrsm (Common->cublasHandle,
+                 CUBLAS_SIDE_RIGHT, CUBLAS_FILL_MODE_LOWER,
+                 CUBLAS_OP_T, CUBLAS_DIAG_NON_UNIT,
+                 (n-j-jb), jb,
+                 &alpha,
+                 devPtrA + (j + j*gpu_lda), gpu_lda,
+                 devPtrA + (j+jb + j*gpu_lda), gpu_lda) ;
+#else
+             cuDoubleComplex calpha  = {1.0,0.0};
+             cublasStatus = cublasZtrsm (Common->cublasHandle,
+                 CUBLAS_SIDE_RIGHT, CUBLAS_FILL_MODE_LOWER,
+                 CUBLAS_OP_C, CUBLAS_DIAG_NON_UNIT,
+                 (n-j-jb), jb,
+                 &calpha,
+                 (cuDoubleComplex *)devPtrA + (j + j*gpu_lda), gpu_lda,
+                 (cuDoubleComplex *)devPtrA + (j+jb + j*gpu_lda), gpu_lda) ;
+#endif
+            if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+            {
+                ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ;
+            }
+        }
+    }
+
+    if (nsrow2 <= 0)
+    {
+        /* No TRSM necessary */
+        cudaFree (Common->devPotrfWork) ;
+        Common->devPotrfWork = NULL ;
+    }
+
+#ifndef NTIMER
+    Common->CHOLMOD_GPU_POTRF_TIME += SuiteSparse_time ( ) - tstart ;
+#endif
+    return (1) ;
+}
+
+
+/* ========================================================================== */
+/* === gpu_triangular_solve ================================================= */
+/* ========================================================================== */
+
+/* The current supernode is columns k1 to k2-1 of L.  Let L1 be the diagonal
+ * block (factorized by dpotrf/zpotrf above; rows/cols k1:k2-1), and L2 be rows
+ * k2:n-1 and columns k1:k2-1 of L.  The triangular system to solve is L2*L1' =
+ * S2, where S2 is overwritten with L2.  More precisely, L2 = S2 / L1' in
+ * MATLAB notation.
+ */
+
+/* Version with pre-allocation in POTRF */
+
+int TEMPLATE (CHOLMOD (gpu_triangular_solve))
+(
+    Int nsrow2,     /* L1 and S2 are nsrow2-by-nscol2 */
+    Int nscol2,     /* L1 is nscol2-by-nscol2 */
+    Int nsrow,      /* leading dimension of L1, L2, and S2 */
+    Int psx,        /* L1 is at Lx+L_ENTRY*psx; L2 at Lx+L_ENTRY*(psx+nscol2)*/
+    double *Lx,     /* holds L1, L2, and S2 */
+    cholmod_common *Common
+)
+{
+    double *devPtrA, *devPtrB ;
+    cudaError_t cudaStat ;
+    cublasStatus_t cublasStatus ;
+    Int gpu_lda, gpu_ldb ;
+#ifdef REAL
+    double alpha  = 1.0 ;
+#else
+    cuDoubleComplex calpha  = {1.0,0.0} ;
+#endif
+
+    if (!Common->devPotrfWork)
+    {
+        /* no workspace for triangular solve */
+        return (0) ;
+    }
+
+#ifndef NTIMER
+    double tstart = SuiteSparse_time ( ) ;
+    Common->CHOLMOD_GPU_TRSM_CALLS++ ;
+#endif
+
+    gpu_lda = ((nscol2+31)/32)*32 ;
+    gpu_ldb = ((nsrow2+31)/32)*32 ;
+
+    devPtrA = Common->devPotrfWork ;
+    devPtrB = devPtrA + gpu_lda * gpu_lda * L_ENTRY ;
+
+    /* ---------------------------------------------------------------------- */
+    /* start the trsm stream */
+    /* ---------------------------------------------------------------------- */
+
+    cublasStatus = cublasSetStream (Common->cublasHandle,
+        Common->cudaStreamTrsm) ;
+    if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS stream") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* do the CUDA BLAS dtrsm */
+    /* ---------------------------------------------------------------------- */
+
+#ifdef REAL
+    cublasStatus = cublasDtrsm (Common->cublasHandle,
+        CUBLAS_SIDE_RIGHT, CUBLAS_FILL_MODE_LOWER,
+        CUBLAS_OP_T, CUBLAS_DIAG_NON_UNIT,
+        nsrow2, nscol2,                             /* M, N */
+        &alpha,                                     /* ALPHA:  1 */
+        devPtrA, gpu_lda,                           /* A, LDA */
+        devPtrB, gpu_ldb) ;                         /* B, LDB */
+#else
+    cublasStatus = cublasZtrsm (Common->cublasHandle,
+        CUBLAS_SIDE_RIGHT, CUBLAS_FILL_MODE_LOWER,
+        CUBLAS_OP_C, CUBLAS_DIAG_NON_UNIT,
+        nsrow2, nscol2,                             /* M, N */
+        &calpha,                                    /* ALPHA:  1 */
+        (const cuDoubleComplex *) devPtrA, gpu_lda, /* A, LDA */
+        (cuDoubleComplex *) devPtrB, gpu_ldb) ;     /* B, LDB: nsrow2 */
+#endif
+    if (cublasStatus != CUBLAS_STATUS_SUCCESS)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU CUBLAS routine failure") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* copy result back to the CPU */
+    /* ---------------------------------------------------------------------- */
+
+    cudaStat = cudaMemcpy2DAsync (Lx + L_ENTRY*(psx + nscol2),
+        nsrow * L_ENTRY * sizeof (Lx [0]),
+        devPtrB, gpu_ldb * L_ENTRY * sizeof (devPtrB [0]),
+        nsrow2 * L_ENTRY * sizeof (devPtrB [0]),
+        nscol2, cudaMemcpyDeviceToHost, Common->cudaStreamTrsm) ;
+    if (cudaStat)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU memcopy from device") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* synchronize with the GPU */
+    /* ---------------------------------------------------------------------- */
+
+    cudaStat = cudaThreadSynchronize ( ) ;
+    if (cudaStat)
+    {
+        ERROR (CHOLMOD_GPU_PROBLEM, "GPU synchronization failure") ;
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* free workspace and return */
+    /* ---------------------------------------------------------------------- */
+    
+    cudaFree (Common->devPotrfWork) ;
+    Common->devPotrfWork = NULL ;
+#ifndef NTIMER
+    Common->CHOLMOD_GPU_TRSM_TIME += SuiteSparse_time ( ) - tstart ;
+#endif
+    return (1) ;
+}
+
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Supernodal/t_cholmod_super_numeric.c b/src/CHOLMOD/Supernodal/t_cholmod_super_numeric.c
new file mode 100644
index 0000000..7ddd780
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/t_cholmod_super_numeric.c
@@ -0,0 +1,912 @@
+/* ========================================================================== */
+/* === Supernodal/t_cholmod_super_numeric =================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2012, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_super_numeric.  All xtypes supported, except
+ * that a zomplex A and F result in a complex L (there is no supernodal
+ * zomplex L).
+ */
+
+/* ========================================================================== */
+/* === complex arithmetic =================================================== */
+/* ========================================================================== */
+
+#include "cholmod_template.h"
+
+#ifdef USING_R
+#include <Rconfig.h>
+#ifdef HAVE_F77_UNDERSCORE
+# define F77_CALL(x)    x ## _
+#else
+# define F77_CALL(x)    x
+#endif
+#define F77_NAME(x)    F77_CALL(x)
+#define F77_SUB(x)     F77_CALL(x)
+#define F77_COM(x)     F77_CALL(x)
+#define F77_COMDECL(x) F77_CALL(x)
+void F77_NAME(dsyrk)(const char *uplo, const char *trans,
+		     const int *n, const int *k,
+		     const double *alpha, const double *a, const int *lda,
+		     const double *beta, double *c, const int *ldc);
+
+void F77_NAME(dpotrf)(const char* uplo, const int* n,
+		      double* a, const int* lda, int* info);
+
+void F77_NAME(dtrsm)(const char *side, const char *uplo,
+		     const char *transa, const char *diag,
+		     const int *m, const int *n, const double *alpha,
+		     const double *a, const int *lda,
+		     double *b, const int *ldb);
+
+void F77_NAME(dtrsv)(const char *uplo, const char *trans,
+		     const char *diag, const int *n,
+		     const double *a, const int *lda,
+		     double *x, const int *incx);
+#endif
+
+#undef L_ENTRY
+#undef L_CLEAR
+#undef L_ASSIGN
+#undef L_MULTADD
+#undef L_ASSEMBLE
+#undef L_ASSEMBLESUB
+
+#ifdef REAL
+
+/* -------------------------------------------------------------------------- */
+/* A, F, and L are all real */
+/* -------------------------------------------------------------------------- */
+
+#define L_ENTRY 1
+#define L_CLEAR(Lx,p)		    Lx [p] = 0
+#define L_ASSIGN(Lx,q, Ax,Az,p)	    Lx [q] = Ax [p]
+#define L_MULTADD(Lx,q, Ax,Az,p, f) Lx [q] += Ax [p] * f [0]
+#define L_ASSEMBLE(Lx,q,b)	    Lx [q] += b [0]
+#define L_ASSEMBLESUB(Lx,q,C,p)	    Lx [q] -= C [p]
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* A and F are complex or zomplex, L and C are complex */
+/* -------------------------------------------------------------------------- */
+
+#define L_ENTRY 2
+#define L_CLEAR(Lx,p)		    Lx [2*(p)] = 0 ; Lx [2*(p)+1] = 0
+#define L_ASSEMBLE(Lx,q,b)	    Lx [2*(q)] += b [0] ;
+#define L_ASSEMBLESUB(Lx,q,C,p)	\
+    Lx [2*(q)  ] -= C [2*(p)  ] ; \
+    Lx [2*(q)+1] -= C [2*(p)+1] ;
+
+#ifdef COMPLEX
+
+/* -------------------------------------------------------------------------- */
+/* A, F, L, and C are all complex */
+/* -------------------------------------------------------------------------- */
+
+#define L_ASSIGN(Lx,q, Ax,Az,p) \
+    Lx [2*(q)  ] = Ax [2*(p)  ] ; \
+    Lx [2*(q)+1] = Ax [2*(p)+1]
+
+#define L_MULTADD(Lx,q, Ax,Az,p, f) \
+    Lx [2*(q)  ] += Ax [2*(p)  ] * f [0] - Ax [2*(p)+1] * f [1] ; \
+    Lx [2*(q)+1] += Ax [2*(p)+1] * f [0] + Ax [2*(p)  ] * f [1]
+
+#else
+
+/* -------------------------------------------------------------------------- */
+/* A and F are zomplex, L and C is complex */
+/* -------------------------------------------------------------------------- */
+
+#define L_ASSIGN(Lx,q, Ax,Az,p)	\
+    Lx [2*(q)  ] = Ax [p] ; \
+    Lx [2*(q)+1] = Az [p] ;
+
+#define L_MULTADD(Lx,q, Ax,Az,p, f) \
+    Lx [2*(q)  ] += Ax [p] * f [0] - Az [p] * f [1] ; \
+    Lx [2*(q)+1] += Az [p] * f [0] + Ax [p] * f [1]
+
+#endif
+#endif
+
+
+/* ========================================================================== */
+/* === t_cholmod_super_numeric ============================================== */
+/* ========================================================================== */
+
+/* This function returns FALSE only if integer overflow occurs in the BLAS.
+ * It returns TRUE otherwise whether or not the matrix is positive definite. */
+
+static int TEMPLATE (cholmod_super_numeric)
+(
+    /* ---- input ---- */
+    cholmod_sparse *A,	/* matrix to factorize */
+    cholmod_sparse *F,	/* F = A' or A(:,f)' */
+    double beta [2],	/* beta*I is added to diagonal of matrix to factorize */
+    /* ---- in/out --- */
+    cholmod_factor *L,	/* factorization */
+    /* -- workspace -- */
+    cholmod_dense *Cwork,	/* size (L->maxcsize)-by-1 */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double one [2], zero [2], fjk [2], tstart ;
+    double *Lx, *Ax, *Fx, *Az, *Fz, *C ;
+    Int *Super, *Head, *Ls, *Lpi, *Lpx, *Map, *SuperMap, *RelativeMap, *Next,
+	*Lpos, *Fp, *Fi, *Fnz, *Ap, *Ai, *Anz, *Iwork, *Next_save, *Lpos_save ;
+    Int nsuper, n, j, i, k, s, p, pend, k1, k2, nscol, psi, psx, psend, nsrow,
+	pj, d, kd1, kd2, info, ndcol, ndrow, pdi, pdx, pdend, pdi1, pdi2, pdx1,
+	ndrow1, ndrow2, px, dancestor, sparent, dnext, nsrow2, ndrow3, pk, pf,
+	pfend, stype, Apacked, Fpacked, q, imap, repeat_supernode, nscol2, ss,
+	nscol_new = 0 ;
+
+    /* If integer overflow occurs in the BLAS, Common->status is set to
+     * CHOLMOD_TOO_LARGE, and the contents of Lx are undefined. */
+    Common->blas_ok = TRUE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nsuper = L->nsuper ;
+    n = L->n ;
+
+    C = Cwork->x ;	/* workspace of size L->maxcsize */
+
+    one [0] = 1.0 ;	/* ALPHA for *syrk, *herk, *gemm, and *trsm */
+    one [1] = 0. ;
+
+    zero [0] = 0. ;	/* BETA for *syrk, *herk, and *gemm */
+    zero [1] = 0. ;
+
+    Iwork = Common->Iwork ;
+    SuperMap    = Iwork ;		    /* size n (i/i/l) */
+    RelativeMap = Iwork + n ;		    /* size n (i/i/l) */
+    Next        = Iwork + 2*((size_t) n) ;			/* size nsuper*/
+    Lpos        = Iwork + 2*((size_t) n) + nsuper ;		/* size nsuper*/
+    Next_save   = Iwork + 2*((size_t) n) + 2*((size_t) nsuper) ;/* size nsuper*/
+    Lpos_save   = Iwork + 2*((size_t) n) + 3*((size_t) nsuper) ;/* size nsuper*/
+
+    Map  = Common->Flag ;   /* size n, use Flag as workspace for Map array */
+    Head = Common->Head ;   /* size n+1, only Head [0..nsuper-1] used */
+
+    Ls = L->s ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+
+    Super = L->super ;
+
+    Lx = L->x ;
+
+#ifdef GPU_BLAS
+    TEMPLATE (CHOLMOD (gpu_init)) (C, L->maxcsize, Common) ;
+#endif
+
+#ifndef NTIMER
+    /* clear GPU / CPU statistics */
+    Common->CHOLMOD_CPU_GEMM_CALLS  = 0 ;
+    Common->CHOLMOD_CPU_SYRK_CALLS  = 0 ;
+    Common->CHOLMOD_CPU_TRSM_CALLS  = 0 ;
+    Common->CHOLMOD_CPU_POTRF_CALLS = 0 ;
+    Common->CHOLMOD_GPU_GEMM_CALLS  = 0 ;
+    Common->CHOLMOD_GPU_SYRK_CALLS  = 0 ;
+    Common->CHOLMOD_GPU_TRSM_CALLS  = 0 ;
+    Common->CHOLMOD_GPU_POTRF_CALLS = 0 ;
+    Common->CHOLMOD_CPU_GEMM_TIME   = 0 ;
+    Common->CHOLMOD_CPU_SYRK_TIME   = 0 ;
+    Common->CHOLMOD_CPU_TRSM_TIME   = 0 ;
+    Common->CHOLMOD_CPU_POTRF_TIME  = 0 ;
+    Common->CHOLMOD_GPU_GEMM_TIME   = 0 ;
+    Common->CHOLMOD_GPU_SYRK_TIME   = 0 ;
+    Common->CHOLMOD_GPU_TRSM_TIME   = 0 ;
+    Common->CHOLMOD_GPU_POTRF_TIME  = 0 ;
+    Common->CHOLMOD_ASSEMBLE_TIME   = 0 ;
+    Common->CHOLMOD_ASSEMBLE_TIME2  = 0 ;
+#endif
+
+    stype = A->stype ;
+
+    if (stype != 0)
+    {
+	/* F not accessed */
+	Fp = NULL ;
+	Fi = NULL ;
+	Fx = NULL ;
+	Fz = NULL ;
+	Fnz = NULL ;
+	Fpacked = TRUE ;
+    }
+    else
+    {
+	Fp = F->p ;
+	Fi = F->i ;
+	Fx = F->x ;
+	Fz = F->z ;
+	Fnz = F->nz ;
+	Fpacked = F->packed ;
+    }
+
+    Ap = A->p ;
+    Ai = A->i ;
+    Ax = A->x ;
+    Az = A->z ;
+    Anz = A->nz ;
+    Apacked = A->packed ;
+
+    /* clear the Map so that changes in the pattern of A can be detected */
+    for (i = 0 ; i < n ; i++)
+    {
+	Map [i] = EMPTY ;
+    }
+
+    /* If the matrix is not positive definite, the supernode s containing the
+     * first zero or negative diagonal entry of L is repeated (but factorized
+     * only up to just before the problematic diagonal entry). The purpose is
+     * to provide MATLAB with [R,p]=chol(A); columns 1 to p-1 of L=R' are
+     * required, where L(p,p) is the problematic diagonal entry.  The 
+     * repeat_supernode flag tells us whether this is the repeated supernode.
+     * Once supernode s is repeated, the factorization is terminated. */
+    repeat_supernode = FALSE ;
+
+    /* ---------------------------------------------------------------------- */
+    /* supernodal numerical factorization */
+    /* ---------------------------------------------------------------------- */
+
+    for (s = 0 ; s < nsuper ; s++)
+    {
+
+	/* ------------------------------------------------------------------ */
+	/* get the size of supernode s */
+	/* ------------------------------------------------------------------ */
+
+	k1 = Super [s] ;	    /* s contains columns k1 to k2-1 of L */
+	k2 = Super [s+1] ;
+	nscol = k2 - k1 ;	    /* # of columns in all of s */
+	psi = Lpi [s] ;		    /* pointer to first row of s in Ls */
+	psx = Lpx [s] ;		    /* pointer to first row of s in Lx */
+	psend = Lpi [s+1] ;	    /* pointer just past last row of s in Ls */
+	nsrow = psend - psi ;	    /* # of rows in all of s */
+
+	PRINT1 (("====================================================\n"
+		"S "ID" k1 "ID" k2 "ID" nsrow "ID" nscol "ID" psi "ID" psend "
+		""ID" psx "ID"\n", s, k1, k2, nsrow, nscol, psi, psend, psx)) ;
+
+	/* ------------------------------------------------------------------ */
+	/* zero the supernode s */
+	/* ------------------------------------------------------------------ */
+
+	ASSERT ((size_t) (psx + nsrow*nscol) <= L->xsize) ;
+
+	pend = psx + nsrow * nscol ;	    /* s is nsrow-by-nscol */
+	for (p = psx ; p < pend ; p++)
+	{
+	    /* Lx [p] = 0 ; */
+	    L_CLEAR (Lx,p) ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* construct the scattered Map for supernode s */
+	/* ------------------------------------------------------------------ */
+
+	/* If row i is the kth row in s, then Map [i] = k.  Similarly, if
+	 * column j is the kth column in s, then  Map [j] = k. */
+
+	for (k = 0 ; k < nsrow ; k++)
+	{
+	    PRINT1 (("  "ID" map "ID"\n", Ls [psi+k], k)) ;
+	    Map [Ls [psi + k]] = k ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* copy matrix into supernode s (lower triangular part only) */
+	/* ------------------------------------------------------------------ */
+
+	pk = psx ;
+	for (k = k1 ; k < k2 ; k++)
+	{
+	    if (stype != 0)
+	    {
+		/* copy the kth column of A into the supernode */
+		p = Ap [k] ;
+		pend = (Apacked) ? (Ap [k+1]) : (p + Anz [k]) ;
+		for ( ; p < pend ; p++)
+		{
+		    /* row i of L is located in row Map [i] of s */
+		    i = Ai [p] ;
+		    if (i >= k)
+		    {
+			/* This test is here simply to avoid a segfault.  If
+			 * the test is false, the numeric factorization of A
+			 * is undefined.  It does not detect all invalid
+			 * entries, only some of them (when debugging is
+			 * enabled, and Map is cleared after each step, then
+			 * all entries not in the pattern of L are detected). */
+			imap = Map [i] ;
+			if (imap >= 0 && imap < nsrow)
+			{
+			    /* Lx [Map [i] + pk] = Ax [p] ; */
+			    L_ASSIGN (Lx,(imap+pk), Ax,Az,p) ;
+			}
+		    }
+		}
+	    }
+	    else
+	    {
+		/* copy the kth column of A*F into the supernode */
+		pf = Fp [k] ;
+		pfend = (Fpacked) ? (Fp [k+1]) : (p + Fnz [k]) ;
+		for ( ; pf < pfend ; pf++)
+		{
+		    j = Fi [pf] ;
+
+		    /* fjk = Fx [pf] ; */
+		    L_ASSIGN (fjk,0, Fx,Fz,pf) ;
+
+		    p = Ap [j] ;
+		    pend = (Apacked) ? (Ap [j+1]) : (p + Anz [j]) ;
+		    for ( ; p < pend ; p++)
+		    {
+			i = Ai [p] ;
+			if (i >= k)
+			{
+			    /* See the discussion of imap above. */
+			    imap = Map [i] ;
+			    if (imap >= 0 && imap < nsrow)
+			    {
+				/* Lx [Map [i] + pk] += Ax [p] * fjk ; */
+				L_MULTADD (Lx,(imap+pk), Ax,Az,p, fjk) ;
+			    }
+			}
+		    }
+		}
+	    }
+	    pk += nsrow ;  /* advance to the next column of the supernode */
+	}
+
+	/* add beta to the diagonal of the supernode, if nonzero */
+	if (beta [0] != 0.0)
+	{
+	    /* note that only the real part of beta is used */
+	    pk = psx ;
+	    for (k = k1 ; k < k2 ; k++)
+	    {
+		/* Lx [pk] += beta [0] ; */
+		L_ASSEMBLE (Lx,pk, beta) ;
+		pk += nsrow + 1 ;	/* advance to the next diagonal entry */
+	    }
+	}
+
+	PRINT1 (("Supernode with just A: repeat: "ID"\n", repeat_supernode)) ;
+	DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+		    Common)) ;
+	PRINT1 (("\n\n")) ;
+
+	/* ------------------------------------------------------------------ */
+	/* save/restore the list of supernodes */
+	/* ------------------------------------------------------------------ */
+
+	if (!repeat_supernode)
+	{
+	    /* Save the list of pending descendants in case s is not positive
+	     * definite.  Also save Lpos for each descendant d, so that we can
+	     * find which part of d is used to update s. */
+	    for (d = Head [s] ; d != EMPTY ; d = Next [d])
+	    {
+		Lpos_save [d] = Lpos [d] ;
+		Next_save [d] = Next [d] ;
+	    }
+	}
+	else
+	{
+	    /* s is not positive definite, and is being repeated.  Restore
+	     * the list of supernodes.  This can be done with pointer assignment
+	     * because all 4 arrays are held within Common->Iwork. */
+	    Lpos = Lpos_save ;
+	    Next = Next_save ;
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* update supernode s with each pending descendant d */
+	/* ------------------------------------------------------------------ */
+
+#ifndef NDEBUG
+	for (d = Head [s] ; d != EMPTY ; d = Next [d])
+	{
+	    PRINT1 (("\nWill update "ID" with Child: "ID"\n", s, d)) ;
+	    DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+			Common)) ;
+	}
+	PRINT1 (("\nNow factorizing supernode "ID":\n", s)) ;
+#endif
+
+	for (d = Head [s] ; d != EMPTY ; d = dnext)
+	{
+
+	    /* -------------------------------------------------------------- */
+	    /* get the size of supernode d */
+	    /* -------------------------------------------------------------- */
+
+	    kd1 = Super [d] ;	    /* d contains cols kd1 to kd2-1 of L */
+	    kd2 = Super [d+1] ;
+	    ndcol = kd2 - kd1 ;	    /* # of columns in all of d */
+	    pdi = Lpi [d] ;	    /* pointer to first row of d in Ls */
+	    pdx = Lpx [d] ;	    /* pointer to first row of d in Lx */
+	    pdend = Lpi [d+1] ;	    /* pointer just past last row of d in Ls */
+	    ndrow = pdend - pdi ;   /* # rows in all of d */
+
+	    PRINT1 (("Child: ")) ;
+	    DEBUG (CHOLMOD(dump_super) (d, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+			Common)) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* find the range of rows of d that affect rows k1 to k2-1 of s */
+	    /* -------------------------------------------------------------- */
+
+	    p = Lpos [d] ;	    /* offset of 1st row of d affecting s */
+	    pdi1 = pdi + p ;	    /* ptr to 1st row of d affecting s in Ls */
+	    pdx1 = pdx + p ;	    /* ptr to 1st row of d affecting s in Lx */
+
+	    /* there must be at least one row remaining in d to update s */
+	    ASSERT (pdi1 < pdend) ;
+	    PRINT1 (("Lpos[d] "ID" pdi1 "ID" Ls[pdi1] "ID"\n",
+			Lpos[d], pdi1, Ls [pdi1])) ;
+	    ASSERT (Ls [pdi1] >= k1 && Ls [pdi1] < k2) ;
+
+	    for (pdi2 = pdi1 ; pdi2 < pdend && Ls [pdi2] < k2 ; pdi2++) ;
+	    ndrow1 = pdi2 - pdi1 ;	    /* # rows in first part of d */
+	    ndrow2 = pdend - pdi1 ;	    /* # rows in remaining d */
+
+	    /* rows Ls [pdi1 ... pdi2-1] are in the range k1 to k2-1.  Since d
+	     * affects s, this set cannot be empty. */
+	    ASSERT (pdi1 < pdi2 && pdi2 <= pdend) ;
+	    PRINT1 (("ndrow1 "ID" ndrow2 "ID"\n", ndrow1, ndrow2)) ;
+	    DEBUG (for (p = pdi1 ; p < pdi2 ; p++)
+		    PRINT1 (("Ls["ID"] "ID"\n", p, Ls[p]))) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct the update matrix C for this supernode d */
+	    /* -------------------------------------------------------------- */
+
+	    /* C = L (k1:n-1, kd1:kd2-1) * L (k1:k2-1, kd1:kd2-1)', except
+	     * that k1:n-1 refers to all of the rows in L, but many of the
+	     * rows are all zero.  Supernode d holds columns kd1 to kd2-1 of L.
+	     * Nonzero rows in the range k1:k2-1 are in the list
+	     * Ls [pdi1 ... pdi2-1], of size ndrow1.  Nonzero rows in the range
+	     * k2:n-1 are in the list Ls [pdi2 ... pdend], of size ndrow2.  Let
+	     * L1 = L (Ls [pdi1 ... pdi2-1], kd1:kd2-1), and let
+	     * L2 = L (Ls [pdi2 ... pdend],  kd1:kd2-1).  C is ndrow2-by-ndrow1.
+	     * Let C1 be the first ndrow1 rows of C and let C2 be the last
+	     * ndrow2-ndrow1 rows of C.  Only the lower triangular part of C1
+	     * needs to be computed since C1 is symmetric.
+	     */
+
+	    /* maxcsize is the largest size of C for all pairs (d,s) */
+	    ASSERT (ndrow2 * ndrow1 <= ((Int) L->maxcsize)) ;
+
+	    /* compute leading ndrow1-by-ndrow1 lower triangular block of C,
+	     * C1 = L1*L1' */
+
+            ndrow3 = ndrow2 - ndrow1 ;  /* number of rows of C2 */
+            ASSERT (ndrow3 >= 0) ;
+
+#ifdef GPU_BLAS
+            if (!TEMPLATE (CHOLMOD (gpu_updateC))
+                (ndrow1, ndrow2, ndrow, ndcol, pdx1, Lx, C, Common))
+#endif
+            {
+#ifndef NTIMER
+                Common->CHOLMOD_CPU_SYRK_CALLS++ ;
+                tstart = SuiteSparse_time () ;
+#endif
+#ifdef REAL
+                BLAS_dsyrk ("L", "N",
+                    ndrow1, ndcol,              /* N, K: L1 is ndrow1-by-ndcol*/
+                    one,                        /* ALPHA:  1 */
+                    Lx + L_ENTRY*pdx1, ndrow,   /* A, LDA: L1, ndrow */
+                    zero,                       /* BETA:   0 */
+                    C, ndrow2) ;                /* C, LDC: C1 */
+#else
+                BLAS_zherk ("L", "N",
+                    ndrow1, ndcol,              /* N, K: L1 is ndrow1-by-ndcol*/
+                    one,                        /* ALPHA:  1 */
+                    Lx + L_ENTRY*pdx1, ndrow,   /* A, LDA: L1, ndrow */
+                    zero,                       /* BETA:   0 */
+                    C, ndrow2) ;                /* C, LDC: C1 */
+#endif
+#ifndef NTIMER
+                Common->CHOLMOD_CPU_SYRK_TIME += SuiteSparse_time () - tstart ;
+#endif
+                /* compute remaining (ndrow2-ndrow1)-by-ndrow1 block of C,
+                 * C2 = L2*L1' */
+                if (ndrow3 > 0)
+                {
+#ifndef NTIMER
+                    Common->CHOLMOD_CPU_GEMM_CALLS++ ;
+                    tstart = SuiteSparse_time () ;
+#endif
+#ifdef REAL
+                    BLAS_dgemm ("N", "C",
+                        ndrow3, ndrow1, ndcol,  /* M, N, K */
+                        one,                    /* ALPHA:  1 */
+                        Lx + L_ENTRY*(pdx1 + ndrow1),   /* A, LDA: L2, ndrow */
+                        ndrow,
+                        Lx + L_ENTRY*pdx1,      /* B, LDB: L1, ndrow */
+                        ndrow,
+                        zero,                   /* BETA:   0 */
+                        C + L_ENTRY*ndrow1,     /* C, LDC: C2 */
+                        ndrow2) ;
+#else
+                    BLAS_zgemm ("N", "C",
+                        ndrow3, ndrow1, ndcol,  /* M, N, K */
+                        one,                    /* ALPHA:  1 */
+                        Lx + L_ENTRY*(pdx1 + ndrow1),/* A, LDA: L2, ndrow */
+                        ndrow,
+                        Lx + L_ENTRY*pdx1,      /* B, LDB: L1, ndrow */
+                        ndrow,
+                        zero,                   /* BETA:   0 */
+                        C + L_ENTRY*ndrow1, /* C, LDC: C2 */
+                        ndrow2) ;
+#endif
+#ifndef NTIMER
+                    Common->CHOLMOD_CPU_GEMM_TIME +=
+                        SuiteSparse_time () - tstart ;
+#endif
+                }
+            }
+
+	    DEBUG (CHOLMOD(dump_real) ("C", C, ndrow2, ndrow1, TRUE, L_ENTRY,
+			Common)) ;
+
+	    /* -------------------------------------------------------------- */
+	    /* construct relative map to assemble d into s */
+	    /* -------------------------------------------------------------- */
+
+	    for (i = 0 ; i < ndrow2 ; i++)
+	    {
+		RelativeMap [i] = Map [Ls [pdi1 + i]] ;
+		ASSERT (RelativeMap [i] >= 0 && RelativeMap [i] < nsrow) ;
+	    }
+
+
+            /* -------------------------------------------------------------- */
+            /* assemble C into supernode s using the relative map */
+            /* -------------------------------------------------------------- */
+
+#ifdef GPU_BLAS
+            TEMPLATE (CHOLMOD (gpu_syncSyrk)) (Common) ;
+            if (ndrow3 <= 0)
+            {
+#endif
+                /* non-GPU version, or GPU version when ndrow3 is zero */
+                pj = 0 ;
+                for (j = 0 ; j < ndrow1 ; j++)              /* cols k1:k2-1 */
+                {
+                    ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ;
+                    ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ;
+                    px = psx + RelativeMap [j] * nsrow ;
+                    for (i = j ; i < ndrow2 ; i++)          /* rows k1:n-1 */
+                    {
+                        ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ;
+                        ASSERT (RelativeMap [i] >= j && RelativeMap[i] < nsrow);
+                        /* Lx [px + RelativeMap [i]] -= C [i + pj] ; */
+                        q = px + RelativeMap [i] ;
+                        L_ASSEMBLESUB (Lx,q, C, i+pj) ;
+                    }
+                    pj += ndrow2 ;
+                }
+#ifdef GPU_BLAS
+            }
+            else
+            {
+                /* GPU version when ndrow3 > zero, splits into two parts */
+#ifndef NTIMER
+                tstart = SuiteSparse_time () ;
+#endif
+                pj = 0 ;
+                for (j = 0 ; j < ndrow1 ; j++)              /* cols k1:k2-1 */
+                {
+                    ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ;
+                    ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ;
+                    px = psx + RelativeMap [j] * nsrow ;
+                    for (i = j ; i < ndrow1 ; i++)          /* rows k1:k2-1 */
+                    {
+                        ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ;
+                        ASSERT (RelativeMap [i] >= j && RelativeMap[i] < nsrow);
+                        /* Lx [px + RelativeMap [i]] -= C [i + pj] ; */
+                        q = px + RelativeMap [i] ;
+                        L_ASSEMBLESUB (Lx,q, C, i+pj) ;
+                    }
+                    pj += ndrow2 ;
+                }
+#ifndef NTIMER
+                Common->CHOLMOD_ASSEMBLE_TIME2 += SuiteSparse_time () - tstart ;
+#endif
+                /* wait for dgemm to finish */
+                TEMPLATE (CHOLMOD (gpu_syncGemm)) (Common) ;
+                pj = 0 ;
+                for (j = 0 ; j < ndrow1 ; j++)              /* cols k1:k2-1 */
+                {
+                    ASSERT (RelativeMap [j] == Map [Ls [pdi1 + j]]) ;
+                    ASSERT (RelativeMap [j] >= 0 && RelativeMap [j] < nscol) ;
+                    px = psx + RelativeMap [j] * nsrow ;
+                    for (i = ndrow1 ; i < ndrow2 ; i++) /* rows k2:n-1 */
+                    {
+                        ASSERT (RelativeMap [i] == Map [Ls [pdi1 + i]]) ;
+                        ASSERT (RelativeMap [i] >= j && RelativeMap[i] < nsrow);
+                        /* Lx [px + RelativeMap [i]] -= C [i + pj] ; */
+                        q = px + RelativeMap [i] ;
+                        L_ASSEMBLESUB (Lx,q, C, i+pj) ;
+                    }
+                    pj += ndrow2 ;
+                }
+#ifndef NTIMER
+                Common->CHOLMOD_ASSEMBLE_TIME += SuiteSparse_time () - tstart ;
+#endif
+            }
+#endif
+
+	    /* -------------------------------------------------------------- */
+	    /* prepare this supernode d for its next ancestor */
+	    /* -------------------------------------------------------------- */
+
+	    dnext = Next [d] ;
+
+	    if (!repeat_supernode)
+	    {
+		/* If node s is being repeated, Head [dancestor] has already
+		 * been cleared (set to EMPTY).  It must remain EMPTY.  The
+		 * dancestor will not be factorized since the factorization
+		 * terminates at node s. */
+		Lpos [d] = pdi2 - pdi ;
+		if (Lpos [d] < ndrow)
+		{
+		    dancestor = SuperMap [Ls [pdi2]] ;
+		    ASSERT (dancestor > s && dancestor < nsuper) ;
+		    /* place d in the link list of its next ancestor */
+		    Next [d] = Head [dancestor] ;
+		    Head [dancestor] = d ;
+		}
+	    }
+	}
+
+	PRINT1 (("\nSupernode with contributions A: repeat: "ID"\n",
+		    repeat_supernode)) ;
+	DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+		    Common)) ;
+	PRINT1 (("\n\n")) ;
+
+	/* ------------------------------------------------------------------ */
+	/* factorize diagonal block of supernode s in LL' */
+	/* ------------------------------------------------------------------ */
+
+	/* The current supernode s is ready to factorize.  It has been updated
+	 * by all descendant supernodes.  Let S = the current supernode, which
+	 * holds rows k1:n-1 and columns k1:k2-1 of the updated matrix.   It
+	 * splits into two parts:  the square diagonal block S1, and the
+	 * rectangular part S2.  Here, S1 is factorized into L1*L1' and
+	 * overwritten by L1.
+	 *
+	 * If supernode s is being repeated, only factorize it up to but not
+	 * including the column containing the problematic entry.
+	 */
+
+	nscol2 = (repeat_supernode) ? (nscol_new) : (nscol) ;
+
+#ifdef GPU_BLAS
+        if (!TEMPLATE (CHOLMOD (gpu_lower_potrf))
+            (nscol2, nsrow, psx, Lx, &info, Common))
+#endif
+        {
+#ifndef NTIMER
+            Common->CHOLMOD_CPU_POTRF_CALLS++ ;
+            tstart = SuiteSparse_time () ;
+#endif
+#ifdef REAL
+            LAPACK_dpotrf ("L",
+                nscol2,                     /* N: nscol2 */
+                Lx + L_ENTRY*psx, nsrow,    /* A, LDA: S1, nsrow */
+                info) ;                     /* INFO */
+#else
+            LAPACK_zpotrf ("L",
+                nscol2,                     /* N: nscol2 */
+                Lx + L_ENTRY*psx, nsrow,    /* A, LDA: S1, nsrow */
+                info) ;                     /* INFO */
+#endif
+#ifndef NTIMER
+            Common->CHOLMOD_CPU_POTRF_TIME += SuiteSparse_time ()- tstart ;
+#endif
+        }
+
+	/* ------------------------------------------------------------------ */
+	/* check if the matrix is not positive definite */
+	/* ------------------------------------------------------------------ */
+
+	if (repeat_supernode)
+	{
+	    /* the leading part has been refactorized; it must have succeeded */
+	    info = 0 ;
+
+	    /* zero out the rest of this supernode */
+	    p = psx + nsrow * nscol_new ;
+	    pend = psx + nsrow * nscol ;	    /* s is nsrow-by-nscol */
+	    for ( ; p < pend ; p++)
+	    {
+		/* Lx [p] = 0 ; */
+		L_CLEAR (Lx,p) ;
+	    }
+	}
+
+	/* info is set to one in LAPACK_*potrf if blas_ok is FALSE.  It is
+	 * set to zero in dpotrf/zpotrf if the factorization was successful. */
+	if (CHECK_BLAS_INT && !Common->blas_ok)
+	{
+	    ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+	}
+
+	if (info != 0)
+	{
+	    /* Matrix is not positive definite.  dpotrf/zpotrf do NOT report an
+	     * error if the diagonal of L has NaN's, only if it has a zero. */
+	    if (Common->status == CHOLMOD_OK)
+	    {
+		ERROR (CHOLMOD_NOT_POSDEF, "matrix not positive definite") ;
+	    }
+
+	    /* L->minor is the column of L that contains a zero or negative
+	     * diagonal term. */
+	    L->minor = k1 + info - 1 ;
+
+	    /* clear the link lists of all subsequent supernodes */
+	    for (ss = s+1 ; ss < nsuper ; ss++)
+	    {
+		Head [ss] = EMPTY ;
+	    }
+
+	    /* zero this supernode, and all remaining supernodes */
+	    pend = L->xsize ;
+	    for (p = psx ; p < pend ; p++)
+	    {
+		/* Lx [p] = 0. ; */
+		L_CLEAR (Lx,p) ;
+	    }
+
+	    /* If L is indefinite, it still contains useful information.
+	     * Supernodes 0 to s-1 are valid, similar to MATLAB [R,p]=chol(A),
+	     * where the 1-based p is identical to the 0-based L->minor.  Since
+	     * L->minor is in the current supernode s, it and any columns to the
+	     * left of it in supernode s are also all zero.  This differs from
+	     * [R,p]=chol(A), which contains nonzero rows 1 to p-1.  Fix this
+	     * by setting repeat_supernode to TRUE, and repeating supernode s.
+	     *
+	     * If Common->quick_return_if_not_posdef is true, then the entire
+	     * supernode s is not factorized; it is left as all zero.
+	     */
+
+	    if (info == 1 || Common->quick_return_if_not_posdef)
+	    {
+		/* If the first column of supernode s contains a zero or
+		 * negative diagonal entry, then it is already properly set to
+		 * zero.  Also, info will be 1 if integer overflow occured in
+		 * the BLAS. */
+		Head [s] = EMPTY ;
+#ifdef GPU_BLAS
+                TEMPLATE (CHOLMOD (gpu_end)) (Common) ;
+#endif
+		return (Common->status >= CHOLMOD_OK) ;
+	    }
+	    else
+	    {
+		/* Repeat supernode s, but only factorize it up to but not
+		 * including the column containing the problematic diagonal
+		 * entry. */
+		repeat_supernode = TRUE ;
+		s-- ;
+		nscol_new = info - 1 ;
+		continue ;
+	    }
+	}
+
+	/* ------------------------------------------------------------------ */
+	/* compute the subdiagonal block and prepare supernode for its parent */
+	/* ------------------------------------------------------------------ */
+
+	nsrow2 = nsrow - nscol2 ;
+	if (nsrow2 > 0)
+	{
+	    /* The current supernode is columns k1 to k2-1 of L.  Let L1 be the
+	     * diagonal block (factorized by dpotrf/zpotrf above; rows/cols
+	     * k1:k2-1), and L2 be rows k2:n-1 and columns k1:k2-1 of L.  The
+	     * triangular system to solve is L2*L1' = S2, where S2 is
+	     * overwritten with L2.  More precisely, L2 = S2 / L1' in MATLAB
+	     * notation.
+	     */
+
+#ifdef GPU_BLAS
+            if (!TEMPLATE (CHOLMOD (gpu_triangular_solve))
+                (nsrow2, nscol2, nsrow, psx, Lx, Common))
+#endif
+            {
+#ifndef NTIMER
+                Common->CHOLMOD_CPU_TRSM_CALLS++ ;
+                tstart = SuiteSparse_time () ;
+#endif
+#ifdef REAL
+                BLAS_dtrsm ("R", "L", "C", "N",
+                    nsrow2, nscol2,                     /* M, N */
+                    one,                                /* ALPHA: 1 */
+                    Lx + L_ENTRY*psx, nsrow,            /* A, LDA: L1, nsrow */
+                    Lx + L_ENTRY*(psx + nscol2),        /* B, LDB, L2, nsrow */
+                    nsrow) ;
+#else
+                BLAS_ztrsm ("R", "L", "C", "N",
+                    nsrow2, nscol2,                     /* M, N */
+                    one,                                /* ALPHA: 1 */
+                    Lx + L_ENTRY*psx, nsrow,            /* A, LDA: L1, nsrow */
+                    Lx + L_ENTRY*(psx + nscol2),        /* B, LDB, L2, nsrow */
+                    nsrow) ;
+#endif
+#ifndef NTIMER
+                Common->CHOLMOD_CPU_TRSM_TIME += SuiteSparse_time () - tstart ;
+#endif
+            }
+
+	    if (CHECK_BLAS_INT && !Common->blas_ok)
+	    {
+		ERROR (CHOLMOD_TOO_LARGE, "problem too large for the BLAS") ;
+	    }
+
+	    if (!repeat_supernode)
+	    {
+		/* Lpos [s] is offset of first row of s affecting its parent */
+		Lpos [s] = nscol ;
+		sparent = SuperMap [Ls [psi + nscol]] ;
+		ASSERT (sparent != EMPTY) ;
+		ASSERT (Ls [psi + nscol] >= Super [sparent]) ;
+		ASSERT (Ls [psi + nscol] <  Super [sparent+1]) ;
+		ASSERT (SuperMap [Ls [psi + nscol]] == sparent) ;
+		ASSERT (sparent > s && sparent < nsuper) ;
+		/* place s in link list of its parent */
+		Next [s] = Head [sparent] ;
+		Head [sparent] = s ;
+	    }
+	}
+
+	Head [s] = EMPTY ;	/* link list for supernode s no longer needed */
+
+	/* clear the Map (debugging only, to detect changes in pattern of A) */
+	DEBUG (for (k = 0 ; k < nsrow ; k++) Map [Ls [psi + k]] = EMPTY) ;
+	DEBUG (CHOLMOD(dump_super) (s, Super, Lpi, Ls, Lpx, Lx, L_ENTRY,
+		    Common)) ;
+
+	if (repeat_supernode)
+	{
+	    /* matrix is not positive definite; finished clean-up for supernode
+	     * containing negative diagonal */
+
+#ifdef GPU_BLAS
+            TEMPLATE (CHOLMOD (gpu_end)) (Common) ;
+#endif
+	    return (Common->status >= CHOLMOD_OK) ;
+	}
+    }
+
+    /* success; matrix is positive definite */
+    L->minor = n ;
+#ifdef GPU_BLAS
+    TEMPLATE (CHOLMOD (gpu_end)) (Common) ;
+#endif
+    return (Common->status >= CHOLMOD_OK) ;
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/CHOLMOD/Supernodal/t_cholmod_super_solve.c b/src/CHOLMOD/Supernodal/t_cholmod_super_solve.c
new file mode 100644
index 0000000..4907397
--- /dev/null
+++ b/src/CHOLMOD/Supernodal/t_cholmod_super_solve.c
@@ -0,0 +1,450 @@
+/* ========================================================================== */
+/* === Supernodal/t_cholmod_super_solve ===================================== */
+/* ========================================================================== */
+
+/* -----------------------------------------------------------------------------
+ * CHOLMOD/Supernodal Module.  Copyright (C) 2005-2006, Timothy A. Davis
+ * The CHOLMOD/Supernodal Module is licensed under Version 2.0 of the GNU
+ * General Public License.  See gpl.txt for a text of the license.
+ * CHOLMOD is also available under other licenses; contact authors for details.
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Template routine for cholmod_super_solve.  Supports real or complex L. */
+
+#include "cholmod_template.h"
+
+#ifdef USING_R
+#include <Rconfig.h>
+#ifdef HAVE_F77_UNDERSCORE
+# define F77_CALL(x)    x ## _
+#else
+# define F77_CALL(x)    x
+#endif
+#define F77_NAME(x)    F77_CALL(x)
+#define F77_SUB(x)     F77_CALL(x)
+#define F77_COM(x)     F77_CALL(x)
+#define F77_COMDECL(x) F77_CALL(x)
+void F77_NAME(dsyrk)(const char *uplo, const char *trans,
+		     const int *n, const int *k,
+		     const double *alpha, const double *a, const int *lda,
+		     const double *beta, double *c, const int *ldc);
+
+void F77_NAME(dpotrf)(const char* uplo, const int* n,
+		      double* a, const int* lda, int* info);
+
+void F77_NAME(dtrsm)(const char *side, const char *uplo,
+		     const char *transa, const char *diag,
+		     const int *m, const int *n, const double *alpha,
+		     const double *a, const int *lda,
+		     double *b, const int *ldb);
+
+void F77_NAME(dtrsv)(const char *uplo, const char *trans,
+		     const char *diag, const int *n,
+		     const double *a, const int *lda,
+		     double *x, const int *incx);
+#endif
+
+static void TEMPLATE (cholmod_super_lsolve)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Xx, *Ex ;
+    double minus_one [2], one [2] ;
+    Int *Lpi, *Lpx, *Ls, *Super ;
+    Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s,
+	nsrow2, n, ps2, j, i, d, nrhs ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrhs = X->ncol ;
+    Ex = E->x ;
+    Xx = X->x ;
+    n = L->n ;
+    d = X->d ;
+
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+    Lx = L->x ;
+    minus_one [0] = -1.0 ;
+    minus_one [1] = 0 ;
+    one [0] = 1.0 ;
+    one [1] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* solve Lx=b */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrhs == 1)
+    {
+
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal.
+	     * L2 is nsrow2-by-nscol.  L1 and L2 have leading dimension of
+	     * nsrow.  x1 is nscol-by-nsrow, with leading dimension n.
+	     * E is nsrow2-by-1, with leading dimension nsrow2.
+	     */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		/* Ex [ii] = Xx [Ls [ps2 + ii]] ; */
+		ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ;
+	    }
+
+#ifdef REAL
+
+	    /* solve L1*x1 (that is, x1 = L1\x1) */
+	    BLAS_dtrsv ("L", "N", "N",
+		nscol,			    /* N:       L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* X, INCX: x1 */
+
+	    /* E = E - L2*x1 */
+	    BLAS_dgemv ("N",
+		nsrow2, nscol,		    /* M, N:    L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Xx + ENTRY_SIZE*k1, 1,	    /* X, INCX: x1 */
+		one,			    /* BETA:    1 */
+		Ex, 1) ;		    /* Y, INCY: E */
+
+#else
+
+	    /* solve L1*x1 (that is, x1 = L1\x1) */
+	    BLAS_ztrsv ("L", "N", "N",
+		nscol,			    /* N:       L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow, /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* X, INCX: x1 */
+
+	    /* E = E - L2*x1 */
+	    BLAS_zgemv ("N",
+		nsrow2, nscol,		    /* M, N:    L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Xx + ENTRY_SIZE*k1, 1,	    /* X, INCX: x1 */
+		one,			    /* BETA:    1 */
+		Ex, 1) ;		    /* Y, INCY: E */
+
+#endif
+
+	    /* scatter E back into X */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		/* Xx [Ls [ps2 + ii]] = Ex [ii] ; */
+		ASSIGN (Xx,-,Ls [ps2 + ii], Ex,-,ii) ;
+	    }
+	}
+    }
+    else
+    {
+
+	for (s = 0 ; s < nsuper ; s++)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		i = Ls [ps2 + ii] ;
+		for (j = 0 ; j < nrhs ; j++)
+		{
+		    /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */
+		    ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ;
+		}
+	    }
+
+#ifdef REAL
+
+	    /* solve L1*x1 */
+	    BLAS_dtrsm ("L", "L", "N", "N",
+		nscol, nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+	    /* E = E - L2*x1 */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_dgemm ("N", "N",
+		    nsrow2, nrhs, nscol,	    /* M, N, K */
+		    minus_one,			    /* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Xx + ENTRY_SIZE*k1, d,	    /* B, LDB: X1 */
+		    one,			    /* BETA:   1 */
+		    Ex, nsrow2) ;		    /* C, LDC: E */
+	    }
+
+#else
+
+	    /* solve L1*x1 */
+	    BLAS_ztrsm ("L", "L", "N", "N",
+		nscol, nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+	    /* E = E - L2*x1 */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_zgemm ("N", "N",
+		    nsrow2, nrhs, nscol,	    /* M, N, K */
+		    minus_one,			    /* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Xx + ENTRY_SIZE*k1, d,	    /* B, LDB: X1 */
+		    one,			    /* BETA:   1 */
+		    Ex, nsrow2) ;		    /* C, LDC: E */
+	    }
+
+#endif
+
+	    /* scatter E back into X */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		i = Ls [ps2 + ii] ;
+		for (j = 0 ; j < nrhs ; j++)
+		{
+		    /* Xx [i + j*d] = Ex [ii + j*nsrow2] ; */
+		    ASSIGN (Xx,-,i+j*d, Ex,-,ii+j*nsrow2) ;
+		}
+	    }
+	}
+    }
+}
+
+
+static void TEMPLATE (cholmod_super_ltsolve)
+(
+    /* ---- input ---- */
+    cholmod_factor *L,	/* factor to use for the forward solve */
+    /* ---- output ---- */
+    cholmod_dense *X,	/* b on input, solution to Lx=b on output */
+    /* ---- workspace ---- */
+    cholmod_dense *E,	/* workspace of size nrhs*(L->maxesize) */
+    /* --------------- */
+    cholmod_common *Common
+)
+{
+    double *Lx, *Xx, *Ex ;
+    double minus_one [2], one [2] ;
+    Int *Lpi, *Lpx, *Ls, *Super ;
+    Int nsuper, k1, k2, psi, psend, psx, nsrow, nscol, ii, s,
+	nsrow2, n, ps2, j, i, d, nrhs ;
+
+    /* ---------------------------------------------------------------------- */
+    /* get inputs */
+    /* ---------------------------------------------------------------------- */
+
+    nrhs = X->ncol ;
+    Ex = E->x ;
+    Xx = X->x ;
+    n = L->n ;
+    d = X->d ;
+
+    nsuper = L->nsuper ;
+    Lpi = L->pi ;
+    Lpx = L->px ;
+    Ls = L->s ;
+    Super = L->super ;
+    Lx = L->x ;
+    minus_one [0] = -1.0 ;
+    minus_one [1] = 0 ;
+    one [0] = 1.0 ;
+    one [1] = 0 ;
+
+    /* ---------------------------------------------------------------------- */
+    /* solve L'x=b */
+    /* ---------------------------------------------------------------------- */
+
+    if (nrhs == 1)
+    {
+
+	for (s = nsuper-1 ; s >= 0 ; s--)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* L1 is nscol-by-nscol, lower triangular with non-unit diagonal.
+	     * L2 is nsrow2-by-nscol.  L1 and L2 have leading dimension of
+	     * nsrow.  x1 is nscol-by-nsrow, with leading dimension n.
+	     * E is nsrow2-by-1, with leading dimension nsrow2.
+	     */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		/* Ex [ii] = Xx [Ls [ps2 + ii]] ; */
+		ASSIGN (Ex,-,ii, Xx,-,Ls [ps2 + ii]) ;
+	    }
+
+#ifdef REAL
+
+	    /* x1 = x1 - L2'*E */
+	    BLAS_dgemv ("C",
+		nsrow2, nscol,		    /* M, N: L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Ex, 1,			    /* X, INCX: Ex */
+		one,			    /* BETA:    1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* Y, INCY: x1 */
+
+	    /* solve L1'*x1 */
+	    BLAS_dtrsv ("L", "C", "N",
+		nscol,			    /* N:	L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow,	    /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;	    /* X, INCX: x1 */
+
+#else
+
+	    /* x1 = x1 - L2'*E */
+	    BLAS_zgemv ("C",
+		nsrow2, nscol,		    /* M, N: L2 is nsrow2-by-nscol */
+		minus_one,		    /* ALPHA:   -1 */
+		Lx + ENTRY_SIZE*(psx + nscol),   /* A, LDA:  L2 */
+		nsrow,
+		Ex, 1,			    /* X, INCX: Ex */
+		one,			    /* BETA:    1 */
+		Xx + ENTRY_SIZE*k1, 1) ;    /* Y, INCY: x1 */
+
+	    /* solve L1'*x1 */
+	    BLAS_ztrsv ("L", "C", "N",
+		nscol,			    /* N:	L1 is nscol-by-nscol */
+		Lx + ENTRY_SIZE*psx, nsrow,	    /* A, LDA:  L1 */
+		Xx + ENTRY_SIZE*k1, 1) ;	    /* X, INCX: x1 */
+
+#endif
+
+	}
+    }
+    else
+    {
+
+	for (s = nsuper-1 ; s >= 0 ; s--)
+	{
+	    k1 = Super [s] ;
+	    k2 = Super [s+1] ;
+	    psi = Lpi [s] ;
+	    psend = Lpi [s+1] ;
+	    psx = Lpx [s] ;
+	    nsrow = psend - psi ;
+	    nscol = k2 - k1 ;
+	    nsrow2 = nsrow - nscol ;
+	    ps2 = psi + nscol ;
+	    ASSERT ((size_t) nsrow2 <= L->maxesize) ;
+
+	    /* E is nsrow2-by-nrhs, with leading dimension nsrow2. */
+
+	    /* gather X into E */
+	    for (ii = 0 ; ii < nsrow2 ; ii++)
+	    {
+		i = Ls [ps2 + ii] ;
+		for (j = 0 ; j < nrhs ; j++)
+		{
+		    /* Ex [ii + j*nsrow2] = Xx [i + j*d] ; */
+		    ASSIGN (Ex,-,ii+j*nsrow2, Xx,-,i+j*d) ;
+		}
+	    }
+
+#ifdef REAL
+
+	    /* x1 = x1 - L2'*E */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_dgemm ("C", "N",
+		    nscol, nrhs, nsrow2,	/* M, N, K */
+		    minus_one,			/* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Ex, nsrow2,			/* B, LDB: E */
+		    one,			/* BETA:   1 */
+		    Xx + ENTRY_SIZE*k1, d) ;	/* C, LDC: x1 */
+	    }
+
+	    /* solve L1'*x1 */
+	    BLAS_dtrsm ("L", "L", "C", "N",
+		nscol,	nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+#else
+
+	    /* x1 = x1 - L2'*E */
+	    if (nsrow2 > 0)
+	    {
+		BLAS_zgemm ("C", "N",
+		    nscol, nrhs, nsrow2,	/* M, N, K */
+		    minus_one,			/* ALPHA:  -1 */
+		    Lx + ENTRY_SIZE*(psx + nscol),  /* A, LDA: L2 */
+		    nsrow,
+		    Ex, nsrow2,			/* B, LDB: E */
+		    one,			/* BETA:   1 */
+		    Xx + ENTRY_SIZE*k1, d) ;	/* C, LDC: x1 */
+	    }
+
+	    /* solve L1'*x1 */
+	    BLAS_ztrsm ("L", "L", "C", "N",
+		nscol,	nrhs,			/* M, N: x1 is nscol-by-nrhs */
+		one,				/* ALPHA:  1 */
+		Lx + ENTRY_SIZE*psx, nsrow,	/* A, LDA: L1 */
+		Xx + ENTRY_SIZE*k1, d) ;	/* B, LDB: x1 */
+
+#endif
+
+	}
+    }
+}
+
+#undef PATTERN
+#undef REAL
+#undef COMPLEX
+#undef ZOMPLEX
diff --git a/src/COLAMD/Include/colamd.h b/src/COLAMD/Include/colamd.h
new file mode 100644
index 0000000..59e6c6b
--- /dev/null
+++ b/src/COLAMD/Include/colamd.h
@@ -0,0 +1,251 @@
+/* ========================================================================== */
+/* === colamd/symamd prototypes and definitions ============================= */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD include file
+
+    You must include this file (colamd.h) in any routine that uses colamd,
+    symamd, or the related macros and definitions.
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (DrTimothyAldenDavis at gmail.com).  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Notice:
+
+	Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+
+	THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY
+	EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+
+	Permission is hereby granted to use, copy, modify, and/or distribute
+	this program, provided that the Copyright, this License, and the
+	Availability of the original version is retained on all copies and made
+	accessible to the end-user of any code or package that includes COLAMD
+	or any modified version of COLAMD. 
+
+    Availability:
+
+	The colamd/symamd library is available at http://www.suitesparse.com
+	This file is required by the colamd.c, colamdmex.c, and symamdmex.c
+	files, and by any C code that calls the routines whose prototypes are
+	listed below, or that uses the colamd/symamd definitions listed below.
+
+*/
+
+#ifndef COLAMD_H
+#define COLAMD_H
+
+/* make it easy for C++ programs to include COLAMD */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === COLAMD version ======================================================= */
+/* ========================================================================== */
+
+/* COLAMD Version 2.4 and later will include the following definitions.
+ * As an example, to test if the version you are using is 2.4 or later:
+ *
+ * #ifdef COLAMD_VERSION
+ *	if (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4)) ...
+ * #endif
+ *
+ * This also works during compile-time:
+ *
+ *  #if defined(COLAMD_VERSION) && (COLAMD_VERSION >= COLAMD_VERSION_CODE (2,4))
+ *    printf ("This is version 2.4 or later\n") ;
+ *  #else
+ *    printf ("This is an early version\n") ;
+ *  #endif
+ *
+ * Versions 2.3 and earlier of COLAMD do not include a #define'd version number.
+ */
+
+#define COLAMD_DATE "Jun 1, 2012"
+#define COLAMD_VERSION_CODE(main,sub) ((main) * 1000 + (sub))
+#define COLAMD_MAIN_VERSION 2
+#define COLAMD_SUB_VERSION 8
+#define COLAMD_SUBSUB_VERSION 0
+#define COLAMD_VERSION \
+	COLAMD_VERSION_CODE(COLAMD_MAIN_VERSION,COLAMD_SUB_VERSION)
+
+/* ========================================================================== */
+/* === Knob and statistics definitions ====================================== */
+/* ========================================================================== */
+
+/* size of the knobs [ ] array.  Only knobs [0..1] are currently used. */
+#define COLAMD_KNOBS 20
+
+/* number of output statistics.  Only stats [0..6] are currently used. */
+#define COLAMD_STATS 20
+
+/* knobs [0] and stats [0]: dense row knob and output statistic. */
+#define COLAMD_DENSE_ROW 0
+
+/* knobs [1] and stats [1]: dense column knob and output statistic. */
+#define COLAMD_DENSE_COL 1
+
+/* knobs [2]: aggressive absorption */
+#define COLAMD_AGGRESSIVE 2
+
+/* stats [2]: memory defragmentation count output statistic */
+#define COLAMD_DEFRAG_COUNT 2
+
+/* stats [3]: colamd status:  zero OK, > 0 warning or notice, < 0 error */
+#define COLAMD_STATUS 3
+
+/* stats [4..6]: error info, or info on jumbled columns */ 
+#define COLAMD_INFO1 4
+#define COLAMD_INFO2 5
+#define COLAMD_INFO3 6
+
+/* error codes returned in stats [3]: */
+#define COLAMD_OK				(0)
+#define COLAMD_OK_BUT_JUMBLED			(1)
+#define COLAMD_ERROR_A_not_present		(-1)
+#define COLAMD_ERROR_p_not_present		(-2)
+#define COLAMD_ERROR_nrow_negative		(-3)
+#define COLAMD_ERROR_ncol_negative		(-4)
+#define COLAMD_ERROR_nnz_negative		(-5)
+#define COLAMD_ERROR_p0_nonzero			(-6)
+#define COLAMD_ERROR_A_too_small		(-7)
+#define COLAMD_ERROR_col_length_negative	(-8)
+#define COLAMD_ERROR_row_index_out_of_bounds	(-9)
+#define COLAMD_ERROR_out_of_memory		(-10)
+#define COLAMD_ERROR_internal_error		(-999)
+
+
+/* ========================================================================== */
+/* === Prototypes of user-callable routines ================================= */
+/* ========================================================================== */
+
+#include "SuiteSparse_config.h"
+
+size_t colamd_recommended	/* returns recommended value of Alen, */
+				/* or 0 if input arguments are erroneous */
+(
+    int nnz,			/* nonzeros in A */
+    int n_row,			/* number of rows in A */
+    int n_col			/* number of columns in A */
+) ;
+
+size_t colamd_l_recommended	/* returns recommended value of Alen, */
+				/* or 0 if input arguments are erroneous */
+(
+    SuiteSparse_long nnz,       /* nonzeros in A */
+    SuiteSparse_long n_row,     /* number of rows in A */
+    SuiteSparse_long n_col      /* number of columns in A */
+) ;
+
+void colamd_set_defaults	/* sets default parameters */
+(				/* knobs argument is modified on output */
+    double knobs [COLAMD_KNOBS]	/* parameter settings for colamd */
+) ;
+
+void colamd_l_set_defaults	/* sets default parameters */
+(				/* knobs argument is modified on output */
+    double knobs [COLAMD_KNOBS]	/* parameter settings for colamd */
+) ;
+
+int colamd			/* returns (1) if successful, (0) otherwise*/
+(				/* A and p arguments are modified on output */
+    int n_row,			/* number of rows in A */
+    int n_col,			/* number of columns in A */
+    int Alen,			/* size of the array A */
+    int A [],			/* row indices of A, of size Alen */
+    int p [],			/* column pointers of A, of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+    int stats [COLAMD_STATS]	/* colamd output statistics and error codes */
+) ;
+
+SuiteSparse_long colamd_l       /* returns (1) if successful, (0) otherwise*/
+(				/* A and p arguments are modified on output */
+    SuiteSparse_long n_row,     /* number of rows in A */
+    SuiteSparse_long n_col,     /* number of columns in A */
+    SuiteSparse_long Alen,      /* size of the array A */
+    SuiteSparse_long A [],      /* row indices of A, of size Alen */
+    SuiteSparse_long p [],      /* column pointers of A, of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameter settings for colamd */
+    SuiteSparse_long stats [COLAMD_STATS]   /* colamd output statistics
+                                             * and error codes */
+) ;
+
+int symamd				/* return (1) if OK, (0) otherwise */
+(
+    int n,				/* number of rows and columns of A */
+    int A [],				/* row indices of A */
+    int p [],				/* column pointers of A */
+    int perm [],			/* output permutation, size n_col+1 */
+    double knobs [COLAMD_KNOBS],	/* parameters (uses defaults if NULL) */
+    int stats [COLAMD_STATS],		/* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+    					/* pointer to calloc (ANSI C) or */
+					/* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+    					/* pointer to free (ANSI C) or */
+    					/* mxFree (for MATLAB mexFunction) */
+) ;
+
+SuiteSparse_long symamd_l               /* return (1) if OK, (0) otherwise */
+(
+    SuiteSparse_long n,                 /* number of rows and columns of A */
+    SuiteSparse_long A [],              /* row indices of A */
+    SuiteSparse_long p [],              /* column pointers of A */
+    SuiteSparse_long perm [],           /* output permutation, size n_col+1 */
+    double knobs [COLAMD_KNOBS],	/* parameters (uses defaults if NULL) */
+    SuiteSparse_long stats [COLAMD_STATS],  /* output stats and error codes */
+    void * (*allocate) (size_t, size_t),
+    					/* pointer to calloc (ANSI C) or */
+					/* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+    					/* pointer to free (ANSI C) or */
+    					/* mxFree (for MATLAB mexFunction) */
+) ;
+
+void colamd_report
+(
+    int stats [COLAMD_STATS]
+) ;
+
+void colamd_l_report
+(
+    SuiteSparse_long stats [COLAMD_STATS]
+) ;
+
+void symamd_report
+(
+    int stats [COLAMD_STATS]
+) ;
+
+void symamd_l_report
+(
+    SuiteSparse_long stats [COLAMD_STATS]
+) ;
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+EXTERN int (*colamd_printf) (const char *, ...) ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* COLAMD_H */
diff --git a/src/COLAMD/Makefile b/src/COLAMD/Makefile
new file mode 100644
index 0000000..622f793
--- /dev/null
+++ b/src/COLAMD/Makefile
@@ -0,0 +1,56 @@
+#------------------------------------------------------------------------------
+# COLAMD Makefile
+#------------------------------------------------------------------------------
+
+VERSION = 2.8.0
+
+default: all
+
+include ../SuiteSparse_config/SuiteSparse_config.mk
+
+demos: all
+
+# Compile all C code
+all:
+	( cd Lib    ; $(MAKE) )
+	( cd Demo   ; $(MAKE) )
+
+# compile just the C-callable libraries (not Demos)
+library:
+	( cd Lib    ; $(MAKE) )
+
+# remove object files, but keep the compiled programs and library archives
+clean:
+	( cd Lib    ; $(MAKE) clean )
+	( cd Demo   ; $(MAKE) clean )
+	( cd MATLAB ; $(RM) $(CLEAN) )
+
+# clean, and then remove compiled programs and library archives
+purge:
+	( cd Lib    ; $(MAKE) purge )
+	( cd Demo   ; $(MAKE) purge )
+	( cd MATLAB ; $(RM) $(CLEAN) ; $(RM) *.mex* )
+
+distclean: purge
+
+# get ready for distribution
+dist: purge
+	( cd Demo   ; $(MAKE) dist )
+
+ccode: library
+
+lib: library
+
+# install COLAMD
+install:
+	$(CP) Lib/libcolamd.a $(INSTALL_LIB)/libcolamd.$(VERSION).a
+	( cd $(INSTALL_LIB) ; ln -sf libcolamd.$(VERSION).a libcolamd.a )
+	$(CP) Include/colamd.h $(INSTALL_INCLUDE)
+	chmod 644 $(INSTALL_LIB)/libcolamd*.a
+	chmod 644 $(INSTALL_INCLUDE)/colamd.h
+
+# uninstall COLAMD
+uninstall:
+	$(RM) $(INSTALL_LIB)/libcolamd*.a
+	$(RM) $(INSTALL_INCLUDE)/colamd.h
+
diff --git a/src/COLAMD/README.txt b/src/COLAMD/README.txt
new file mode 100644
index 0000000..6c5edf0
--- /dev/null
+++ b/src/COLAMD/README.txt
@@ -0,0 +1,118 @@
+COLAMD, Copyright 1998-2012, Timothy A. Davis.  http://www.suitesparse.com
+-------------------------------------------------------------------------------
+
+The COLAMD column approximate minimum degree ordering algorithm computes
+a permutation vector P such that the LU factorization of A (:,P)
+tends to be sparser than that of A.  The Cholesky factorization of
+(A (:,P))'*(A (:,P)) will also tend to be sparser than that of A'*A.
+SYMAMD is a symmetric minimum degree ordering method based on COLAMD,
+available as a MATLAB-callable function.  It constructs a matrix M such
+that M'*M has the same pattern as A, and then uses COLAMD to compute a column
+ordering of M.  Colamd and symamd tend to be faster and generate better
+orderings than their MATLAB counterparts, colmmd and symmmd.
+
+To compile and test the colamd m-files and mexFunctions, just unpack the
+COLAMD/ directory from the COLAMD.tar.gz file, and run MATLAB from
+within that directory.  Next, type colamd_test to compile and test colamd
+and symamd.  This will work on any computer with MATLAB (Unix, PC, or Mac).
+Alternatively, type "make" (in Unix) to compile and run a simple example C
+code, without using MATLAB.
+
+To compile and install the colamd m-files and mexFunctions, just cd to
+COLAMD/MATLAB and type colamd_install in the MATLAB command window.
+A short demo will run.  Optionally, type colamd_test to run an extensive tests.
+Type "make" in Unix in the COLAMD directory to compile the C-callable
+library and to run a short demo.
+
+Colamd is a built-in routine in MATLAB, available from The 
+Mathworks, Inc.  Under most cases, the compiled COLAMD from Versions 2.0 to the
+current version do not differ.  Colamd Versions 2.2 and 2.3 differ only in their
+mexFunction interaces to MATLAB.  v2.4 fixes a bug in the symamd routine in
+v2.3.  The bug (in v2.3 and earlier) has no effect on the MATLAB symamd
+mexFunction.  v2.5 adds additional checks for integer overflow, so that
+the "int" version can be safely used with 64-bit pointers.  Refer to the
+ChangeLog for more details.
+
+To use colamd and symamd within an application written in C, all you need are
+colamd.c, colamd_global.c, and colamd.h, which are the C-callable
+colamd/symamd codes.  See colamd.c for more information on how to call
+colamd from a C program.
+
+Requires SuiteSparse_config, in the ../SuiteSparse_config directory relative to
+this directory.
+
+See the colamd.c file or http://www.suitesparse.com for the license to COLAMD.
+
+Related papers:
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+	minimum degree ordering algorithm, ACM Transactions on Mathematical
+	Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+	an approximate column minimum degree ordering algorithm, ACM
+	Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+	2004.
+
+	"An approximate minimum degree column ordering algorithm",
+	S. I. Larimore, MS Thesis, Dept. of Computer and Information
+	Science and Engineering, University of Florida, Gainesville, FL,
+	1998.  CISE Tech Report TR-98-016.
+
+	Approximate Deficiency for Ordering the Columns of a Matrix,
+	J. L. Kern, Senior Thesis, Dept. of Computer and Information
+	Science and Engineering, University of Florida, Gainesville, FL,
+	1999.
+
+
+Authors:  Stefan I. Larimore and Timothy A. Davis,
+in collaboration with John Gilbert, Xerox PARC (now at UC Santa Barbara),
+and Esmong Ng, Lawrence Berkeley National Laboratory (much of this work
+he did while at Oak Ridge National Laboratory). 
+
+COLAMD files:
+
+    Demo	    simple demo
+    Doc		    additional documentation (see colamd.c for more)
+    Include	    include file
+    Lib		    compiled C-callable library
+    Makefile	    primary Unix Makefile
+    MATLAB	    MATLAB functions
+    README.txt	    this file
+    Source	    C source code
+
+    ./Demo:
+    colamd_example.c	    simple example
+    colamd_example.out	    output of colamd_example.c
+    colamd_l_example.c	    simple example, long integers
+    colamd_l_example.out    output of colamd_l_example.c
+    Makefile		    Makefile for C demos
+
+    ./Doc:
+    ChangeLog	    change log
+    lesser.txt	    license
+
+    ./Include:
+    colamd.h	    include file
+
+    ./Lib:
+    Makefile	    Makefile for C-callable library
+
+    ./MATLAB:
+    colamd2.m		MATLAB interface for colamd2
+    colamd_demo.m	simple demo
+    colamd_install.m	compile and install colamd2 and symamd2
+    colamd_make.m	compile colamd2 and symamd2
+    colamdmex.ca	MATLAB mexFunction for colamd2
+    colamd_test.m	extensive test
+    colamdtestmex.c	test function for colamd
+    Contents.m		contents of the MATLAB directory
+    luflops.m		test code
+    Makefile		Makefile for MATLAB functions
+    symamd2.m		MATLAB interface for symamd2
+    symamdmex.c		MATLAB mexFunction for symamd2
+    symamdtestmex.c	test function for symamd
+
+    ./Source:
+    colamd.c		primary source code
+    colamd_global.c	globally defined function pointers (malloc, free, ...)
diff --git a/src/COLAMD/Source/colamd.c b/src/COLAMD/Source/colamd.c
new file mode 100644
index 0000000..a20e9e1
--- /dev/null
+++ b/src/COLAMD/Source/colamd.c
@@ -0,0 +1,3604 @@
+/* ========================================================================== */
+/* === colamd/symamd - a sparse matrix column ordering algorithm ============ */
+/* ========================================================================== */
+
+/* COLAMD / SYMAMD
+
+    colamd:  an approximate minimum degree column ordering algorithm,
+    	for LU factorization of symmetric or unsymmetric matrices,
+	QR factorization, least squares, interior point methods for
+	linear programming problems, and other related problems.
+
+    symamd:  an approximate minimum degree ordering algorithm for Cholesky
+    	factorization of symmetric matrices.
+
+    Purpose:
+
+	Colamd computes a permutation Q such that the Cholesky factorization of
+	(AQ)'(AQ) has less fill-in and requires fewer floating point operations
+	than A'A.  This also provides a good ordering for sparse partial
+	pivoting methods, P(AQ) = LU, where Q is computed prior to numerical
+	factorization, and P is computed during numerical factorization via
+	conventional partial pivoting with row interchanges.  Colamd is the
+	column ordering method used in SuperLU, part of the ScaLAPACK library.
+	It is also available as built-in function in MATLAB Version 6,
+	available from MathWorks, Inc. (http://www.mathworks.com).  This
+	routine can be used in place of colmmd in MATLAB.
+
+    	Symamd computes a permutation P of a symmetric matrix A such that the
+	Cholesky factorization of PAP' has less fill-in and requires fewer
+	floating point operations than A.  Symamd constructs a matrix M such
+	that M'M has the same nonzero pattern of A, and then orders the columns
+	of M using colmmd.  The column ordering of M is then returned as the
+	row and column ordering P of A. 
+
+    Authors:
+
+	The authors of the code itself are Stefan I. Larimore and Timothy A.
+	Davis (DrTimothyAldenDavis at gmail.com).  The algorithm was
+	developed in collaboration with John Gilbert, Xerox PARC, and Esmond
+	Ng, Oak Ridge National Laboratory.
+
+    Acknowledgements:
+
+	This work was supported by the National Science Foundation, under
+	grants DMS-9504974 and DMS-9803599.
+
+    Copyright and License:
+
+	Copyright (c) 1998-2007, Timothy A. Davis, All Rights Reserved.
+	COLAMD is also available under alternate licenses, contact T. Davis
+	for details.
+
+	This library is free software; you can redistribute it and/or
+	modify it under the terms of the GNU Lesser General Public
+	License as published by the Free Software Foundation; either
+	version 2.1 of the License, or (at your option) any later version.
+
+	This library 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
+	Lesser General Public License for more details.
+
+	You should have received a copy of the GNU Lesser General Public
+	License along with this library; if not, write to the Free Software
+	Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
+	USA
+
+	Permission is hereby granted to use or copy this program under the
+	terms of the GNU LGPL, provided that the Copyright, this License,
+	and the Availability of the original version is retained on all copies.
+	User documentation of any code that uses this code or any modified
+	version of this code must cite the Copyright, this License, the
+	Availability note, and "Used by permission." Permission to modify
+	the code and to distribute modified code is granted, provided the
+	Copyright, this License, and the Availability note are retained,
+	and a notice that the code was modified is included.
+
+    Availability:
+
+	The colamd/symamd library is available at http://www.suitesparse.com
+	Appears as ACM Algorithm 836.
+
+    See the ChangeLog file for changes since Version 1.0.
+
+    References:
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate column
+	minimum degree ordering algorithm, ACM Transactions on Mathematical
+	Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+	T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836: COLAMD,
+	an approximate column minimum degree ordering algorithm, ACM
+	Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+	2004.
+
+*/
+
+/* ========================================================================== */
+/* === Description of user-callable routines ================================ */
+/* ========================================================================== */
+
+/* COLAMD includes both int and SuiteSparse_long versions of all its routines.
+    The description below is for the int version.  For SuiteSparse_long, all
+    int arguments become SuiteSparse_long.  SuiteSparse_long is normally
+    defined as long, except for WIN64.
+
+    ----------------------------------------------------------------------------
+    colamd_recommended:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    size_t colamd_recommended (int nnz, int n_row, int n_col) ;
+	    size_t colamd_l_recommended (SuiteSparse_long nnz,
+                SuiteSparse_long n_row, SuiteSparse_long n_col) ;
+
+	Purpose:
+
+	    Returns recommended value of Alen for use by colamd.  Returns 0
+	    if any input argument is negative.  The use of this routine
+	    is optional.  Not needed for symamd, which dynamically allocates
+	    its own memory.
+
+	    Note that in v2.4 and earlier, these routines returned int or long.
+	    They now return a value of type size_t.
+
+	Arguments (all input arguments):
+
+	    int nnz ;		Number of nonzeros in the matrix A.  This must
+				be the same value as p [n_col] in the call to
+				colamd - otherwise you will get a wrong value
+				of the recommended memory to use.
+
+	    int n_row ;		Number of rows in the matrix A.
+
+	    int n_col ;		Number of columns in the matrix A.
+
+    ----------------------------------------------------------------------------
+    colamd_set_defaults:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    colamd_set_defaults (double knobs [COLAMD_KNOBS]) ;
+	    colamd_l_set_defaults (double knobs [COLAMD_KNOBS]) ;
+
+	Purpose:
+
+	    Sets the default parameters.  The use of this routine is optional.
+
+	Arguments:
+
+	    double knobs [COLAMD_KNOBS] ;	Output only.
+
+		NOTE: the meaning of the dense row/col knobs has changed in v2.4
+
+		knobs [0] and knobs [1] control dense row and col detection:
+
+		Colamd: rows with more than
+		max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n_col))
+		entries are removed prior to ordering.  Columns with more than
+		max (16, knobs [COLAMD_DENSE_COL] * sqrt (MIN (n_row,n_col)))
+		entries are removed prior to
+		ordering, and placed last in the output column ordering. 
+
+		Symamd: uses only knobs [COLAMD_DENSE_ROW], which is knobs [0].
+		Rows and columns with more than
+		max (16, knobs [COLAMD_DENSE_ROW] * sqrt (n))
+		entries are removed prior to ordering, and placed last in the
+		output ordering.
+
+		COLAMD_DENSE_ROW and COLAMD_DENSE_COL are defined as 0 and 1,
+		respectively, in colamd.h.  Default values of these two knobs
+		are both 10.  Currently, only knobs [0] and knobs [1] are
+		used, but future versions may use more knobs.  If so, they will
+		be properly set to their defaults by the future version of
+		colamd_set_defaults, so that the code that calls colamd will
+		not need to change, assuming that you either use
+		colamd_set_defaults, or pass a (double *) NULL pointer as the
+		knobs array to colamd or symamd.
+
+	    knobs [2]: aggressive absorption
+
+	        knobs [COLAMD_AGGRESSIVE] controls whether or not to do
+	        aggressive absorption during the ordering.  Default is TRUE.
+
+
+    ----------------------------------------------------------------------------
+    colamd:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    int colamd (int n_row, int n_col, int Alen, int *A, int *p,
+	    	double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS]) ;
+	    SuiteSparse_long colamd_l (SuiteSparse_long n_row,
+                SuiteSparse_long n_col, SuiteSparse_long Alen,
+                SuiteSparse_long *A, SuiteSparse_long *p, double knobs
+                [COLAMD_KNOBS], SuiteSparse_long stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Computes a column ordering (Q) of A such that P(AQ)=LU or
+	    (AQ)'AQ=LL' have less fill-in and require fewer floating point
+	    operations than factorizing the unpermuted matrix A or A'A,
+	    respectively.
+	    
+	Returns:
+
+	    TRUE (1) if successful, FALSE (0) otherwise.
+
+	Arguments:
+
+	    int n_row ;		Input argument.
+
+		Number of rows in the matrix A.
+		Restriction:  n_row >= 0.
+		Colamd returns FALSE if n_row is negative.
+
+	    int n_col ;		Input argument.
+
+		Number of columns in the matrix A.
+		Restriction:  n_col >= 0.
+		Colamd returns FALSE if n_col is negative.
+
+	    int Alen ;		Input argument.
+
+		Restriction (see note):
+		Alen >= 2*nnz + 6*(n_col+1) + 4*(n_row+1) + n_col
+		Colamd returns FALSE if these conditions are not met.
+
+		Note:  this restriction makes an modest assumption regarding
+		the size of the two typedef's structures in colamd.h.
+		We do, however, guarantee that
+
+			Alen >= colamd_recommended (nnz, n_row, n_col)
+
+		will be sufficient.  Note: the macro version does not check
+		for integer overflow, and thus is not recommended.  Use
+		the colamd_recommended routine instead.
+
+	    int A [Alen] ;	Input argument, undefined on output.
+
+		A is an integer array of size Alen.  Alen must be at least as
+		large as the bare minimum value given above, but this is very
+		low, and can result in excessive run time.  For best
+		performance, we recommend that Alen be greater than or equal to
+		colamd_recommended (nnz, n_row, n_col), which adds
+		nnz/5 to the bare minimum value given above.
+
+		On input, the row indices of the entries in column c of the
+		matrix are held in A [(p [c]) ... (p [c+1]-1)].  The row indices
+		in a given column c need not be in ascending order, and
+		duplicate row indices may be be present.  However, colamd will
+		work a little faster if both of these conditions are met
+		(Colamd puts the matrix into this format, if it finds that the
+		the conditions are not met).
+
+		The matrix is 0-based.  That is, rows are in the range 0 to
+		n_row-1, and columns are in the range 0 to n_col-1.  Colamd
+		returns FALSE if any row index is out of range.
+
+		The contents of A are modified during ordering, and are
+		undefined on output.
+
+	    int p [n_col+1] ;	Both input and output argument.
+
+		p is an integer array of size n_col+1.  On input, it holds the
+		"pointers" for the column form of the matrix A.  Column c of
+		the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+		entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+		for all c in the range 0 to n_col-1.  The value p [n_col] is
+		thus the total number of entries in the pattern of the matrix A.
+		Colamd returns FALSE if these conditions are not met.
+
+		On output, if colamd returns TRUE, the array p holds the column
+		permutation (Q, for P(AQ)=LU or (AQ)'(AQ)=LL'), where p [0] is
+		the first column index in the new ordering, and p [n_col-1] is
+		the last.  That is, p [k] = j means that column j of A is the
+		kth pivot column, in AQ, where k is in the range 0 to n_col-1
+		(p [0] = j means that column j of A is the first column in AQ).
+
+		If colamd returns FALSE, then no permutation is returned, and
+		p is undefined on output.
+
+	    double knobs [COLAMD_KNOBS] ;	Input argument.
+
+		See colamd_set_defaults for a description.
+
+	    int stats [COLAMD_STATS] ;		Output argument.
+
+		Statistics on the ordering, and error status.
+		See colamd.h for related definitions.
+		Colamd returns FALSE if stats is not present.
+
+		stats [0]:  number of dense or empty rows ignored.
+
+		stats [1]:  number of dense or empty columns ignored (and
+				ordered last in the output permutation p)
+				Note that a row can become "empty" if it
+				contains only "dense" and/or "empty" columns,
+				and similarly a column can become "empty" if it
+				only contains "dense" and/or "empty" rows.
+
+		stats [2]:  number of garbage collections performed.
+				This can be excessively high if Alen is close
+				to the minimum required value.
+
+		stats [3]:  status code.  < 0 is an error code.
+			    > 1 is a warning or notice.
+
+			0	OK.  Each column of the input matrix contained
+				row indices in increasing order, with no
+				duplicates.
+
+			1	OK, but columns of input matrix were jumbled
+				(unsorted columns or duplicate entries).  Colamd
+				had to do some extra work to sort the matrix
+				first and remove duplicate entries, but it
+				still was able to return a valid permutation
+				(return value of colamd was TRUE).
+
+					stats [4]: highest numbered column that
+						is unsorted or has duplicate
+						entries.
+					stats [5]: last seen duplicate or
+						unsorted row index.
+					stats [6]: number of duplicate or
+						unsorted row indices.
+
+			-1	A is a null pointer
+
+			-2	p is a null pointer
+
+			-3 	n_row is negative
+
+					stats [4]: n_row
+
+			-4	n_col is negative
+
+					stats [4]: n_col
+
+			-5	number of nonzeros in matrix is negative
+
+					stats [4]: number of nonzeros, p [n_col]
+
+			-6	p [0] is nonzero
+
+					stats [4]: p [0]
+
+			-7	A is too small
+
+					stats [4]: required size
+					stats [5]: actual size (Alen)
+
+			-8	a column has a negative number of entries
+
+					stats [4]: column with < 0 entries
+					stats [5]: number of entries in col
+
+			-9	a row index is out of bounds
+
+					stats [4]: column with bad row index
+					stats [5]: bad row index
+					stats [6]: n_row, # of rows of matrx
+
+			-10	(unused; see symamd.c)
+
+			-999	(unused; see symamd.c)
+
+		Future versions may return more statistics in the stats array.
+
+	Example:
+	
+	    See colamd_example.c for a complete example.
+
+	    To order the columns of a 5-by-4 matrix with 11 nonzero entries in
+	    the following nonzero pattern
+
+	    	x 0 x 0
+		x 0 x x
+		0 x x 0
+		0 0 x x
+		x x 0 0
+
+	    with default knobs and no output statistics, do the following:
+
+		#include "colamd.h"
+		#define ALEN 100
+		int A [ALEN] = {0, 1, 4, 2, 4, 0, 1, 2, 3, 1, 3} ;
+		int p [ ] = {0, 3, 5, 9, 11} ;
+		int stats [COLAMD_STATS] ;
+		colamd (5, 4, ALEN, A, p, (double *) NULL, stats) ;
+
+	    The permutation is returned in the array p, and A is destroyed.
+
+    ----------------------------------------------------------------------------
+    symamd:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    int symamd (int n, int *A, int *p, int *perm,
+	    	double knobs [COLAMD_KNOBS], int stats [COLAMD_STATS],
+		void (*allocate) (size_t, size_t), void (*release) (void *)) ;
+	    SuiteSparse_long symamd_l (SuiteSparse_long n, SuiteSparse_long *A,
+                SuiteSparse_long *p, SuiteSparse_long *perm, double knobs
+                [COLAMD_KNOBS], SuiteSparse_long stats [COLAMD_STATS], void
+                (*allocate) (size_t, size_t), void (*release) (void *)) ;
+
+	Purpose:
+
+    	    The symamd routine computes an ordering P of a symmetric sparse
+	    matrix A such that the Cholesky factorization PAP' = LL' remains
+	    sparse.  It is based on a column ordering of a matrix M constructed
+	    so that the nonzero pattern of M'M is the same as A.  The matrix A
+	    is assumed to be symmetric; only the strictly lower triangular part
+	    is accessed.  You must pass your selected memory allocator (usually
+	    calloc/free or mxCalloc/mxFree) to symamd, for it to allocate
+	    memory for the temporary matrix M.
+
+	Returns:
+
+	    TRUE (1) if successful, FALSE (0) otherwise.
+
+	Arguments:
+
+	    int n ;		Input argument.
+
+	    	Number of rows and columns in the symmetrix matrix A.
+		Restriction:  n >= 0.
+		Symamd returns FALSE if n is negative.
+
+	    int A [nnz] ;	Input argument.
+
+	    	A is an integer array of size nnz, where nnz = p [n].
+		
+		The row indices of the entries in column c of the matrix are
+		held in A [(p [c]) ... (p [c+1]-1)].  The row indices in a
+		given column c need not be in ascending order, and duplicate
+		row indices may be present.  However, symamd will run faster
+		if the columns are in sorted order with no duplicate entries. 
+
+		The matrix is 0-based.  That is, rows are in the range 0 to
+		n-1, and columns are in the range 0 to n-1.  Symamd
+		returns FALSE if any row index is out of range.
+
+		The contents of A are not modified.
+
+	    int p [n+1] ;   	Input argument.
+
+		p is an integer array of size n+1.  On input, it holds the
+		"pointers" for the column form of the matrix A.  Column c of
+		the matrix A is held in A [(p [c]) ... (p [c+1]-1)].  The first
+		entry, p [0], must be zero, and p [c] <= p [c+1] must hold
+		for all c in the range 0 to n-1.  The value p [n] is
+		thus the total number of entries in the pattern of the matrix A.
+		Symamd returns FALSE if these conditions are not met.
+
+		The contents of p are not modified.
+
+	    int perm [n+1] ;   	Output argument.
+
+		On output, if symamd returns TRUE, the array perm holds the
+		permutation P, where perm [0] is the first index in the new
+		ordering, and perm [n-1] is the last.  That is, perm [k] = j
+		means that row and column j of A is the kth column in PAP',
+		where k is in the range 0 to n-1 (perm [0] = j means
+		that row and column j of A are the first row and column in
+		PAP').  The array is used as a workspace during the ordering,
+		which is why it must be of length n+1, not just n.
+
+	    double knobs [COLAMD_KNOBS] ;	Input argument.
+
+		See colamd_set_defaults for a description.
+
+	    int stats [COLAMD_STATS] ;		Output argument.
+
+		Statistics on the ordering, and error status.
+		See colamd.h for related definitions.
+		Symamd returns FALSE if stats is not present.
+
+		stats [0]:  number of dense or empty row and columns ignored
+				(and ordered last in the output permutation 
+				perm).  Note that a row/column can become
+				"empty" if it contains only "dense" and/or
+				"empty" columns/rows.
+
+		stats [1]:  (same as stats [0])
+
+		stats [2]:  number of garbage collections performed.
+
+		stats [3]:  status code.  < 0 is an error code.
+			    > 1 is a warning or notice.
+
+			0	OK.  Each column of the input matrix contained
+				row indices in increasing order, with no
+				duplicates.
+
+			1	OK, but columns of input matrix were jumbled
+				(unsorted columns or duplicate entries).  Symamd
+				had to do some extra work to sort the matrix
+				first and remove duplicate entries, but it
+				still was able to return a valid permutation
+				(return value of symamd was TRUE).
+
+					stats [4]: highest numbered column that
+						is unsorted or has duplicate
+						entries.
+					stats [5]: last seen duplicate or
+						unsorted row index.
+					stats [6]: number of duplicate or
+						unsorted row indices.
+
+			-1	A is a null pointer
+
+			-2	p is a null pointer
+
+			-3	(unused, see colamd.c)
+
+			-4 	n is negative
+
+					stats [4]: n
+
+			-5	number of nonzeros in matrix is negative
+
+					stats [4]: # of nonzeros (p [n]).
+
+			-6	p [0] is nonzero
+
+					stats [4]: p [0]
+
+			-7	(unused)
+
+			-8	a column has a negative number of entries
+
+					stats [4]: column with < 0 entries
+					stats [5]: number of entries in col
+
+			-9	a row index is out of bounds
+
+					stats [4]: column with bad row index
+					stats [5]: bad row index
+					stats [6]: n_row, # of rows of matrx
+
+			-10	out of memory (unable to allocate temporary
+				workspace for M or count arrays using the
+				"allocate" routine passed into symamd).
+
+		Future versions may return more statistics in the stats array.
+
+	    void * (*allocate) (size_t, size_t)
+
+	    	A pointer to a function providing memory allocation.  The
+		allocated memory must be returned initialized to zero.  For a
+		C application, this argument should normally be a pointer to
+		calloc.  For a MATLAB mexFunction, the routine mxCalloc is
+		passed instead.
+
+	    void (*release) (size_t, size_t)
+
+	    	A pointer to a function that frees memory allocated by the
+		memory allocation routine above.  For a C application, this
+		argument should normally be a pointer to free.  For a MATLAB
+		mexFunction, the routine mxFree is passed instead.
+
+
+    ----------------------------------------------------------------------------
+    colamd_report:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    colamd_report (int stats [COLAMD_STATS]) ;
+	    colamd_l_report (SuiteSparse_long stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Prints the error status and statistics recorded in the stats
+	    array on the standard error output (for a standard C routine)
+	    or on the MATLAB output (for a mexFunction).
+
+	Arguments:
+
+	    int stats [COLAMD_STATS] ;	Input only.  Statistics from colamd.
+
+
+    ----------------------------------------------------------------------------
+    symamd_report:
+    ----------------------------------------------------------------------------
+
+	C syntax:
+
+	    #include "colamd.h"
+	    symamd_report (int stats [COLAMD_STATS]) ;
+	    symamd_l_report (SuiteSparse_long stats [COLAMD_STATS]) ;
+
+	Purpose:
+
+	    Prints the error status and statistics recorded in the stats
+	    array on the standard error output (for a standard C routine)
+	    or on the MATLAB output (for a mexFunction).
+
+	Arguments:
+
+	    int stats [COLAMD_STATS] ;	Input only.  Statistics from symamd.
+
+
+*/
+
+/* ========================================================================== */
+/* === Scaffolding code definitions  ======================================== */
+/* ========================================================================== */
+
+/* Ensure that debugging is turned off: */
+#ifndef NDEBUG
+#define NDEBUG
+#endif
+
+/* turn on debugging by uncommenting the following line
+ #undef NDEBUG
+*/
+
+/*
+   Our "scaffolding code" philosophy:  In our opinion, well-written library
+   code should keep its "debugging" code, and just normally have it turned off
+   by the compiler so as not to interfere with performance.  This serves
+   several purposes:
+
+   (1) assertions act as comments to the reader, telling you what the code
+	expects at that point.  All assertions will always be true (unless
+	there really is a bug, of course).
+
+   (2) leaving in the scaffolding code assists anyone who would like to modify
+	the code, or understand the algorithm (by reading the debugging output,
+	one can get a glimpse into what the code is doing).
+
+   (3) (gasp!) for actually finding bugs.  This code has been heavily tested
+	and "should" be fully functional and bug-free ... but you never know...
+
+    The code will become outrageously slow when debugging is
+    enabled.  To control the level of debugging output, set an environment
+    variable D to 0 (little), 1 (some), 2, 3, or 4 (lots).  When debugging,
+    you should see the following message on the standard output:
+
+    	colamd: debug version, D = 1 (THIS WILL BE SLOW!)
+
+    or a similar message for symamd.  If you don't, then debugging has not
+    been enabled.
+
+*/
+
+/* ========================================================================== */
+/* === Include files ======================================================== */
+/* ========================================================================== */
+
+#include "colamd.h"
+#include <limits.h>
+#include <math.h>
+
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+#include "matrix.h"
+#endif /* MATLAB_MEX_FILE */
+
+#if !defined (NPRINT) || !defined (NDEBUG)
+#include <stdio.h>
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+/* ========================================================================== */
+/* === int or SuiteSparse_long ============================================== */
+/* ========================================================================== */
+
+#ifdef DLONG
+
+#define Int SuiteSparse_long
+#define ID  SuiteSparse_long_id
+#define Int_MAX SuiteSparse_long_max
+
+#define COLAMD_recommended colamd_l_recommended
+#define COLAMD_set_defaults colamd_l_set_defaults
+#define COLAMD_MAIN colamd_l
+#define SYMAMD_MAIN symamd_l
+#define COLAMD_report colamd_l_report
+#define SYMAMD_report symamd_l_report
+
+#else
+
+#define Int int
+#define ID "%d"
+#define Int_MAX INT_MAX
+
+#define COLAMD_recommended colamd_recommended
+#define COLAMD_set_defaults colamd_set_defaults
+#define COLAMD_MAIN colamd
+#define SYMAMD_MAIN symamd
+#define COLAMD_report colamd_report
+#define SYMAMD_report symamd_report
+
+#endif
+
+/* ========================================================================== */
+/* === Row and Column structures ============================================ */
+/* ========================================================================== */
+
+/* User code that makes use of the colamd/symamd routines need not directly */
+/* reference these structures.  They are used only for colamd_recommended. */
+
+typedef struct Colamd_Col_struct
+{
+    Int start ;		/* index for A of first row in this column, or DEAD */
+			/* if column is dead */
+    Int length ;	/* number of rows in this column */
+    union
+    {
+	Int thickness ;	/* number of original columns represented by this */
+			/* col, if the column is alive */
+	Int parent ;	/* parent in parent tree super-column structure, if */
+			/* the column is dead */
+    } shared1 ;
+    union
+    {
+	Int score ;	/* the score used to maintain heap, if col is alive */
+	Int order ;	/* pivot ordering of this column, if col is dead */
+    } shared2 ;
+    union
+    {
+	Int headhash ;	/* head of a hash bucket, if col is at the head of */
+			/* a degree list */
+	Int hash ;	/* hash value, if col is not in a degree list */
+	Int prev ;	/* previous column in degree list, if col is in a */
+			/* degree list (but not at the head of a degree list) */
+    } shared3 ;
+    union
+    {
+	Int degree_next ;	/* next column, if col is in a degree list */
+	Int hash_next ;		/* next column, if col is in a hash list */
+    } shared4 ;
+
+} Colamd_Col ;
+
+typedef struct Colamd_Row_struct
+{
+    Int start ;		/* index for A of first col in this row */
+    Int length ;	/* number of principal columns in this row */
+    union
+    {
+	Int degree ;	/* number of principal & non-principal columns in row */
+	Int p ;		/* used as a row pointer in init_rows_cols () */
+    } shared1 ;
+    union
+    {
+	Int mark ;	/* for computing set differences and marking dead rows*/
+	Int first_column ;/* first column in row (used in garbage collection) */
+    } shared2 ;
+
+} Colamd_Row ;
+
+/* ========================================================================== */
+/* === Definitions ========================================================== */
+/* ========================================================================== */
+
+/* Routines are either PUBLIC (user-callable) or PRIVATE (not user-callable) */
+#define PUBLIC
+#define PRIVATE static
+
+#define DENSE_DEGREE(alpha,n) \
+    ((Int) MAX (16.0, (alpha) * sqrt ((double) (n))))
+
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define ONES_COMPLEMENT(r) (-(r)-1)
+
+/* -------------------------------------------------------------------------- */
+/* Change for version 2.1:  define TRUE and FALSE only if not yet defined */  
+/* -------------------------------------------------------------------------- */
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* -------------------------------------------------------------------------- */
+
+#define EMPTY	(-1)
+
+/* Row and column status */
+#define ALIVE	(0)
+#define DEAD	(-1)
+
+/* Column status */
+#define DEAD_PRINCIPAL		(-1)
+#define DEAD_NON_PRINCIPAL	(-2)
+
+/* Macros for row and column status update and checking. */
+#define ROW_IS_DEAD(r)			ROW_IS_MARKED_DEAD (Row[r].shared2.mark)
+#define ROW_IS_MARKED_DEAD(row_mark)	(row_mark < ALIVE)
+#define ROW_IS_ALIVE(r)			(Row [r].shared2.mark >= ALIVE)
+#define COL_IS_DEAD(c)			(Col [c].start < ALIVE)
+#define COL_IS_ALIVE(c)			(Col [c].start >= ALIVE)
+#define COL_IS_DEAD_PRINCIPAL(c)	(Col [c].start == DEAD_PRINCIPAL)
+#define KILL_ROW(r)			{ Row [r].shared2.mark = DEAD ; }
+#define KILL_PRINCIPAL_COL(c)		{ Col [c].start = DEAD_PRINCIPAL ; }
+#define KILL_NON_PRINCIPAL_COL(c)	{ Col [c].start = DEAD_NON_PRINCIPAL ; }
+
+/* ========================================================================== */
+/* === Colamd reporting mechanism =========================================== */
+/* ========================================================================== */
+
+#if defined (MATLAB_MEX_FILE) || defined (MATHWORKS)
+/* In MATLAB, matrices are 1-based to the user, but 0-based internally */
+#define INDEX(i) ((i)+1)
+#else
+/* In C, matrices are 0-based and indices are reported as such in *_report */
+#define INDEX(i) (i)
+#endif
+
+/* All output goes through the PRINTF macro.  */
+#define PRINTF(params) { if (colamd_printf != NULL) (void) colamd_printf params ; }
+
+/* ========================================================================== */
+/* === Prototypes of PRIVATE routines ======================================= */
+/* ========================================================================== */
+
+PRIVATE Int init_rows_cols
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int p [],
+    Int stats [COLAMD_STATS]
+) ;
+
+PRIVATE void init_scoring
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    double knobs [COLAMD_KNOBS],
+    Int *p_n_row2,
+    Int *p_n_col2,
+    Int *p_max_deg
+) ;
+
+PRIVATE Int find_ordering
+(
+    Int n_row,
+    Int n_col,
+    Int Alen,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int n_col2,
+    Int max_deg,
+    Int pfree,
+    Int aggressive
+) ;
+
+PRIVATE void order_children
+(
+    Int n_col,
+    Colamd_Col Col [],
+    Int p []
+) ;
+
+PRIVATE void detect_super_cols
+(
+
+#ifndef NDEBUG
+    Int n_col,
+    Colamd_Row Row [],
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],
+    Int A [],
+    Int head [],
+    Int row_start,
+    Int row_length
+) ;
+
+PRIVATE Int garbage_collection
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int *pfree
+) ;
+
+PRIVATE Int clear_mark
+(
+    Int tag_mark,
+    Int max_mark,
+    Int n_row,
+    Colamd_Row Row []
+) ;
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+) ;
+
+/* ========================================================================== */
+/* === Debugging prototypes and definitions ================================= */
+/* ========================================================================== */
+
+#ifndef NDEBUG
+
+#include <assert.h>
+
+/* colamd_debug is the *ONLY* global variable, and is only */
+/* present when debugging */
+
+PRIVATE Int colamd_debug = 0 ;	/* debug print level */
+
+#define DEBUG0(params) { PRINTF (params) ; }
+#define DEBUG1(params) { if (colamd_debug >= 1) PRINTF (params) ; }
+#define DEBUG2(params) { if (colamd_debug >= 2) PRINTF (params) ; }
+#define DEBUG3(params) { if (colamd_debug >= 3) PRINTF (params) ; }
+#define DEBUG4(params) { if (colamd_debug >= 4) PRINTF (params) ; }
+
+#ifdef MATLAB_MEX_FILE
+#define ASSERT(expression) (mxAssert ((expression), ""))
+#else
+#define ASSERT(expression) (assert (expression))
+#endif /* MATLAB_MEX_FILE */
+
+PRIVATE void colamd_get_debug	/* gets the debug print level from getenv */
+(
+    char *method
+) ;
+
+PRIVATE void debug_deg_lists
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+) ;
+
+PRIVATE void debug_mark
+(
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+) ;
+
+PRIVATE void debug_matrix
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+) ;
+
+PRIVATE void debug_structures
+(
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+) ;
+
+#else /* NDEBUG */
+
+/* === No debugging ========================================================= */
+
+#define DEBUG0(params) ;
+#define DEBUG1(params) ;
+#define DEBUG2(params) ;
+#define DEBUG3(params) ;
+#define DEBUG4(params) ;
+
+#define ASSERT(expression)
+
+#endif /* NDEBUG */
+
+/* ========================================================================== */
+/* === USER-CALLABLE ROUTINES: ============================================== */
+/* ========================================================================== */
+
+/* ========================================================================== */
+/* === colamd_recommended =================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_recommended routine returns the suggested size for Alen.  This
+    value has been determined to provide good balance between the number of
+    garbage collections and the memory requirements for colamd.  If any
+    argument is negative, or if integer overflow occurs, a 0 is returned as an
+    error condition.  2*nnz space is required for the row and column
+    indices of the matrix. COLAMD_C (n_col) + COLAMD_R (n_row) space is
+    required for the Col and Row arrays, respectively, which are internal to
+    colamd (roughly 6*n_col + 4*n_row).  An additional n_col space is the
+    minimal amount of "elbow room", and nnz/5 more space is recommended for
+    run time efficiency.
+
+    Alen is approximately 2.2*nnz + 7*n_col + 4*n_row + 10.
+
+    This function is not needed when using symamd.
+*/
+
+/* add two values of type size_t, and check for integer overflow */
+static size_t t_add (size_t a, size_t b, int *ok)
+{
+    (*ok) = (*ok) && ((a + b) >= MAX (a,b)) ;
+    return ((*ok) ? (a + b) : 0) ;
+}
+
+/* compute a*k where k is a small integer, and check for integer overflow */
+static size_t t_mult (size_t a, size_t k, int *ok)
+{
+    size_t i, s = 0 ;
+    for (i = 0 ; i < k ; i++)
+    {
+	s = t_add (s, a, ok) ;
+    }
+    return (s) ;
+}
+
+/* size of the Col and Row structures */
+#define COLAMD_C(n_col,ok) \
+    ((t_mult (t_add (n_col, 1, ok), sizeof (Colamd_Col), ok) / sizeof (Int)))
+
+#define COLAMD_R(n_row,ok) \
+    ((t_mult (t_add (n_row, 1, ok), sizeof (Colamd_Row), ok) / sizeof (Int)))
+
+
+PUBLIC size_t COLAMD_recommended	/* returns recommended value of Alen. */
+(
+    /* === Parameters ======================================================= */
+
+    Int nnz,			/* number of nonzeros in A */
+    Int n_row,			/* number of rows in A */
+    Int n_col			/* number of columns in A */
+)
+{
+    size_t s, c, r ;
+    int ok = TRUE ;
+    if (nnz < 0 || n_row < 0 || n_col < 0)
+    {
+	return (0) ;
+    }
+    s = t_mult (nnz, 2, &ok) ;	    /* 2*nnz */
+    c = COLAMD_C (n_col, &ok) ;	    /* size of column structures */
+    r = COLAMD_R (n_row, &ok) ;	    /* size of row structures */
+    s = t_add (s, c, &ok) ;
+    s = t_add (s, r, &ok) ;
+    s = t_add (s, n_col, &ok) ;	    /* elbow room */
+    s = t_add (s, nnz/5, &ok) ;	    /* elbow room */
+    ok = ok && (s < Int_MAX) ;
+    return (ok ? s : 0) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_set_defaults ================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd_set_defaults routine sets the default values of the user-
+    controllable parameters for colamd and symamd:
+
+	Colamd: rows with more than max (16, knobs [0] * sqrt (n_col))
+	entries are removed prior to ordering.  Columns with more than
+	max (16, knobs [1] * sqrt (MIN (n_row,n_col))) entries are removed
+	prior to ordering, and placed last in the output column ordering. 
+
+	Symamd: Rows and columns with more than max (16, knobs [0] * sqrt (n))
+	entries are removed prior to ordering, and placed last in the
+	output ordering.
+
+	knobs [0]	dense row control
+
+	knobs [1]	dense column control
+
+	knobs [2]	if nonzero, do aggresive absorption
+
+	knobs [3..19]	unused, but future versions might use this
+
+*/
+
+PUBLIC void COLAMD_set_defaults
+(
+    /* === Parameters ======================================================= */
+
+    double knobs [COLAMD_KNOBS]		/* knob array */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+
+    if (!knobs)
+    {
+	return ;			/* no knobs to initialize */
+    }
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+	knobs [i] = 0 ;
+    }
+    knobs [COLAMD_DENSE_ROW] = 10 ;
+    knobs [COLAMD_DENSE_COL] = 10 ;
+    knobs [COLAMD_AGGRESSIVE] = TRUE ;	/* default: do aggressive absorption*/
+}
+
+
+/* ========================================================================== */
+/* === symamd =============================================================== */
+/* ========================================================================== */
+
+PUBLIC Int SYMAMD_MAIN			/* return TRUE if OK, FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n,				/* number of rows and columns of A */
+    Int A [],				/* row indices of A */
+    Int p [],				/* column pointers of A */
+    Int perm [],			/* output permutation, size n+1 */
+    double knobs [COLAMD_KNOBS],	/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS],		/* output statistics and error codes */
+    void * (*allocate) (size_t, size_t),
+    					/* pointer to calloc (ANSI C) or */
+					/* mxCalloc (for MATLAB mexFunction) */
+    void (*release) (void *)
+    					/* pointer to free (ANSI C) or */
+    					/* mxFree (for MATLAB mexFunction) */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *count ;		/* length of each column of M, and col pointer*/
+    Int *mark ;			/* mark array for finding duplicate entries */
+    Int *M ;			/* row indices of matrix M */
+    size_t Mlen ;		/* length of M */
+    Int n_row ;			/* number of rows in M */
+    Int nnz ;			/* number of entries in A */
+    Int i ;			/* row index of A */
+    Int j ;			/* column index of A */
+    Int k ;			/* row index of M */ 
+    Int mnz ;			/* number of nonzeros in M */
+    Int pp ;			/* index into a column of A */
+    Int last_row ;		/* last row seen in the current column */
+    Int length ;		/* number of nonzeros in a column */
+
+    double cknobs [COLAMD_KNOBS] ;		/* knobs for colamd */
+    double default_knobs [COLAMD_KNOBS] ;	/* default knobs for colamd */
+
+#ifndef NDEBUG
+    colamd_get_debug ("symamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+	DEBUG0 (("symamd: stats not present\n")) ;
+	return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+	stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)
+    {
+    	stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+	DEBUG0 (("symamd: A not present\n")) ;
+	return (FALSE) ;
+    }
+
+    if (!p)		/* p is not present */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+	DEBUG0 (("symamd: p not present\n")) ;
+    	return (FALSE) ;
+    }
+
+    if (n < 0)		/* n must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+	stats [COLAMD_INFO1] = n ;
+	DEBUG0 (("symamd: n negative %d\n", n)) ;
+    	return (FALSE) ;
+    }
+
+    nnz = p [n] ;
+    if (nnz < 0)	/* nnz must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+	stats [COLAMD_INFO1] = nnz ;
+	DEBUG0 (("symamd: number of entries negative %d\n", nnz)) ;
+	return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero ;
+	stats [COLAMD_INFO1] = p [0] ;
+	DEBUG0 (("symamd: p[0] not zero %d\n", p [0])) ;
+	return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+	COLAMD_set_defaults (default_knobs) ;
+	knobs = default_knobs ;
+    }
+
+    /* === Allocate count and mark ========================================== */
+
+    count = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!count)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+	DEBUG0 (("symamd: allocate count (size %d) failed\n", n+1)) ;
+	return (FALSE) ;
+    }
+
+    mark = (Int *) ((*allocate) (n+1, sizeof (Int))) ;
+    if (!mark)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+	(*release) ((void *) count) ;
+	DEBUG0 (("symamd: allocate mark (size %d) failed\n", n+1)) ;
+	return (FALSE) ;
+    }
+
+    /* === Compute column counts of M, check if A is valid ================== */
+
+    stats [COLAMD_INFO3] = 0 ;  /* number of duplicate or unsorted row indices*/
+
+    for (i = 0 ; i < n ; i++)
+    {
+    	mark [i] = -1 ;
+    }
+
+    for (j = 0 ; j < n ; j++)
+    {
+	last_row = -1 ;
+
+	length = p [j+1] - p [j] ;
+	if (length < 0)
+	{
+	    /* column pointers must be non-decreasing */
+	    stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+	    stats [COLAMD_INFO1] = j ;
+	    stats [COLAMD_INFO2] = length ;
+	    (*release) ((void *) count) ;
+	    (*release) ((void *) mark) ;
+	    DEBUG0 (("symamd: col %d negative length %d\n", j, length)) ;
+	    return (FALSE) ;
+	}
+
+	for (pp = p [j] ; pp < p [j+1] ; pp++)
+	{
+	    i = A [pp] ;
+	    if (i < 0 || i >= n)
+	    {
+		/* row index i, in column j, is out of bounds */
+		stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+		stats [COLAMD_INFO1] = j ;
+		stats [COLAMD_INFO2] = i ;
+		stats [COLAMD_INFO3] = n ;
+		(*release) ((void *) count) ;
+		(*release) ((void *) mark) ;
+		DEBUG0 (("symamd: row %d col %d out of bounds\n", i, j)) ;
+		return (FALSE) ;
+	    }
+
+	    if (i <= last_row || mark [i] == j)
+	    {
+		/* row index is unsorted or repeated (or both), thus col */
+		/* is jumbled.  This is a notice, not an error condition. */
+		stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+		stats [COLAMD_INFO1] = j ;
+		stats [COLAMD_INFO2] = i ;
+		(stats [COLAMD_INFO3]) ++ ;
+		DEBUG1 (("symamd: row %d col %d unsorted/duplicate\n", i, j)) ;
+	    }
+
+	    if (i > j && mark [i] != j)
+	    {
+		/* row k of M will contain column indices i and j */
+		count [i]++ ;
+		count [j]++ ;
+	    }
+
+	    /* mark the row as having been seen in this column */
+	    mark [i] = j ;
+
+	    last_row = i ;
+	}
+    }
+
+    /* v2.4: removed free(mark) */
+
+    /* === Compute column pointers of M ===================================== */
+
+    /* use output permutation, perm, for column pointers of M */
+    perm [0] = 0 ;
+    for (j = 1 ; j <= n ; j++)
+    {
+	perm [j] = perm [j-1] + count [j-1] ;
+    }
+    for (j = 0 ; j < n ; j++)
+    {
+	count [j] = perm [j] ;
+    }
+
+    /* === Construct M ====================================================== */
+
+    mnz = perm [n] ;
+    n_row = mnz / 2 ;
+    Mlen = COLAMD_recommended (mnz, n_row, n) ;
+    M = (Int *) ((*allocate) (Mlen, sizeof (Int))) ;
+    DEBUG0 (("symamd: M is %d-by-%d with %d entries, Mlen = %g\n",
+    	n_row, n, mnz, (double) Mlen)) ;
+
+    if (!M)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_out_of_memory ;
+	(*release) ((void *) count) ;
+	(*release) ((void *) mark) ;
+	DEBUG0 (("symamd: allocate M (size %g) failed\n", (double) Mlen)) ;
+	return (FALSE) ;
+    }
+
+    k = 0 ;
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK)
+    {
+	/* Matrix is OK */
+	for (j = 0 ; j < n ; j++)
+	{
+	    ASSERT (p [j+1] - p [j] >= 0) ;
+	    for (pp = p [j] ; pp < p [j+1] ; pp++)
+	    {
+		i = A [pp] ;
+		ASSERT (i >= 0 && i < n) ;
+		if (i > j)
+		{
+		    /* row k of M contains column indices i and j */
+		    M [count [i]++] = k ;
+		    M [count [j]++] = k ;
+		    k++ ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* Matrix is jumbled.  Do not add duplicates to M.  Unsorted cols OK. */
+	DEBUG0 (("symamd: Duplicates in A.\n")) ;
+	for (i = 0 ; i < n ; i++)
+	{
+	    mark [i] = -1 ;
+	}
+	for (j = 0 ; j < n ; j++)
+	{
+	    ASSERT (p [j+1] - p [j] >= 0) ;
+	    for (pp = p [j] ; pp < p [j+1] ; pp++)
+	    {
+		i = A [pp] ;
+		ASSERT (i >= 0 && i < n) ;
+		if (i > j && mark [i] != j)
+		{
+		    /* row k of M contains column indices i and j */
+		    M [count [i]++] = k ;
+		    M [count [j]++] = k ;
+		    k++ ;
+		    mark [i] = j ;
+		}
+	    }
+	}
+	/* v2.4: free(mark) moved below */
+    }
+
+    /* count and mark no longer needed */
+    (*release) ((void *) count) ;
+    (*release) ((void *) mark) ;	/* v2.4: free (mark) moved here */
+    ASSERT (k == n_row) ;
+
+    /* === Adjust the knobs for M =========================================== */
+
+    for (i = 0 ; i < COLAMD_KNOBS ; i++)
+    {
+	cknobs [i] = knobs [i] ;
+    }
+
+    /* there are no dense rows in M */
+    cknobs [COLAMD_DENSE_ROW] = -1 ;
+    cknobs [COLAMD_DENSE_COL] = knobs [COLAMD_DENSE_ROW] ;
+
+    /* === Order the columns of M =========================================== */
+
+    /* v2.4: colamd cannot fail here, so the error check is removed */
+    (void) COLAMD_MAIN (n_row, n, (Int) Mlen, M, perm, cknobs, stats) ;
+
+    /* Note that the output permutation is now in perm */
+
+    /* === get the statistics for symamd from colamd ======================== */
+
+    /* a dense column in colamd means a dense row and col in symamd */
+    stats [COLAMD_DENSE_ROW] = stats [COLAMD_DENSE_COL] ;
+
+    /* === Free M =========================================================== */
+
+    (*release) ((void *) M) ;
+    DEBUG0 (("symamd: done.\n")) ;
+    return (TRUE) ;
+
+}
+
+/* ========================================================================== */
+/* === colamd =============================================================== */
+/* ========================================================================== */
+
+/*
+    The colamd routine computes a column ordering Q of a sparse matrix
+    A such that the LU factorization P(AQ) = LU remains sparse, where P is
+    selected via partial pivoting.   The routine can also be viewed as
+    providing a permutation Q such that the Cholesky factorization
+    (AQ)'(AQ) = LL' remains sparse.
+*/
+
+PUBLIC Int COLAMD_MAIN		/* returns TRUE if successful, FALSE otherwise*/
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows in A */
+    Int n_col,			/* number of columns in A */
+    Int Alen,			/* length of A */
+    Int A [],			/* row indices of A */
+    Int p [],			/* pointers to columns in A */
+    double knobs [COLAMD_KNOBS],/* parameters (uses defaults if NULL) */
+    Int stats [COLAMD_STATS]	/* output statistics and error codes */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;			/* loop index */
+    Int nnz ;			/* nonzeros in A */
+    size_t Row_size ;		/* size of Row [], in integers */
+    size_t Col_size ;		/* size of Col [], in integers */
+    size_t need ;		/* minimum required length of A */
+    Colamd_Row *Row ;		/* pointer into A of Row [0..n_row] array */
+    Colamd_Col *Col ;		/* pointer into A of Col [0..n_col] array */
+    Int n_col2 ;		/* number of non-dense, non-empty columns */
+    Int n_row2 ;		/* number of non-dense, non-empty rows */
+    Int ngarbage ;		/* number of garbage collections performed */
+    Int max_deg ;		/* maximum row degree */
+    double default_knobs [COLAMD_KNOBS] ;	/* default knobs array */
+    Int aggressive ;		/* do aggressive absorption */
+    int ok ;
+
+#ifndef NDEBUG
+    colamd_get_debug ("colamd") ;
+#endif /* NDEBUG */
+
+    /* === Check the input arguments ======================================== */
+
+    if (!stats)
+    {
+	DEBUG0 (("colamd: stats not present\n")) ;
+	return (FALSE) ;
+    }
+    for (i = 0 ; i < COLAMD_STATS ; i++)
+    {
+	stats [i] = 0 ;
+    }
+    stats [COLAMD_STATUS] = COLAMD_OK ;
+    stats [COLAMD_INFO1] = -1 ;
+    stats [COLAMD_INFO2] = -1 ;
+
+    if (!A)		/* A is not present */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_A_not_present ;
+	DEBUG0 (("colamd: A not present\n")) ;
+	return (FALSE) ;
+    }
+
+    if (!p)		/* p is not present */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p_not_present ;
+	DEBUG0 (("colamd: p not present\n")) ;
+    	return (FALSE) ;
+    }
+
+    if (n_row < 0)	/* n_row must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nrow_negative ;
+	stats [COLAMD_INFO1] = n_row ;
+	DEBUG0 (("colamd: nrow negative %d\n", n_row)) ;
+    	return (FALSE) ;
+    }
+
+    if (n_col < 0)	/* n_col must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_ncol_negative ;
+	stats [COLAMD_INFO1] = n_col ;
+	DEBUG0 (("colamd: ncol negative %d\n", n_col)) ;
+    	return (FALSE) ;
+    }
+
+    nnz = p [n_col] ;
+    if (nnz < 0)	/* nnz must be >= 0 */
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_nnz_negative ;
+	stats [COLAMD_INFO1] = nnz ;
+	DEBUG0 (("colamd: number of entries negative %d\n", nnz)) ;
+	return (FALSE) ;
+    }
+
+    if (p [0] != 0)
+    {
+	stats [COLAMD_STATUS] = COLAMD_ERROR_p0_nonzero	;
+	stats [COLAMD_INFO1] = p [0] ;
+	DEBUG0 (("colamd: p[0] not zero %d\n", p [0])) ;
+	return (FALSE) ;
+    }
+
+    /* === If no knobs, set default knobs =================================== */
+
+    if (!knobs)
+    {
+	COLAMD_set_defaults (default_knobs) ;
+	knobs = default_knobs ;
+    }
+
+    aggressive = (knobs [COLAMD_AGGRESSIVE] != FALSE) ;
+
+    /* === Allocate the Row and Col arrays from array A ===================== */
+
+    ok = TRUE ;
+    Col_size = COLAMD_C (n_col, &ok) ;	    /* size of Col array of structs */
+    Row_size = COLAMD_R (n_row, &ok) ;	    /* size of Row array of structs */
+
+    /* need = 2*nnz + n_col + Col_size + Row_size ; */
+    need = t_mult (nnz, 2, &ok) ;
+    need = t_add (need, n_col, &ok) ;
+    need = t_add (need, Col_size, &ok) ;
+    need = t_add (need, Row_size, &ok) ;
+
+    if (!ok || need > (size_t) Alen || need > Int_MAX)
+    {
+	/* not enough space in array A to perform the ordering */
+	stats [COLAMD_STATUS] = COLAMD_ERROR_A_too_small ;
+	stats [COLAMD_INFO1] = need ;
+	stats [COLAMD_INFO2] = Alen ;
+	DEBUG0 (("colamd: Need Alen >= %d, given only Alen = %d\n", need,Alen));
+	return (FALSE) ;
+    }
+
+    Alen -= Col_size + Row_size ;
+    Col = (Colamd_Col *) &A [Alen] ;
+    Row = (Colamd_Row *) &A [Alen + Col_size] ;
+
+    /* === Construct the row and column data structures ===================== */
+
+    if (!init_rows_cols (n_row, n_col, Row, Col, A, p, stats))
+    {
+	/* input matrix is invalid */
+	DEBUG0 (("colamd: Matrix invalid\n")) ;
+	return (FALSE) ;
+    }
+
+    /* === Initialize scores, kill dense rows/columns ======================= */
+
+    init_scoring (n_row, n_col, Row, Col, A, p, knobs,
+	&n_row2, &n_col2, &max_deg) ;
+
+    /* === Order the supercolumns =========================================== */
+
+    ngarbage = find_ordering (n_row, n_col, Alen, Row, Col, A, p,
+	n_col2, max_deg, 2*nnz, aggressive) ;
+
+    /* === Order the non-principal columns ================================== */
+
+    order_children (n_col, Col, p) ;
+
+    /* === Return statistics in stats ======================================= */
+
+    stats [COLAMD_DENSE_ROW] = n_row - n_row2 ;
+    stats [COLAMD_DENSE_COL] = n_col - n_col2 ;
+    stats [COLAMD_DEFRAG_COUNT] = ngarbage ;
+    DEBUG0 (("colamd: done.\n")) ; 
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === colamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void COLAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("colamd", stats) ;
+}
+
+
+/* ========================================================================== */
+/* === symamd_report ======================================================== */
+/* ========================================================================== */
+
+PUBLIC void SYMAMD_report
+(
+    Int stats [COLAMD_STATS]
+)
+{
+    print_report ("symamd", stats) ;
+}
+
+
+
+/* ========================================================================== */
+/* === NON-USER-CALLABLE ROUTINES: ========================================== */
+/* ========================================================================== */
+
+/* There are no user-callable routines beyond this point in the file */
+
+
+/* ========================================================================== */
+/* === init_rows_cols ======================================================= */
+/* ========================================================================== */
+
+/*
+    Takes the column form of the matrix in A and creates the row form of the
+    matrix.  Also, row and column attributes are stored in the Col and Row
+    structs.  If the columns are un-sorted or contain duplicate row indices,
+    this routine will also sort and remove duplicate row indices from the
+    column form of the matrix.  Returns FALSE if the matrix is invalid,
+    TRUE otherwise.  Not user-callable.
+*/
+
+PRIVATE Int init_rows_cols	/* returns TRUE if OK, or FALSE otherwise */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* row indices of A, of size Alen */
+    Int p [],			/* pointers to columns in A, of size n_col+1 */
+    Int stats [COLAMD_STATS]	/* colamd statistics */ 
+)
+{
+    /* === Local variables ================================================== */
+
+    Int col ;			/* a column index */
+    Int row ;			/* a row index */
+    Int *cp ;			/* a column pointer */
+    Int *cp_end ;		/* a pointer to the end of a column */
+    Int *rp ;			/* a row pointer */
+    Int *rp_end ;		/* a pointer to the end of a row */
+    Int last_row ;		/* previous row */
+
+    /* === Initialize columns, and check column pointers ==================== */
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	Col [col].start = p [col] ;
+	Col [col].length = p [col+1] - p [col] ;
+
+	if (Col [col].length < 0)
+	{
+	    /* column pointers must be non-decreasing */
+	    stats [COLAMD_STATUS] = COLAMD_ERROR_col_length_negative ;
+	    stats [COLAMD_INFO1] = col ;
+	    stats [COLAMD_INFO2] = Col [col].length ;
+	    DEBUG0 (("colamd: col %d length %d < 0\n", col, Col [col].length)) ;
+	    return (FALSE) ;
+	}
+
+	Col [col].shared1.thickness = 1 ;
+	Col [col].shared2.score = 0 ;
+	Col [col].shared3.prev = EMPTY ;
+	Col [col].shared4.degree_next = EMPTY ;
+    }
+
+    /* p [0..n_col] no longer needed, used as "head" in subsequent routines */
+
+    /* === Scan columns, compute row degrees, and check row indices ========= */
+
+    stats [COLAMD_INFO3] = 0 ;	/* number of duplicate or unsorted row indices*/
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Row [row].length = 0 ;
+	Row [row].shared2.mark = -1 ;
+    }
+
+    for (col = 0 ; col < n_col ; col++)
+    {
+	last_row = -1 ;
+
+	cp = &A [p [col]] ;
+	cp_end = &A [p [col+1]] ;
+
+	while (cp < cp_end)
+	{
+	    row = *cp++ ;
+
+	    /* make sure row indices within range */
+	    if (row < 0 || row >= n_row)
+	    {
+		stats [COLAMD_STATUS] = COLAMD_ERROR_row_index_out_of_bounds ;
+		stats [COLAMD_INFO1] = col ;
+		stats [COLAMD_INFO2] = row ;
+		stats [COLAMD_INFO3] = n_row ;
+		DEBUG0 (("colamd: row %d col %d out of bounds\n", row, col)) ;
+		return (FALSE) ;
+	    }
+
+	    if (row <= last_row || Row [row].shared2.mark == col)
+	    {
+		/* row index are unsorted or repeated (or both), thus col */
+		/* is jumbled.  This is a notice, not an error condition. */
+		stats [COLAMD_STATUS] = COLAMD_OK_BUT_JUMBLED ;
+		stats [COLAMD_INFO1] = col ;
+		stats [COLAMD_INFO2] = row ;
+		(stats [COLAMD_INFO3]) ++ ;
+		DEBUG1 (("colamd: row %d col %d unsorted/duplicate\n",row,col));
+	    }
+
+	    if (Row [row].shared2.mark != col)
+	    {
+		Row [row].length++ ;
+	    }
+	    else
+	    {
+		/* this is a repeated entry in the column, */
+		/* it will be removed */
+		Col [col].length-- ;
+	    }
+
+	    /* mark the row as having been seen in this column */
+	    Row [row].shared2.mark = col ;
+
+	    last_row = row ;
+	}
+    }
+
+    /* === Compute row pointers ============================================= */
+
+    /* row form of the matrix starts directly after the column */
+    /* form of matrix in A */
+    Row [0].start = p [n_col] ;
+    Row [0].shared1.p = Row [0].start ;
+    Row [0].shared2.mark = -1 ;
+    for (row = 1 ; row < n_row ; row++)
+    {
+	Row [row].start = Row [row-1].start + Row [row-1].length ;
+	Row [row].shared1.p = Row [row].start ;
+	Row [row].shared2.mark = -1 ;
+    }
+
+    /* === Create row form ================================================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+	/* if cols jumbled, watch for repeated row indices */
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    cp = &A [p [col]] ;
+	    cp_end = &A [p [col+1]] ;
+	    while (cp < cp_end)
+	    {
+		row = *cp++ ;
+		if (Row [row].shared2.mark != col)
+		{
+		    A [(Row [row].shared1.p)++] = col ;
+		    Row [row].shared2.mark = col ;
+		}
+	    }
+	}
+    }
+    else
+    {
+	/* if cols not jumbled, we don't need the mark (this is faster) */
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    cp = &A [p [col]] ;
+	    cp_end = &A [p [col+1]] ;
+	    while (cp < cp_end)
+	    {
+		A [(Row [*cp++].shared1.p)++] = col ;
+	    }
+	}
+    }
+
+    /* === Clear the row marks and set row degrees ========================== */
+
+    for (row = 0 ; row < n_row ; row++)
+    {
+	Row [row].shared2.mark = 0 ;
+	Row [row].shared1.degree = Row [row].length ;
+    }
+
+    /* === See if we need to re-create columns ============================== */
+
+    if (stats [COLAMD_STATUS] == COLAMD_OK_BUT_JUMBLED)
+    {
+    	DEBUG0 (("colamd: reconstructing column form, matrix jumbled\n")) ;
+
+#ifndef NDEBUG
+	/* make sure column lengths are correct */
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    p [col] = Col [col].length ;
+	}
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    rp = &A [Row [row].start] ;
+	    rp_end = rp + Row [row].length ;
+	    while (rp < rp_end)
+	    {
+		p [*rp++]-- ;
+	    }
+	}
+	for (col = 0 ; col < n_col ; col++)
+	{
+	    ASSERT (p [col] == 0) ;
+	}
+	/* now p is all zero (different than when debugging is turned off) */
+#endif /* NDEBUG */
+
+	/* === Compute col pointers ========================================= */
+
+	/* col form of the matrix starts at A [0]. */
+	/* Note, we may have a gap between the col form and the row */
+	/* form if there were duplicate entries, if so, it will be */
+	/* removed upon the first garbage collection */
+	Col [0].start = 0 ;
+	p [0] = Col [0].start ;
+	for (col = 1 ; col < n_col ; col++)
+	{
+	    /* note that the lengths here are for pruned columns, i.e. */
+	    /* no duplicate row indices will exist for these columns */
+	    Col [col].start = Col [col-1].start + Col [col-1].length ;
+	    p [col] = Col [col].start ;
+	}
+
+	/* === Re-create col form =========================================== */
+
+	for (row = 0 ; row < n_row ; row++)
+	{
+	    rp = &A [Row [row].start] ;
+	    rp_end = rp + Row [row].length ;
+	    while (rp < rp_end)
+	    {
+		A [(p [*rp++])++] = row ;
+	    }
+	}
+    }
+
+    /* === Done.  Matrix is not (or no longer) jumbled ====================== */
+
+    return (TRUE) ;
+}
+
+
+/* ========================================================================== */
+/* === init_scoring ========================================================= */
+/* ========================================================================== */
+
+/*
+    Kills dense or empty columns and rows, calculates an initial score for
+    each column, and places all columns in the degree lists.  Not user-callable.
+*/
+
+PRIVATE void init_scoring
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* column form and row form of A */
+    Int head [],		/* of size n_col+1 */
+    double knobs [COLAMD_KNOBS],/* parameters */
+    Int *p_n_row2,		/* number of non-dense, non-empty rows */
+    Int *p_n_col2,		/* number of non-dense, non-empty columns */
+    Int *p_max_deg		/* maximum row degree */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int c ;			/* a column index */
+    Int r, row ;		/* a row index */
+    Int *cp ;			/* a column pointer */
+    Int deg ;			/* degree of a row or column */
+    Int *cp_end ;		/* a pointer to the end of a column */
+    Int *new_cp ;		/* new column pointer */
+    Int col_length ;		/* length of pruned column */
+    Int score ;			/* current column score */
+    Int n_col2 ;		/* number of non-dense, non-empty columns */
+    Int n_row2 ;		/* number of non-dense, non-empty rows */
+    Int dense_row_count ;	/* remove rows with more entries than this */
+    Int dense_col_count ;	/* remove cols with more entries than this */
+    Int min_score ;		/* smallest column score */
+    Int max_deg ;		/* maximum row degree */
+    Int next_col ;		/* Used to add to degree list.*/
+
+#ifndef NDEBUG
+    Int debug_count ;		/* debug only. */
+#endif /* NDEBUG */
+
+    /* === Extract knobs ==================================================== */
+
+    /* Note: if knobs contains a NaN, this is undefined: */
+    if (knobs [COLAMD_DENSE_ROW] < 0)
+    {
+	/* only remove completely dense rows */
+	dense_row_count = n_col-1 ;
+    }
+    else
+    {
+	dense_row_count = DENSE_DEGREE (knobs [COLAMD_DENSE_ROW], n_col) ;
+    }
+    if (knobs [COLAMD_DENSE_COL] < 0)
+    {
+	/* only remove completely dense columns */
+	dense_col_count = n_row-1 ;
+    }
+    else
+    {
+	dense_col_count =
+	    DENSE_DEGREE (knobs [COLAMD_DENSE_COL], MIN (n_row, n_col)) ;
+    }
+
+    DEBUG1 (("colamd: densecount: %d %d\n", dense_row_count, dense_col_count)) ;
+    max_deg = 0 ;
+    n_col2 = n_col ;
+    n_row2 = n_row ;
+
+    /* === Kill empty columns =============================================== */
+
+    /* Put the empty columns at the end in their natural order, so that LU */
+    /* factorization can proceed as far as possible. */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	deg = Col [c].length ;
+	if (deg == 0)
+	{
+	    /* this is a empty column, kill and order it last */
+	    Col [c].shared2.order = --n_col2 ;
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+    }
+    DEBUG1 (("colamd: null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense columns =============================================== */
+
+    /* Put the dense columns at the end, in their natural order */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* skip any dead columns */
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	deg = Col [c].length ;
+	if (deg > dense_col_count)
+	{
+	    /* this is a dense column, kill and order it last */
+	    Col [c].shared2.order = --n_col2 ;
+	    /* decrement the row degrees */
+	    cp = &A [Col [c].start] ;
+	    cp_end = cp + Col [c].length ;
+	    while (cp < cp_end)
+	    {
+		Row [*cp++].shared1.degree-- ;
+	    }
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+    }
+    DEBUG1 (("colamd: Dense and null columns killed: %d\n", n_col - n_col2)) ;
+
+    /* === Kill dense and empty rows ======================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	deg = Row [r].shared1.degree ;
+	ASSERT (deg >= 0 && deg <= n_col) ;
+	if (deg > dense_row_count || deg == 0)
+	{
+	    /* kill a dense or empty row */
+	    KILL_ROW (r) ;
+	    --n_row2 ;
+	}
+	else
+	{
+	    /* keep track of max degree of remaining rows */
+	    max_deg = MAX (max_deg, deg) ;
+	}
+    }
+    DEBUG1 (("colamd: Dense and null rows killed: %d\n", n_row - n_row2)) ;
+
+    /* === Compute initial column scores ==================================== */
+
+    /* At this point the row degrees are accurate.  They reflect the number */
+    /* of "live" (non-dense) columns in each row.  No empty rows exist. */
+    /* Some "live" columns may contain only dead rows, however.  These are */
+    /* pruned in the code below. */
+
+    /* now find the initial matlab score for each column */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* skip dead column */
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	score = 0 ;
+	cp = &A [Col [c].start] ;
+	new_cp = cp ;
+	cp_end = cp + Col [c].length ;
+	while (cp < cp_end)
+	{
+	    /* get a row */
+	    row = *cp++ ;
+	    /* skip if dead */
+	    if (ROW_IS_DEAD (row))
+	    {
+		continue ;
+	    }
+	    /* compact the column */
+	    *new_cp++ = row ;
+	    /* add row's external degree */
+	    score += Row [row].shared1.degree - 1 ;
+	    /* guard against integer overflow */
+	    score = MIN (score, n_col) ;
+	}
+	/* determine pruned column length */
+	col_length = (Int) (new_cp - &A [Col [c].start]) ;
+	if (col_length == 0)
+	{
+	    /* a newly-made null column (all rows in this col are "dense" */
+	    /* and have already been killed) */
+	    DEBUG2 (("Newly null killed: %d\n", c)) ;
+	    Col [c].shared2.order = --n_col2 ;
+	    KILL_PRINCIPAL_COL (c) ;
+	}
+	else
+	{
+	    /* set column length and set score */
+	    ASSERT (score >= 0) ;
+	    ASSERT (score <= n_col) ;
+	    Col [c].length = col_length ;
+	    Col [c].shared2.score = score ;
+	}
+    }
+    DEBUG1 (("colamd: Dense, null, and newly-null columns killed: %d\n",
+    	n_col-n_col2)) ;
+
+    /* At this point, all empty rows and columns are dead.  All live columns */
+    /* are "clean" (containing no dead rows) and simplicial (no supercolumns */
+    /* yet).  Rows may contain dead columns, but all live rows contain at */
+    /* least one live column. */
+
+#ifndef NDEBUG
+    debug_structures (n_row, n_col, Row, Col, A, n_col2) ;
+#endif /* NDEBUG */
+
+    /* === Initialize degree lists ========================================== */
+
+#ifndef NDEBUG
+    debug_count = 0 ;
+#endif /* NDEBUG */
+
+    /* clear the hash buckets */
+    for (c = 0 ; c <= n_col ; c++)
+    {
+	head [c] = EMPTY ;
+    }
+    min_score = n_col ;
+    /* place in reverse order, so low column indices are at the front */
+    /* of the lists.  This is to encourage natural tie-breaking */
+    for (c = n_col-1 ; c >= 0 ; c--)
+    {
+	/* only add principal columns to degree lists */
+	if (COL_IS_ALIVE (c))
+	{
+	    DEBUG4 (("place %d score %d minscore %d ncol %d\n",
+		c, Col [c].shared2.score, min_score, n_col)) ;
+
+	    /* === Add columns score to DList =============================== */
+
+	    score = Col [c].shared2.score ;
+
+	    ASSERT (min_score >= 0) ;
+	    ASSERT (min_score <= n_col) ;
+	    ASSERT (score >= 0) ;
+	    ASSERT (score <= n_col) ;
+	    ASSERT (head [score] >= EMPTY) ;
+
+	    /* now add this column to dList at proper score location */
+	    next_col = head [score] ;
+	    Col [c].shared3.prev = EMPTY ;
+	    Col [c].shared4.degree_next = next_col ;
+
+	    /* if there already was a column with the same score, set its */
+	    /* previous pointer to this new column */
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = c ;
+	    }
+	    head [score] = c ;
+
+	    /* see if this score is less than current min */
+	    min_score = MIN (min_score, score) ;
+
+#ifndef NDEBUG
+	    debug_count++ ;
+#endif /* NDEBUG */
+
+	}
+    }
+
+#ifndef NDEBUG
+    DEBUG1 (("colamd: Live cols %d out of %d, non-princ: %d\n",
+	debug_count, n_col, n_col-debug_count)) ;
+    ASSERT (debug_count == n_col2) ;
+    debug_deg_lists (n_row, n_col, Row, Col, head, min_score, n_col2, max_deg) ;
+#endif /* NDEBUG */
+
+    /* === Return number of remaining columns, and max row degree =========== */
+
+    *p_n_col2 = n_col2 ;
+    *p_n_row2 = n_row2 ;
+    *p_max_deg = max_deg ;
+}
+
+
+/* ========================================================================== */
+/* === find_ordering ======================================================== */
+/* ========================================================================== */
+
+/*
+    Order the principal columns of the supercolumn form of the matrix
+    (no supercolumns on input).  Uses a minimum approximate column minimum
+    degree ordering method.  Not user-callable.
+*/
+
+PRIVATE Int find_ordering	/* return the number of garbage collections */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows of A */
+    Int n_col,			/* number of columns of A */
+    Int Alen,			/* size of A, 2*nnz + n_col or larger */
+    Colamd_Row Row [],		/* of size n_row+1 */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* column form and row form of A */
+    Int head [],		/* of size n_col+1 */
+    Int n_col2,			/* Remaining columns to order */
+    Int max_deg,		/* Maximum row degree */
+    Int pfree,			/* index of first free slot (2*nnz on entry) */
+    Int aggressive
+)
+{
+    /* === Local variables ================================================== */
+
+    Int k ;			/* current pivot ordering step */
+    Int pivot_col ;		/* current pivot column */
+    Int *cp ;			/* a column pointer */
+    Int *rp ;			/* a row pointer */
+    Int pivot_row ;		/* current pivot row */
+    Int *new_cp ;		/* modified column pointer */
+    Int *new_rp ;		/* modified row pointer */
+    Int pivot_row_start ;	/* pointer to start of pivot row */
+    Int pivot_row_degree ;	/* number of columns in pivot row */
+    Int pivot_row_length ;	/* number of supercolumns in pivot row */
+    Int pivot_col_score ;	/* score of pivot column */
+    Int needed_memory ;		/* free space needed for pivot row */
+    Int *cp_end ;		/* pointer to the end of a column */
+    Int *rp_end ;		/* pointer to the end of a row */
+    Int row ;			/* a row index */
+    Int col ;			/* a column index */
+    Int max_score ;		/* maximum possible score */
+    Int cur_score ;		/* score of current column */
+    unsigned Int hash ;		/* hash value for supernode detection */
+    Int head_column ;		/* head of hash bucket */
+    Int first_col ;		/* first column in hash bucket */
+    Int tag_mark ;		/* marker value for mark array */
+    Int row_mark ;		/* Row [row].shared2.mark */
+    Int set_difference ;	/* set difference size of row with pivot row */
+    Int min_score ;		/* smallest column score */
+    Int col_thickness ;		/* "thickness" (no. of columns in a supercol) */
+    Int max_mark ;		/* maximum value of tag_mark */
+    Int pivot_col_thickness ;	/* number of columns represented by pivot col */
+    Int prev_col ;		/* Used by Dlist operations. */
+    Int next_col ;		/* Used by Dlist operations. */
+    Int ngarbage ;		/* number of garbage collections performed */
+
+#ifndef NDEBUG
+    Int debug_d ;		/* debug loop counter */
+    Int debug_step = 0 ;	/* debug loop counter */
+#endif /* NDEBUG */
+
+    /* === Initialization and clear mark ==================================== */
+
+    max_mark = INT_MAX - n_col ;	/* INT_MAX defined in <limits.h> */
+    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+    min_score = 0 ;
+    ngarbage = 0 ;
+    DEBUG1 (("colamd: Ordering, n_col2=%d\n", n_col2)) ;
+
+    /* === Order the columns ================================================ */
+
+    for (k = 0 ; k < n_col2 ; /* 'k' is incremented below */)
+    {
+
+#ifndef NDEBUG
+	if (debug_step % 100 == 0)
+	{
+	    DEBUG2 (("\n...       Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+	}
+	else
+	{
+	    DEBUG3 (("\n----------Step k: %d out of n_col2: %d\n", k, n_col2)) ;
+	}
+	debug_step++ ;
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k, max_deg) ;
+	debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+
+	/* === Select pivot column, and order it ============================ */
+
+	/* make sure degree list isn't empty */
+	ASSERT (min_score >= 0) ;
+	ASSERT (min_score <= n_col) ;
+	ASSERT (head [min_score] >= EMPTY) ;
+
+#ifndef NDEBUG
+	for (debug_d = 0 ; debug_d < min_score ; debug_d++)
+	{
+	    ASSERT (head [debug_d] == EMPTY) ;
+	}
+#endif /* NDEBUG */
+
+	/* get pivot column from head of minimum degree list */
+	while (head [min_score] == EMPTY && min_score < n_col)
+	{
+	    min_score++ ;
+	}
+	pivot_col = head [min_score] ;
+	ASSERT (pivot_col >= 0 && pivot_col <= n_col) ;
+	next_col = Col [pivot_col].shared4.degree_next ;
+	head [min_score] = next_col ;
+	if (next_col != EMPTY)
+	{
+	    Col [next_col].shared3.prev = EMPTY ;
+	}
+
+	ASSERT (COL_IS_ALIVE (pivot_col)) ;
+
+	/* remember score for defrag check */
+	pivot_col_score = Col [pivot_col].shared2.score ;
+
+	/* the pivot column is the kth column in the pivot order */
+	Col [pivot_col].shared2.order = k ;
+
+	/* increment order count by column thickness */
+	pivot_col_thickness = Col [pivot_col].shared1.thickness ;
+	k += pivot_col_thickness ;
+	ASSERT (pivot_col_thickness > 0) ;
+	DEBUG3 (("Pivot col: %d thick %d\n", pivot_col, pivot_col_thickness)) ;
+
+	/* === Garbage_collection, if necessary ============================= */
+
+	needed_memory = MIN (pivot_col_score, n_col - k) ;
+	if (pfree + needed_memory >= Alen)
+	{
+	    pfree = garbage_collection (n_row, n_col, Row, Col, A, &A [pfree]) ;
+	    ngarbage++ ;
+	    /* after garbage collection we will have enough */
+	    ASSERT (pfree + needed_memory < Alen) ;
+	    /* garbage collection has wiped out the Row[].shared2.mark array */
+	    tag_mark = clear_mark (0, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+	    debug_matrix (n_row, n_col, Row, Col, A) ;
+#endif /* NDEBUG */
+	}
+
+	/* === Compute pivot row pattern ==================================== */
+
+	/* get starting location for this new merged row */
+	pivot_row_start = pfree ;
+
+	/* initialize new row counts to zero */
+	pivot_row_degree = 0 ;
+
+	/* tag pivot column as having been visited so it isn't included */
+	/* in merged pivot row */
+	Col [pivot_col].shared1.thickness = -pivot_col_thickness ;
+
+	/* pivot row is the union of all rows in the pivot column pattern */
+	cp = &A [Col [pivot_col].start] ;
+	cp_end = cp + Col [pivot_col].length ;
+	while (cp < cp_end)
+	{
+	    /* get a row */
+	    row = *cp++ ;
+	    DEBUG4 (("Pivot col pattern %d %d\n", ROW_IS_ALIVE (row), row)) ;
+	    /* skip if row is dead */
+	    if (ROW_IS_ALIVE (row))
+	    {
+		rp = &A [Row [row].start] ;
+		rp_end = rp + Row [row].length ;
+		while (rp < rp_end)
+		{
+		    /* get a column */
+		    col = *rp++ ;
+		    /* add the column, if alive and untagged */
+		    col_thickness = Col [col].shared1.thickness ;
+		    if (col_thickness > 0 && COL_IS_ALIVE (col))
+		    {
+			/* tag column in pivot row */
+			Col [col].shared1.thickness = -col_thickness ;
+			ASSERT (pfree < Alen) ;
+			/* place column in pivot row */
+			A [pfree++] = col ;
+			pivot_row_degree += col_thickness ;
+		    }
+		}
+	    }
+	}
+
+	/* clear tag on pivot column */
+	Col [pivot_col].shared1.thickness = pivot_col_thickness ;
+	max_deg = MAX (max_deg, pivot_row_degree) ;
+
+#ifndef NDEBUG
+	DEBUG3 (("check2\n")) ;
+	debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+	/* === Kill all rows used to construct pivot row ==================== */
+
+	/* also kill pivot row, temporarily */
+	cp = &A [Col [pivot_col].start] ;
+	cp_end = cp + Col [pivot_col].length ;
+	while (cp < cp_end)
+	{
+	    /* may be killing an already dead row */
+	    row = *cp++ ;
+	    DEBUG3 (("Kill row in pivot col: %d\n", row)) ;
+	    KILL_ROW (row) ;
+	}
+
+	/* === Select a row index to use as the new pivot row =============== */
+
+	pivot_row_length = pfree - pivot_row_start ;
+	if (pivot_row_length > 0)
+	{
+	    /* pick the "pivot" row arbitrarily (first row in col) */
+	    pivot_row = A [Col [pivot_col].start] ;
+	    DEBUG3 (("Pivotal row is %d\n", pivot_row)) ;
+	}
+	else
+	{
+	    /* there is no pivot row, since it is of zero length */
+	    pivot_row = EMPTY ;
+	    ASSERT (pivot_row_length == 0) ;
+	}
+	ASSERT (Col [pivot_col].length > 0 || pivot_row_length == 0) ;
+
+	/* === Approximate degree computation =============================== */
+
+	/* Here begins the computation of the approximate degree.  The column */
+	/* score is the sum of the pivot row "length", plus the size of the */
+	/* set differences of each row in the column minus the pattern of the */
+	/* pivot row itself.  The column ("thickness") itself is also */
+	/* excluded from the column score (we thus use an approximate */
+	/* external degree). */
+
+	/* The time taken by the following code (compute set differences, and */
+	/* add them up) is proportional to the size of the data structure */
+	/* being scanned - that is, the sum of the sizes of each column in */
+	/* the pivot row.  Thus, the amortized time to compute a column score */
+	/* is proportional to the size of that column (where size, in this */
+	/* context, is the column "length", or the number of row indices */
+	/* in that column).  The number of row indices in a column is */
+	/* monotonically non-decreasing, from the length of the original */
+	/* column on input to colamd. */
+
+	/* === Compute set differences ====================================== */
+
+	DEBUG3 (("** Computing set differences phase. **\n")) ;
+
+	/* pivot row is currently dead - it will be revived later. */
+
+	DEBUG3 (("Pivot row: ")) ;
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    col = *rp++ ;
+	    ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+	    DEBUG3 (("Col: %d\n", col)) ;
+
+	    /* clear tags used to construct pivot row pattern */
+	    col_thickness = -Col [col].shared1.thickness ;
+	    ASSERT (col_thickness > 0) ;
+	    Col [col].shared1.thickness = col_thickness ;
+
+	    /* === Remove column from degree list =========================== */
+
+	    cur_score = Col [col].shared2.score ;
+	    prev_col = Col [col].shared3.prev ;
+	    next_col = Col [col].shared4.degree_next ;
+	    ASSERT (cur_score >= 0) ;
+	    ASSERT (cur_score <= n_col) ;
+	    ASSERT (cur_score >= EMPTY) ;
+	    if (prev_col == EMPTY)
+	    {
+		head [cur_score] = next_col ;
+	    }
+	    else
+	    {
+		Col [prev_col].shared4.degree_next = next_col ;
+	    }
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = prev_col ;
+	    }
+
+	    /* === Scan the column ========================================== */
+
+	    cp = &A [Col [col].start] ;
+	    cp_end = cp + Col [col].length ;
+	    while (cp < cp_end)
+	    {
+		/* get a row */
+		row = *cp++ ;
+		row_mark = Row [row].shared2.mark ;
+		/* skip if dead */
+		if (ROW_IS_MARKED_DEAD (row_mark))
+		{
+		    continue ;
+		}
+		ASSERT (row != pivot_row) ;
+		set_difference = row_mark - tag_mark ;
+		/* check if the row has been seen yet */
+		if (set_difference < 0)
+		{
+		    ASSERT (Row [row].shared1.degree <= max_deg) ;
+		    set_difference = Row [row].shared1.degree ;
+		}
+		/* subtract column thickness from this row's set difference */
+		set_difference -= col_thickness ;
+		ASSERT (set_difference >= 0) ;
+		/* absorb this row if the set difference becomes zero */
+		if (set_difference == 0 && aggressive)
+		{
+		    DEBUG3 (("aggressive absorption. Row: %d\n", row)) ;
+		    KILL_ROW (row) ;
+		}
+		else
+		{
+		    /* save the new mark */
+		    Row [row].shared2.mark = set_difference + tag_mark ;
+		}
+	    }
+	}
+
+#ifndef NDEBUG
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k-pivot_row_degree, max_deg) ;
+#endif /* NDEBUG */
+
+	/* === Add up set differences for each column ======================= */
+
+	DEBUG3 (("** Adding set differences phase. **\n")) ;
+
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    /* get a column */
+	    col = *rp++ ;
+	    ASSERT (COL_IS_ALIVE (col) && col != pivot_col) ;
+	    hash = 0 ;
+	    cur_score = 0 ;
+	    cp = &A [Col [col].start] ;
+	    /* compact the column */
+	    new_cp = cp ;
+	    cp_end = cp + Col [col].length ;
+
+	    DEBUG4 (("Adding set diffs for Col: %d.\n", col)) ;
+
+	    while (cp < cp_end)
+	    {
+		/* get a row */
+		row = *cp++ ;
+		ASSERT(row >= 0 && row < n_row) ;
+		row_mark = Row [row].shared2.mark ;
+		/* skip if dead */
+		if (ROW_IS_MARKED_DEAD (row_mark))
+		{
+		    DEBUG4 ((" Row %d, dead\n", row)) ;
+		    continue ;
+		}
+		DEBUG4 ((" Row %d, set diff %d\n", row, row_mark-tag_mark));
+		ASSERT (row_mark >= tag_mark) ;
+		/* compact the column */
+		*new_cp++ = row ;
+		/* compute hash function */
+		hash += row ;
+		/* add set difference */
+		cur_score += row_mark - tag_mark ;
+		/* integer overflow... */
+		cur_score = MIN (cur_score, n_col) ;
+	    }
+
+	    /* recompute the column's length */
+	    Col [col].length = (Int) (new_cp - &A [Col [col].start]) ;
+
+	    /* === Further mass elimination ================================= */
+
+	    if (Col [col].length == 0)
+	    {
+		DEBUG4 (("further mass elimination. Col: %d\n", col)) ;
+		/* nothing left but the pivot row in this column */
+		KILL_PRINCIPAL_COL (col) ;
+		pivot_row_degree -= Col [col].shared1.thickness ;
+		ASSERT (pivot_row_degree >= 0) ;
+		/* order it */
+		Col [col].shared2.order = k ;
+		/* increment order count by column thickness */
+		k += Col [col].shared1.thickness ;
+	    }
+	    else
+	    {
+		/* === Prepare for supercolumn detection ==================== */
+
+		DEBUG4 (("Preparing supercol detection for Col: %d.\n", col)) ;
+
+		/* save score so far */
+		Col [col].shared2.score = cur_score ;
+
+		/* add column to hash table, for supercolumn detection */
+		hash %= n_col + 1 ;
+
+		DEBUG4 ((" Hash = %d, n_col = %d.\n", hash, n_col)) ;
+		ASSERT (((Int) hash) <= n_col) ;
+
+		head_column = head [hash] ;
+		if (head_column > EMPTY)
+		{
+		    /* degree list "hash" is non-empty, use prev (shared3) of */
+		    /* first column in degree list as head of hash bucket */
+		    first_col = Col [head_column].shared3.headhash ;
+		    Col [head_column].shared3.headhash = col ;
+		}
+		else
+		{
+		    /* degree list "hash" is empty, use head as hash bucket */
+		    first_col = - (head_column + 2) ;
+		    head [hash] = - (col + 2) ;
+		}
+		Col [col].shared4.hash_next = first_col ;
+
+		/* save hash function in Col [col].shared3.hash */
+		Col [col].shared3.hash = (Int) hash ;
+		ASSERT (COL_IS_ALIVE (col)) ;
+	    }
+	}
+
+	/* The approximate external column degree is now computed.  */
+
+	/* === Supercolumn detection ======================================== */
+
+	DEBUG3 (("** Supercolumn detection phase. **\n")) ;
+
+	detect_super_cols (
+
+#ifndef NDEBUG
+		n_col, Row,
+#endif /* NDEBUG */
+
+		Col, A, head, pivot_row_start, pivot_row_length) ;
+
+	/* === Kill the pivotal column ====================================== */
+
+	KILL_PRINCIPAL_COL (pivot_col) ;
+
+	/* === Clear mark =================================================== */
+
+	tag_mark = clear_mark (tag_mark+max_deg+1, max_mark, n_row, Row) ;
+
+#ifndef NDEBUG
+	DEBUG3 (("check3\n")) ;
+	debug_mark (n_row, Row, tag_mark, max_mark) ;
+#endif /* NDEBUG */
+
+	/* === Finalize the new pivot row, and column scores ================ */
+
+	DEBUG3 (("** Finalize scores phase. **\n")) ;
+
+	/* for each column in pivot row */
+	rp = &A [pivot_row_start] ;
+	/* compact the pivot row */
+	new_rp = rp ;
+	rp_end = rp + pivot_row_length ;
+	while (rp < rp_end)
+	{
+	    col = *rp++ ;
+	    /* skip dead columns */
+	    if (COL_IS_DEAD (col))
+	    {
+		continue ;
+	    }
+	    *new_rp++ = col ;
+	    /* add new pivot row to column */
+	    A [Col [col].start + (Col [col].length++)] = pivot_row ;
+
+	    /* retrieve score so far and add on pivot row's degree. */
+	    /* (we wait until here for this in case the pivot */
+	    /* row's degree was reduced due to mass elimination). */
+	    cur_score = Col [col].shared2.score + pivot_row_degree ;
+
+	    /* calculate the max possible score as the number of */
+	    /* external columns minus the 'k' value minus the */
+	    /* columns thickness */
+	    max_score = n_col - k - Col [col].shared1.thickness ;
+
+	    /* make the score the external degree of the union-of-rows */
+	    cur_score -= Col [col].shared1.thickness ;
+
+	    /* make sure score is less or equal than the max score */
+	    cur_score = MIN (cur_score, max_score) ;
+	    ASSERT (cur_score >= 0) ;
+
+	    /* store updated score */
+	    Col [col].shared2.score = cur_score ;
+
+	    /* === Place column back in degree list ========================= */
+
+	    ASSERT (min_score >= 0) ;
+	    ASSERT (min_score <= n_col) ;
+	    ASSERT (cur_score >= 0) ;
+	    ASSERT (cur_score <= n_col) ;
+	    ASSERT (head [cur_score] >= EMPTY) ;
+	    next_col = head [cur_score] ;
+	    Col [col].shared4.degree_next = next_col ;
+	    Col [col].shared3.prev = EMPTY ;
+	    if (next_col != EMPTY)
+	    {
+		Col [next_col].shared3.prev = col ;
+	    }
+	    head [cur_score] = col ;
+
+	    /* see if this score is less than current min */
+	    min_score = MIN (min_score, cur_score) ;
+
+	}
+
+#ifndef NDEBUG
+	debug_deg_lists (n_row, n_col, Row, Col, head,
+		min_score, n_col2-k, max_deg) ;
+#endif /* NDEBUG */
+
+	/* === Resurrect the new pivot row ================================== */
+
+	if (pivot_row_degree > 0)
+	{
+	    /* update pivot row length to reflect any cols that were killed */
+	    /* during super-col detection and mass elimination */
+	    Row [pivot_row].start  = pivot_row_start ;
+	    Row [pivot_row].length = (Int) (new_rp - &A[pivot_row_start]) ;
+	    ASSERT (Row [pivot_row].length > 0) ;
+	    Row [pivot_row].shared1.degree = pivot_row_degree ;
+	    Row [pivot_row].shared2.mark = 0 ;
+	    /* pivot row is no longer dead */
+
+	    DEBUG1 (("Resurrect Pivot_row %d deg: %d\n",
+			pivot_row, pivot_row_degree)) ;
+	}
+    }
+
+    /* === All principal columns have now been ordered ====================== */
+
+    return (ngarbage) ;
+}
+
+
+/* ========================================================================== */
+/* === order_children ======================================================= */
+/* ========================================================================== */
+
+/*
+    The find_ordering routine has ordered all of the principal columns (the
+    representatives of the supercolumns).  The non-principal columns have not
+    yet been ordered.  This routine orders those columns by walking up the
+    parent tree (a column is a child of the column which absorbed it).  The
+    final permutation vector is then placed in p [0 ... n_col-1], with p [0]
+    being the first column, and p [n_col-1] being the last.  It doesn't look
+    like it at first glance, but be assured that this routine takes time linear
+    in the number of columns.  Although not immediately obvious, the time
+    taken by this routine is O (n_col), that is, linear in the number of
+    columns.  Not user-callable.
+*/
+
+PRIVATE void order_children
+(
+    /* === Parameters ======================================================= */
+
+    Int n_col,			/* number of columns of A */
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int p []			/* p [0 ... n_col-1] is the column permutation*/
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;			/* loop counter for all columns */
+    Int c ;			/* column index */
+    Int parent ;		/* index of column's parent */
+    Int order ;			/* column's order */
+
+    /* === Order each non-principal column ================================== */
+
+    for (i = 0 ; i < n_col ; i++)
+    {
+	/* find an un-ordered non-principal column */
+	ASSERT (COL_IS_DEAD (i)) ;
+	if (!COL_IS_DEAD_PRINCIPAL (i) && Col [i].shared2.order == EMPTY)
+	{
+	    parent = i ;
+	    /* once found, find its principal parent */
+	    do
+	    {
+		parent = Col [parent].shared1.parent ;
+	    } while (!COL_IS_DEAD_PRINCIPAL (parent)) ;
+
+	    /* now, order all un-ordered non-principal columns along path */
+	    /* to this parent.  collapse tree at the same time */
+	    c = i ;
+	    /* get order of parent */
+	    order = Col [parent].shared2.order ;
+
+	    do
+	    {
+		ASSERT (Col [c].shared2.order == EMPTY) ;
+
+		/* order this column */
+		Col [c].shared2.order = order++ ;
+		/* collaps tree */
+		Col [c].shared1.parent = parent ;
+
+		/* get immediate parent of this column */
+		c = Col [c].shared1.parent ;
+
+		/* continue until we hit an ordered column.  There are */
+		/* guarranteed not to be anymore unordered columns */
+		/* above an ordered column */
+	    } while (Col [c].shared2.order == EMPTY) ;
+
+	    /* re-order the super_col parent to largest order for this group */
+	    Col [parent].shared2.order = order ;
+	}
+    }
+
+    /* === Generate the permutation ========================================= */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	p [Col [c].shared2.order] = c ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === detect_super_cols ==================================================== */
+/* ========================================================================== */
+
+/*
+    Detects supercolumns by finding matches between columns in the hash buckets.
+    Check amongst columns in the set A [row_start ... row_start + row_length-1].
+    The columns under consideration are currently *not* in the degree lists,
+    and have already been placed in the hash buckets.
+
+    The hash bucket for columns whose hash function is equal to h is stored
+    as follows:
+
+	if head [h] is >= 0, then head [h] contains a degree list, so:
+
+		head [h] is the first column in degree bucket h.
+		Col [head [h]].headhash gives the first column in hash bucket h.
+
+	otherwise, the degree list is empty, and:
+
+		-(head [h] + 2) is the first column in hash bucket h.
+
+    For a column c in a hash bucket, Col [c].shared3.prev is NOT a "previous
+    column" pointer.  Col [c].shared3.hash is used instead as the hash number
+    for that column.  The value of Col [c].shared4.hash_next is the next column
+    in the same hash bucket.
+
+    Assuming no, or "few" hash collisions, the time taken by this routine is
+    linear in the sum of the sizes (lengths) of each column whose score has
+    just been computed in the approximate degree computation.
+    Not user-callable.
+*/
+
+PRIVATE void detect_super_cols
+(
+    /* === Parameters ======================================================= */
+
+#ifndef NDEBUG
+    /* these two parameters are only needed when debugging is enabled: */
+    Int n_col,			/* number of columns of A */
+    Colamd_Row Row [],		/* of size n_row+1 */
+#endif /* NDEBUG */
+
+    Colamd_Col Col [],		/* of size n_col+1 */
+    Int A [],			/* row indices of A */
+    Int head [],		/* head of degree lists and hash buckets */
+    Int row_start,		/* pointer to set of columns to check */
+    Int row_length		/* number of columns to check */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int hash ;			/* hash value for a column */
+    Int *rp ;			/* pointer to a row */
+    Int c ;			/* a column index */
+    Int super_c ;		/* column index of the column to absorb into */
+    Int *cp1 ;			/* column pointer for column super_c */
+    Int *cp2 ;			/* column pointer for column c */
+    Int length ;		/* length of column super_c */
+    Int prev_c ;		/* column preceding c in hash bucket */
+    Int i ;			/* loop counter */
+    Int *rp_end ;		/* pointer to the end of the row */
+    Int col ;			/* a column index in the row to check */
+    Int head_column ;		/* first column in hash bucket or degree list */
+    Int first_col ;		/* first column in hash bucket */
+
+    /* === Consider each column in the row ================================== */
+
+    rp = &A [row_start] ;
+    rp_end = rp + row_length ;
+    while (rp < rp_end)
+    {
+	col = *rp++ ;
+	if (COL_IS_DEAD (col))
+	{
+	    continue ;
+	}
+
+	/* get hash number for this column */
+	hash = Col [col].shared3.hash ;
+	ASSERT (hash <= n_col) ;
+
+	/* === Get the first column in this hash bucket ===================== */
+
+	head_column = head [hash] ;
+	if (head_column > EMPTY)
+	{
+	    first_col = Col [head_column].shared3.headhash ;
+	}
+	else
+	{
+	    first_col = - (head_column + 2) ;
+	}
+
+	/* === Consider each column in the hash bucket ====================== */
+
+	for (super_c = first_col ; super_c != EMPTY ;
+	    super_c = Col [super_c].shared4.hash_next)
+	{
+	    ASSERT (COL_IS_ALIVE (super_c)) ;
+	    ASSERT (Col [super_c].shared3.hash == hash) ;
+	    length = Col [super_c].length ;
+
+	    /* prev_c is the column preceding column c in the hash bucket */
+	    prev_c = super_c ;
+
+	    /* === Compare super_c with all columns after it ================ */
+
+	    for (c = Col [super_c].shared4.hash_next ;
+		 c != EMPTY ; c = Col [c].shared4.hash_next)
+	    {
+		ASSERT (c != super_c) ;
+		ASSERT (COL_IS_ALIVE (c)) ;
+		ASSERT (Col [c].shared3.hash == hash) ;
+
+		/* not identical if lengths or scores are different */
+		if (Col [c].length != length ||
+		    Col [c].shared2.score != Col [super_c].shared2.score)
+		{
+		    prev_c = c ;
+		    continue ;
+		}
+
+		/* compare the two columns */
+		cp1 = &A [Col [super_c].start] ;
+		cp2 = &A [Col [c].start] ;
+
+		for (i = 0 ; i < length ; i++)
+		{
+		    /* the columns are "clean" (no dead rows) */
+		    ASSERT (ROW_IS_ALIVE (*cp1))  ;
+		    ASSERT (ROW_IS_ALIVE (*cp2))  ;
+		    /* row indices will same order for both supercols, */
+		    /* no gather scatter nessasary */
+		    if (*cp1++ != *cp2++)
+		    {
+			break ;
+		    }
+		}
+
+		/* the two columns are different if the for-loop "broke" */
+		if (i != length)
+		{
+		    prev_c = c ;
+		    continue ;
+		}
+
+		/* === Got it!  two columns are identical =================== */
+
+		ASSERT (Col [c].shared2.score == Col [super_c].shared2.score) ;
+
+		Col [super_c].shared1.thickness += Col [c].shared1.thickness ;
+		Col [c].shared1.parent = super_c ;
+		KILL_NON_PRINCIPAL_COL (c) ;
+		/* order c later, in order_children() */
+		Col [c].shared2.order = EMPTY ;
+		/* remove c from hash bucket */
+		Col [prev_c].shared4.hash_next = Col [c].shared4.hash_next ;
+	    }
+	}
+
+	/* === Empty this hash bucket ======================================= */
+
+	if (head_column > EMPTY)
+	{
+	    /* corresponding degree list "hash" is not empty */
+	    Col [head_column].shared3.headhash = EMPTY ;
+	}
+	else
+	{
+	    /* corresponding degree list "hash" is empty */
+	    head [hash] = EMPTY ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === garbage_collection =================================================== */
+/* ========================================================================== */
+
+/*
+    Defragments and compacts columns and rows in the workspace A.  Used when
+    all avaliable memory has been used while performing row merging.  Returns
+    the index of the first free position in A, after garbage collection.  The
+    time taken by this routine is linear is the size of the array A, which is
+    itself linear in the number of nonzeros in the input matrix.
+    Not user-callable.
+*/
+
+PRIVATE Int garbage_collection  /* returns the new value of pfree */
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,			/* number of rows */
+    Int n_col,			/* number of columns */
+    Colamd_Row Row [],		/* row info */
+    Colamd_Col Col [],		/* column info */
+    Int A [],			/* A [0 ... Alen-1] holds the matrix */
+    Int *pfree			/* &A [0] ... pfree is in use */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int *psrc ;			/* source pointer */
+    Int *pdest ;		/* destination pointer */
+    Int j ;			/* counter */
+    Int r ;			/* a row index */
+    Int c ;			/* a column index */
+    Int length ;		/* length of a row or column */
+
+#ifndef NDEBUG
+    Int debug_rows ;
+    DEBUG2 (("Defrag..\n")) ;
+    for (psrc = &A[0] ; psrc < pfree ; psrc++) ASSERT (*psrc >= 0) ;
+    debug_rows = 0 ;
+#endif /* NDEBUG */
+
+    /* === Defragment the columns =========================================== */
+
+    pdest = &A[0] ;
+    for (c = 0 ; c < n_col ; c++)
+    {
+	if (COL_IS_ALIVE (c))
+	{
+	    psrc = &A [Col [c].start] ;
+
+	    /* move and compact the column */
+	    ASSERT (pdest <= psrc) ;
+	    Col [c].start = (Int) (pdest - &A [0]) ;
+	    length = Col [c].length ;
+	    for (j = 0 ; j < length ; j++)
+	    {
+		r = *psrc++ ;
+		if (ROW_IS_ALIVE (r))
+		{
+		    *pdest++ = r ;
+		}
+	    }
+	    Col [c].length = (Int) (pdest - &A [Col [c].start]) ;
+	}
+    }
+
+    /* === Prepare to defragment the rows =================================== */
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_DEAD (r) || (Row [r].length == 0))
+	{
+	    /* This row is already dead, or is of zero length.  Cannot compact
+	     * a row of zero length, so kill it.  NOTE: in the current version,
+	     * there are no zero-length live rows.  Kill the row (for the first
+	     * time, or again) just to be safe. */
+	    KILL_ROW (r) ;
+	}
+	else
+	{
+	    /* save first column index in Row [r].shared2.first_column */
+	    psrc = &A [Row [r].start] ;
+	    Row [r].shared2.first_column = *psrc ;
+	    ASSERT (ROW_IS_ALIVE (r)) ;
+	    /* flag the start of the row with the one's complement of row */
+	    *psrc = ONES_COMPLEMENT (r) ;
+#ifndef NDEBUG
+	    debug_rows++ ;
+#endif /* NDEBUG */
+	}
+    }
+
+    /* === Defragment the rows ============================================== */
+
+    psrc = pdest ;
+    while (psrc < pfree)
+    {
+	/* find a negative number ... the start of a row */
+	if (*psrc++ < 0)
+	{
+	    psrc-- ;
+	    /* get the row index */
+	    r = ONES_COMPLEMENT (*psrc) ;
+	    ASSERT (r >= 0 && r < n_row) ;
+	    /* restore first column index */
+	    *psrc = Row [r].shared2.first_column ;
+	    ASSERT (ROW_IS_ALIVE (r)) ;
+	    ASSERT (Row [r].length > 0) ;
+	    /* move and compact the row */
+	    ASSERT (pdest <= psrc) ;
+	    Row [r].start = (Int) (pdest - &A [0]) ;
+	    length = Row [r].length ;
+	    for (j = 0 ; j < length ; j++)
+	    {
+		c = *psrc++ ;
+		if (COL_IS_ALIVE (c))
+		{
+		    *pdest++ = c ;
+		}
+	    }
+	    Row [r].length = (Int) (pdest - &A [Row [r].start]) ;
+	    ASSERT (Row [r].length > 0) ;
+#ifndef NDEBUG
+	    debug_rows-- ;
+#endif /* NDEBUG */
+	}
+    }
+    /* ensure we found all the rows */
+    ASSERT (debug_rows == 0) ;
+
+    /* === Return the new value of pfree ==================================== */
+
+    return ((Int) (pdest - &A [0])) ;
+}
+
+
+/* ========================================================================== */
+/* === clear_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Clears the Row [].shared2.mark array, and returns the new tag_mark.
+    Return value is the new tag_mark.  Not user-callable.
+*/
+
+PRIVATE Int clear_mark	/* return the new value for tag_mark */
+(
+    /* === Parameters ======================================================= */
+
+    Int tag_mark,	/* new value of tag_mark */
+    Int max_mark,	/* max allowed value of tag_mark */
+
+    Int n_row,		/* number of rows in A */
+    Colamd_Row Row []	/* Row [0 ... n_row-1].shared2.mark is set to zero */
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    if (tag_mark <= 0 || tag_mark >= max_mark)
+    {
+	for (r = 0 ; r < n_row ; r++)
+	{
+	    if (ROW_IS_ALIVE (r))
+	    {
+		Row [r].shared2.mark = 0 ;
+	    }
+	}
+	tag_mark = 1 ;
+    }
+
+    return (tag_mark) ;
+}
+
+
+/* ========================================================================== */
+/* === print_report ========================================================= */
+/* ========================================================================== */
+
+PRIVATE void print_report
+(
+    char *method,
+    Int stats [COLAMD_STATS]
+)
+{
+
+    Int i1, i2, i3 ;
+
+    PRINTF (("\n%s version %d.%d, %s: ", method,
+	    COLAMD_MAIN_VERSION, COLAMD_SUB_VERSION, COLAMD_DATE)) ;
+
+    if (!stats)
+    {
+    	PRINTF (("No statistics available.\n")) ;
+	return ;
+    }
+
+    i1 = stats [COLAMD_INFO1] ;
+    i2 = stats [COLAMD_INFO2] ;
+    i3 = stats [COLAMD_INFO3] ;
+
+    if (stats [COLAMD_STATUS] >= 0)
+    {
+    	PRINTF (("OK.  ")) ;
+    }
+    else
+    {
+    	PRINTF (("ERROR.  ")) ;
+    }
+
+    switch (stats [COLAMD_STATUS])
+    {
+
+	case COLAMD_OK_BUT_JUMBLED:
+
+	    PRINTF(("Matrix has unsorted or duplicate row indices.\n")) ;
+
+	    PRINTF(("%s: number of duplicate or out-of-order row indices: %d\n",
+	    method, i3)) ;
+
+	    PRINTF(("%s: last seen duplicate or out-of-order row index:   %d\n",
+	    method, INDEX (i2))) ;
+
+	    PRINTF(("%s: last seen in column:                             %d",
+	    method, INDEX (i1))) ;
+
+	    /* no break - fall through to next case instead */
+
+	case COLAMD_OK:
+
+	    PRINTF(("\n")) ;
+
+ 	    PRINTF(("%s: number of dense or empty rows ignored:           %d\n",
+	    method, stats [COLAMD_DENSE_ROW])) ;
+
+	    PRINTF(("%s: number of dense or empty columns ignored:        %d\n",
+	    method, stats [COLAMD_DENSE_COL])) ;
+
+	    PRINTF(("%s: number of garbage collections performed:         %d\n",
+	    method, stats [COLAMD_DEFRAG_COUNT])) ;
+	    break ;
+
+	case COLAMD_ERROR_A_not_present:
+
+	    PRINTF(("Array A (row indices of matrix) not present.\n")) ;
+	    break ;
+
+	case COLAMD_ERROR_p_not_present:
+
+	    PRINTF(("Array p (column pointers for matrix) not present.\n")) ;
+	    break ;
+
+	case COLAMD_ERROR_nrow_negative:
+
+	    PRINTF(("Invalid number of rows (%d).\n", i1)) ;
+	    break ;
+
+	case COLAMD_ERROR_ncol_negative:
+
+	    PRINTF(("Invalid number of columns (%d).\n", i1)) ;
+	    break ;
+
+	case COLAMD_ERROR_nnz_negative:
+
+	    PRINTF(("Invalid number of nonzero entries (%d).\n", i1)) ;
+	    break ;
+
+	case COLAMD_ERROR_p0_nonzero:
+
+	    PRINTF(("Invalid column pointer, p [0] = %d, must be zero.\n", i1));
+	    break ;
+
+	case COLAMD_ERROR_A_too_small:
+
+	    PRINTF(("Array A too small.\n")) ;
+	    PRINTF(("        Need Alen >= %d, but given only Alen = %d.\n",
+	    i1, i2)) ;
+	    break ;
+
+	case COLAMD_ERROR_col_length_negative:
+
+	    PRINTF
+	    (("Column %d has a negative number of nonzero entries (%d).\n",
+	    INDEX (i1), i2)) ;
+	    break ;
+
+	case COLAMD_ERROR_row_index_out_of_bounds:
+
+	    PRINTF
+	    (("Row index (row %d) out of bounds (%d to %d) in column %d.\n",
+	    INDEX (i2), INDEX (0), INDEX (i3-1), INDEX (i1))) ;
+	    break ;
+
+	case COLAMD_ERROR_out_of_memory:
+
+	    PRINTF(("Out of memory.\n")) ;
+	    break ;
+
+	/* v2.4: internal-error case deleted */
+    }
+}
+
+
+
+
+/* ========================================================================== */
+/* === colamd debugging routines ============================================ */
+/* ========================================================================== */
+
+/* When debugging is disabled, the remainder of this file is ignored. */
+
+#ifndef NDEBUG
+
+
+/* ========================================================================== */
+/* === debug_structures ===================================================== */
+/* ========================================================================== */
+
+/*
+    At this point, all empty rows and columns are dead.  All live columns
+    are "clean" (containing no dead rows) and simplicial (no supercolumns
+    yet).  Rows may contain dead columns, but all live rows contain at
+    least one live column.
+*/
+
+PRIVATE void debug_structures
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A [],
+    Int n_col2
+)
+{
+    /* === Local variables ================================================== */
+
+    Int i ;
+    Int c ;
+    Int *cp ;
+    Int *cp_end ;
+    Int len ;
+    Int score ;
+    Int r ;
+    Int *rp ;
+    Int *rp_end ;
+    Int deg ;
+
+    /* === Check A, Row, and Col ============================================ */
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	if (COL_IS_ALIVE (c))
+	{
+	    len = Col [c].length ;
+	    score = Col [c].shared2.score ;
+	    DEBUG4 (("initial live col %5d %5d %5d\n", c, len, score)) ;
+	    ASSERT (len > 0) ;
+	    ASSERT (score >= 0) ;
+	    ASSERT (Col [c].shared1.thickness == 1) ;
+	    cp = &A [Col [c].start] ;
+	    cp_end = cp + len ;
+	    while (cp < cp_end)
+	    {
+		r = *cp++ ;
+		ASSERT (ROW_IS_ALIVE (r)) ;
+	    }
+	}
+	else
+	{
+	    i = Col [c].shared2.order ;
+	    ASSERT (i >= n_col2 && i < n_col) ;
+	}
+    }
+
+    for (r = 0 ; r < n_row ; r++)
+    {
+	if (ROW_IS_ALIVE (r))
+	{
+	    i = 0 ;
+	    len = Row [r].length ;
+	    deg = Row [r].shared1.degree ;
+	    ASSERT (len > 0) ;
+	    ASSERT (deg > 0) ;
+	    rp = &A [Row [r].start] ;
+	    rp_end = rp + len ;
+	    while (rp < rp_end)
+	    {
+		c = *rp++ ;
+		if (COL_IS_ALIVE (c))
+		{
+		    i++ ;
+		}
+	    }
+	    ASSERT (i > 0) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_deg_lists ====================================================== */
+/* ========================================================================== */
+
+/*
+    Prints the contents of the degree lists.  Counts the number of columns
+    in the degree list and compares it to the total it should have.  Also
+    checks the row degrees.
+*/
+
+PRIVATE void debug_deg_lists
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int head [],
+    Int min_score,
+    Int should,
+    Int max_deg
+)
+{
+    /* === Local variables ================================================== */
+
+    Int deg ;
+    Int col ;
+    Int have ;
+    Int row ;
+
+    /* === Check the degree lists =========================================== */
+
+    if (n_col > 10000 && colamd_debug <= 0)
+    {
+	return ;
+    }
+    have = 0 ;
+    DEBUG4 (("Degree lists: %d\n", min_score)) ;
+    for (deg = 0 ; deg <= n_col ; deg++)
+    {
+	col = head [deg] ;
+	if (col == EMPTY)
+	{
+	    continue ;
+	}
+	DEBUG4 (("%d:", deg)) ;
+	while (col != EMPTY)
+	{
+	    DEBUG4 ((" %d", col)) ;
+	    have += Col [col].shared1.thickness ;
+	    ASSERT (COL_IS_ALIVE (col)) ;
+	    col = Col [col].shared4.degree_next ;
+	}
+	DEBUG4 (("\n")) ;
+    }
+    DEBUG4 (("should %d have %d\n", should, have)) ;
+    ASSERT (should == have) ;
+
+    /* === Check the row degrees ============================================ */
+
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+	return ;
+    }
+    for (row = 0 ; row < n_row ; row++)
+    {
+	if (ROW_IS_ALIVE (row))
+	{
+	    ASSERT (Row [row].shared1.degree <= max_deg) ;
+	}
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_mark =========================================================== */
+/* ========================================================================== */
+
+/*
+    Ensures that the tag_mark is less that the maximum and also ensures that
+    each entry in the mark array is less than the tag mark.
+*/
+
+PRIVATE void debug_mark
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Colamd_Row Row [],
+    Int tag_mark,
+    Int max_mark
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+
+    /* === Check the Row marks ============================================== */
+
+    ASSERT (tag_mark > 0 && tag_mark <= max_mark) ;
+    if (n_row > 10000 && colamd_debug <= 0)
+    {
+	return ;
+    }
+    for (r = 0 ; r < n_row ; r++)
+    {
+	ASSERT (Row [r].shared2.mark < tag_mark) ;
+    }
+}
+
+
+/* ========================================================================== */
+/* === debug_matrix ========================================================= */
+/* ========================================================================== */
+
+/*
+    Prints out the contents of the columns and the rows.
+*/
+
+PRIVATE void debug_matrix
+(
+    /* === Parameters ======================================================= */
+
+    Int n_row,
+    Int n_col,
+    Colamd_Row Row [],
+    Colamd_Col Col [],
+    Int A []
+)
+{
+    /* === Local variables ================================================== */
+
+    Int r ;
+    Int c ;
+    Int *rp ;
+    Int *rp_end ;
+    Int *cp ;
+    Int *cp_end ;
+
+    /* === Dump the rows and columns of the matrix ========================== */
+
+    if (colamd_debug < 3)
+    {
+	return ;
+    }
+    DEBUG3 (("DUMP MATRIX:\n")) ;
+    for (r = 0 ; r < n_row ; r++)
+    {
+	DEBUG3 (("Row %d alive? %d\n", r, ROW_IS_ALIVE (r))) ;
+	if (ROW_IS_DEAD (r))
+	{
+	    continue ;
+	}
+	DEBUG3 (("start %d length %d degree %d\n",
+		Row [r].start, Row [r].length, Row [r].shared1.degree)) ;
+	rp = &A [Row [r].start] ;
+	rp_end = rp + Row [r].length ;
+	while (rp < rp_end)
+	{
+	    c = *rp++ ;
+	    DEBUG4 (("	%d col %d\n", COL_IS_ALIVE (c), c)) ;
+	}
+    }
+
+    for (c = 0 ; c < n_col ; c++)
+    {
+	DEBUG3 (("Col %d alive? %d\n", c, COL_IS_ALIVE (c))) ;
+	if (COL_IS_DEAD (c))
+	{
+	    continue ;
+	}
+	DEBUG3 (("start %d length %d shared1 %d shared2 %d\n",
+		Col [c].start, Col [c].length,
+		Col [c].shared1.thickness, Col [c].shared2.score)) ;
+	cp = &A [Col [c].start] ;
+	cp_end = cp + Col [c].length ;
+	while (cp < cp_end)
+	{
+	    r = *cp++ ;
+	    DEBUG4 (("	%d row %d\n", ROW_IS_ALIVE (r), r)) ;
+	}
+    }
+}
+
+PRIVATE void colamd_get_debug
+(
+    char *method
+)
+{
+    FILE *f ;
+    colamd_debug = 0 ;		/* no debug printing */
+    f = fopen ("debug", "r") ;
+    if (f == (FILE *) NULL)
+    {
+	colamd_debug = 0 ;
+    }
+    else
+    {
+	fscanf (f, "%d", &colamd_debug) ;
+	fclose (f) ;
+    }
+    DEBUG0 (("%s: debug version, D = %d (THIS WILL BE SLOW!)\n",
+    	method, colamd_debug)) ;
+}
+
+#endif /* NDEBUG */
diff --git a/src/COLAMD/Source/colamd_global.c b/src/COLAMD/Source/colamd_global.c
new file mode 100644
index 0000000..88a2aed
--- /dev/null
+++ b/src/COLAMD/Source/colamd_global.c
@@ -0,0 +1,24 @@
+/* ========================================================================== */
+/* === colamd_global.c ====================================================== */
+/* ========================================================================== */
+
+/* ----------------------------------------------------------------------------
+ * COLAMD, Copyright (C) 2007, Timothy A. Davis.
+ * See License.txt for the Version 2.1 of the GNU Lesser General Public License
+ * http://www.suitesparse.com
+ * -------------------------------------------------------------------------- */
+
+/* Global variables for COLAMD */
+
+#ifndef NPRINT
+#ifdef MATLAB_MEX_FILE
+#include "mex.h"
+int (*colamd_printf) (const char *, ...) = mexPrintf ;
+#else
+#include <stdio.h>
+int (*colamd_printf) (const char *, ...) = printf ;
+#endif
+#else
+int (*colamd_printf) (const char *, ...) = ((void *) 0) ;
+#endif
+
diff --git a/src/Makevars.in b/src/Makevars.in
index 33cec79..eade686 100644
--- a/src/Makevars.in
+++ b/src/Makevars.in
@@ -1,10 +1,14 @@
-PKG_CFLAGS=-DUSING_R -I. -Ics -Iglpk -Iglpk/amd -Iglpk/colamd -Iplfit \
-	@CPPFLAGS@ @CFLAGS@ -DNDEBUG \
+
+PKG_CFLAGS=-DUSING_R -I. -Iinclude -Ics -Iglpk -Iplfit \
+        -ICHOLMOD/Include -IAMD/Include -ICOLAMD/Include \
+	-ISuiteSparse_config \
+	@CPPFLAGS@ @CFLAGS@ -DNDEBUG -DNPARTITION -DNTIMER -DNCAMD -DNPRINT\
 	-DPACKAGE_VERSION=\"@PACKAGE_VERSION@\" -DINTERNAL_ARPACK \
 	-DIGRAPH_THREAD_LOCAL=/**/
 PKG_CXXFLAGS= -DUSING_R -DIGRAPH_THREAD_LOCAL=/**/ -DNDEBUG -Iprpack -I. \
-	-DPRPACK_IGRAPH_SUPPORT
+	-Iinclude -DPRPACK_IGRAPH_SUPPORT
 PKG_LIBS=@XML2_LIBS@ @GMP_LIBS@ @GLPK_LIBS@ $(FLIBS) $(LAPACK_LIBS) $(BLAS_LIBS)
 
 all: $(SHLIB)
 
+OBJECTS=AMD/Source/amd.o AMD/Source/amd_1.o AMD/Source/amd_2.o AMD/Source/amd_aat.o AMD/Source/amd_control.o AMD/Source/amd_defaults.o AMD/Source/amd_dump.o AMD/Source/amd_global.o AMD/Source/amd_info.o AMD/Source/amd_order.o AMD/Source/amd_post_tree.o AMD/Source/amd_postorder.o AMD/Source/amd_preprocess.o AMD/Source/amd_valid.o AMD/Source/amdbar.o CHOLMOD/Check/cholmod_check.o CHOLMOD/Check/cholmod_read.o CHOLMOD/Check/cholmod_write.o CHOLMOD/Cholesky/cholmod_amd.o CHOLMOD/Cholesky/chol [...]
diff --git a/src/Makevars.win b/src/Makevars.win
index f892451..13f49b7 100644
--- a/src/Makevars.win
+++ b/src/Makevars.win
@@ -1,6 +1,7 @@
 
-PKG_CPPFLAGS= -I${LIB_XML}/include/libxml2 -I${LIB_XML}/include -DLIBXML_STATIC -DUSING_R -DHAVE_FMEMOPEN=0 -DHAVE_OPEN_MEMSTREAM=0 -DHAVE_RINTF -DWin32 -DHAVE_LIBXML -Wall -DPACKAGE_VERSION=\"0.7.1\" -DHAVE_FMIN=1 -DHAVE_LOG2=1 -DHAVE_SNPRINTF -Ics -Iglpk -DHAVE_GLPK=1 -Iglpk/amd -Iglpk/colamd -Iplfit -Iprpack -DIGRAPH_THREAD_LOCAL=/**/ -DPRPACK_IGRAPH_SUPPORT -I.
+PKG_CPPFLAGS= -I${LIB_XML}/include/libxml2 -I${LIB_XML}/include -DLIBXML_STATIC -DUSING_R -DHAVE_FMEMOPEN=0 -DHAVE_OPEN_MEMSTREAM=0 -DHAVE_RINTF -DWin32 -DHAVE_LIBXML -Wall -DPACKAGE_VERSION=\"1.0.1\" -DHAVE_FMIN=1 -DHAVE_LOG2=1 -DHAVE_SNPRINTF -Ics -Iglpk -DHAVE_GLPK=1 -Iplfit -Iprpack -DIGRAPH_THREAD_LOCAL=/**/ -DPRPACK_IGRAPH_SUPPORT -I. -Iinclude -ICHOLMOD/Include -IAMD/Include -ICOLAMD/Include -ISuiteSparse_config -DNDEBUG -DNPARTITION -DNTIMER -DNCAMD -DNPRINT -I$(LIB_GMP)/include
 
-PKG_CFLAGS = -DINTERNAL_ARPACK -I.
+PKG_CFLAGS = -DINTERNAL_ARPACK -I. -I$(LIB_GMP)/include
 
-PKG_LIBS = -L${LIB_XML}/lib -lxml2 -liconv -lz -lws2_32 $(BLAS_LIBS) $(LAPACK_LIBS)
+PKG_LIBS = -L${LIB_XML}/lib -lxml2 -liconv -lz -lws2_32 -lgmp -L$(LIB_GMP)/lib $(BLAS_LIBS) $(LAPACK_LIBS)
+OBJECTS=AMD/Source/amd.o AMD/Source/amd_1.o AMD/Source/amd_2.o AMD/Source/amd_aat.o AMD/Source/amd_control.o AMD/Source/amd_defaults.o AMD/Source/amd_dump.o AMD/Source/amd_global.o AMD/Source/amd_info.o AMD/Source/amd_order.o AMD/Source/amd_post_tree.o AMD/Source/amd_postorder.o AMD/Source/amd_preprocess.o AMD/Source/amd_valid.o AMD/Source/amdbar.o CHOLMOD/Check/cholmod_check.o CHOLMOD/Check/cholmod_read.o CHOLMOD/Check/cholmod_write.o CHOLMOD/Cholesky/cholmod_amd.o CHOLMOD/Cholesky/chol [...]
diff --git a/src/SuiteSparse_config/Makefile b/src/SuiteSparse_config/Makefile
new file mode 100644
index 0000000..3c621bd
--- /dev/null
+++ b/src/SuiteSparse_config/Makefile
@@ -0,0 +1,43 @@
+#-------------------------------------------------------------------------------
+# SuiteSparse_config Makefile
+#-------------------------------------------------------------------------------
+
+VERSION = 4.2.1
+
+default: ccode
+
+include SuiteSparse_config.mk
+
+ccode: libsuitesparseconfig.a
+
+all: libsuitesparseconfig.a
+
+library: libsuitesparseconfig.a
+
+libsuitesparseconfig.a: SuiteSparse_config.c SuiteSparse_config.h
+	$(CC) $(CF) -c SuiteSparse_config.c
+	$(ARCHIVE) libsuitesparseconfig.a SuiteSparse_config.o
+	$(RANLIB) libsuitesparseconfig.a
+	- $(RM) SuiteSparse_config.o
+
+distclean: purge
+
+purge: clean
+	- $(RM) *.o *.a
+
+clean:
+	- $(RM) -r $(CLEAN)
+
+# install SuiteSparse_config
+install:
+	$(CP) libsuitesparseconfig.a $(INSTALL_LIB)/libsuitesparseconfig.$(VERSION).a
+	( cd $(INSTALL_LIB) ; ln -sf libsuitesparseconfig.$(VERSION).a libsuitesparseconfig.a )
+	$(CP) SuiteSparse_config.h $(INSTALL_INCLUDE)
+	chmod 644 $(INSTALL_LIB)/libsuitesparseconfig*.a
+	chmod 644 $(INSTALL_INCLUDE)/SuiteSparse_config.h
+
+# uninstall SuiteSparse_config
+uninstall:
+	$(RM) $(INSTALL_LIB)/libsuitesparseconfig*.a
+	$(RM) $(INSTALL_INCLUDE)/SuiteSparse_config.h
+
diff --git a/src/SuiteSparse_config/README.txt b/src/SuiteSparse_config/README.txt
new file mode 100644
index 0000000..bc85ace
--- /dev/null
+++ b/src/SuiteSparse_config/README.txt
@@ -0,0 +1,48 @@
+SuiteSparse_config, 2013, Timothy A. Davis, http://www.suitesparse.com
+(formerly the UFconfig package)
+
+SuiteSparse_config contains configuration settings for all many of the software
+packages that I develop or co-author.  Note that older versions of some of
+these packages do not require SuiteSparse_config.
+
+  Package  Description
+  -------  -----------
+  AMD      approximate minimum degree ordering
+  CAMD     constrained AMD
+  COLAMD   column approximate minimum degree ordering
+  CCOLAMD  constrained approximate minimum degree ordering
+  UMFPACK  sparse LU factorization, with the BLAS
+  CXSparse int/long/real/complex version of CSparse
+  CHOLMOD  sparse Cholesky factorization, update/downdate
+  KLU      sparse LU factorization, BLAS-free
+  BTF      permutation to block triangular form
+  LDL      concise sparse LDL'
+  LPDASA   LP Dual Active Set Algorithm
+  RBio     read/write files in Rutherford/Boeing format
+  SPQR     sparse QR factorization (full name: SuiteSparseQR)
+
+SuiteSparse_config is not required by these packages:
+
+  CSparse       a Concise Sparse matrix package
+  MATLAB_Tools  toolboxes for use in MATLAB
+
+In addition, the xerbla/ directory contains Fortan and C versions of the
+BLAS/LAPACK xerbla routine, which is called when an invalid input is passed to
+the BLAS or LAPACK.  The xerbla provided here does not print any message, so
+the entire Fortran I/O library does not need to be linked into a C application.
+Most versions of the BLAS contain xerbla, but those from K. Goto do not.  Use
+this if you need too.
+
+If you edit this directory (SuiteSparse_config.mk in particular) then you
+must do "make purge ; make" in the parent directory to recompile all of
+SuiteSparse.  Otherwise, the changes will not necessarily be applied.
+
+--------------------------------------------------------------------------------
+A note on the update to SuiteSparse Version 4.0.0:  The SuiteSparse_long macro
+defines an integer that is 64-bits in size on 64-bit platforms, and 32-bits on
+32-bit platforms.  It was formerly called UF_long, but UF_long has been removed
+because of potential name conflicts.  UF_long is still available to user codes,
+but it can now be safely #undef'd in case of name conflicts in user code.
+Future codes should use SuiteSparse_long in place of UF_long.
+--------------------------------------------------------------------------------
+
diff --git a/src/SuiteSparse_config/SuiteSparse_config.c b/src/SuiteSparse_config/SuiteSparse_config.c
new file mode 100644
index 0000000..4387b4b
--- /dev/null
+++ b/src/SuiteSparse_config/SuiteSparse_config.c
@@ -0,0 +1,191 @@
+/* ========================================================================== */
+/* === SuiteSparse_config =================================================== */
+/* ========================================================================== */
+
+/* Copyright (c) 2012, Timothy A. Davis.  No licensing restrictions
+ * apply to this file or to the SuiteSparse_config directory.
+ * Author: Timothy A. Davis.
+ */
+
+#include "SuiteSparse_config.h"
+
+/* -------------------------------------------------------------------------- */
+/* SuiteSparse_malloc: malloc wrapper */
+/* -------------------------------------------------------------------------- */
+
+void *SuiteSparse_malloc    /* pointer to allocated block of memory */
+(
+    size_t nitems,          /* number of items to malloc (>=1 is enforced) */
+    size_t size_of_item,    /* sizeof each item */
+    int *ok,                /* TRUE if successful, FALSE otherwise */
+    SuiteSparse_config *config      /* SuiteSparse-wide configuration */
+)
+{
+    void *p ;
+    if (nitems < 1) nitems = 1 ;
+    if (nitems * size_of_item != ((double) nitems) * size_of_item)
+    {
+        /* Int overflow */
+        *ok = 0 ;
+        return (NULL) ;
+    }
+    if (!config || config->malloc_memory == NULL)
+    {
+        /* use malloc by default */
+        p = (void *) malloc (nitems * size_of_item) ;
+    }
+    else
+    {
+        /* use the pointer to malloc in the config */
+        p = (void *) (config->malloc_memory) (nitems * size_of_item) ;
+    }
+    *ok = (p != NULL) ;
+    return (p) ;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* SuiteSparse_free: free wrapper */
+/* -------------------------------------------------------------------------- */
+
+void *SuiteSparse_free      /* always returns NULL */
+(
+    void *p,                /* block to free */
+    SuiteSparse_config *config        /* SuiteSparse-wide configuration */
+)
+{
+    if (p)
+    {
+        if (!config || config->free_memory == NULL)
+        {
+            /* use free by default */
+            free (p) ;
+        }
+        else
+        {
+            /* use the pointer to free in the config */
+            (config->free_memory) (p) ;
+        }
+    }
+    return (NULL) ;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* SuiteSparse_tic: return current wall clock time */
+/* -------------------------------------------------------------------------- */
+
+/* Returns the number of seconds (tic [0]) and nanoseconds (tic [1]) since some
+ * unspecified but fixed time in the past.  If no timer is installed, zero is
+ * returned.  A scalar double precision value for 'tic' could be used, but this
+ * might cause loss of precision because clock_getttime returns the time from
+ * some distant time in the past.  Thus, an array of size 2 is used.
+ *
+ * The timer is enabled by default.  To disable the timer, compile with
+ * -DNTIMER.  If enabled on a POSIX C 1993 system, the timer requires linking
+ * with the -lrt library.
+ *
+ * example:
+ *
+ *      double tic [2], r, s, t ;
+ *      SuiteSparse_tic (tic) ;     // start the timer
+ *      // do some work A
+ *      t = SuiteSparse_toc (tic) ; // t is time for work A, in seconds
+ *      // do some work B
+ *      s = SuiteSparse_toc (tic) ; // s is time for work A and B, in seconds
+ *      SuiteSparse_tic (tic) ;     // restart the timer
+ *      // do some work C
+ *      r = SuiteSparse_toc (tic) ; // s is time for work C, in seconds
+ *
+ * A double array of size 2 is used so that this routine can be more easily
+ * ported to non-POSIX systems.  The caller does not rely on the POSIX
+ * <time.h> include file.
+ */
+
+#ifdef SUITESPARSE_TIMER_ENABLED
+
+#include <time.h>
+
+void SuiteSparse_tic
+(
+    double tic [2]      /* output, contents undefined on input */
+)
+{
+    /* POSIX C 1993 timer, requires -librt */
+    struct timespec t ;
+    clock_gettime (CLOCK_MONOTONIC, &t) ;
+    tic [0] = (double) (t.tv_sec) ;
+    tic [1] = (double) (t.tv_nsec) ;
+}
+
+#else
+
+void SuiteSparse_tic
+(
+    double tic [2]      /* output, contents undefined on input */
+)
+{
+    /* no timer installed */
+    tic [0] = 0 ;
+    tic [1] = 0 ;
+}
+
+#endif
+
+
+/* -------------------------------------------------------------------------- */
+/* SuiteSparse_toc: return time since last tic */
+/* -------------------------------------------------------------------------- */
+
+/* Assuming SuiteSparse_tic is accurate to the nanosecond, this function is
+ * accurate down to the nanosecond for 2^53 nanoseconds since the last call to
+ * SuiteSparse_tic, which is sufficient for SuiteSparse (about 104 days).  If
+ * additional accuracy is required, the caller can use two calls to
+ * SuiteSparse_tic and do the calculations differently.
+ */
+
+double SuiteSparse_toc  /* returns time in seconds since last tic */
+(
+    double tic [2]  /* input, not modified from last call to SuiteSparse_tic */
+)
+{
+    double toc [2] ;
+    SuiteSparse_tic (toc) ;
+    return ((toc [0] - tic [0]) + 1e-9 * (toc [1] - tic [1])) ;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* SuiteSparse_time: return current wallclock time in seconds */
+/* -------------------------------------------------------------------------- */
+
+/* This function might not be accurate down to the nanosecond. */
+
+double SuiteSparse_time  /* returns current wall clock time in seconds */
+(
+    void
+)
+{
+    double toc [2] ;
+    SuiteSparse_tic (toc) ;
+    return (toc [0] + 1e-9 * toc [1]) ;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* SuiteSparse_version: return the current version of SuiteSparse */
+/* -------------------------------------------------------------------------- */
+
+int SuiteSparse_version
+(
+    int version [3]
+)
+{
+    if (version != NULL)
+    {
+        version [0] = SUITESPARSE_MAIN_VERSION ;
+        version [1] = SUITESPARSE_SUB_VERSION ;
+        version [2] = SUITESPARSE_SUBSUB_VERSION ;
+    }
+    return (SUITESPARSE_VERSION) ;
+}
diff --git a/src/SuiteSparse_config/SuiteSparse_config.h b/src/SuiteSparse_config/SuiteSparse_config.h
new file mode 100644
index 0000000..fff5ea0
--- /dev/null
+++ b/src/SuiteSparse_config/SuiteSparse_config.h
@@ -0,0 +1,202 @@
+/* ========================================================================== */
+/* === SuiteSparse_config =================================================== */
+/* ========================================================================== */
+
+/* Configuration file for SuiteSparse: a Suite of Sparse matrix packages
+ * (AMD, COLAMD, CCOLAMD, CAMD, CHOLMOD, UMFPACK, CXSparse, and others).
+ *
+ * SuiteSparse_config.h provides the definition of the long integer.  On most
+ * systems, a C program can be compiled in LP64 mode, in which long's and
+ * pointers are both 64-bits, and int's are 32-bits.  Windows 64, however, uses
+ * the LLP64 model, in which int's and long's are 32-bits, and long long's and
+ * pointers are 64-bits.
+ *
+ * SuiteSparse packages that include long integer versions are
+ * intended for the LP64 mode.  However, as a workaround for Windows 64
+ * (and perhaps other systems), the long integer can be redefined.
+ *
+ * If _WIN64 is defined, then the __int64 type is used instead of long.
+ *
+ * The long integer can also be defined at compile time.  For example, this
+ * could be added to SuiteSparse_config.mk:
+ *
+ * CFLAGS = -O -D'SuiteSparse_long=long long' \
+ *  -D'SuiteSparse_long_max=9223372036854775801' -D'SuiteSparse_long_idd="lld"'
+ *
+ * This file defines SuiteSparse_long as either long (on all but _WIN64) or
+ * __int64 on Windows 64.  The intent is that a SuiteSparse_long is always a
+ * 64-bit integer in a 64-bit code.  ptrdiff_t might be a better choice than
+ * long; it is always the same size as a pointer.
+ *
+ * This file also defines the SUITESPARSE_VERSION and related definitions.
+ *
+ * Copyright (c) 2012, Timothy A. Davis.  No licensing restrictions apply
+ * to this file or to the SuiteSparse_config directory.
+ * Author: Timothy A. Davis.
+ */
+
+#ifndef _SUITESPARSECONFIG_H
+#define _SUITESPARSECONFIG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <limits.h>
+#include <stdlib.h>
+
+/* ========================================================================== */
+/* === SuiteSparse_long ===================================================== */
+/* ========================================================================== */
+
+#ifndef SuiteSparse_long
+
+#ifdef _WIN64
+
+#define SuiteSparse_long __int64
+#define SuiteSparse_long_max _I64_MAX
+#define SuiteSparse_long_idd "I64d"
+
+#else
+
+#define SuiteSparse_long long
+#define SuiteSparse_long_max LONG_MAX
+#define SuiteSparse_long_idd "ld"
+
+#endif
+#define SuiteSparse_long_id "%" SuiteSparse_long_idd
+#endif
+
+/* For backward compatibility with prior versions of SuiteSparse.  The UF_*
+ * macros are deprecated and will be removed in a future version. */
+#ifndef UF_long
+#define UF_long     SuiteSparse_long
+#define UF_long_max SuiteSparse_long_max
+#define UF_long_idd SuiteSparse_long_idd
+#define UF_long_id  SuiteSparse_long_id
+#endif
+
+/* ========================================================================== */
+/* === SuiteSparse_config parameters and functions ========================== */
+/* ========================================================================== */
+
+/* SuiteSparse-wide parameters will be placed in this struct. */
+
+typedef struct SuiteSparse_config_struct
+{
+    void *(*malloc_memory) (size_t) ;           /* pointer to malloc */
+    void *(*realloc_memory) (void *, size_t) ;  /* pointer to realloc */
+    void (*free_memory) (void *) ;              /* pointer to free */
+    void *(*calloc_memory) (size_t, size_t) ;   /* pointer to calloc */
+
+} SuiteSparse_config ;
+
+void *SuiteSparse_malloc    /* pointer to allocated block of memory */
+(
+    size_t nitems,          /* number of items to malloc (>=1 is enforced) */
+    size_t size_of_item,    /* sizeof each item */
+    int *ok,                /* TRUE if successful, FALSE otherwise */
+    SuiteSparse_config *config        /* SuiteSparse-wide configuration */
+) ;
+
+void *SuiteSparse_free      /* always returns NULL */
+(
+    void *p,                /* block to free */
+    SuiteSparse_config *config        /* SuiteSparse-wide configuration */
+) ;
+
+void SuiteSparse_tic    /* start the timer */
+(
+    double tic [2]      /* output, contents undefined on input */
+) ;
+
+double SuiteSparse_toc  /* return time in seconds since last tic */
+(
+    double tic [2]      /* input: from last call to SuiteSparse_tic */
+) ;
+
+double SuiteSparse_time  /* returns current wall clock time in seconds */
+(
+    void
+) ;
+
+/* determine which timer to use, if any */
+#ifndef NTIMER
+#ifdef _POSIX_C_SOURCE
+#if    _POSIX_C_SOURCE >= 199309L
+#define SUITESPARSE_TIMER_ENABLED
+#endif
+#endif
+#endif
+
+/* ========================================================================== */
+/* === SuiteSparse version ================================================== */
+/* ========================================================================== */
+
+/* SuiteSparse is not a package itself, but a collection of packages, some of
+ * which must be used together (UMFPACK requires AMD, CHOLMOD requires AMD,
+ * COLAMD, CAMD, and CCOLAMD, etc).  A version number is provided here for the
+ * collection itself.  The versions of packages within each version of
+ * SuiteSparse are meant to work together.  Combining one packge from one
+ * version of SuiteSparse, with another package from another version of
+ * SuiteSparse, may or may not work.
+ *
+ * SuiteSparse contains the following packages:
+ *
+ *  SuiteSparse_config version 4.2.1 (version always the same as SuiteSparse)
+ *  AMD             version 2.3.1
+ *  BTF             version 1.2.0
+ *  CAMD            version 2.3.1
+ *  CCOLAMD         version 2.8.0
+ *  CHOLMOD         version 2.1.2
+ *  COLAMD          version 2.8.0
+ *  CSparse         version 3.1.2
+ *  CXSparse        version 3.1.2
+ *  KLU             version 1.2.1
+ *  LDL             version 2.1.0
+ *  RBio            version 2.1.1
+ *  SPQR            version 1.3.1 (full name is SuiteSparseQR)
+ *  UMFPACK         version 5.6.2
+ *  MATLAB_Tools    various packages & M-files
+ *
+ * Other package dependencies:
+ *  BLAS            required by CHOLMOD and UMFPACK
+ *  LAPACK          required by CHOLMOD
+ *  METIS 4.0.1     required by CHOLMOD (optional) and KLU (optional)
+ */
+
+
+int SuiteSparse_version     /* returns SUITESPARSE_VERSION */
+(
+    /* output, not defined on input.  Not used if NULL.  Returns
+       the three version codes in version [0..2]:
+       version [0] is SUITESPARSE_MAIN_VERSION
+       version [1] is SUITESPARSE_SUB_VERSION
+       version [2] is SUITESPARSE_SUBSUB_VERSION
+       */
+    int version [3]
+) ;
+
+/* Versions prior to 4.2.0 do not have the above function.  The following
+   code fragment will work with any version of SuiteSparse:
+
+   #ifdef SUITESPARSE_HAS_VERSION_FUNCTION
+   v = SuiteSparse_version (NULL) ;
+   #else
+   v = SUITESPARSE_VERSION ;
+   #endif
+*/
+#define SUITESPARSE_HAS_VERSION_FUNCTION
+
+#define SUITESPARSE_DATE "April 25, 2013"
+#define SUITESPARSE_VER_CODE(main,sub) ((main) * 1000 + (sub))
+#define SUITESPARSE_MAIN_VERSION 4
+#define SUITESPARSE_SUB_VERSION 2
+#define SUITESPARSE_SUBSUB_VERSION 1
+#define SUITESPARSE_VERSION \
+    SUITESPARSE_VER_CODE(SUITESPARSE_MAIN_VERSION,SUITESPARSE_SUB_VERSION)
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/SuiteSparse_config/SuiteSparse_config.mk b/src/SuiteSparse_config/SuiteSparse_config.mk
new file mode 100644
index 0000000..52faeff
--- /dev/null
+++ b/src/SuiteSparse_config/SuiteSparse_config.mk
@@ -0,0 +1,393 @@
+#===============================================================================
+# SuiteSparse_config.mk:  common configuration file for the SuiteSparse
+#===============================================================================
+
+# This file contains all configuration settings for all packages authored or
+# co-authored by Tim Davis:
+#
+# Package Version       Description
+# ------- -------       -----------
+# AMD	  1.2 or later  approximate minimum degree ordering
+# COLAMD  2.4 or later  column approximate minimum degree ordering
+# CCOLAMD 1.0 or later  constrained column approximate minimum degree ordering
+# CAMD    any		constrained approximate minimum degree ordering
+# UMFPACK 4.5 or later	sparse LU factorization, with the BLAS
+# CHOLMOD any		sparse Cholesky factorization, update/downdate
+# KLU	  0.8 or later  sparse LU factorization, BLAS-free
+# BTF	  0.8 or later  permutation to block triangular form
+# LDL	  1.2 or later	concise sparse LDL'
+# CXSparse any		extended version of CSparse (int/long, real/complex)
+# SuiteSparseQR	any	sparse QR factorization
+# RBio    2.0 or later  read/write sparse matrices in Rutherford-Boeing format
+#
+# By design, this file is NOT included in the CSparse makefile.
+# That package is fully stand-alone.  CSparse is primarily for teaching;
+# production code should use CXSparse.
+#
+# The SuiteSparse_config directory and the above packages should all appear in
+# a single directory, in order for the Makefile's within each package to find
+# this file.
+#
+# To enable an option of the form "# OPTION = ...", edit this file and
+# delete the "#" in the first column of the option you wish to use.
+#
+# The use of METIS 4.0.1 is optional.  To exclude METIS, you must compile with
+# CHOLMOD_CONFIG set to -DNPARTITION.  See below for details.  However, if you
+# do not have a metis-4.0 directory inside the SuiteSparse directory, the
+# */Makefile's that optionally rely on METIS will automatically detect this
+# and compile without METIS.
+
+#------------------------------------------------------------------------------
+# Generic configuration
+#------------------------------------------------------------------------------
+
+# Using standard definitions from the make environment, typically:
+#
+#   CC              cc      C compiler
+#   CXX             g++     C++ compiler
+#   CFLAGS          [ ]     flags for C and C++ compiler
+#   CPPFLAGS        [ ]     flags for C and C++ compiler
+#   TARGET_ARCH     [ ]     target architecture
+#   FFLAGS          [ ]     flags for Fortran compiler
+#   RM              rm -f   delete a file
+#   AR              ar      create a static *.a library archive
+#   ARFLAGS         rv      flags for ar
+#   MAKE            make    make itself (sometimes called gmake)
+#
+# You can redefine them here, but by default they are used from the
+# default make environment.
+
+# C and C++ compiler flags.  The first three are standard for *.c and *.cpp
+# Add -DNTIMER if you do use any timing routines (otherwise -lrt is required).
+# CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O3 -fexceptions -fPIC -DNTIMER
+  CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O3 -fexceptions -fPIC
+
+# ranlib, and ar, for generating libraries.  If you don't need ranlib,
+# just change it to RANLAB = echo
+RANLIB = ranlib
+ARCHIVE = $(AR) $(ARFLAGS)
+
+# copy and delete a file
+CP = cp -f
+MV = mv -f
+
+# Fortran compiler (not required for 'make' or 'make library')
+F77 = gfortran
+F77FLAGS = $(FFLAGS) -O
+F77LIB =
+
+# C and Fortran libraries.  Remove -lrt if you don't have it.
+  LIB = -lm -lrt
+# Using the following requires CF = ... -DNTIMER on POSIX C systems.
+# LIB = -lm
+
+# For "make install"
+INSTALL_LIB = /usr/local/lib
+INSTALL_INCLUDE = /usr/local/include
+
+# Which version of MAKE you are using (default is "make")
+# MAKE = make
+# MAKE = gmake
+
+#------------------------------------------------------------------------------
+# BLAS and LAPACK configuration:
+#------------------------------------------------------------------------------
+
+# UMFPACK and CHOLMOD both require the BLAS.  CHOLMOD also requires LAPACK.
+# See Kazushige Goto's BLAS at http://www.cs.utexas.edu/users/flame/goto/ or
+# http://www.tacc.utexas.edu/~kgoto/ for the best BLAS to use with CHOLMOD.
+# LAPACK is at http://www.netlib.org/lapack/ .  You can use the standard
+# Fortran LAPACK along with Goto's BLAS to obtain very good performance.
+# CHOLMOD gets a peak numeric factorization rate of 3.6 Gflops on a 3.2 GHz
+# Pentium 4 (512K cache, 4GB main memory) with the Goto BLAS, and 6 Gflops
+# on a 2.5Ghz dual-core AMD Opteron.
+
+# These settings will probably not work, since there is no fixed convention for
+# naming the BLAS and LAPACK library (*.a or *.so) files.
+
+# This is probably slow ... it might connect to the Standard Reference BLAS:
+BLAS = -lblas -lgfortran
+LAPACK = -llapack
+
+# NOTE: this next option for the "Goto BLAS" has nothing to do with a "goto"
+# statement.  Rather, the Goto BLAS is written by Dr. Kazushige Goto.
+# Using the Goto BLAS:
+# BLAS = -lgoto -lgfortran -lgfortranbegin
+# BLAS = -lgoto2 -lgfortran -lgfortranbegin -lpthread
+
+# Using non-optimized versions:
+# BLAS = -lblas_plain -lgfortran -lgfortranbegin
+# LAPACK = -llapack_plain
+
+# BLAS = -lblas_plain -lgfortran -lgfortranbegin
+# LAPACK = -llapack
+
+# The BLAS might not contain xerbla, an error-handling routine for LAPACK and
+# the BLAS.  Also, the standard xerbla requires the Fortran I/O library, and
+# stops the application program if an error occurs.  A C version of xerbla
+# distributed with this software (SuiteSparse_config/xerbla/libcerbla.a)
+# includes a Fortran-callable xerbla routine that prints nothing and does not
+# stop the application program.  This is optional.
+
+# XERBLA = ../../SuiteSparse_config/xerbla/libcerbla.a 
+
+# If you wish to use the XERBLA in LAPACK and/or the BLAS instead,
+# use this option:
+XERBLA = 
+
+# If you wish to use the Fortran SuiteSparse_config/xerbla/xerbla.f instead,
+# use this:
+
+# XERBLA = ../../SuiteSparse_config/xerbla/libxerbla.a 
+
+#------------------------------------------------------------------------------
+# GPU configuration for CHOLMOD, using the CUDA BLAS
+#------------------------------------------------------------------------------
+
+# no cuda
+GPU_BLAS_PATH =
+GPU_CONFIG =
+
+# with cuda BLAS acceleration for CHOLMOD
+# GPU_BLAS_PATH=/usr/local/cuda
+# GPU_CONFIG=-DGPU_BLAS -I$(GPU_BLAS_PATH)/include
+
+#------------------------------------------------------------------------------
+# METIS, optionally used by CHOLMOD
+#------------------------------------------------------------------------------
+
+# If you do not have METIS, or do not wish to use it in CHOLMOD, you must
+# compile CHOLMOD with the -DNPARTITION flag.
+
+# The path is relative to where it is used, in CHOLMOD/Lib, CHOLMOD/MATLAB, etc.
+# You may wish to use an absolute path.  METIS is optional.  Compile
+# CHOLMOD with -DNPARTITION if you do not wish to use METIS.
+METIS_PATH = ../../metis-4.0
+METIS = ../../metis-4.0/libmetis.a
+
+#------------------------------------------------------------------------------
+# UMFPACK configuration:
+#------------------------------------------------------------------------------
+
+# Configuration flags for UMFPACK.  See UMFPACK/Source/umf_config.h for details.
+#
+# -DNBLAS	do not use the BLAS.  UMFPACK will be very slow.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	do not use the Sun Perf. Library (default is use it on Solaris)
+# -DNRECIPROCAL	do not multiply by the reciprocal
+# -DNO_DIVIDE_BY_ZERO	do not divide by zero
+# -DNCHOLMOD    do not use CHOLMOD as a ordering method.  If -DNCHOLMOD is
+#               included in UMFPACK_CONFIG, then UMFPACK  does not rely on
+#               CHOLMOD, CAMD, CCOLAMD, COLAMD, and METIS.
+
+UMFPACK_CONFIG =
+
+# uncomment this line to compile UMFPACK without CHOLMOD:
+# UMFPACK_CONFIG = -DNCHOLMOD
+
+#------------------------------------------------------------------------------
+# CHOLMOD configuration
+#------------------------------------------------------------------------------
+
+# CHOLMOD Library Modules, which appear in libcholmod.a:
+# Core		requires: none
+# Check		requires: Core
+# Cholesky	requires: Core, AMD, COLAMD.  optional: Partition, Supernodal
+# MatrixOps	requires: Core
+# Modify	requires: Core
+# Partition	requires: Core, CCOLAMD, METIS.  optional: Cholesky
+# Supernodal	requires: Core, BLAS, LAPACK
+#
+# CHOLMOD test/demo Modules (all are GNU GPL, do not appear in libcholmod.a):
+# Tcov		requires: Core, Check, Cholesky, MatrixOps, Modify, Supernodal
+#		optional: Partition
+# Valgrind	same as Tcov
+# Demo		requires: Core, Check, Cholesky, MatrixOps, Supernodal
+#		optional: Partition
+#
+# Configuration flags:
+# -DNCHECK	    do not include the Check module.	   License GNU LGPL
+# -DNCHOLESKY	    do not include the Cholesky module.	   License GNU LGPL
+# -DNPARTITION	    do not include the Partition module.   License GNU LGPL
+#		    also do not include METIS.
+# -DNCAMD           do not use CAMD, etc from Partition module.    GNU LGPL
+# -DNGPL	    do not include any GNU GPL Modules in the CHOLMOD library:
+# -DNMATRIXOPS	    do not include the MatrixOps module.   License GNU GPL
+# -DNMODIFY	    do not include the Modify module.      License GNU GPL
+# -DNSUPERNODAL     do not include the Supernodal module.  License GNU GPL
+#
+# -DNPRINT	    do not print anything.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		    	LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	    for Solaris only.  If defined, do not use the Sun
+#			Performance Library
+
+CHOLMOD_CONFIG = $(GPU_CONFIG)
+
+# uncomment this line to compile CHOLMOD without METIS:
+# CHOLMOD_CONFIG = -DNPARTITION
+
+#------------------------------------------------------------------------------
+# SuiteSparseQR configuration:
+#------------------------------------------------------------------------------
+
+# The SuiteSparseQR library can be compiled with the following options:
+#
+# -DNPARTITION      do not include the CHOLMOD partition module
+# -DNEXPERT         do not include the functions in SuiteSparseQR_expert.cpp
+# -DHAVE_TBB        enable the use of Intel's Threading Building Blocks (TBB)
+
+# default, without timing, without TBB:
+SPQR_CONFIG =
+# with TBB:
+# SPQR_CONFIG = -DHAVE_TBB
+
+# This is needed for IBM AIX: (but not for and C codes, just C++)
+# SPQR_CONFIG = -DBLAS_NO_UNDERSCORE
+
+# with TBB, you must select this:
+# TBB = -ltbb
+# without TBB:
+TBB =
+
+#------------------------------------------------------------------------------
+# Linux
+#------------------------------------------------------------------------------
+
+# Using default compilers:
+# CC = gcc
+# CF = $(CFLAGS) -O3 -fexceptions
+
+# alternatives:
+# CF = $(CFLAGS) -g -fexceptions \
+   	-Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi \
+        -funit-at-a-time
+# CF = $(CFLAGS) -O3 -fexceptions \
+   	-Wall -W -Werror -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi
+# CF = $(CFLAGS) -O3 -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+# CF = $(CFLAGS) -O3
+# CF = $(CFLAGS) -O3 -g -fexceptions
+# CF = $(CFLAGS) -g -fexceptions \
+   	-Wall -W -Wshadow \
+    	-Wredundant-decls -Wdisabled-optimization -ansi
+
+# consider:
+# -fforce-addr -fmove-all-movables -freduce-all-givs -ftsp-ordering
+# -frename-registers -ffast-math -funroll-loops
+
+# Using the Goto BLAS:
+# BLAS = -lgoto -lfrtbegin -lg2c $(XERBLA) -lpthread
+
+# Using Intel's icc and ifort compilers:
+#   (does not work for mexFunctions unless you add a mexopts.sh file)
+# F77 = ifort
+# CC = icc
+# CF = $(CFLAGS) -O3 -xN -vec_report=0
+# CF = $(CFLAGS) -g
+
+# 64bit:
+# F77FLAGS = -O -m64
+# CF = $(CFLAGS) -O3 -fexceptions -m64
+# BLAS = -lgoto64 -lfrtbegin -lg2c -lpthread $(XERBLA)
+# LAPACK = -llapack64
+
+# SUSE Linux 10.1, AMD Opteron, with GOTO Blas
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+
+# SUSE Linux 10.1, Intel Pentium, with GOTO Blas
+# F77 = gfortran
+# BLAS = -lgoto -lgfortran
+
+#------------------------------------------------------------------------------
+# Mac
+#------------------------------------------------------------------------------
+
+# As recommended by macports, http://suitesparse.darwinports.com/
+# I've tested them myself on Mac OSX 10.6.1 and 10.6.8 (Snow Leopard),
+# on my MacBook Air, and they work fine.
+
+# F77 = gfortran
+# CF = $(CFLAGS) -O3 -fno-common -fexceptions -DNTIMER
+# BLAS = -framework Accelerate
+# LAPACK = -framework Accelerate
+# LIB = -lm
+
+#------------------------------------------------------------------------------
+# Solaris
+#------------------------------------------------------------------------------
+
+# 32-bit
+# CF = $(CFLAGS) -KPIC -dalign -xc99=%none -Xc -xlibmieee -xO5 -xlibmil -m32
+
+# 64-bit
+# CF = $(CFLAGS) -fast -KPIC -xc99=%none -xlibmieee -xlibmil -m64 -Xc
+
+# FFLAGS = -fast -KPIC -dalign -xlibmil -m64
+
+# The Sun Performance Library includes both LAPACK and the BLAS:
+# BLAS = -xlic_lib=sunperf
+# LAPACK =
+
+
+#------------------------------------------------------------------------------
+# Compaq Alpha
+#------------------------------------------------------------------------------
+
+# 64-bit mode only
+# CF = $(CFLAGS) -O2 -std1
+# BLAS = -ldxml
+# LAPACK =
+
+#------------------------------------------------------------------------------
+# IBM RS 6000
+#------------------------------------------------------------------------------
+
+# BLAS = -lessl
+# LAPACK =
+
+# 32-bit mode:
+# CF = $(CFLAGS) -O4 -qipa -qmaxmem=16384 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384
+
+# 64-bit mode:
+# CF = $(CFLAGS) -O4 -qipa -qmaxmem=16384 -q64 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384 -q64
+
+#------------------------------------------------------------------------------
+# SGI IRIX
+#------------------------------------------------------------------------------
+
+# BLAS = -lscsl
+# LAPACK =
+
+# 32-bit mode
+# CF = $(CFLAGS) -O
+
+# 64-bit mode (32 bit int's and 64-bit long's):
+# CF = $(CFLAGS) -64
+# F77FLAGS = -64
+
+# SGI doesn't have ranlib
+# RANLIB = echo
+
+#------------------------------------------------------------------------------
+# AMD Opteron (64 bit)
+#------------------------------------------------------------------------------
+
+# BLAS = -lgoto_opteron64 -lg2c
+# LAPACK = -llapack_opteron64
+
+# SUSE Linux 10.1, AMD Opteron
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+# LAPACK = -llapack_opteron64
+
+#------------------------------------------------------------------------------
+# remove object files and profile output
+#------------------------------------------------------------------------------
+
+CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d *.gcda *.gcno
diff --git a/src/SuiteSparse_config/SuiteSparse_config_GPU.mk b/src/SuiteSparse_config/SuiteSparse_config_GPU.mk
new file mode 100644
index 0000000..b56f209
--- /dev/null
+++ b/src/SuiteSparse_config/SuiteSparse_config_GPU.mk
@@ -0,0 +1,393 @@
+#===============================================================================
+# SuiteSparse_config.mk:  common configuration file for the SuiteSparse
+#===============================================================================
+
+# This file contains all configuration settings for all packages authored or
+# co-authored by Tim Davis:
+#
+# Package Version       Description
+# ------- -------       -----------
+# AMD	  1.2 or later  approximate minimum degree ordering
+# COLAMD  2.4 or later  column approximate minimum degree ordering
+# CCOLAMD 1.0 or later  constrained column approximate minimum degree ordering
+# CAMD    any		constrained approximate minimum degree ordering
+# UMFPACK 4.5 or later	sparse LU factorization, with the BLAS
+# CHOLMOD any		sparse Cholesky factorization, update/downdate
+# KLU	  0.8 or later  sparse LU factorization, BLAS-free
+# BTF	  0.8 or later  permutation to block triangular form
+# LDL	  1.2 or later	concise sparse LDL'
+# CXSparse any		extended version of CSparse (int/long, real/complex)
+# SuiteSparseQR	any	sparse QR factorization
+# RBio    2.0 or later  read/write sparse matrices in Rutherford-Boeing format
+#
+# By design, this file is NOT included in the CSparse makefile.
+# That package is fully stand-alone.  CSparse is primarily for teaching;
+# production code should use CXSparse.
+#
+# The SuiteSparse_config directory and the above packages should all appear in
+# a single directory, in order for the Makefile's within each package to find
+# this file.
+#
+# To enable an option of the form "# OPTION = ...", edit this file and
+# delete the "#" in the first column of the option you wish to use.
+#
+# The use of METIS 4.0.1 is optional.  To exclude METIS, you must compile with
+# CHOLMOD_CONFIG set to -DNPARTITION.  See below for details.  However, if you
+# do not have a metis-4.0 directory inside the SuiteSparse directory, the
+# */Makefile's that optionally rely on METIS will automatically detect this
+# and compile without METIS.
+
+#------------------------------------------------------------------------------
+# Generic configuration
+#------------------------------------------------------------------------------
+
+# Using standard definitions from the make environment, typically:
+#
+#   CC              cc      C compiler
+#   CXX             g++     C++ compiler
+#   CFLAGS          [ ]     flags for C and C++ compiler
+#   CPPFLAGS        [ ]     flags for C and C++ compiler
+#   TARGET_ARCH     [ ]     target architecture
+#   FFLAGS          [ ]     flags for Fortran compiler
+#   RM              rm -f   delete a file
+#   AR              ar      create a static *.a library archive
+#   ARFLAGS         rv      flags for ar
+#   MAKE            make    make itself (sometimes called gmake)
+#
+# You can redefine them here, but by default they are used from the
+# default make environment.
+
+# C and C++ compiler flags.  The first three are standard for *.c and *.cpp
+# Add -DNTIMER if you do use any timing routines (otherwise -lrt is required).
+# CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O3 -fexceptions -fPIC -DNTIMER
+  CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O3 -fexceptions -fPIC
+
+# ranlib, and ar, for generating libraries.  If you don't need ranlib,
+# just change it to RANLAB = echo
+RANLIB = ranlib
+ARCHIVE = $(AR) $(ARFLAGS)
+
+# copy and delete a file
+CP = cp -f
+MV = mv -f
+
+# Fortran compiler (not required for 'make' or 'make library')
+F77 = gfortran
+F77FLAGS = $(FFLAGS) -O
+F77LIB =
+
+# C and Fortran libraries.  Remove -lrt if you don't have it.
+  LIB = -lm -lrt
+# Using the following requires CF = ... -DNTIMER on POSIX C systems.
+# LIB = -lm
+
+# For "make install"
+INSTALL_LIB = /usr/local/lib
+INSTALL_INCLUDE = /usr/local/include
+
+# Which version of MAKE you are using (default is "make")
+# MAKE = make
+# MAKE = gmake
+
+#------------------------------------------------------------------------------
+# BLAS and LAPACK configuration:
+#------------------------------------------------------------------------------
+
+# UMFPACK and CHOLMOD both require the BLAS.  CHOLMOD also requires LAPACK.
+# See Kazushige Goto's BLAS at http://www.cs.utexas.edu/users/flame/goto/ or
+# http://www.tacc.utexas.edu/~kgoto/ for the best BLAS to use with CHOLMOD.
+# LAPACK is at http://www.netlib.org/lapack/ .  You can use the standard
+# Fortran LAPACK along with Goto's BLAS to obtain very good performance.
+# CHOLMOD gets a peak numeric factorization rate of 3.6 Gflops on a 3.2 GHz
+# Pentium 4 (512K cache, 4GB main memory) with the Goto BLAS, and 6 Gflops
+# on a 2.5Ghz dual-core AMD Opteron.
+
+# These settings will probably not work, since there is no fixed convention for
+# naming the BLAS and LAPACK library (*.a or *.so) files.
+
+# This is probably slow ... it might connect to the Standard Reference BLAS:
+BLAS = -lblas -lgfortran
+LAPACK = -llapack
+
+# NOTE: this next option for the "Goto BLAS" has nothing to do with a "goto"
+# statement.  Rather, the Goto BLAS is written by Dr. Kazushige Goto.
+# Using the Goto BLAS:
+# BLAS = -lgoto -lgfortran -lgfortranbegin
+# BLAS = -lgoto2 -lgfortran -lgfortranbegin -lpthread
+
+# Using non-optimized versions:
+# BLAS = -lblas_plain -lgfortran -lgfortranbegin
+# LAPACK = -llapack_plain
+
+# BLAS = -lblas_plain -lgfortran -lgfortranbegin
+# LAPACK = -llapack
+
+# The BLAS might not contain xerbla, an error-handling routine for LAPACK and
+# the BLAS.  Also, the standard xerbla requires the Fortran I/O library, and
+# stops the application program if an error occurs.  A C version of xerbla
+# distributed with this software (SuiteSparse_config/xerbla/libcerbla.a)
+# includes a Fortran-callable xerbla routine that prints nothing and does not
+# stop the application program.  This is optional.
+
+# XERBLA = ../../SuiteSparse_config/xerbla/libcerbla.a 
+
+# If you wish to use the XERBLA in LAPACK and/or the BLAS instead,
+# use this option:
+XERBLA = 
+
+# If you wish to use the Fortran SuiteSparse_config/xerbla/xerbla.f instead,
+# use this:
+
+# XERBLA = ../../SuiteSparse_config/xerbla/libxerbla.a 
+
+#------------------------------------------------------------------------------
+# GPU configuration for CHOLMOD, using the CUDA BLAS
+#------------------------------------------------------------------------------
+
+# no cuda
+# GPU_BLAS_PATH =
+# GPU_CONFIG =
+
+# with cuda BLAS acceleration for CHOLMOD
+  GPU_BLAS_PATH=/usr/local/cuda
+  GPU_CONFIG=-DGPU_BLAS -I$(GPU_BLAS_PATH)/include
+
+#------------------------------------------------------------------------------
+# METIS, optionally used by CHOLMOD
+#------------------------------------------------------------------------------
+
+# If you do not have METIS, or do not wish to use it in CHOLMOD, you must
+# compile CHOLMOD with the -DNPARTITION flag.
+
+# The path is relative to where it is used, in CHOLMOD/Lib, CHOLMOD/MATLAB, etc.
+# You may wish to use an absolute path.  METIS is optional.  Compile
+# CHOLMOD with -DNPARTITION if you do not wish to use METIS.
+METIS_PATH = ../../metis-4.0
+METIS = ../../metis-4.0/libmetis.a
+
+#------------------------------------------------------------------------------
+# UMFPACK configuration:
+#------------------------------------------------------------------------------
+
+# Configuration flags for UMFPACK.  See UMFPACK/Source/umf_config.h for details.
+#
+# -DNBLAS	do not use the BLAS.  UMFPACK will be very slow.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	do not use the Sun Perf. Library (default is use it on Solaris)
+# -DNRECIPROCAL	do not multiply by the reciprocal
+# -DNO_DIVIDE_BY_ZERO	do not divide by zero
+# -DNCHOLMOD    do not use CHOLMOD as a ordering method.  If -DNCHOLMOD is
+#               included in UMFPACK_CONFIG, then UMFPACK  does not rely on
+#               CHOLMOD, CAMD, CCOLAMD, COLAMD, and METIS.
+
+UMFPACK_CONFIG =
+
+# uncomment this line to compile UMFPACK without CHOLMOD:
+# UMFPACK_CONFIG = -DNCHOLMOD
+
+#------------------------------------------------------------------------------
+# CHOLMOD configuration
+#------------------------------------------------------------------------------
+
+# CHOLMOD Library Modules, which appear in libcholmod.a:
+# Core		requires: none
+# Check		requires: Core
+# Cholesky	requires: Core, AMD, COLAMD.  optional: Partition, Supernodal
+# MatrixOps	requires: Core
+# Modify	requires: Core
+# Partition	requires: Core, CCOLAMD, METIS.  optional: Cholesky
+# Supernodal	requires: Core, BLAS, LAPACK
+#
+# CHOLMOD test/demo Modules (all are GNU GPL, do not appear in libcholmod.a):
+# Tcov		requires: Core, Check, Cholesky, MatrixOps, Modify, Supernodal
+#		optional: Partition
+# Valgrind	same as Tcov
+# Demo		requires: Core, Check, Cholesky, MatrixOps, Supernodal
+#		optional: Partition
+#
+# Configuration flags:
+# -DNCHECK	    do not include the Check module.	   License GNU LGPL
+# -DNCHOLESKY	    do not include the Cholesky module.	   License GNU LGPL
+# -DNPARTITION	    do not include the Partition module.   License GNU LGPL
+#		    also do not include METIS.
+# -DNCAMD           do not use CAMD, etc from Partition module.    GNU LGPL
+# -DNGPL	    do not include any GNU GPL Modules in the CHOLMOD library:
+# -DNMATRIXOPS	    do not include the MatrixOps module.   License GNU GPL
+# -DNMODIFY	    do not include the Modify module.      License GNU GPL
+# -DNSUPERNODAL     do not include the Supernodal module.  License GNU GPL
+#
+# -DNPRINT	    do not print anything.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		    	LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	    for Solaris only.  If defined, do not use the Sun
+#			Performance Library
+
+CHOLMOD_CONFIG = $(GPU_CONFIG)
+
+# uncomment this line to compile CHOLMOD without METIS:
+# CHOLMOD_CONFIG = -DNPARTITION
+
+#------------------------------------------------------------------------------
+# SuiteSparseQR configuration:
+#------------------------------------------------------------------------------
+
+# The SuiteSparseQR library can be compiled with the following options:
+#
+# -DNPARTITION      do not include the CHOLMOD partition module
+# -DNEXPERT         do not include the functions in SuiteSparseQR_expert.cpp
+# -DHAVE_TBB        enable the use of Intel's Threading Building Blocks (TBB)
+
+# default, without timing, without TBB:
+SPQR_CONFIG =
+# with TBB:
+# SPQR_CONFIG = -DHAVE_TBB
+
+# This is needed for IBM AIX: (but not for and C codes, just C++)
+# SPQR_CONFIG = -DBLAS_NO_UNDERSCORE
+
+# with TBB, you must select this:
+# TBB = -ltbb
+# without TBB:
+TBB =
+
+#------------------------------------------------------------------------------
+# Linux
+#------------------------------------------------------------------------------
+
+# Using default compilers:
+# CC = gcc
+# CF = $(CFLAGS) -O3 -fexceptions
+
+# alternatives:
+# CF = $(CFLAGS) -g -fexceptions \
+   	-Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi \
+        -funit-at-a-time
+# CF = $(CFLAGS) -O3 -fexceptions \
+   	-Wall -W -Werror -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi
+# CF = $(CFLAGS) -O3 -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+# CF = $(CFLAGS) -O3
+# CF = $(CFLAGS) -O3 -g -fexceptions
+# CF = $(CFLAGS) -g -fexceptions \
+   	-Wall -W -Wshadow \
+    	-Wredundant-decls -Wdisabled-optimization -ansi
+
+# consider:
+# -fforce-addr -fmove-all-movables -freduce-all-givs -ftsp-ordering
+# -frename-registers -ffast-math -funroll-loops
+
+# Using the Goto BLAS:
+# BLAS = -lgoto -lfrtbegin -lg2c $(XERBLA) -lpthread
+
+# Using Intel's icc and ifort compilers:
+#   (does not work for mexFunctions unless you add a mexopts.sh file)
+# F77 = ifort
+# CC = icc
+# CF = $(CFLAGS) -O3 -xN -vec_report=0
+# CF = $(CFLAGS) -g
+
+# 64bit:
+# F77FLAGS = -O -m64
+# CF = $(CFLAGS) -O3 -fexceptions -m64
+# BLAS = -lgoto64 -lfrtbegin -lg2c -lpthread $(XERBLA)
+# LAPACK = -llapack64
+
+# SUSE Linux 10.1, AMD Opteron, with GOTO Blas
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+
+# SUSE Linux 10.1, Intel Pentium, with GOTO Blas
+# F77 = gfortran
+# BLAS = -lgoto -lgfortran
+
+#------------------------------------------------------------------------------
+# Mac
+#------------------------------------------------------------------------------
+
+# As recommended by macports, http://suitesparse.darwinports.com/
+# I've tested them myself on Mac OSX 10.6.1 and 10.6.8 (Snow Leopard),
+# on my MacBook Air, and they work fine.
+
+# F77 = gfortran
+# CF = $(CFLAGS) -O3 -fno-common -fexceptions -DNTIMER
+# BLAS = -framework Accelerate
+# LAPACK = -framework Accelerate
+# LIB = -lm
+
+#------------------------------------------------------------------------------
+# Solaris
+#------------------------------------------------------------------------------
+
+# 32-bit
+# CF = $(CFLAGS) -KPIC -dalign -xc99=%none -Xc -xlibmieee -xO5 -xlibmil -m32
+
+# 64-bit
+# CF = $(CFLAGS) -fast -KPIC -xc99=%none -xlibmieee -xlibmil -m64 -Xc
+
+# FFLAGS = -fast -KPIC -dalign -xlibmil -m64
+
+# The Sun Performance Library includes both LAPACK and the BLAS:
+# BLAS = -xlic_lib=sunperf
+# LAPACK =
+
+
+#------------------------------------------------------------------------------
+# Compaq Alpha
+#------------------------------------------------------------------------------
+
+# 64-bit mode only
+# CF = $(CFLAGS) -O2 -std1
+# BLAS = -ldxml
+# LAPACK =
+
+#------------------------------------------------------------------------------
+# IBM RS 6000
+#------------------------------------------------------------------------------
+
+# BLAS = -lessl
+# LAPACK =
+
+# 32-bit mode:
+# CF = $(CFLAGS) -O4 -qipa -qmaxmem=16384 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384
+
+# 64-bit mode:
+# CF = $(CFLAGS) -O4 -qipa -qmaxmem=16384 -q64 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384 -q64
+
+#------------------------------------------------------------------------------
+# SGI IRIX
+#------------------------------------------------------------------------------
+
+# BLAS = -lscsl
+# LAPACK =
+
+# 32-bit mode
+# CF = $(CFLAGS) -O
+
+# 64-bit mode (32 bit int's and 64-bit long's):
+# CF = $(CFLAGS) -64
+# F77FLAGS = -64
+
+# SGI doesn't have ranlib
+# RANLIB = echo
+
+#------------------------------------------------------------------------------
+# AMD Opteron (64 bit)
+#------------------------------------------------------------------------------
+
+# BLAS = -lgoto_opteron64 -lg2c
+# LAPACK = -llapack_opteron64
+
+# SUSE Linux 10.1, AMD Opteron
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+# LAPACK = -llapack_opteron64
+
+#------------------------------------------------------------------------------
+# remove object files and profile output
+#------------------------------------------------------------------------------
+
+CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d *.gcda *.gcno
diff --git a/src/SuiteSparse_config/SuiteSparse_config_Mac.mk b/src/SuiteSparse_config/SuiteSparse_config_Mac.mk
new file mode 100644
index 0000000..811e99c
--- /dev/null
+++ b/src/SuiteSparse_config/SuiteSparse_config_Mac.mk
@@ -0,0 +1,395 @@
+#===============================================================================
+# SuiteSparse_config_Mac.mk:  Mac configuration file for the SuiteSparse
+# To use this configuration, delete the SuiteSparse_config.mk file that
+# comes with SuiteSparse and rename this file as SuiteSparse_config.mk .
+#===============================================================================
+
+# This file contains all configuration settings for all packages authored or
+# co-authored by Tim Davis:
+#
+# Package Version       Description
+# ------- -------       -----------
+# AMD	  1.2 or later  approximate minimum degree ordering
+# COLAMD  2.4 or later  column approximate minimum degree ordering
+# CCOLAMD 1.0 or later  constrained column approximate minimum degree ordering
+# CAMD    any		constrained approximate minimum degree ordering
+# UMFPACK 4.5 or later	sparse LU factorization, with the BLAS
+# CHOLMOD any		sparse Cholesky factorization, update/downdate
+# KLU	  0.8 or later  sparse LU factorization, BLAS-free
+# BTF	  0.8 or later  permutation to block triangular form
+# LDL	  1.2 or later	concise sparse LDL'
+# CXSparse any		extended version of CSparse (int/long, real/complex)
+# SuiteSparseQR	any	sparse QR factorization
+# RBio    2.0 or later  read/write sparse matrices in Rutherford-Boeing format
+#
+# By design, this file is NOT included in the CSparse makefile.
+# That package is fully stand-alone.  CSparse is primarily for teaching;
+# production code should use CXSparse.
+#
+# The SuiteSparse_config directory and the above packages should all appear in
+# a single directory, in order for the Makefile's within each package to find
+# this file.
+#
+# To enable an option of the form "# OPTION = ...", edit this file and
+# delete the "#" in the first column of the option you wish to use.
+#
+# The use of METIS 4.0.1 is optional.  To exclude METIS, you must compile with
+# CHOLMOD_CONFIG set to -DNPARTITION.  See below for details.  However, if you
+# do not have a metis-4.0 directory inside the SuiteSparse directory, the
+# */Makefile's that optionally rely on METIS will automatically detect this
+# and compile without METIS.
+
+#------------------------------------------------------------------------------
+# Generic configuration
+#------------------------------------------------------------------------------
+
+# Using standard definitions from the make environment, typically:
+#
+#   CC              cc      C compiler
+#   CXX             g++     C++ compiler
+#   CFLAGS          [ ]     flags for C and C++ compiler
+#   CPPFLAGS        [ ]     flags for C and C++ compiler
+#   TARGET_ARCH     [ ]     target architecture
+#   FFLAGS          [ ]     flags for Fortran compiler
+#   RM              rm -f   delete a file
+#   AR              ar      create a static *.a library archive
+#   ARFLAGS         rv      flags for ar
+#   MAKE            make    make itself (sometimes called gmake)
+#
+# You can redefine them here, but by default they are used from the
+# default make environment.
+
+# C and C++ compiler flags.  The first three are standard for *.c and *.cpp
+# Add -DNTIMER if you do use any timing routines (otherwise -lrt is required).
+# CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O3 -fexceptions -fPIC -DNTIMER
+  CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O3 -fexceptions -fPIC
+
+# ranlib, and ar, for generating libraries.  If you don't need ranlib,
+# just change it to RANLAB = echo
+RANLIB = ranlib
+ARCHIVE = $(AR) $(ARFLAGS)
+
+# copy and delete a file
+CP = cp -f
+MV = mv -f
+
+# Fortran compiler (not required for 'make' or 'make library')
+F77 = gfortran
+F77FLAGS = $(FFLAGS) -O
+F77LIB =
+
+# C and Fortran libraries.  Remove -lrt if you don't have it.
+  LIB = -lm -lrt
+# Using the following requires CF = ... -DNTIMER on POSIX C systems.
+# LIB = -lm
+
+# For "make install"
+INSTALL_LIB = /usr/local/lib
+INSTALL_INCLUDE = /usr/local/include
+
+# Which version of MAKE you are using (default is "make")
+# MAKE = make
+# MAKE = gmake
+
+#------------------------------------------------------------------------------
+# BLAS and LAPACK configuration:
+#------------------------------------------------------------------------------
+
+# UMFPACK and CHOLMOD both require the BLAS.  CHOLMOD also requires LAPACK.
+# See Kazushige Goto's BLAS at http://www.cs.utexas.edu/users/flame/goto/ or
+# http://www.tacc.utexas.edu/~kgoto/ for the best BLAS to use with CHOLMOD.
+# LAPACK is at http://www.netlib.org/lapack/ .  You can use the standard
+# Fortran LAPACK along with Goto's BLAS to obtain very good performance.
+# CHOLMOD gets a peak numeric factorization rate of 3.6 Gflops on a 3.2 GHz
+# Pentium 4 (512K cache, 4GB main memory) with the Goto BLAS, and 6 Gflops
+# on a 2.5Ghz dual-core AMD Opteron.
+
+# These settings will probably not work, since there is no fixed convention for
+# naming the BLAS and LAPACK library (*.a or *.so) files.
+
+# This is probably slow ... it might connect to the Standard Reference BLAS:
+BLAS = -lblas -lgfortran
+LAPACK = -llapack
+
+# NOTE: this next option for the "Goto BLAS" has nothing to do with a "goto"
+# statement.  Rather, the Goto BLAS is written by Dr. Kazushige Goto.
+# Using the Goto BLAS:
+# BLAS = -lgoto -lgfortran -lgfortranbegin
+# BLAS = -lgoto2 -lgfortran -lgfortranbegin -lpthread
+
+# Using non-optimized versions:
+# BLAS = -lblas_plain -lgfortran -lgfortranbegin
+# LAPACK = -llapack_plain
+
+# BLAS = -lblas_plain -lgfortran -lgfortranbegin
+# LAPACK = -llapack
+
+# The BLAS might not contain xerbla, an error-handling routine for LAPACK and
+# the BLAS.  Also, the standard xerbla requires the Fortran I/O library, and
+# stops the application program if an error occurs.  A C version of xerbla
+# distributed with this software (SuiteSparse_config/xerbla/libcerbla.a)
+# includes a Fortran-callable xerbla routine that prints nothing and does not
+# stop the application program.  This is optional.
+
+# XERBLA = ../../SuiteSparse_config/xerbla/libcerbla.a 
+
+# If you wish to use the XERBLA in LAPACK and/or the BLAS instead,
+# use this option:
+XERBLA = 
+
+# If you wish to use the Fortran SuiteSparse_config/xerbla/xerbla.f instead,
+# use this:
+
+# XERBLA = ../../SuiteSparse_config/xerbla/libxerbla.a 
+
+#------------------------------------------------------------------------------
+# GPU configuration for CHOLMOD, using the CUDA BLAS
+#------------------------------------------------------------------------------
+
+# no cuda
+GPU_BLAS_PATH =
+GPU_CONFIG =
+
+# with cuda BLAS acceleration for CHOLMOD
+# GPU_BLAS_PATH=/usr/local/cuda
+# GPU_CONFIG=-DGPU_BLAS -I$(GPU_BLAS_PATH)/include
+
+#------------------------------------------------------------------------------
+# METIS, optionally used by CHOLMOD
+#------------------------------------------------------------------------------
+
+# If you do not have METIS, or do not wish to use it in CHOLMOD, you must
+# compile CHOLMOD with the -DNPARTITION flag.
+
+# The path is relative to where it is used, in CHOLMOD/Lib, CHOLMOD/MATLAB, etc.
+# You may wish to use an absolute path.  METIS is optional.  Compile
+# CHOLMOD with -DNPARTITION if you do not wish to use METIS.
+METIS_PATH = ../../metis-4.0
+METIS = ../../metis-4.0/libmetis.a
+
+#------------------------------------------------------------------------------
+# UMFPACK configuration:
+#------------------------------------------------------------------------------
+
+# Configuration flags for UMFPACK.  See UMFPACK/Source/umf_config.h for details.
+#
+# -DNBLAS	do not use the BLAS.  UMFPACK will be very slow.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	do not use the Sun Perf. Library (default is use it on Solaris)
+# -DNRECIPROCAL	do not multiply by the reciprocal
+# -DNO_DIVIDE_BY_ZERO	do not divide by zero
+# -DNCHOLMOD    do not use CHOLMOD as a ordering method.  If -DNCHOLMOD is
+#               included in UMFPACK_CONFIG, then UMFPACK  does not rely on
+#               CHOLMOD, CAMD, CCOLAMD, COLAMD, and METIS.
+
+UMFPACK_CONFIG =
+
+# uncomment this line to compile UMFPACK without CHOLMOD:
+# UMFPACK_CONFIG = -DNCHOLMOD
+
+#------------------------------------------------------------------------------
+# CHOLMOD configuration
+#------------------------------------------------------------------------------
+
+# CHOLMOD Library Modules, which appear in libcholmod.a:
+# Core		requires: none
+# Check		requires: Core
+# Cholesky	requires: Core, AMD, COLAMD.  optional: Partition, Supernodal
+# MatrixOps	requires: Core
+# Modify	requires: Core
+# Partition	requires: Core, CCOLAMD, METIS.  optional: Cholesky
+# Supernodal	requires: Core, BLAS, LAPACK
+#
+# CHOLMOD test/demo Modules (all are GNU GPL, do not appear in libcholmod.a):
+# Tcov		requires: Core, Check, Cholesky, MatrixOps, Modify, Supernodal
+#		optional: Partition
+# Valgrind	same as Tcov
+# Demo		requires: Core, Check, Cholesky, MatrixOps, Supernodal
+#		optional: Partition
+#
+# Configuration flags:
+# -DNCHECK	    do not include the Check module.	   License GNU LGPL
+# -DNCHOLESKY	    do not include the Cholesky module.	   License GNU LGPL
+# -DNPARTITION	    do not include the Partition module.   License GNU LGPL
+#		    also do not include METIS.
+# -DNCAMD           do not use CAMD, etc from Partition module.    GNU LGPL
+# -DNGPL	    do not include any GNU GPL Modules in the CHOLMOD library:
+# -DNMATRIXOPS	    do not include the MatrixOps module.   License GNU GPL
+# -DNMODIFY	    do not include the Modify module.      License GNU GPL
+# -DNSUPERNODAL     do not include the Supernodal module.  License GNU GPL
+#
+# -DNPRINT	    do not print anything.
+# -D'LONGBLAS=long' or -DLONGBLAS='long long' defines the integers used by
+#  		    	LAPACK and the BLAS (defaults to 'int')
+# -DNSUNPERF	    for Solaris only.  If defined, do not use the Sun
+#			Performance Library
+
+CHOLMOD_CONFIG = $(GPU_CONFIG)
+
+# uncomment this line to compile CHOLMOD without METIS:
+# CHOLMOD_CONFIG = -DNPARTITION
+
+#------------------------------------------------------------------------------
+# SuiteSparseQR configuration:
+#------------------------------------------------------------------------------
+
+# The SuiteSparseQR library can be compiled with the following options:
+#
+# -DNPARTITION      do not include the CHOLMOD partition module
+# -DNEXPERT         do not include the functions in SuiteSparseQR_expert.cpp
+# -DHAVE_TBB        enable the use of Intel's Threading Building Blocks (TBB)
+
+# default, without timing, without TBB:
+SPQR_CONFIG =
+# with TBB:
+# SPQR_CONFIG = -DHAVE_TBB
+
+# This is needed for IBM AIX: (but not for and C codes, just C++)
+# SPQR_CONFIG = -DBLAS_NO_UNDERSCORE
+
+# with TBB, you must select this:
+# TBB = -ltbb
+# without TBB:
+TBB =
+
+#------------------------------------------------------------------------------
+# Linux
+#------------------------------------------------------------------------------
+
+# Using default compilers:
+# CC = gcc
+# CF = $(CFLAGS) -O3 -fexceptions
+
+# alternatives:
+# CF = $(CFLAGS) -g -fexceptions \
+   	-Wall -W -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi \
+        -funit-at-a-time
+# CF = $(CFLAGS) -O3 -fexceptions \
+   	-Wall -W -Werror -Wshadow -Wmissing-prototypes -Wstrict-prototypes \
+    	-Wredundant-decls -Wnested-externs -Wdisabled-optimization -ansi
+# CF = $(CFLAGS) -O3 -fexceptions -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE
+# CF = $(CFLAGS) -O3
+# CF = $(CFLAGS) -O3 -g -fexceptions
+# CF = $(CFLAGS) -g -fexceptions \
+   	-Wall -W -Wshadow \
+    	-Wredundant-decls -Wdisabled-optimization -ansi
+
+# consider:
+# -fforce-addr -fmove-all-movables -freduce-all-givs -ftsp-ordering
+# -frename-registers -ffast-math -funroll-loops
+
+# Using the Goto BLAS:
+# BLAS = -lgoto -lfrtbegin -lg2c $(XERBLA) -lpthread
+
+# Using Intel's icc and ifort compilers:
+#   (does not work for mexFunctions unless you add a mexopts.sh file)
+# F77 = ifort
+# CC = icc
+# CF = $(CFLAGS) -O3 -xN -vec_report=0
+# CF = $(CFLAGS) -g
+
+# 64bit:
+# F77FLAGS = -O -m64
+# CF = $(CFLAGS) -O3 -fexceptions -m64
+# BLAS = -lgoto64 -lfrtbegin -lg2c -lpthread $(XERBLA)
+# LAPACK = -llapack64
+
+# SUSE Linux 10.1, AMD Opteron, with GOTO Blas
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+
+# SUSE Linux 10.1, Intel Pentium, with GOTO Blas
+# F77 = gfortran
+# BLAS = -lgoto -lgfortran
+
+#------------------------------------------------------------------------------
+# Mac
+#------------------------------------------------------------------------------
+
+# As recommended by macports, http://suitesparse.darwinports.com/
+# I've tested them myself on Mac OSX 10.6.1 and 10.6.8 (Snow Leopard),
+# on my MacBook Air, and they work fine.
+
+  F77 = gfortran
+  CF = $(CFLAGS) -O3 -fno-common -fexceptions -DNTIMER
+  BLAS = -framework Accelerate
+  LAPACK = -framework Accelerate
+  LIB = -lm
+
+#------------------------------------------------------------------------------
+# Solaris
+#------------------------------------------------------------------------------
+
+# 32-bit
+# CF = $(CFLAGS) -KPIC -dalign -xc99=%none -Xc -xlibmieee -xO5 -xlibmil -m32
+
+# 64-bit
+# CF = $(CFLAGS) -fast -KPIC -xc99=%none -xlibmieee -xlibmil -m64 -Xc
+
+# FFLAGS = -fast -KPIC -dalign -xlibmil -m64
+
+# The Sun Performance Library includes both LAPACK and the BLAS:
+# BLAS = -xlic_lib=sunperf
+# LAPACK =
+
+
+#------------------------------------------------------------------------------
+# Compaq Alpha
+#------------------------------------------------------------------------------
+
+# 64-bit mode only
+# CF = $(CFLAGS) -O2 -std1
+# BLAS = -ldxml
+# LAPACK =
+
+#------------------------------------------------------------------------------
+# IBM RS 6000
+#------------------------------------------------------------------------------
+
+# BLAS = -lessl
+# LAPACK =
+
+# 32-bit mode:
+# CF = $(CFLAGS) -O4 -qipa -qmaxmem=16384 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384
+
+# 64-bit mode:
+# CF = $(CFLAGS) -O4 -qipa -qmaxmem=16384 -q64 -qproto
+# F77FLAGS = -O4 -qipa -qmaxmem=16384 -q64
+
+#------------------------------------------------------------------------------
+# SGI IRIX
+#------------------------------------------------------------------------------
+
+# BLAS = -lscsl
+# LAPACK =
+
+# 32-bit mode
+# CF = $(CFLAGS) -O
+
+# 64-bit mode (32 bit int's and 64-bit long's):
+# CF = $(CFLAGS) -64
+# F77FLAGS = -64
+
+# SGI doesn't have ranlib
+# RANLIB = echo
+
+#------------------------------------------------------------------------------
+# AMD Opteron (64 bit)
+#------------------------------------------------------------------------------
+
+# BLAS = -lgoto_opteron64 -lg2c
+# LAPACK = -llapack_opteron64
+
+# SUSE Linux 10.1, AMD Opteron
+# F77 = gfortran
+# BLAS = -lgoto_opteron64 -lgfortran
+# LAPACK = -llapack_opteron64
+
+#------------------------------------------------------------------------------
+# remove object files and profile output
+#------------------------------------------------------------------------------
+
+CLEAN = *.o *.obj *.ln *.bb *.bbg *.da *.tcov *.gcov gmon.out *.bak *.d *.gcda *.gcno
diff --git a/src/adjlist.c b/src/adjlist.c
index 865abe1..9703b27 100644
--- a/src/adjlist.c
+++ b/src/adjlist.c
@@ -445,8 +445,8 @@ int igraph_inclist_remove_duplicate(const igraph_t *graph,
   long int i;
   long int n=al->length;
   for (i=0; i<n; i++) {
-    igraph_vector_t *v=&al->incs[i];
-    long int j, p=1, l=igraph_vector_size(v);
+    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. */
@@ -456,7 +456,7 @@ int igraph_inclist_remove_duplicate(const igraph_t *graph,
 	VECTOR(*v)[p++] = e;
       }
     }
-    igraph_vector_resize(v, p);
+    igraph_vector_int_resize(v, p);
   }
   
   return 0;
@@ -467,8 +467,8 @@ int igraph_inclist_print(const igraph_inclist_t *al) {
   long int i;
   long int n=al->length;
   for (i=0; i<n; i++) {
-    igraph_vector_t *v=&al->incs[i];
-    igraph_vector_print(v);
+    igraph_vector_int_t *v=&al->incs[i];
+    igraph_vector_int_print(v);
   }
   return 0;
 }
@@ -478,8 +478,8 @@ int igraph_inclist_fprint(const igraph_inclist_t *al, FILE *outfile) {
   long int i;
   long int n=al->length;
   for (i=0; i<n; i++) {
-    igraph_vector_t *v=&al->incs[i];
-    igraph_vector_fprint(v, outfile);
+    igraph_vector_int_t *v=&al->incs[i];
+    igraph_vector_int_fprint(v, outfile);
   }
   return 0;
 }
@@ -509,27 +509,37 @@ int igraph_inclist_init(const igraph_t *graph,
 			      igraph_inclist_t *il, 
 			      igraph_neimode_t mode) {
   igraph_integer_t i;
+  igraph_vector_t tmp;
 
   if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {
     IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_EINVMODE);
   }
 
+  igraph_vector_init(&tmp, 0);
+  IGRAPH_FINALLY(igraph_vector_destroy, &tmp);
+
   if (!igraph_is_directed(graph)) { mode=IGRAPH_ALL; }
 
   il->length=igraph_vcount(graph);
-  il->incs=igraph_Calloc(il->length, igraph_vector_t);
+  il->incs=igraph_Calloc(il->length, igraph_vector_int_t);
   if (il->incs == 0) {
     IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_ENOMEM);
   }
 
   IGRAPH_FINALLY(igraph_inclist_destroy, il);  
   for (i=0; i<il->length; i++) {
+    int j, n;
     IGRAPH_ALLOW_INTERRUPTION();
-    IGRAPH_CHECK(igraph_vector_init(&il->incs[i], 0));
-    IGRAPH_CHECK(igraph_incident(graph, &il->incs[i], i, mode));
+    IGRAPH_CHECK(igraph_incident(graph, &tmp, i, mode));
+    n=igraph_vector_size(&tmp);
+    IGRAPH_CHECK(igraph_vector_int_init(&il->incs[i], n));
+    for (j=0; j<n; j++) {
+      VECTOR(il->incs[i])[j] = VECTOR(tmp)[j];
+    }
   }
   
-  IGRAPH_FINALLY_CLEAN(1);
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(2);
   return 0;
 }
 
@@ -552,14 +562,14 @@ int igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n) {
   long int i;
 
   il->length=n;
-  il->incs=igraph_Calloc(il->length, igraph_vector_t);
+  il->incs=igraph_Calloc(il->length, igraph_vector_int_t);
   if (il->incs == 0) {
     IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_ENOMEM);
   }
 
   IGRAPH_FINALLY(igraph_inclist_destroy, il);  
   for (i=0; i<n; i++) {
-    IGRAPH_CHECK(igraph_vector_init(&il->incs[i], 0));
+    IGRAPH_CHECK(igraph_vector_int_init(&il->incs[i], 0));
   }
   
   IGRAPH_FINALLY_CLEAN(1);
@@ -578,9 +588,9 @@ int igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n) {
 void igraph_inclist_destroy(igraph_inclist_t *il) {
   long int i;
   for (i=0; i<il->length; i++) {
-    /* This works if some igraph_vector_t's are 0, because igraph_vector_destroy can
-       handle this. */
-    igraph_vector_destroy(&il->incs[i]);
+    /* This works if some igraph_vector_int_t's are 0, 
+       because igraph_vector_destroy can handle this. */
+    igraph_vector_int_destroy(&il->incs[i]);
   }
   igraph_Free(il->incs);
 }
@@ -596,7 +606,7 @@ void igraph_inclist_destroy(igraph_inclist_t *il) {
 void igraph_inclist_clear(igraph_inclist_t *il) {
   long int i;
   for (i=0; i<il->length; i++) {
-    igraph_vector_clear(&il->incs[i]);
+    igraph_vector_int_clear(&il->incs[i]);
   }
 }
 
diff --git a/src/bigint.c b/src/bigint.c
index 9616b8a..3d06cbd 100644
--- a/src/bigint.c
+++ b/src/bigint.c
@@ -25,12 +25,6 @@
 #include "igraph_error.h"
 #include "igraph_memory.h"
 
-#define BASE_LIMB
-#include "igraph_pmt.h"
-#include "vector.pmt"
-#include "igraph_pmt_off.h"
-#undef BASE_LIMB
-
 int igraph_biguint_init(igraph_biguint_t *b) {
   IGRAPH_CHECK(igraph_vector_limb_init(&b->v, IGRAPH_BIGUINT_DEFAULT_SIZE));
   igraph_vector_limb_clear(&b->v);
diff --git a/src/blas.c b/src/blas.c
index 041546e..c62493e 100644
--- a/src/blas.c
+++ b/src/blas.c
@@ -102,3 +102,9 @@ void igraph_blas_dgemv_array(igraph_bool_t transpose, igraph_real_t alpha,
   igraphdgemv_(&trans, &m, &n, &alpha, VECTOR(a->data), &m,
                (igraph_real_t*)x, &inc, &beta, y, &inc);
 }
+
+igraph_real_t igraph_blas_dnrm2(const igraph_vector_t *v) {
+  int n =igraph_vector_size(v);
+  int one = 1;
+  return igraphdnrm2_(&n, VECTOR(*v), &one);
+}
diff --git a/src/cattributes.c b/src/cattributes.c
index a7f413f..4018f57 100644
--- a/src/cattributes.c
+++ b/src/cattributes.c
@@ -88,6 +88,14 @@ int igraph_i_cattributes_copy_attribute_record(igraph_attribute_record_t **newre
     IGRAPH_CHECK(igraph_strvector_copy(newstr, str));
     IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
     (*newrec)->value=newstr;
+  } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
+    igraph_vector_bool_t *log = (igraph_vector_bool_t*) rec->value;
+    igraph_vector_bool_t *newlog = igraph_Calloc(1, igraph_vector_bool_t);
+    if (!newlog) { IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM); }
+    IGRAPH_FINALLY(igraph_free, newlog);
+    IGRAPH_CHECK(igraph_vector_bool_copy(newlog, log));
+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newlog);
+    (*newrec)->value = newlog;
   }
 
   IGRAPH_FINALLY_CLEAN(4);
@@ -171,6 +179,7 @@ void igraph_i_cattribute_copy_free(igraph_i_cattributes_t *attr) {
   long int i, n, a;
   igraph_vector_t *num;
   igraph_strvector_t *str;
+  igraph_vector_bool_t *boolvec;
   igraph_attribute_record_t *rec;
   for (a=0; a<3; a++) {
     n=igraph_vector_ptr_size(als[a]);
@@ -181,6 +190,10 @@ void igraph_i_cattribute_copy_free(igraph_i_cattributes_t *attr) {
 	num=(igraph_vector_t*)rec->value;
 	igraph_vector_destroy(num);
 	igraph_free(num);
+      } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
+	boolvec=(igraph_vector_bool_t*)rec->value;
+	igraph_vector_bool_destroy(boolvec);
+	igraph_free(boolvec);
       } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 	str=(igraph_strvector_t*)rec->value;
 	igraph_strvector_destroy(str);
@@ -296,6 +309,16 @@ int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
 	IGRAPH_FINALLY(igraph_free, newstr);
 	IGRAPH_STRVECTOR_INIT_FINALLY(newstr, origlen);
 	newrec->value=newstr;
+      } else if (type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+	igraph_vector_bool_t *newbool=igraph_Calloc(1, igraph_vector_bool_t);
+	if (!newbool) {
+	  IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, newbool);
+	IGRAPH_CHECK(igraph_vector_bool_init(newbool, origlen));
+	IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
+	newrec->value=newbool;
+	igraph_vector_bool_fill(newbool, 0);
       }
       IGRAPH_CHECK(igraph_vector_ptr_push_back(val, newrec));
       IGRAPH_FINALLY_CLEAN(4);
@@ -315,11 +338,14 @@ int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
       /* This attribute is present in nattr */
       igraph_vector_t *oldnum, *newnum;
       igraph_strvector_t *oldstr, *newstr;
+      igraph_vector_bool_t *oldbool, *newbool;
       newrec=VECTOR(*nattr)[j];
       oldnum=(igraph_vector_t*)oldrec->value;
       newnum=(igraph_vector_t*)newrec->value;
       oldstr=(igraph_strvector_t*)oldrec->value;
       newstr=(igraph_strvector_t*)newrec->value;
+      oldbool=(igraph_vector_bool_t*)oldrec->value;
+      newbool=(igraph_vector_bool_t*)newrec->value;
       if (oldrec->type != newrec->type) {
 	IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);
       }
@@ -336,6 +362,12 @@ int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
 	}
 	IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr));
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	if (nv != igraph_vector_bool_size(newbool)) {
+	  IGRAPH_ERROR("Invalid Boolean attribute length", IGRAPH_EINVAL);
+	}
+	IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool));
+	break;
       default:
 	IGRAPH_WARNING("Invalid attribute type");	
 	break;
@@ -344,6 +376,7 @@ int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
       /* No such attribute, append NA's */
       igraph_vector_t *oldnum=(igraph_vector_t *)oldrec->value;
       igraph_strvector_t *oldstr=(igraph_strvector_t*)oldrec->value;
+      igraph_vector_bool_t *oldbool=(igraph_vector_bool_t*)oldrec->value;
       switch (oldrec->type) {
       case IGRAPH_ATTRIBUTE_NUMERIC:
 	IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen+nv));
@@ -354,6 +387,12 @@ int igraph_i_cattribute_add_vertices(igraph_t *graph, long int nv,
       case IGRAPH_ATTRIBUTE_STRING:
 	IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen+nv));
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen+nv));
+	for (j=origlen; j<origlen+nv; j++) {
+	  VECTOR(*oldbool)[j]=0;
+	}
+	break;
       default:
 	IGRAPH_WARNING("Invalid attribute type");
 	break;
@@ -380,6 +419,10 @@ void igraph_i_cattribute_permute_free(igraph_vector_ptr_t *v) {
       igraph_strvector_t *strv= (igraph_strvector_t*) rec->value;
       igraph_strvector_destroy(strv);
       igraph_Free(strv);
+    } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
+      igraph_vector_bool_t *boolv= (igraph_vector_bool_t*) rec->value;
+      igraph_vector_bool_destroy(boolv);
+      igraph_Free(boolv);
     }
     igraph_Free(rec);
   }
@@ -402,6 +445,7 @@ int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
       igraph_attribute_type_t type=oldrec->type;
       igraph_vector_t *num, *newnum;
       igraph_strvector_t *str, *newstr;
+      igraph_vector_bool_t *oldbool, *newbool;
       switch (type) {
       case IGRAPH_ATTRIBUTE_NUMERIC:
 	num=(igraph_vector_t*) oldrec->value;
@@ -416,6 +460,20 @@ int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
 	igraph_Free(num);
 	IGRAPH_FINALLY_CLEAN(1);
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	oldbool=(igraph_vector_bool_t*) oldrec->value;
+	newbool=igraph_Calloc(1, igraph_vector_bool_t);
+	if (!newbool) {
+	  IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
+	IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
+	igraph_vector_bool_index(oldbool, newbool, idx);
+	oldrec->value=newbool;
+	igraph_vector_bool_destroy(oldbool);
+	igraph_Free(oldbool);
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
       case IGRAPH_ATTRIBUTE_STRING:
 	str=(igraph_strvector_t*)oldrec->value;
 	newstr=igraph_Calloc(1, igraph_strvector_t);
@@ -457,6 +515,7 @@ int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
       igraph_attribute_type_t type=oldrec->type;
       igraph_vector_t *num, *newnum;
       igraph_strvector_t *str, *newstr;
+      igraph_vector_bool_t *oldbool, *newbool;
       
       /* The record itself */
       igraph_attribute_record_t *new_rec=
@@ -481,6 +540,18 @@ int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
 	new_rec->value=newnum;
 	IGRAPH_FINALLY_CLEAN(1);
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	oldbool=(igraph_vector_bool_t*)oldrec->value;
+	newbool=igraph_Calloc(1, igraph_vector_bool_t);
+	if (!newbool) {
+	  IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
+	IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
+	igraph_vector_bool_index(oldbool, newbool, idx);
+	new_rec->value=newbool;
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
       case IGRAPH_ATTRIBUTE_STRING:
 	str=(igraph_strvector_t*)oldrec->value;
 	newstr=igraph_Calloc(1, igraph_strvector_t);
@@ -503,6 +574,15 @@ int igraph_i_cattribute_permute_vertices(const igraph_t *graph,
   return 0;
 }
 
+typedef int igraph_cattributes_combine_num_t(const igraph_vector_t *input, 
+					     igraph_real_t *output);
+
+typedef int igraph_cattributes_combine_str_t(const igraph_strvector_t *input,
+					     char **output);
+
+typedef int igraph_cattributes_combine_bool_t(const igraph_vector_bool_t *input,
+					      igraph_bool_t *output);
+
 int igraph_i_cattributes_cn_sum(const igraph_attribute_record_t *oldrec, 
 				igraph_attribute_record_t * newrec, 
 				const igraph_vector_ptr_t *merges) {
@@ -767,12 +847,6 @@ int igraph_i_cattributes_cn_mean(const igraph_attribute_record_t *oldrec,
   return 0;
 }
 
-typedef int igraph_cattributes_combine_num_t(const igraph_vector_t *input, 
-					     igraph_real_t *output);
-
-typedef int igraph_cattributes_combine_str_t(const igraph_strvector_t *input,
-					     char **output);
-
 int igraph_i_cattributes_cn_func(const igraph_attribute_record_t *oldrec,
 				 igraph_attribute_record_t *newrec,
 				 const igraph_vector_ptr_t *merges, 
@@ -812,6 +886,272 @@ int igraph_i_cattributes_cn_func(const igraph_attribute_record_t *oldrec,
   return 0;
 }
 
+int igraph_i_cattributes_cb_random(const igraph_attribute_record_t *oldrec, 
+				   igraph_attribute_record_t * newrec, 
+				   const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  RNG_BEGIN();
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int n=igraph_vector_size(idx);
+    if (n==0) {
+      VECTOR(*newv)[i]=0;
+    } else if (n==1) {
+      VECTOR(*newv)[i]=VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
+    } else {
+      long int r=RNG_INTEGER(0, n-1);
+      VECTOR(*newv)[i]=VECTOR(*oldv)[ (long int) VECTOR(*idx)[r] ];
+    }
+  }
+
+  RNG_END();
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cb_first(const igraph_attribute_record_t *oldrec, 
+				  igraph_attribute_record_t * newrec, 
+				  const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int n=igraph_vector_size(idx);
+    if (n==0) {
+      VECTOR(*newv)[i]=0;
+    } else {
+      VECTOR(*newv)[i]=VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];
+    }
+  }
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cb_last(const igraph_attribute_record_t *oldrec, 
+				 igraph_attribute_record_t * newrec, 
+				 const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int n=igraph_vector_size(idx);
+    if (n==0) {
+      VECTOR(*newv)[i]=0;
+    } else {
+      VECTOR(*newv)[i]=VECTOR(*oldv)[ (long int) VECTOR(*idx)[n-1] ];
+    }
+  }
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cb_all_is_true(const igraph_attribute_record_t *oldrec, 
+				        igraph_attribute_record_t * newrec, 
+				        const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i, j, n, x;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    n=igraph_vector_size(idx);
+    VECTOR(*newv)[i]=1;
+    for (j=0; j<n; j++) {
+      x=(long int) VECTOR(*idx)[j];
+      if (!VECTOR(*oldv)[x]) {
+	VECTOR(*newv)[i]=0;
+	break;
+      }
+    }
+  }
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cb_any_is_true(const igraph_attribute_record_t *oldrec, 
+				        igraph_attribute_record_t * newrec, 
+				        const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i, j, n, x;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    n=igraph_vector_size(idx);
+    VECTOR(*newv)[i]=0;
+    for (j=0; j<n; j++) {
+      x=(long int) VECTOR(*idx)[j];
+      if (VECTOR(*oldv)[x]) {
+	VECTOR(*newv)[i]=1;
+	break;
+      }
+    }
+  }
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cb_majority(const igraph_attribute_record_t *oldrec, 
+				     igraph_attribute_record_t * newrec, 
+				     const igraph_vector_ptr_t *merges) {
+
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i, j, n, x, num_trues;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  RNG_BEGIN();
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    
+    n=igraph_vector_size(idx);
+
+    num_trues = 0;
+    for (j=0; j<n; j++) {
+      x=(long int) VECTOR(*idx)[j];
+      if (VECTOR(*oldv)[x]) {
+	num_trues++;
+      }
+    }
+
+    if (n % 2 != 0) {
+      VECTOR(*newv)[i] = (num_trues > n/2);
+    } else {
+      if (num_trues == n/2) {
+	VECTOR(*newv)[i] = (RNG_UNIF01() < 0.5);
+      } else {
+	VECTOR(*newv)[i] = (num_trues > n/2);
+      }
+    }
+  }
+
+  RNG_END();
+
+  IGRAPH_FINALLY_CLEAN(2);
+  newrec->value = newv;  
+
+  return 0;
+}
+
+int igraph_i_cattributes_cb_func(const igraph_attribute_record_t *oldrec,
+				 igraph_attribute_record_t *newrec,
+				 const igraph_vector_ptr_t *merges, 
+				 igraph_cattributes_combine_bool_t *func) {
+  
+  const igraph_vector_bool_t *oldv=oldrec->value;
+  long int newlen=igraph_vector_ptr_size(merges);
+  long int i;
+  igraph_vector_bool_t *newv=igraph_Calloc(1, igraph_vector_bool_t);
+  igraph_vector_bool_t values;
+
+  if (!newv) {
+    IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, newv);
+  IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  IGRAPH_CHECK(igraph_vector_bool_init(&values, 0));
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);
+
+  for (i=0; i<newlen; i++) {
+    igraph_vector_t *idx=VECTOR(*merges)[i];
+    long int j, n=igraph_vector_size(idx);
+    igraph_bool_t res;
+
+    IGRAPH_CHECK(igraph_vector_bool_resize(&values, n));
+    for (j=0; j<n; j++) {
+      long int x=(long int) VECTOR(*idx)[j];
+      VECTOR(values)[j] = VECTOR(*oldv)[x];
+    }
+
+    IGRAPH_CHECK(func(&values, &res));
+    VECTOR(*newv)[i] = res;
+  }
+  
+  igraph_vector_bool_destroy(&values);
+  IGRAPH_FINALLY_CLEAN(3);
+  newrec->value = newv;
+  
+  return 0;
+}
+
 int igraph_i_cattributes_sn_random(const igraph_attribute_record_t *oldrec,
 				   igraph_attribute_record_t *newrec,
 				   const igraph_vector_ptr_t *merges) {
@@ -1067,6 +1407,8 @@ int igraph_i_cattribute_combine_vertices(const igraph_t *graph,
       (igraph_cattributes_combine_num_t*) funcs[i];
     igraph_cattributes_combine_str_t *strfunc=
       (igraph_cattributes_combine_str_t*) funcs[i];
+    igraph_cattributes_combine_bool_t *boolfunc=
+      (igraph_cattributes_combine_bool_t*) funcs[i];
     
     if (todo==IGRAPH_ATTRIBUTE_COMBINE_DEFAULT || 
 	todo==IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
@@ -1125,6 +1467,42 @@ int igraph_i_cattribute_combine_vertices(const igraph_t *graph,
 		     IGRAPH_UNIMPLEMENTED);
 	break;
       }
+    } else if (type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+      switch (todo) {
+      case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges,
+						  boolfunc));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_SUM:
+      case IGRAPH_ATTRIBUTE_COMBINE_MAX:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_PROD:
+      case IGRAPH_ATTRIBUTE_COMBINE_MIN:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
+      case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_LAST:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
+	IGRAPH_ERROR("Cannot calculate concatenation of Booleans", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      default:
+	IGRAPH_ERROR("Unknown attribute_combination",
+		     IGRAPH_UNIMPLEMENTED);
+	break;
+      }
     } else if (type==IGRAPH_ATTRIBUTE_STRING) {
       switch (todo) {
       case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
@@ -1305,6 +1683,16 @@ int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
 	IGRAPH_VECTOR_INIT_FINALLY(newnum, origlen);
 	newrec->value=newnum;
 	igraph_vector_fill(newnum, IGRAPH_NAN);
+      } else if (type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+	igraph_vector_bool_t *newbool=igraph_Calloc(1, igraph_vector_bool_t);
+	if (!newbool) {
+	  IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_FINALLY(igraph_free, newbool);
+	IGRAPH_CHECK(igraph_vector_bool_init(newbool, origlen));
+	IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
+	newrec->value=newbool;
+	igraph_vector_bool_fill(newbool, 0);
       } else if (type==IGRAPH_ATTRIBUTE_STRING) {
 	igraph_strvector_t *newstr=igraph_Calloc(1, igraph_strvector_t);
 	if (!newstr) {
@@ -1332,11 +1720,14 @@ int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
       /* This attribute is present in nattr */
       igraph_vector_t *oldnum, *newnum;
       igraph_strvector_t *oldstr, *newstr;
+      igraph_vector_bool_t *oldbool, *newbool;
       newrec=VECTOR(*nattr)[j];
       oldnum=(igraph_vector_t*)oldrec->value;
       newnum=(igraph_vector_t*)newrec->value;
       oldstr=(igraph_strvector_t*)oldrec->value;
       newstr=(igraph_strvector_t*)newrec->value;
+      oldbool=(igraph_vector_bool_t*)oldrec->value;
+      newbool=(igraph_vector_bool_t*)newrec->value;
       if (oldrec->type != newrec->type) {
 	IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);
       }
@@ -1353,6 +1744,12 @@ int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
 	}
 	IGRAPH_CHECK(igraph_strvector_append(oldstr, newstr));
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	if (ne != igraph_vector_bool_size(newbool)) {
+	  IGRAPH_ERROR("Invalid Boolean attribute length", IGRAPH_EINVAL);
+	}
+	IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool));
+	break;
       default:
 	IGRAPH_WARNING("Invalid attribute type");	
 	break;
@@ -1361,6 +1758,7 @@ int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
       /* No such attribute, append NA's */
       igraph_vector_t *oldnum=(igraph_vector_t *)oldrec->value;
       igraph_strvector_t *oldstr=(igraph_strvector_t*)oldrec->value;
+      igraph_vector_bool_t *oldbool=(igraph_vector_bool_t *)oldrec->value;
       switch (oldrec->type) {
       case IGRAPH_ATTRIBUTE_NUMERIC:
 	IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen+ne));
@@ -1371,6 +1769,12 @@ int igraph_i_cattribute_add_edges(igraph_t *graph, const igraph_vector_t *edges,
       case IGRAPH_ATTRIBUTE_STRING:
 	IGRAPH_CHECK(igraph_strvector_resize(oldstr, origlen+ne));
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen+ne));
+	for (j=origlen; j<origlen+ne; j++) {
+	  VECTOR(*oldbool)[j]=0;
+	}
+	break;
       default:
 	IGRAPH_WARNING("Invalid attribute type");
 	break;
@@ -1433,12 +1837,13 @@ int igraph_i_cattribute_permute_edges(const igraph_t *graph,
       igraph_attribute_type_t type=oldrec->type;
       igraph_vector_t *num, *newnum;
       igraph_strvector_t *str, *newstr;
+      igraph_vector_bool_t *oldbool, *newbool;
       switch (type) {
       case IGRAPH_ATTRIBUTE_NUMERIC:
 	num=(igraph_vector_t*) oldrec->value;
 	newnum=igraph_Calloc(1, igraph_vector_t);
 	if (!newnum) {
-	  IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
+	  IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
 	}
 	IGRAPH_VECTOR_INIT_FINALLY(newnum, 0);
 	igraph_vector_index(num, newnum, idx);
@@ -1447,11 +1852,25 @@ int igraph_i_cattribute_permute_edges(const igraph_t *graph,
 	igraph_Free(num);
 	IGRAPH_FINALLY_CLEAN(1);
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	oldbool=(igraph_vector_bool_t*) oldrec->value;
+	newbool=igraph_Calloc(1, igraph_vector_bool_t);
+	if (!newbool) {
+	  IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
+	IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
+	igraph_vector_bool_index(oldbool, newbool, idx);
+	oldrec->value=newbool;
+	igraph_vector_bool_destroy(oldbool);
+	igraph_Free(oldbool);
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
       case IGRAPH_ATTRIBUTE_STRING:
 	str=(igraph_strvector_t*)oldrec->value;
 	newstr=igraph_Calloc(1, igraph_strvector_t);
 	if (!newstr) {
-	  IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
+	  IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
 	}
 	IGRAPH_CHECK(igraph_strvector_init(newstr, 0));
 	IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
@@ -1485,6 +1904,7 @@ int igraph_i_cattribute_permute_edges(const igraph_t *graph,
       igraph_attribute_type_t type=oldrec->type;
       igraph_vector_t *num, *newnum;
       igraph_strvector_t *str, *newstr;
+      igraph_vector_bool_t *oldbool, *newbool;
       
       /* The record itself */
       igraph_attribute_record_t *new_rec=
@@ -1501,7 +1921,7 @@ int igraph_i_cattribute_permute_edges(const igraph_t *graph,
 	num=(igraph_vector_t*) oldrec->value;
 	newnum=igraph_Calloc(1, igraph_vector_t);
 	if (!newnum) {
-	  IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
+	  IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
 	}
 	IGRAPH_VECTOR_INIT_FINALLY(newnum, 0);
 	igraph_vector_index(num, newnum, idx);
@@ -1512,7 +1932,7 @@ int igraph_i_cattribute_permute_edges(const igraph_t *graph,
 	str=(igraph_strvector_t*)oldrec->value;
 	newstr=igraph_Calloc(1, igraph_strvector_t);
 	if (!newstr) {
-	  IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);
+	  IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
 	}
 	IGRAPH_CHECK(igraph_strvector_init(newstr, 0));
 	IGRAPH_FINALLY(igraph_strvector_destroy, newstr);
@@ -1520,6 +1940,18 @@ int igraph_i_cattribute_permute_edges(const igraph_t *graph,
 	new_rec->value=newstr;
 	IGRAPH_FINALLY_CLEAN(1);
 	break;
+      case IGRAPH_ATTRIBUTE_BOOLEAN:
+	oldbool=(igraph_vector_bool_t*) oldrec->value;
+	newbool=igraph_Calloc(1, igraph_vector_bool_t);
+	if (!newbool) {
+	  IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);
+	}
+	IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));
+	IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);
+	igraph_vector_bool_index(oldbool, newbool, idx);
+	new_rec->value=newbool;
+	IGRAPH_FINALLY_CLEAN(1);
+	break;
       default:
 	IGRAPH_WARNING("Unknown edge attribute ignored");
       }
@@ -1583,6 +2015,8 @@ int igraph_i_cattribute_combine_edges(const igraph_t *graph,
       (igraph_cattributes_combine_num_t*) funcs[i];
     igraph_cattributes_combine_str_t *strfunc=
       (igraph_cattributes_combine_str_t*) funcs[i];
+    igraph_cattributes_combine_bool_t *boolfunc=
+      (igraph_cattributes_combine_bool_t*) funcs[i];
     
     if (todo==IGRAPH_ATTRIBUTE_COMBINE_DEFAULT || 
 	todo==IGRAPH_ATTRIBUTE_COMBINE_IGNORE) {
@@ -1641,6 +2075,42 @@ int igraph_i_cattribute_combine_edges(const igraph_t *graph,
 		     IGRAPH_UNIMPLEMENTED);
 	break;
       }
+    } else if (type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+      switch (todo) {
+      case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges,
+						  boolfunc));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_SUM:
+      case IGRAPH_ATTRIBUTE_COMBINE_MAX:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_PROD:
+      case IGRAPH_ATTRIBUTE_COMBINE_MIN:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_MEAN:
+      case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_FIRST:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_LAST:
+	IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges));
+	break;
+      case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:
+	IGRAPH_ERROR("Cannot calculate concatenation of Booleans", 
+		     IGRAPH_EATTRCOMBINE);
+	break;
+      default:
+	IGRAPH_ERROR("Unknown attribute_combination",
+		     IGRAPH_UNIMPLEMENTED);
+	break;
+      }
     } else if (type==IGRAPH_ATTRIBUTE_STRING) {
       switch (todo) {
       case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:
@@ -1916,7 +2386,8 @@ int igraph_i_cattribute_get_bool_vertex_attr(const igraph_t *graph,
 					     igraph_vector_bool_t *value) {
   igraph_i_cattributes_t *attr=graph->attr;
   igraph_vector_ptr_t *val=&attr->val;
-  long int j;
+  igraph_vit_t it;
+  long int i, j, v;
   igraph_attribute_record_t *rec;
   igraph_vector_bool_t *log;
   igraph_bool_t l=igraph_i_cattribute_find(val, name, &j);
@@ -1931,13 +2402,11 @@ int igraph_i_cattribute_get_bool_vertex_attr(const igraph_t *graph,
     igraph_vector_bool_clear(value);
     IGRAPH_CHECK(igraph_vector_bool_append(value, log));
   } else {
-    igraph_vit_t it;
-    long int i=0;
     IGRAPH_CHECK(igraph_vit_create(graph, vs, &it));
     IGRAPH_FINALLY(igraph_vit_destroy, &it);
     IGRAPH_CHECK(igraph_vector_bool_resize(value, IGRAPH_VIT_SIZE(it)));
-    for (; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
-      long int v=IGRAPH_VIT_GET(it);
+    for (i = 0; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {
+      v=IGRAPH_VIT_GET(it);
       VECTOR(*value)[i]=VECTOR(*log)[v];
     }
     igraph_vit_destroy(&it);
@@ -3593,6 +4062,9 @@ void igraph_i_cattribute_free_rec(igraph_attribute_record_t *rec) {
   } else if (rec->type==IGRAPH_ATTRIBUTE_STRING) {
     igraph_strvector_t *str=(igraph_strvector_t*)rec->value;
     igraph_strvector_destroy(str);
+  } else if (rec->type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+    igraph_vector_bool_t *boolvec=(igraph_vector_bool_t*)rec->value;
+    igraph_vector_bool_destroy(boolvec);
   }
   igraph_Free(rec->name);
   igraph_Free(rec->value);
diff --git a/src/centrality.c b/src/centrality.c
index fb15908..d8ac030 100644
--- a/src/centrality.c
+++ b/src/centrality.c
@@ -117,15 +117,15 @@ int igraph_i_eigenvector_centrality2(igraph_real_t *to, const igraph_real_t *fro
   const igraph_t *graph=data->graph;
   const igraph_inclist_t *inclist=data->inclist;
   const igraph_vector_t *weights=data->weights;
-  igraph_vector_t *edges;
+  igraph_vector_int_t *edges;
   long int i, j, nlen;
 
   for (i=0; i<n; i++) {
     edges=igraph_inclist_get(inclist, i);
-    nlen=igraph_vector_size(edges);
+    nlen=igraph_vector_int_size(edges);
     to[i]=0.0;
     for (j=0; j<nlen; j++) {
-      long int edge=(long int) VECTOR(*edges)[j];
+      long int edge=VECTOR(*edges)[j];
       long int nei=IGRAPH_OTHER(graph, edge, i);
       igraph_real_t w=VECTOR(*weights)[edge];
       to[i] += w * from[nei];
@@ -617,12 +617,12 @@ int igraph_i_kleinberg_weighted(igraph_real_t *to,
   igraph_vector_t *tmp = data->tmp;
   const igraph_vector_t *weights = data->weights; 
   const igraph_t *g = data->graph;
-  igraph_vector_t *neis;
+  igraph_vector_int_t *neis;
   long int i, j, nlen;
   
   for (i=0; i<n; i++) {
     neis=igraph_inclist_get(in, i);
-    nlen=igraph_vector_size(neis);
+    nlen=igraph_vector_int_size(neis);
     VECTOR(*tmp)[i]=0.0;
     for (j=0; j<nlen; j++) {
       long int nei_edge = (long int) VECTOR(*neis)[j];
@@ -633,7 +633,7 @@ int igraph_i_kleinberg_weighted(igraph_real_t *to,
   
   for (i=0; i<n; i++) {
     neis=igraph_inclist_get(out, i);
-    nlen=igraph_vector_size(neis);
+    nlen=igraph_vector_int_size(neis);
     to[i]=0.0;
     for (j=0; j<nlen; j++) {
       long int nei_edge=(long int) VECTOR(*neis)[j];
@@ -984,7 +984,7 @@ int igraph_i_pagerank2(igraph_real_t *to, const igraph_real_t *from,
   igraph_vector_t *reset=data->reset;
   long int i, j, nlen;
   igraph_real_t sumfrom=0.0;
-  igraph_vector_t *neis;
+  igraph_vector_int_t *neis;
   igraph_real_t fact=1-data->damping;
 
   /*
@@ -1000,7 +1000,7 @@ int igraph_i_pagerank2(igraph_real_t *to, const igraph_real_t *from,
   
   for (i=0; i<n; i++) {
     neis=igraph_inclist_get(inclist, i);
-    nlen=igraph_vector_size(neis);
+    nlen=igraph_vector_int_size(neis);
     to[i]=0.0;
     for (j=0; j<nlen; j++) {
       long int edge=(long int) VECTOR(*neis)[j];
@@ -1634,7 +1634,7 @@ int igraph_i_betweenness_estimate_weighted(const igraph_t *graph,
     while (!igraph_2wheap_empty(&Q)) {
       long int minnei=igraph_2wheap_max_index(&Q);
       igraph_real_t mindist=-igraph_2wheap_delete_max(&Q);
-      igraph_vector_t *neis;
+      igraph_vector_int_t *neis;
       long int nlen;
       
       igraph_stack_push(&S, minnei);
@@ -1643,7 +1643,7 @@ int igraph_i_betweenness_estimate_weighted(const igraph_t *graph,
       
       /* Now check all neighbors of 'minnei' for a shorter path */
       neis=igraph_inclist_get(&inclist, minnei);
-      nlen=igraph_vector_size(neis);
+      nlen=igraph_vector_int_size(neis);
       for (j=0; j<nlen; j++) {
 	long int edge=(long int) VECTOR(*neis)[j];
 	long int to=IGRAPH_OTHER(graph, edge, minnei);
@@ -2081,7 +2081,7 @@ int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph,
     while (!igraph_2wheap_empty(&Q)) {
       long int minnei=igraph_2wheap_max_index(&Q);
       igraph_real_t mindist=-igraph_2wheap_delete_max(&Q);
-      igraph_vector_t *neis;
+      igraph_vector_int_t *neis;
       long int nlen;
 
 /*       printf("SP to %li is final, dist: %g, nrgeo: %li\n", minnei, */
@@ -2092,7 +2092,7 @@ int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph,
       if (cutoff >=0 && VECTOR(distance)[minnei] >= cutoff+1.0) { continue; }
 
       neis=igraph_inclist_get(&inclist, minnei);
-      nlen=igraph_vector_size(neis);
+      nlen=igraph_vector_int_size(neis);
       for (j=0; j<nlen; j++) {
 	long int edge=(long int) VECTOR(*neis)[j];
 	long int to=IGRAPH_OTHER(graph, edge, minnei);
@@ -2101,26 +2101,26 @@ int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph,
 	
 	if (curdist==0) {
 	  /* This is the first finite distance to 'to' */
-	  igraph_vector_t *v=igraph_inclist_get(&fathers, to);
+	  igraph_vector_int_t *v=igraph_inclist_get(&fathers, to);
 /* 	  printf("Found first path to %li (from %li)\n", to, minnei); */
-	  igraph_vector_resize(v,1);
+	  igraph_vector_int_resize(v,1);
 	  VECTOR(*v)[0]=edge;
 	  VECTOR(nrgeo)[to] = VECTOR(nrgeo)[minnei];
 	  VECTOR(distance)[to]=altdist+1.0;
 	  IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, to, -altdist));
 	} else if (altdist < curdist-1) {
 	  /* This is a shorter path */
-	  igraph_vector_t *v =igraph_inclist_get(&fathers, to);
+	  igraph_vector_int_t *v =igraph_inclist_get(&fathers, to);
 /* 	  printf("Found a shorter path to %li (from %li)\n", to, minnei); */
-	  igraph_vector_resize(v,1);
+	  igraph_vector_int_resize(v,1);
 	  VECTOR(*v)[0]=edge;
 	  VECTOR(nrgeo)[to] = VECTOR(nrgeo)[minnei];
 	  VECTOR(distance)[to] = altdist+1.0;
 	  IGRAPH_CHECK(igraph_2wheap_modify(&Q, to, -altdist));
 	} else if (altdist == curdist-1) {
-	  igraph_vector_t *v=igraph_inclist_get(&fathers, to);
+	  igraph_vector_int_t *v=igraph_inclist_get(&fathers, to);
 /* 	  printf("Found a second SP to %li (from %li)\n", to, minnei); */
-	  igraph_vector_push_back(v, edge);
+	  igraph_vector_int_push_back(v, edge);
 	  VECTOR(nrgeo)[to] += VECTOR(nrgeo)[minnei];
 	}
       }
@@ -2129,8 +2129,8 @@ int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph,
 
     while (!igraph_stack_empty(&S)) {
       long int w=(long int) igraph_stack_pop(&S);
-      igraph_vector_t *fatv=igraph_inclist_get(&fathers, w);
-      long int fatv_len=igraph_vector_size(fatv);
+      igraph_vector_int_t *fatv=igraph_inclist_get(&fathers, w);
+      long int fatv_len=igraph_vector_int_size(fatv);
 /*       printf("Popping %li.\n", w); */
       for (j=0; j<fatv_len; j++) {
 	long int fedge=(long int) VECTOR(*fatv)[j];
@@ -2146,7 +2146,7 @@ int igraph_i_edge_betweenness_estimate_weighted(const igraph_t *graph,
       VECTOR(tmpscore)[w]=0;
       VECTOR(distance)[w]=0;
       VECTOR(nrgeo)[w]=0;
-      igraph_vector_clear(fatv);
+      igraph_vector_int_clear(fatv);
     }
     
   } /* source < no_of_nodes */
@@ -2266,7 +2266,7 @@ int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res
 
   igraph_inclist_t elist_out, elist_in;
   igraph_inclist_t *elist_out_p, *elist_in_p;
-  igraph_vector_t *neip;
+  igraph_vector_int_t *neip;
   long int neino;
   long int i;
 
@@ -2336,7 +2336,7 @@ int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res
       if (cutoff > 0 && distance[actnode] >= cutoff ) continue;
 
       neip=igraph_inclist_get(elist_out_p, actnode);
-      neino=igraph_vector_size(neip);
+      neino=igraph_vector_int_size(neip);
       for (i=0; i<neino; i++) {
 	igraph_integer_t edge=(igraph_integer_t) VECTOR(*neip)[i], from, to;
 	long int neighbor;
@@ -2366,7 +2366,7 @@ int igraph_edge_betweenness_estimate(const igraph_t *graph, igraph_vector_t *res
       
       /* set the temporary score of the friends */
       neip=igraph_inclist_get(elist_in_p, actnode);
-      neino=igraph_vector_size(neip);
+      neino=igraph_vector_int_size(neip);
       for (i=0; i<neino; i++) {
 	igraph_integer_t from, to;
 	long int neighbor;
diff --git a/src/community.c b/src/community.c
index 3370679..95e6696 100644
--- a/src/community.c
+++ b/src/community.c
@@ -388,7 +388,7 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
   
   igraph_inclist_t elist_out, elist_in, fathers;
   igraph_inclist_t *elist_out_p, *elist_in_p;
-  igraph_vector_t *neip;
+  igraph_vector_int_t *neip;
   long int neino;
   igraph_vector_t eb;
   long int maxedge, pos;
@@ -512,7 +512,7 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
           long int actnode=(long int) igraph_dqueue_pop(&q);
           
           neip=igraph_inclist_get(elist_out_p, actnode);
-          neino=igraph_vector_size(neip);
+          neino=igraph_vector_int_size(neip);
           for (i=0; i<neino; i++) {
             igraph_integer_t edge=(igraph_integer_t) VECTOR(*neip)[i], from, to;
             long int neighbor;
@@ -542,7 +542,7 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
           
           /* set the temporary score of the friends */
           neip=igraph_inclist_get(elist_in_p, actnode);
-          neino=igraph_vector_size(neip);
+          neino=igraph_vector_int_size(neip);
           for (i=0; i<neino; i++) {
             long int edge = (long int) VECTOR(*neip)[i];
             long int neighbor = IGRAPH_OTHER(graph, edge, actnode);
@@ -581,19 +581,19 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
           igraph_stack_push(&stack, minnei);
 
           neip=igraph_inclist_get(elist_out_p, minnei);
-          neino=igraph_vector_size(neip);
+          neino=igraph_vector_int_size(neip);
 
           for (i=0; i<neino; i++) {
-            long int edge=(long int) VECTOR(*neip)[i];
+            long int edge=VECTOR(*neip)[i];
             long int to=IGRAPH_OTHER(graph, edge, minnei);
             igraph_real_t altdist = mindist + VECTOR(*weights)[edge];
             igraph_real_t curdist = distance[to];
-            igraph_vector_t *v;
+            igraph_vector_int_t *v;
 
             if (curdist == 0) {
               /* This is the first finite distance to 'to' */
               v = igraph_inclist_get(&fathers, to);
-              igraph_vector_resize(v, 1);
+              igraph_vector_int_resize(v, 1);
               VECTOR(*v)[0] = edge;
               nrgeo[to] = nrgeo[minnei];
               distance[to] = altdist + 1.0;
@@ -601,7 +601,7 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
             } else if (altdist < curdist-1) {
               /* This is a shorter path */
               v = igraph_inclist_get(&fathers, to);
-              igraph_vector_resize(v, 1);
+              igraph_vector_int_resize(v, 1);
               VECTOR(*v)[0] = edge;
               nrgeo[to] = nrgeo[minnei];
               distance[to] = altdist + 1.0;
@@ -609,7 +609,7 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
             } else if (altdist == curdist-1) {
               /* Another path with the same length */
               v = igraph_inclist_get(&fathers, to);
-              igraph_vector_push_back(v, edge);
+              igraph_vector_int_push_back(v, edge);
               nrgeo[to] += nrgeo[minnei];
             }
           }
@@ -617,8 +617,8 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
 
         while (!igraph_stack_empty(&stack)) {
           long int w = (long int) igraph_stack_pop(&stack);
-          igraph_vector_t *fatv = igraph_inclist_get(&fathers, w);
-          long int fatv_len = igraph_vector_size(fatv);
+          igraph_vector_int_t *fatv = igraph_inclist_get(&fathers, w);
+          long int fatv_len = igraph_vector_int_size(fatv);
 
           for (i = 0; i < fatv_len; i++) {
             long int fedge = (long int) VECTOR(*fatv)[i];
@@ -630,7 +630,7 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
           tmpscore[w] = 0;
           distance[w] = 0;
           nrgeo[w] = 0;
-          igraph_vector_clear(fatv);
+          igraph_vector_int_clear(fatv);
         }
       } /* source < no_of_nodes */
     }
@@ -649,16 +649,16 @@ int igraph_community_edge_betweenness(const igraph_t *graph,
     igraph_edge(graph, (igraph_integer_t) maxedge, &from, &to);
 
     neip=igraph_inclist_get(elist_in_p, to);
-    neino=igraph_vector_size(neip);
-    igraph_vector_search(neip, 0, maxedge, &pos);
+    neino=igraph_vector_int_size(neip);
+    igraph_vector_int_search(neip, 0, maxedge, &pos);
     VECTOR(*neip)[pos]=VECTOR(*neip)[neino-1];
-    igraph_vector_pop_back(neip);
+    igraph_vector_int_pop_back(neip);
     
     neip=igraph_inclist_get(elist_out_p, from);
-    neino=igraph_vector_size(neip);
-    igraph_vector_search(neip, 0, maxedge, &pos);
+    neino=igraph_vector_int_size(neip);
+    igraph_vector_int_search(neip, 0, maxedge, &pos);
     VECTOR(*neip)[pos]=VECTOR(*neip)[neino-1];
-    igraph_vector_pop_back(neip);
+    igraph_vector_int_pop_back(neip);
   }
 
   IGRAPH_PROGRESS("Edge betweenness community detection: ", 100.0, NULL);
@@ -1273,8 +1273,8 @@ int igraph_i_community_leading_eigenvector_weighted(igraph_real_t *to,
   /* Ax */
   for (j=0; j<size; j++) {
     long int oldid=(long int) VECTOR(*idx)[j];
-    igraph_vector_t *inc=igraph_inclist_get(inclist, oldid);
-    nlen=igraph_vector_size(inc);
+    igraph_vector_int_t *inc=igraph_inclist_get(inclist, oldid);
+    nlen=igraph_vector_int_size(inc);
     to[j]=0.0;
     VECTOR(*tmp)[j]=0.0;
     for (k=0; k<nlen; k++) {
@@ -1337,8 +1337,8 @@ int igraph_i_community_leading_eigenvector2_weighted(igraph_real_t *to,
   /* Ax */
   for (j=0; j<size; j++) {
     long int oldid=(long int) VECTOR(*idx)[j];
-    igraph_vector_t *inc=igraph_inclist_get(inclist, oldid);
-    nlen=igraph_vector_size(inc);
+    igraph_vector_int_t *inc=igraph_inclist_get(inclist, oldid);
+    nlen=igraph_vector_int_size(inc);
     to[j]=0.0;
     VECTOR(*tmp)[j]=0.0;
     for (k=0; k<nlen; k++) {
@@ -2236,7 +2236,7 @@ int igraph_community_label_propagation(const igraph_t *graph,
     long int v1, num_neis;
     igraph_real_t max_count;
     igraph_vector_int_t *neis;
-    igraph_vector_t *ineis;
+    igraph_vector_int_t *ineis;
     igraph_bool_t was_zero;
 
     running = 0;
@@ -2253,7 +2253,7 @@ int igraph_community_label_propagation(const igraph_t *graph,
       max_count = 0.0;
       if (weights) {
         ineis = igraph_inclist_get(&il, v1);
-        num_neis = igraph_vector_size(ineis);
+        num_neis = igraph_vector_int_size(ineis);
         for (j=0; j<num_neis; j++) {
           k = (long int) VECTOR(*membership)[
 		     (long)IGRAPH_OTHER(graph, VECTOR(*ineis)[j], v1) ];
diff --git a/src/components.c b/src/components.c
index 151f5d1..ccf36e5 100644
--- a/src/components.c
+++ b/src/components.c
@@ -26,6 +26,7 @@
 #include "igraph_interface.h"
 #include "igraph_adjlist.h"
 #include "igraph_interrupt_internal.h"
+#include "igraph_progress.h"
 #include "igraph_structural.h"
 #include "igraph_dqueue.h"
 #include "igraph_stack.h"
@@ -166,21 +167,22 @@ int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
   long int no_of_nodes=igraph_vcount(graph);
   igraph_vector_t next_nei=IGRAPH_VECTOR_NULL;
   
-  long int i;
+  long int i, n, num_seen;
   igraph_dqueue_t q=IGRAPH_DQUEUE_NULL;
   
   long int no_of_clusters=1;
   long int act_cluster_size;
 
   igraph_vector_t out=IGRAPH_VECTOR_NULL;
-  igraph_vector_t tmp=IGRAPH_VECTOR_NULL;
+  const igraph_vector_int_t* tmp;
+
+  igraph_adjlist_t adjlist;
 
   /* The result */
 
   IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes);
   IGRAPH_VECTOR_INIT_FINALLY(&out, 0);
   IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);
-  IGRAPH_VECTOR_INIT_FINALLY(&tmp, 0);
 
   if (membership) {
     IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));
@@ -191,25 +193,30 @@ int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
   if (csize) {
     igraph_vector_clear(csize);
   }
-  
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
+  num_seen = 0;
   for (i=0; i<no_of_nodes; i++) {
     IGRAPH_ALLOW_INTERRUPTION();
-    IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) i,
-				  IGRAPH_OUT));
-    if (VECTOR(next_nei)[i] > igraph_vector_size(&tmp)) { continue; }
+
+    tmp = igraph_adjlist_get(&adjlist, i);
+    if (VECTOR(next_nei)[i] > igraph_vector_int_size(tmp)) {
+      continue;
+    }
     
     IGRAPH_CHECK(igraph_dqueue_push(&q, i));
     while (!igraph_dqueue_empty(&q)) {
       long int act_node=(long int) igraph_dqueue_back(&q);
-      IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) act_node,
-				    IGRAPH_OUT));
+      tmp = igraph_adjlist_get(&adjlist, act_node);
       if (VECTOR(next_nei)[act_node]==0) {
 	/* this is the first time we've met this vertex */
 	VECTOR(next_nei)[act_node]++;
-      } else if (VECTOR(next_nei)[act_node] <= igraph_vector_size(&tmp)) {
+      } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) {
 	/* we've already met this vertex but it has more children */
-	long int neighbor=(long int) VECTOR(tmp)[(long int)
-						 VECTOR(next_nei)[act_node]-1];
+	long int neighbor=(long int) VECTOR(*tmp)[(long int)
+						  VECTOR(next_nei)[act_node]-1];
 	if (VECTOR(next_nei)[neighbor] == 0) {
 	  IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
 	}
@@ -218,18 +225,35 @@ int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
 	/* we've met this vertex and it has no more children */
 	IGRAPH_CHECK(igraph_vector_push_back(&out, act_node));
 	igraph_dqueue_pop_back(&q);
+	num_seen++;
+
+	if (num_seen % 10000 == 0) {
+	  /* time to report progress and allow the user to interrupt */
+	  IGRAPH_PROGRESS("Strongly connected components: ",
+	      num_seen * 50.0 / no_of_nodes, NULL);
+	  IGRAPH_ALLOW_INTERRUPTION();
+	}
       }
     } /* while q */
   }  /* for */
 
+  IGRAPH_PROGRESS("Strongly connected components: ", 50.0, NULL);
+
+  igraph_adjlist_destroy(&adjlist);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN));
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);
+
   /* OK, we've the 'out' values for the nodes, let's use them in
      decreasing order with the help of a heap */
 
-  igraph_vector_null(&next_nei);                            /* mark already
-							added vertices */
+  igraph_vector_null(&next_nei);             /* mark already added vertices */
+  num_seen = 0;
+
   while (!igraph_vector_empty(&out)) {
     long int grandfather=(long int) igraph_vector_pop_back(&out);
-    IGRAPH_ALLOW_INTERRUPTION();
+
     if (VECTOR(next_nei)[grandfather] != 0) { continue; }
     VECTOR(next_nei)[grandfather]=1;
     act_cluster_size=1;
@@ -238,12 +262,20 @@ int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
     }
     IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather));
     
+    num_seen++;
+    if (num_seen % 10000 == 0) {
+      /* time to report progress and allow the user to interrupt */
+      IGRAPH_PROGRESS("Strongly connected components: ",
+	  50.0 + num_seen * 50.0 / no_of_nodes, NULL);
+      IGRAPH_ALLOW_INTERRUPTION();
+    }
+
     while (!igraph_dqueue_empty(&q)) {
       long int act_node=(long int) igraph_dqueue_pop_back(&q);
-      IGRAPH_CHECK(igraph_neighbors(graph, &tmp, (igraph_integer_t) act_node, 
-				    IGRAPH_IN));
-      for (i=0; i<igraph_vector_size(&tmp); i++) {
-	long int neighbor=(long int) VECTOR(tmp)[i];
+      tmp = igraph_adjlist_get(&adjlist, act_node);
+      n = igraph_vector_int_size(tmp);
+      for (i=0; i<n; i++) {
+	long int neighbor=(long int) VECTOR(*tmp)[i];
 	if (VECTOR(next_nei)[neighbor] != 0) { continue; }
 	IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));
 	VECTOR(next_nei)[neighbor]=1;
@@ -251,20 +283,31 @@ int igraph_clusters_strong(const igraph_t *graph, igraph_vector_t *membership,
 	if (membership) {
 	  VECTOR(*membership)[neighbor]=no_of_clusters-1;
 	}
+
+	num_seen++;
+	if (num_seen % 10000 == 0) {
+	  /* time to report progress and allow the user to interrupt */
+	  IGRAPH_PROGRESS("Strongly connected components: ",
+	      50.0 + num_seen * 50.0 / no_of_nodes, NULL);
+	  IGRAPH_ALLOW_INTERRUPTION();
+	}
       }
     }
+
     no_of_clusters++;
     if (csize) {
       IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size));
     }
   }
   
+  IGRAPH_PROGRESS("Strongly connected components: ", 100.0, NULL);
+
   if (no) { *no=(igraph_integer_t) no_of_clusters-1; }
 
   /* Clean up, return */
 
+  igraph_adjlist_destroy(&adjlist);
   igraph_vector_destroy(&out);
-  igraph_vector_destroy(&tmp);
   igraph_dqueue_destroy(&q);
   igraph_vector_destroy(&next_nei);
   IGRAPH_FINALLY_CLEAN(4);
@@ -631,7 +674,7 @@ int igraph_biconnected_components(const igraph_t *graph,
   igraph_vector_long_t nextptr;
   igraph_vector_long_t num, low;
   igraph_vector_bool_t found;
-  igraph_vector_t *adjedges;
+  igraph_vector_int_t *adjedges;
   igraph_stack_t path;
   igraph_vector_t edgestack;
   igraph_inclist_t inclist;
@@ -697,7 +740,7 @@ int igraph_biconnected_components(const igraph_t *graph,
       long int actnext=VECTOR(nextptr)[act];
       
       adjedges=igraph_inclist_get(&inclist, act);
-      n=igraph_vector_size(adjedges);
+      n=igraph_vector_int_size(adjedges);
       if (actnext < n) {
 	/* Step down (maybe) */
 	long int edge=(long int) VECTOR(*adjedges)[actnext];
@@ -789,9 +832,9 @@ int igraph_biconnected_components(const igraph_t *graph,
 		IGRAPH_FINALLY(igraph_vector_destroy, vv);
 		for (ii=0; ii<no_vert; ii++) {
 		  long int vert=(long int) VECTOR(*nodes)[ii];
-		  igraph_vector_t *edges=igraph_inclist_get(&inclist, 
+		  igraph_vector_int_t *edges=igraph_inclist_get(&inclist, 
 								vert);
-		  long int j, nn=igraph_vector_size(edges);
+		  long int j, nn=igraph_vector_int_size(edges);
 		  for (j=0; j<nn; j++) {
 		    long int e=(long int) VECTOR(*edges)[j];
 		    long int nei=IGRAPH_OTHER(graph, e, vert);
diff --git a/src/config.h.in b/src/config.h.in
index 6d99c15..4e249e7 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -1,4 +1,4 @@
-/* src/config.h.in.  Generated from configure.in by autoheader.  */
+/* src/config.h.in.  Generated from configure.ac by autoheader.  */
 
 /* Define to 1 if you have the `expm1' function. */
 #undef HAVE_EXPM1
@@ -36,6 +36,15 @@
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
 /* Define to 1 if you have the `rint' function. */
 #undef HAVE_RINT
 
@@ -45,6 +54,9 @@
 /* Define to 1 if you have the `round' function. */
 #undef HAVE_ROUND
 
+/* Define if struct sockaddr contains sa_len */
+#undef HAVE_SA_LEN
+
 /* Define to 1 if you have the `snprintf' function. */
 #undef HAVE_SNPRINTF
 
@@ -66,12 +78,30 @@
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
 /* Define to 1 if you have the sys/times.h header */
 #undef HAVE_TIMES_H
 
diff --git a/src/cs_add.c b/src/cs/cs_add.c
similarity index 100%
rename from src/cs_add.c
rename to src/cs/cs_add.c
diff --git a/src/cs_amd.c b/src/cs/cs_amd.c
similarity index 100%
rename from src/cs_amd.c
rename to src/cs/cs_amd.c
diff --git a/src/cs_chol.c b/src/cs/cs_chol.c
similarity index 100%
rename from src/cs_chol.c
rename to src/cs/cs_chol.c
diff --git a/src/cs_cholsol.c b/src/cs/cs_cholsol.c
similarity index 100%
rename from src/cs_cholsol.c
rename to src/cs/cs_cholsol.c
diff --git a/src/cs_compress.c b/src/cs/cs_compress.c
similarity index 100%
rename from src/cs_compress.c
rename to src/cs/cs_compress.c
diff --git a/src/cs_counts.c b/src/cs/cs_counts.c
similarity index 100%
rename from src/cs_counts.c
rename to src/cs/cs_counts.c
diff --git a/src/cs_cumsum.c b/src/cs/cs_cumsum.c
similarity index 100%
rename from src/cs_cumsum.c
rename to src/cs/cs_cumsum.c
diff --git a/src/cs_dfs.c b/src/cs/cs_dfs.c
similarity index 100%
rename from src/cs_dfs.c
rename to src/cs/cs_dfs.c
diff --git a/src/cs_dmperm.c b/src/cs/cs_dmperm.c
similarity index 100%
rename from src/cs_dmperm.c
rename to src/cs/cs_dmperm.c
diff --git a/src/cs_droptol.c b/src/cs/cs_droptol.c
similarity index 100%
rename from src/cs_droptol.c
rename to src/cs/cs_droptol.c
diff --git a/src/cs_dropzeros.c b/src/cs/cs_dropzeros.c
similarity index 100%
rename from src/cs_dropzeros.c
rename to src/cs/cs_dropzeros.c
diff --git a/src/cs_dupl.c b/src/cs/cs_dupl.c
similarity index 100%
rename from src/cs_dupl.c
rename to src/cs/cs_dupl.c
diff --git a/src/cs_entry.c b/src/cs/cs_entry.c
similarity index 100%
rename from src/cs_entry.c
rename to src/cs/cs_entry.c
diff --git a/src/cs_ereach.c b/src/cs/cs_ereach.c
similarity index 100%
rename from src/cs_ereach.c
rename to src/cs/cs_ereach.c
diff --git a/src/cs_etree.c b/src/cs/cs_etree.c
similarity index 100%
rename from src/cs_etree.c
rename to src/cs/cs_etree.c
diff --git a/src/cs_fkeep.c b/src/cs/cs_fkeep.c
similarity index 100%
rename from src/cs_fkeep.c
rename to src/cs/cs_fkeep.c
diff --git a/src/cs_gaxpy.c b/src/cs/cs_gaxpy.c
similarity index 100%
rename from src/cs_gaxpy.c
rename to src/cs/cs_gaxpy.c
diff --git a/src/cs_happly.c b/src/cs/cs_happly.c
similarity index 100%
rename from src/cs_happly.c
rename to src/cs/cs_happly.c
diff --git a/src/cs_house.c b/src/cs/cs_house.c
similarity index 100%
rename from src/cs_house.c
rename to src/cs/cs_house.c
diff --git a/src/cs_ipvec.c b/src/cs/cs_ipvec.c
similarity index 100%
rename from src/cs_ipvec.c
rename to src/cs/cs_ipvec.c
diff --git a/src/cs_leaf.c b/src/cs/cs_leaf.c
similarity index 100%
rename from src/cs_leaf.c
rename to src/cs/cs_leaf.c
diff --git a/src/cs_load.c b/src/cs/cs_load.c
similarity index 100%
rename from src/cs_load.c
rename to src/cs/cs_load.c
diff --git a/src/cs_lsolve.c b/src/cs/cs_lsolve.c
similarity index 100%
rename from src/cs_lsolve.c
rename to src/cs/cs_lsolve.c
diff --git a/src/cs_ltsolve.c b/src/cs/cs_ltsolve.c
similarity index 100%
rename from src/cs_ltsolve.c
rename to src/cs/cs_ltsolve.c
diff --git a/src/cs_lu.c b/src/cs/cs_lu.c
similarity index 100%
rename from src/cs_lu.c
rename to src/cs/cs_lu.c
diff --git a/src/cs_lusol.c b/src/cs/cs_lusol.c
similarity index 100%
rename from src/cs_lusol.c
rename to src/cs/cs_lusol.c
diff --git a/src/cs_malloc.c b/src/cs/cs_malloc.c
similarity index 100%
rename from src/cs_malloc.c
rename to src/cs/cs_malloc.c
diff --git a/src/cs_maxtrans.c b/src/cs/cs_maxtrans.c
similarity index 100%
rename from src/cs_maxtrans.c
rename to src/cs/cs_maxtrans.c
diff --git a/src/cs_multiply.c b/src/cs/cs_multiply.c
similarity index 100%
rename from src/cs_multiply.c
rename to src/cs/cs_multiply.c
diff --git a/src/cs_norm.c b/src/cs/cs_norm.c
similarity index 100%
rename from src/cs_norm.c
rename to src/cs/cs_norm.c
diff --git a/src/cs_permute.c b/src/cs/cs_permute.c
similarity index 100%
rename from src/cs_permute.c
rename to src/cs/cs_permute.c
diff --git a/src/cs_pinv.c b/src/cs/cs_pinv.c
similarity index 100%
rename from src/cs_pinv.c
rename to src/cs/cs_pinv.c
diff --git a/src/cs_post.c b/src/cs/cs_post.c
similarity index 100%
rename from src/cs_post.c
rename to src/cs/cs_post.c
diff --git a/src/cs_print.c b/src/cs/cs_print.c
similarity index 100%
rename from src/cs_print.c
rename to src/cs/cs_print.c
diff --git a/src/cs_pvec.c b/src/cs/cs_pvec.c
similarity index 100%
rename from src/cs_pvec.c
rename to src/cs/cs_pvec.c
diff --git a/src/cs_qr.c b/src/cs/cs_qr.c
similarity index 100%
rename from src/cs_qr.c
rename to src/cs/cs_qr.c
diff --git a/src/cs_qrsol.c b/src/cs/cs_qrsol.c
similarity index 100%
rename from src/cs_qrsol.c
rename to src/cs/cs_qrsol.c
diff --git a/src/cs/cs_randperm.c b/src/cs/cs_randperm.c
new file mode 100644
index 0000000..48ad4ae
--- /dev/null
+++ b/src/cs/cs_randperm.c
@@ -0,0 +1,49 @@
+/*
+ * CXSPARSE: a Concise Sparse Matrix package - Extended.
+ * Copyright (c) 2006-2009, Timothy A. Davis.
+ * http://www.cise.ufl.edu/research/sparse/CXSparse
+ * 
+ * CXSparse is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * CXSparse 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
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this Module; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#pragma clang diagnostic ignored "-Wsign-conversion"
+
+#include "igraph_random.h"
+
+#include "cs.h"
+/* return a random permutation vector, the identity perm, or p = n-1:-1:0.
+ * seed = -1 means p = n-1:-1:0.  seed = 0 means p = identity.  otherwise
+ * p = random permutation.  */
+CS_INT *cs_randperm (CS_INT n, CS_INT seed)
+{
+    CS_INT *p, k, j, t ;
+    if (seed == 0) return (NULL) ;      /* return p = NULL (identity) */
+    p = cs_malloc (n, sizeof (CS_INT)) ;   /* allocate result */
+    if (!p) return (NULL) ;             /* out of memory */
+    for (k = 0 ; k < n ; k++) p [k] = n-k-1 ;
+    if (seed == -1) return (p) ;        /* return reverse permutation */
+    /* srand (seed) ;                      /\* get new random number seed *\/ */
+    RNG_BEGIN();
+    for (k = 0 ; k < n ; k++)
+    {
+        /* j = k + (rand ( ) % (n-k)) ;    /\* j = rand CS_INT in range k to n-1 *\/ */
+      j = k + RNG_INTEGER(k, n-1) ;
+        t = p [j] ;                     /* swap p[k] and p[j] */
+        p [j] = p [k] ;
+        p [k] = t ;
+    }
+    RNG_END();
+    return (p) ;
+}
diff --git a/src/cs_reach.c b/src/cs/cs_reach.c
similarity index 100%
rename from src/cs_reach.c
rename to src/cs/cs_reach.c
diff --git a/src/cs_scatter.c b/src/cs/cs_scatter.c
similarity index 100%
rename from src/cs_scatter.c
rename to src/cs/cs_scatter.c
diff --git a/src/cs_scc.c b/src/cs/cs_scc.c
similarity index 100%
rename from src/cs_scc.c
rename to src/cs/cs_scc.c
diff --git a/src/cs_schol.c b/src/cs/cs_schol.c
similarity index 100%
rename from src/cs_schol.c
rename to src/cs/cs_schol.c
diff --git a/src/cs_spsolve.c b/src/cs/cs_spsolve.c
similarity index 100%
rename from src/cs_spsolve.c
rename to src/cs/cs_spsolve.c
diff --git a/src/cs_sqr.c b/src/cs/cs_sqr.c
similarity index 100%
rename from src/cs_sqr.c
rename to src/cs/cs_sqr.c
diff --git a/src/cs_symperm.c b/src/cs/cs_symperm.c
similarity index 100%
rename from src/cs_symperm.c
rename to src/cs/cs_symperm.c
diff --git a/src/cs_tdfs.c b/src/cs/cs_tdfs.c
similarity index 100%
rename from src/cs_tdfs.c
rename to src/cs/cs_tdfs.c
diff --git a/src/cs_transpose.c b/src/cs/cs_transpose.c
similarity index 100%
rename from src/cs_transpose.c
rename to src/cs/cs_transpose.c
diff --git a/src/cs_updown.c b/src/cs/cs_updown.c
similarity index 100%
rename from src/cs_updown.c
rename to src/cs/cs_updown.c
diff --git a/src/cs_usolve.c b/src/cs/cs_usolve.c
similarity index 100%
rename from src/cs_usolve.c
rename to src/cs/cs_usolve.c
diff --git a/src/cs_util.c b/src/cs/cs_util.c
similarity index 100%
rename from src/cs_util.c
rename to src/cs/cs_util.c
diff --git a/src/cs_utsolve.c b/src/cs/cs_utsolve.c
similarity index 100%
rename from src/cs_utsolve.c
rename to src/cs/cs_utsolve.c
diff --git a/src/cs_randperm.c b/src/cs_randperm.c
deleted file mode 100644
index 014578a..0000000
--- a/src/cs_randperm.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * CXSPARSE: a Concise Sparse Matrix package - Extended.
- * Copyright (c) 2006-2009, Timothy A. Davis.
- * http://www.cise.ufl.edu/research/sparse/CXSparse
- * 
- * CXSparse is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- * 
- * CXSparse 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
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this Module; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#pragma clang diagnostic ignored "-Wsign-conversion"
-
-#include "cs.h"
-/* return a random permutation vector, the identity perm, or p = n-1:-1:0.
- * seed = -1 means p = n-1:-1:0.  seed = 0 means p = identity.  otherwise
- * p = random permutation.  */
-CS_INT *cs_randperm (CS_INT n, CS_INT seed)
-{
-    CS_INT *p, k, j, t ;
-    if (seed == 0) return (NULL) ;      /* return p = NULL (identity) */
-    p = cs_malloc (n, sizeof (CS_INT)) ;   /* allocate result */
-    if (!p) return (NULL) ;             /* out of memory */
-    for (k = 0 ; k < n ; k++) p [k] = n-k-1 ;
-    if (seed == -1) return (p) ;        /* return reverse permutation */
-    srand (seed) ;                      /* get new random number seed */
-    for (k = 0 ; k < n ; k++)
-    {
-        j = k + (rand ( ) % (n-k)) ;    /* j = rand CS_INT in range k to n-1 */
-        t = p [j] ;                     /* swap p[k] and p[j] */
-        p [j] = p [k] ;
-        p [k] = t ;
-    }
-    return (p) ;
-}
diff --git a/src/dotproduct.c b/src/dotproduct.c
new file mode 100644
index 0000000..4ec7b52
--- /dev/null
+++ b/src/dotproduct.c
@@ -0,0 +1,276 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_games.h"
+#include "igraph_random.h"
+#include "igraph_constructors.h"
+#include "igraph_lapack.h"
+
+/**
+ * \function igraph_dot_product_game
+ * Generate a random dot product graph
+ * 
+ * In this model, each vertex is represented by a latent
+ * position vector. Probability of an edge between two vertices are given
+ * by the dot product of their latent position vectors.
+ * 
+ * </para><para>
+ * See also Christine Leigh Myers Nickel: Random dot product graphs, a
+ * model for social networks. Dissertation, Johns Hopkins University,
+ * Maryland, USA, 2006.
+ * 
+ * \param graph The output graph is stored here.
+ * \param vecs A matrix in which each latent position vector is a 
+ *    column. The dot product of the latent position vectors should be
+ *    in the [0,1] interval, otherwise a warning is given. For
+ *    negative dot products, no edges are added; dot products that are
+ *    larger than one always add an edge.
+ * \param directed Should the generated graph be directed?
+ * \return Error code.
+ * 
+ * Time complexity: O(n*n*m), where n is the number of vertices, 
+ * and m is the length of the latent vectors.
+ *
+ * \sa \ref igraph_sample_dirichlet(), \ref
+ * igraph_sample_sphere_volume(), \ref igraph_sample_sphere_surface()
+ * for functions to generate the latent vectors.
+ */ 
+
+int igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,
+			    igraph_bool_t directed) {
+
+  igraph_integer_t nrow=igraph_matrix_nrow(vecs);
+  igraph_integer_t ncol=igraph_matrix_ncol(vecs);
+  int i, j;
+  igraph_vector_t edges;
+  igraph_bool_t warned_neg=0, warned_big=0;
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+    
+  RNG_BEGIN();
+
+  for (i = 0; i < ncol; i++) {
+    int from=directed ? 0 : i+1;
+    igraph_vector_t v1;
+    igraph_vector_view(&v1, &MATRIX(*vecs, 0, i), nrow);
+    for (j = from; j < ncol; j++) {
+      if (i==j) { continue; }
+      igraph_real_t prob;
+      igraph_vector_t v2;
+      igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow);
+      igraph_lapack_ddot(&v1, &v2, &prob);
+      if (prob < 0 && ! warned_neg) {
+	warned_neg=1;
+	IGRAPH_WARNING("Negative connection probability in "
+		       "dot-product graph");
+      } else if (prob > 1 && ! warned_big) {
+	warned_big=1;
+	IGRAPH_WARNING("Greater than 1 connection probability in "
+		       "dot-product graph");
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+      } else if (RNG_UNIF01() < prob) { 
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, i));
+	IGRAPH_CHECK(igraph_vector_push_back(&edges, j));
+      }
+    }
+  }
+
+  RNG_END();
+  
+  igraph_create(graph, &edges, ncol, directed);
+  igraph_vector_destroy(&edges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_sample_sphere_surface
+ * Sample points uniformly from the surface of a sphere
+ * 
+ * The center of the sphere is at the origin.
+ * 
+ * \param dim The dimension of the random vectors.
+ * \param n The number of vectors to sample.
+ * \param radius Radius of the sphere, it must be positive.
+ * \param positive Whether to restrict sampling to the positive 
+ *    orthant.}
+ * \param res Pointer to an initialized matrix, the result is 
+ *    stored here, each column will be a sampled vector. The matrix is
+ *    resized, as needed.}
+ * \return Error code.
+ * 
+ * Time complexity: O(n*dim*g), where g is the time complexity of 
+ * generating a standard normal random number.
+ * 
+ * \sa \ref igraph_sample_sphere_volume(), \ref
+ * igraph_sample_dirichlet() for other similar samplers.
+ */
+
+int igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n,
+				 igraph_real_t radius, 
+				 igraph_bool_t positive, 
+				 igraph_matrix_t *res) {
+  igraph_integer_t i, j;
+
+  if (dim < 2) {
+    IGRAPH_ERROR("Sphere must be at least two dimensional to sample from "
+		 "surface", IGRAPH_EINVAL);
+  }
+  if (n < 0) {
+    IGRAPH_ERROR("Number of samples must be non-negative", IGRAPH_EINVAL);
+  }
+  if (radius <= 0) {
+    IGRAPH_ERROR("Sphere radius must be positive", IGRAPH_EINVAL);
+  }
+  
+  IGRAPH_CHECK(igraph_matrix_resize(res, dim, n));
+
+  RNG_BEGIN();
+
+  for (i = 0; i < n; i++) {
+    igraph_real_t *col=&MATRIX(*res, 0, i);
+    igraph_real_t sum=0.0;
+    for (j = 0; j < dim; j++) {
+      col[j] = RNG_NORMAL(0, 1);
+      sum += col[j] * col[j];
+    }
+    sum = sqrt(sum);
+    for (j = 0; j < dim; j++) {
+      col[j] = radius * col[j] / sum;
+    }
+    if (positive) {
+      for (j = 0; j < dim; j++) {
+	col[j] = fabs(col[j]);
+      }
+    }
+  }
+
+  RNG_END();
+
+  return 0;
+}
+
+/**
+ * \function igraph_sample_sphere_volume
+ * Sample points uniformly from the volume of a sphere
+ * 
+ * The center of the sphere is at the origin.
+ * 
+ * \param dim The dimension of the random vectors.
+ * \param n The number of vectors to sample.
+ * \param radius Radius of the sphere, it must be positive.
+ * \param positive Whether to restrict sampling to the positive 
+ *    orthant.}
+ * \param res Pointer to an initialized matrix, the result is 
+ *    stored here, each column will be a sampled vector. The matrix is
+ *    resized, as needed.}
+ * \return Error code.
+ *
+ * Time complexity: O(n*dim*g), where g is the time complexity of 
+ * generating a standard normal random number.
+ * 
+ * \sa \ref igraph_sample_sphere_surface(), \ref
+ * igraph_sample_dirichlet() for other similar samplers. 
+ */
+
+
+int igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n,
+				igraph_real_t radius,
+				igraph_bool_t positive,
+				igraph_matrix_t *res) {
+
+  igraph_integer_t i, j;
+
+  /* Arguments are checked by the following call */
+
+  IGRAPH_CHECK(igraph_sample_sphere_surface(dim, n, radius, positive, res));
+  
+  RNG_BEGIN();
+
+  for (i = 0; i < n; i++) {
+    igraph_real_t *col=&MATRIX(*res, 0, i);
+    igraph_real_t U=pow(RNG_UNIF01(), 1.0/dim);
+    for (j = 0; j < dim; j++) { col[j] *= U; }
+  }
+
+  RNG_END();
+  
+  return 0;
+}
+
+/**
+ * \function igraph_sample_dirichlet
+ * Sample points from a Dirichlet distribution
+ *
+ * \param n The number of vectors to sample.
+ * \param alpha The parameters of the Dirichlet distribution. They
+ *    must be positive. The length of this vector gives the dimension
+ *    of the generated samples.
+ * \param res Pointer to an initialized matrix, the result is stored
+ *    here, one sample in each column. It will be resized, as needed.
+ * \return Error code.
+ * 
+ * Time complexity: O(n * dim * g), where dim is the dimension of the
+ * sample vectors, set by the length of alpha, and g is the time
+ * complexity of sampling from a Gamma distribution.
+ * 
+ * \sa \ref igraph_sample_sphere_surface() and 
+ * \ref igraph_sample_sphere_volume() for other methods to sample
+ * latent vectors.
+ */
+
+int igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha,
+			    igraph_matrix_t *res) {
+
+  igraph_integer_t len=igraph_vector_size(alpha);
+  igraph_integer_t i;
+  igraph_vector_t vec;
+
+  if (n < 0) {
+    IGRAPH_ERROR("Number of samples should be non-negative",
+		 IGRAPH_EINVAL);
+  }
+  if (len < 2) {
+    IGRAPH_ERROR("Dirichlet parameter vector too short, must "
+		 "have at least two entries", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(alpha) <= 0) {
+    IGRAPH_ERROR("Dirichlet concentration parameters must be positive",
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_matrix_resize(res, len, n));
+
+  RNG_BEGIN();
+
+  for (i = 0; i < n; i++) {
+    igraph_vector_view(&vec, &MATRIX(*res, 0, i), len);
+    igraph_rng_get_dirichlet(igraph_rng_default(), alpha, &vec);
+  }
+
+  RNG_END();
+
+  return 0;
+}
diff --git a/src/dqueue.c b/src/dqueue.c
index 45a2d62..0d2a423 100644
--- a/src/dqueue.c
+++ b/src/dqueue.c
@@ -47,3 +47,9 @@
 #include "dqueue.pmt"
 #include "igraph_pmt_off.h"
 #undef BASE_BOOL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "dqueue.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
diff --git a/src/dqueue.pmt b/src/dqueue.pmt
index 3835863..08d67cd 100644
--- a/src/dqueue.pmt
+++ b/src/dqueue.pmt
@@ -22,7 +22,6 @@
 */
 
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_error.h"
 #include "config.h"
 
diff --git a/src/drl_layout.cpp b/src/drl_layout.cpp
index 3bf3f41..20f53ba 100644
--- a/src/drl_layout.cpp
+++ b/src/drl_layout.cpp
@@ -417,7 +417,7 @@ int igraph_layout_drl_options_init(igraph_layout_drl_options_t *options,
     options->simmer_damping_mult = 0;
     
   default:
-    IGRAPH_ERROR("Unkown DrL template", IGRAPH_EINVAL);
+    IGRAPH_ERROR("Unknown DrL template", IGRAPH_EINVAL);
     break;
   }
 
diff --git a/src/embedding.c b/src/embedding.c
new file mode 100644
index 0000000..af5c223
--- /dev/null
+++ b/src/embedding.c
@@ -0,0 +1,1116 @@
+/* -*- mode: C -*-  */
+/*
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_embedding.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_random.h"
+#include "igraph_centrality.h"
+#include "igraph_blas.h"
+
+typedef struct {
+  const igraph_t *graph;
+  const igraph_vector_t *cvec;
+  const igraph_vector_t *cvec2;
+  igraph_adjlist_t *outlist, *inlist;
+  igraph_inclist_t *eoutlist, *einlist;
+  igraph_vector_t *tmp;
+  const igraph_vector_t *weights;
+} igraph_i_asembedding_data_t;
+
+/* Adjacency matrix, unweighted, undirected.
+   Eigendecomposition is used */
+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;
+  const igraph_vector_t *cvec=data->cvec;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* to = (A+cD) from */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(outlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      to[i] += from[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  return 0;
+}
+
+/* Adjacency matrix, weighted, undirected.
+   Eigendecomposition is used. */
+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;
+  const igraph_vector_t *cvec=data->cvec;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_int_t *incs;
+  int i, j, nlen;
+
+  /* to = (A+cD) from */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(outlist, i);
+    nlen=igraph_vector_int_size(incs);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      to[i] += w * from[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  return 0;
+}
+
+/* Adjacency matrix, unweighted, directed. SVD. */
+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;
+  igraph_adjlist_t *inlist=data->inlist;
+  const igraph_vector_t *cvec=data->cvec;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* tmp = (A+cD)' from */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(inlist, i);
+    nlen=igraph_vector_int_size(neis);
+    VECTOR(*tmp)[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      VECTOR(*tmp)[i] += from[nei];
+    }
+    VECTOR(*tmp)[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  /* to = (A+cD) tmp */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(outlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      to[i] += VECTOR(*tmp)[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * VECTOR(*tmp)[i];
+  }
+
+  return 0;
+}
+
+/* Adjacency matrix, unweighted, directed. SVD, right eigenvectors */
+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;
+  const igraph_vector_t *cvec=data->cvec;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* to = (A+cD)' from */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(inlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      to[i] += from[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  return 0;
+}
+
+/* Adjacency matrix, weighted, directed. SVD. */
+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;
+  igraph_inclist_t *inlist=data->einlist;
+  const igraph_vector_t *cvec=data->cvec;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *incs;
+  int i, j, nlen;
+
+  /* tmp = (A+cD)' from */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(inlist, i);
+    nlen=igraph_vector_int_size(incs);
+    VECTOR(*tmp)[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      VECTOR(*tmp)[i] += w * from[nei];
+    }
+    VECTOR(*tmp)[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  /* to = (A+cD) tmp */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(outlist, i);
+    nlen=igraph_vector_int_size(incs);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      to[i] += w * VECTOR(*tmp)[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * VECTOR(*tmp)[i];
+  }
+
+  return 0;
+}
+
+/* Adjacency matrix, weighted, directed. SVD, right eigenvectors. */
+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;
+  const igraph_vector_t *cvec=data->cvec;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_int_t *incs;
+  int i, j, nlen;
+
+  /* to = (A+cD)' from */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(inlist, i);
+    nlen=igraph_vector_int_size(incs);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      to[i] += w * from[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  return 0;
+}
+
+/* Laplacian D-A, unweighted, undirected. Eigendecomposition. */
+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;
+  const igraph_vector_t *cvec=data->cvec;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* to = (D-A) from */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(outlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      to[i] -= from[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  return 0;
+}
+
+/* Laplacian D-A, weighted, undirected. Eigendecomposition. */
+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;
+  const igraph_vector_t *cvec=data->cvec;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_int_t *incs;
+  int i, j, nlen;
+
+  /* to = (D-A) from */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(outlist, i);
+    nlen=igraph_vector_int_size(incs);
+    to[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      to[i] -= w * from[nei];
+    }
+    to[i] += VECTOR(*cvec)[i] * from[i];
+  }
+
+  return 0;
+}
+
+/* Laplacian DAD, unweighted, undirected. Eigendecomposition. */
+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;
+  igraph_adjlist_t *outlist=data->outlist;
+  const igraph_vector_t *cvec=data->cvec;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* to = D^1/2 from */
+  for (i=0; i<n; i++) {
+    to[i] = VECTOR(*cvec)[i] * from[i];
+  }
+
+  /* tmp = A to */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(outlist, i);
+    nlen=igraph_vector_int_size(neis);
+    VECTOR(*tmp)[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int nei=(long int) VECTOR(*neis)[j];
+      VECTOR(*tmp)[i] += to[nei];
+    }
+  }
+
+  /* to = D tmp */
+  for (i=0; i<n; i++) {
+    to[i] = VECTOR(*cvec)[i] * VECTOR(*tmp)[i];
+  }
+
+  return 0;
+}
+
+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;
+  igraph_inclist_t *outlist=data->eoutlist;
+  const igraph_vector_t *cvec=data->cvec;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *incs;
+  int i, j, nlen;
+
+  /* to = D^-1/2 from */
+  for (i=0; i<n; i++) {
+    to[i] = VECTOR(*cvec)[i] * from[i];
+  }
+
+  /* tmp = A' to */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(outlist, i);
+    nlen=igraph_vector_int_size(incs);
+    VECTOR(*tmp)[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      VECTOR(*tmp)[i] += w * to[nei];
+    }
+  }
+
+  /* to = D tmp */
+  for (i=0; i<n; i++) {
+    to[i] = VECTOR(*cvec)[i] * VECTOR(*cvec)[i] * VECTOR(*tmp)[i];
+  }
+
+  /* tmp = A to */
+  for (i=0; i<n; i++) {
+    incs=igraph_inclist_get(outlist, i);
+    nlen=igraph_vector_int_size(incs);
+    VECTOR(*tmp)[i]=0.0;
+    for (j=0; j<nlen; j++) {
+      long int edge=VECTOR(*incs)[j];
+      long int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      VECTOR(*tmp)[i] += w * to[nei];
+    }
+  }
+
+  /* to = D^-1/2 tmp */
+  for (i=0; i<n; i++) {
+    to[i] = VECTOR(*cvec)[i] * VECTOR(*tmp)[i];
+  }
+
+  return 0;
+}
+
+/* Laplacian I-DAD, unweighted, undirected. Eigendecomposition. */
+int igraph_i_lsembedding_idad(igraph_real_t *to, const igraph_real_t *from,
+			      int n, void *extra) {
+
+  int i;
+
+  igraph_i_lsembedding_dad(to, from, n, extra);
+  for (i=0; i<n; i++) { to[i] = from[i] - to[i]; }
+
+  return 0;
+}
+
+int igraph_i_lsembedding_idadw(igraph_real_t *to, const igraph_real_t *from,
+			       int n, void *extra) {
+  int i;
+
+  igraph_i_lsembedding_dadw(to, from, n, extra);
+  for (i=0; i<n; i++) { to[i] = from[i] - to[i]; }
+
+  return 0;
+}
+
+/* Laplacian OAP, unweighted, directed. SVD. */
+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;
+  igraph_adjlist_t *outlist=data->outlist;
+  igraph_adjlist_t *inlist=data->inlist;
+  const igraph_vector_t *deg_in=data->cvec;
+  const igraph_vector_t *deg_out=data->cvec2;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* tmp = O' from */
+  for (i=0; i<n; i++) { VECTOR(*tmp)[i] = VECTOR(*deg_out)[i] * from[i]; }
+
+  /* to = A' tmp */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(inlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int nei=VECTOR(*neis)[j];
+      to[i] += VECTOR(*tmp)[nei];
+    }
+  }
+
+  /* tmp = P' to */
+  for (i=0; i<n; i++) { VECTOR(*tmp)[i] = VECTOR(*deg_in)[i] * to[i]; }
+
+  /* to = P tmp */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i]; }
+
+  /* tmp = A to */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(outlist, i);
+    nlen=igraph_vector_int_size(neis);
+    VECTOR(*tmp)[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int nei=VECTOR(*neis)[j];
+      VECTOR(*tmp)[i] += to[nei];
+    }
+  }
+
+  /* to = O tmp */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_out)[i] * VECTOR(*tmp)[i]; }
+
+  return 0;
+}
+
+/* Laplacian OAP, unweighted, directed. SVD, right eigenvectors. */
+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;
+  igraph_adjlist_t *inlist=data->inlist;
+  const igraph_vector_t *deg_in=data->cvec;
+  const igraph_vector_t *deg_out=data->cvec2;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* to = O' from */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_out)[i] * from[i]; }
+
+  /* tmp = A' to */
+  for (i=0; i<n; i++) {
+    neis=igraph_adjlist_get(inlist, i);
+    nlen=igraph_vector_int_size(neis);
+    VECTOR(*tmp)[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int nei=VECTOR(*neis)[j];
+      VECTOR(*tmp)[i] += to[nei];
+    }
+  }
+
+  /* to = P' tmp */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i]; }
+
+  return 0;
+}
+
+/* Laplacian OAP, weighted, directed. SVD. */
+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;
+  igraph_inclist_t *outlist=data->eoutlist;
+  igraph_inclist_t *inlist=data->einlist;
+  const igraph_vector_t *deg_in=data->cvec;
+  const igraph_vector_t *deg_out=data->cvec2;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* tmp = O' from */
+  for (i=0; i<n; i++) { VECTOR(*tmp)[i] = VECTOR(*deg_out)[i] * from[i]; }
+
+  /* to = A' tmp */
+  for (i=0; i<n; i++) {
+    neis=igraph_inclist_get(inlist, i);
+    nlen=igraph_vector_int_size(neis);
+    to[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int edge=VECTOR(*neis)[j];
+      int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      to[i] += w * VECTOR(*tmp)[nei];
+    }
+  }
+
+  /* tmp = P' to */
+  for (i=0; i<n; i++) { VECTOR(*tmp)[i] = VECTOR(*deg_in)[i] * to[i]; }
+
+  /* to = P tmp */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i]; }
+
+  /* tmp = A to */
+  for (i=0; i<n; i++) {
+    neis=igraph_inclist_get(outlist, i);
+    nlen=igraph_vector_int_size(neis);
+    VECTOR(*tmp)[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int edge=VECTOR(*neis)[j];
+      int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      VECTOR(*tmp)[i] += w * to[nei];
+    }
+  }
+
+  /* to = O tmp */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_out)[i] * VECTOR(*tmp)[i]; }
+
+  return 0;
+}
+
+/* Laplacian OAP, weighted, directed. SVD, right eigenvectors. */
+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;
+  igraph_inclist_t *inlist=data->einlist;
+  const igraph_vector_t *deg_in=data->cvec;
+  const igraph_vector_t *deg_out=data->cvec2;
+  const igraph_vector_t *weights=data->weights;
+  const igraph_t *graph=data->graph;
+  igraph_vector_t *tmp=data->tmp;
+  igraph_vector_int_t *neis;
+  int i, j, nlen;
+
+  /* to = O' from */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_out)[i] * from[i]; }
+
+  /* tmp = A' to */
+  for (i=0; i<n; i++) {
+    neis=igraph_inclist_get(inlist, i);
+    nlen=igraph_vector_int_size(neis);
+    VECTOR(*tmp)[i] = 0.0;
+    for (j=0; j<nlen; j++) {
+      int edge=VECTOR(*neis)[j];
+      int nei=IGRAPH_OTHER(graph, edge, i);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      VECTOR(*tmp)[i] += w * to[nei];
+    }
+  }
+
+  /* to = P' tmp */
+  for (i=0; i<n; i++) { to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i]; }
+
+  return 0;
+}
+
+int igraph_i_spectral_embedding(const igraph_t *graph,
+				igraph_integer_t no,
+				const igraph_vector_t *weights,
+				igraph_eigen_which_position_t which,
+				igraph_bool_t scaled,
+				igraph_matrix_t *X,
+				igraph_matrix_t *Y,
+				igraph_vector_t *D,
+				const igraph_vector_t *cvec,
+                                const igraph_vector_t *cvec2,
+				igraph_arpack_options_t *options,
+				igraph_arpack_function_t *callback,
+				igraph_arpack_function_t *callback_right,
+				igraph_bool_t symmetric,
+				igraph_bool_t eigen,
+                                igraph_bool_t zapsmall) {
+
+  igraph_integer_t vc=igraph_vcount(graph);
+  igraph_vector_t tmp;
+  igraph_adjlist_t outlist, inlist;
+  igraph_inclist_t eoutlist, einlist;
+  int i, j, cveclen=igraph_vector_size(cvec);
+  igraph_i_asembedding_data_t data={ graph, cvec, cvec2, &outlist, &inlist,
+				     &eoutlist, &einlist, &tmp, weights };
+  igraph_vector_t tmpD;
+
+  if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (which != IGRAPH_EIGEN_LM &&
+      which != IGRAPH_EIGEN_LA &&
+      which != IGRAPH_EIGEN_SA) {
+    IGRAPH_ERROR("Invalid eigenvalue chosen, must be one of "
+		 "`largest magnitude', `largest algebraic' or "
+		 "`smallest algebraic'", IGRAPH_EINVAL);
+  }
+
+  if (no > vc) {
+    IGRAPH_ERROR("Too many singular values requested", IGRAPH_EINVAL);
+  }
+  if (no <= 0) {
+    IGRAPH_ERROR("No singular values requested", IGRAPH_EINVAL);
+  }
+
+  if (cveclen != 1 && cveclen != vc) {
+    IGRAPH_ERROR("Augmentation vector size is invalid, it should be "
+		 "the number of vertices or scalar", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_matrix_resize(X, vc, no));
+  if (Y) { IGRAPH_CHECK(igraph_matrix_resize(Y, vc, no)); }
+
+  /* empty graph */
+  if (igraph_ecount(graph) == 0) {
+    igraph_matrix_null(X);
+    if (Y) { igraph_matrix_null(Y); }
+    return 0;
+  }
+
+  igraph_vector_init(&tmp, vc);
+  IGRAPH_FINALLY(igraph_vector_destroy, &tmp);
+  if (!weights) {
+    IGRAPH_CHECK(igraph_adjlist_init(graph, &outlist, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_adjlist_destroy, &outlist);
+    if (!symmetric) {
+      IGRAPH_CHECK(igraph_adjlist_init(graph, &inlist, IGRAPH_IN));
+      IGRAPH_FINALLY(igraph_adjlist_destroy, &inlist);
+    }
+  } else {
+    IGRAPH_CHECK(igraph_inclist_init(graph, &eoutlist, IGRAPH_OUT));
+    IGRAPH_FINALLY(igraph_inclist_destroy, &eoutlist);
+    if (!symmetric) {
+      IGRAPH_CHECK(igraph_inclist_init(graph, &einlist, IGRAPH_IN));
+      IGRAPH_FINALLY(igraph_inclist_destroy, &einlist);
+    }
+  }
+  IGRAPH_VECTOR_INIT_FINALLY(&tmpD, no);
+
+  options->n=vc;
+  options->start=0;		/* random start vector */
+  options->nev=no;
+  switch (which) {
+  case IGRAPH_EIGEN_LM:
+    options->which[0]='L'; options->which[1]='M';
+    break;
+  case IGRAPH_EIGEN_LA:
+    options->which[0]='L'; options->which[1]='A';
+    break;
+  case IGRAPH_EIGEN_SA:
+    options->which[0]='S'; options->which[1]='A';
+    break;
+  default:
+    break;
+  }
+  options->ncv = no + 3;
+  if (options->ncv > vc) { options->ncv = vc; }
+
+  IGRAPH_CHECK(igraph_arpack_rssolve(callback, &data, options, 0, &tmpD, X));
+
+  if (!symmetric) {
+    /* calculate left eigenvalues */
+    IGRAPH_CHECK(igraph_matrix_resize(Y, vc, no));
+    for (i = 0; i < no; i++) {
+      igraph_real_t norm;
+      igraph_vector_t v;
+      callback_right(&MATRIX(*Y, 0, i), &MATRIX(*X, 0, i), vc, &data);
+      igraph_vector_view(&v, &MATRIX(*Y, 0, i), vc);
+      norm = 1.0 / igraph_blas_dnrm2(&v);
+      igraph_vector_scale(&v, norm);
+    }
+  } else if (Y) {
+    IGRAPH_CHECK(igraph_matrix_update(Y, X));
+  }
+
+  if (zapsmall) {
+    igraph_vector_zapsmall(&tmpD, 0);
+    igraph_matrix_zapsmall(X, 0);
+    if (Y) { igraph_matrix_zapsmall(Y, 0); }
+  }
+
+  if (D) {
+    igraph_vector_update(D, &tmpD);
+    if (!eigen) {
+      for (i=0; i<no; i++) {
+	VECTOR(*D)[i] = sqrt(VECTOR(*D)[i]);
+      }
+    }
+  }
+
+  if (scaled) {
+    if (eigen) {
+      /* eigenvalues were calculated */
+      for (i=0; i<no; i++) {
+	VECTOR(tmpD)[i] = sqrt(fabs(VECTOR(tmpD)[i]));
+      }
+    } else {
+      /* singular values were calculated */
+      for (i=0; i<no; i++) {
+	VECTOR(tmpD)[i] = sqrt(sqrt(VECTOR(tmpD)[i]));
+      }
+    }
+
+    for (j=0; j<vc; j++) {
+      for (i=0; i<no; i++) {
+	MATRIX(*X, j, i) *= VECTOR(tmpD)[i];
+      }
+    }
+
+    if (Y) {
+      for (j=0; j<vc; j++) {
+	for (i=0; i<no; i++) {
+	  MATRIX(*Y, j, i) *= VECTOR(tmpD)[i];
+	}
+      }
+    }
+  }
+
+  igraph_vector_destroy(&tmpD);
+  if (!weights) {
+    if (!symmetric) {
+      igraph_adjlist_destroy(&inlist);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    igraph_adjlist_destroy(&outlist);
+  } else {
+    if (!symmetric) {
+      igraph_inclist_destroy(&einlist);
+      IGRAPH_FINALLY_CLEAN(1);
+    }
+    igraph_inclist_destroy(&eoutlist);
+  }
+  igraph_vector_destroy(&tmp);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \function igraph_adjacency_spectral_embedding
+ * Adjacency spectral embedding
+ *
+ * Spectral decomposition of the adjacency matrices of graphs.
+ * This function computes a \code{no}-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,
+ * where the graph is a random dot product graph generated using latent
+ * position vectors in R^no 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
+ * 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.)
+ *
+ * \param graph The input graph, can be directed or undirected.
+ * \param no 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
+ *        singular values are used for the spectral embedding.
+ * \param weights Optional edge weights. Supply a null pointer for
+ *        unweighted graphs.
+ * \param which Which eigenvalues (or singular values, for directed
+ *        graphs) to use, possible values:
+ *        <code>IGRAPH_EIGEN_LM</code>: the ones with the largest magnitude,
+ *        <code>IGRAPH_EIGEN_LA</code>: the (algebraic) largest ones, or
+ *        <code>IGRAPH_EIGEN_SA</code>: the (algebraic) smallest ones.
+ *        For directed graphs, <code>IGRAPH_EIGEN_LM</code> and
+ *        <code>IGRAPH_EIGEN_LA</code> are the same, because singular
+ *        values are used for the orderinf instead of eigenvalues.
+ * \param scaled Whether to return X and Y (if scaled is non-zero), or
+ *        U and V.
+ * \param X Initialized matrix, the estimated latent positions are
+ *        stored here.
+ * \param Y Initialized matrix or a null pointer. If not a null
+ *        pointer, then the second half of the latent positions are
+ *        stored here. (For undirected graphs, this always equals X.)
+ * \param D Initialized vector or a null pointer. If not a null
+ *        pointer, then the eigenvalues (for undirected graphs) or the
+ *        singular values (for directed graphs) are stored here.
+ * \param cvec A numeric vector, its length is the number vertices in the
+ *        graph. This vector is added to the diagonal of the adjacency
+ *        matrix, before performing the SVD.
+ * \param options Options to ARPACK. See \ref igraph_arpack_options_t
+ *        for details. Note that the function overwrites the
+ *        <code>n</code> (number of vertices), <code>nev</code> and
+ *        <code>which</code> parameters and it always starts the
+ *        calculation from a random start vector.
+ * \return Error code.
+ *
+ */
+
+int igraph_adjacency_spectral_embedding(const igraph_t *graph,
+				igraph_integer_t no,
+				const igraph_vector_t *weights,
+				igraph_eigen_which_position_t which,
+				igraph_bool_t scaled,
+				igraph_matrix_t *X,
+				igraph_matrix_t *Y,
+				igraph_vector_t *D,
+				const igraph_vector_t *cvec,
+				igraph_arpack_options_t *options) {
+
+  igraph_arpack_function_t *callback, *callback_right;
+  igraph_bool_t directed=igraph_is_directed(graph);
+
+  if (directed) {
+    callback = weights ? igraph_i_asembeddingw : igraph_i_asembedding;
+    callback_right = (weights ? igraph_i_asembeddingw_right :
+		      igraph_i_asembedding_right);
+  } else {
+    callback = weights ? igraph_i_asembeddinguw : igraph_i_asembeddingu;
+    callback_right = 0;
+  }
+
+  return igraph_i_spectral_embedding(graph, no, 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,
+                     igraph_integer_t no,
+                     const igraph_vector_t *weights,
+                     igraph_eigen_which_position_t which,
+                     igraph_neimode_t degmode,
+                     igraph_laplacian_spectral_embedding_type_t type,
+                     igraph_bool_t scaled,
+                     igraph_matrix_t *X,
+                     igraph_matrix_t *Y,
+                     igraph_vector_t *D,
+                     igraph_arpack_options_t *options) {
+
+  igraph_arpack_function_t *callback;
+  igraph_vector_t deg;
+
+  switch (type) {
+  case IGRAPH_EMBEDDING_D_A:
+    callback = weights ? igraph_i_lsembedding_daw : igraph_i_lsembedding_da;
+    break;
+  case IGRAPH_EMBEDDING_DAD:
+    callback = weights ? igraph_i_lsembedding_dadw : igraph_i_lsembedding_dad;
+    break;
+  case IGRAPH_EMBEDDING_I_DAD:
+    callback = weights ? igraph_i_lsembedding_idadw : igraph_i_lsembedding_idad;
+    break;
+  default:
+    IGRAPH_ERROR("Invalid Laplacian spectral embedding type",
+                 IGRAPH_EINVAL);
+    break;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&deg, 0);
+  igraph_strength(graph, &deg, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1,
+                  weights);
+
+  switch (type) {
+  case IGRAPH_EMBEDDING_D_A:
+    break;
+  case IGRAPH_EMBEDDING_DAD:
+  case IGRAPH_EMBEDDING_I_DAD:
+    {
+      int i, n=igraph_vector_size(&deg);
+      for (i=0; i<n; i++) {
+        VECTOR(deg)[i] = 1.0/sqrt(VECTOR(deg)[i]);
+      }
+    }
+    break;
+  default:
+    break;
+  }
+
+  IGRAPH_CHECK(igraph_i_spectral_embedding(graph, no, weights, which,
+                        scaled, X, Y, D, /*cvec=*/ &deg, /*deg2=*/ 0,
+			options, callback, 0, /*symmetric=*/ 1,
+                        /*eigen=*/ 1, /*zapsmall=*/ 1));
+
+  igraph_vector_destroy(&deg);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+int igraph_i_lse_dir(const igraph_t *graph,
+                     igraph_integer_t no,
+                     const igraph_vector_t *weights,
+                     igraph_eigen_which_position_t which,
+                     igraph_neimode_t degmode,
+                     igraph_laplacian_spectral_embedding_type_t type,
+                     igraph_bool_t scaled,
+                     igraph_matrix_t *X,
+                     igraph_matrix_t *Y,
+                     igraph_vector_t *D,
+                     igraph_arpack_options_t *options) {
+
+  igraph_arpack_function_t *callback =
+    weights ? igraph_i_lseembedding_oapw : igraph_i_lseembedding_oap;
+  igraph_arpack_function_t *callback_right =
+    weights ? igraph_i_lseembedding_oapw_right :
+    igraph_i_lseembedding_oap_right;
+  igraph_vector_t deg_in, deg_out;
+  int i, n=igraph_vcount(graph);
+
+  if (type != IGRAPH_EMBEDDING_OAP) {
+    IGRAPH_ERROR("Invalid Laplacian spectral embedding type", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&deg_in, n);
+  IGRAPH_VECTOR_INIT_FINALLY(&deg_out, n);
+  igraph_strength(graph, &deg_in, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1,
+                  weights);
+  igraph_strength(graph, &deg_out, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1,
+                  weights);
+
+  for (i=0; i<n; i++) {
+    VECTOR(deg_in)[i] = 1.0 / sqrt(VECTOR(deg_in)[i]);
+    VECTOR(deg_out)[i] = 1.0 / sqrt(VECTOR(deg_out)[i]);
+  }
+
+  IGRAPH_CHECK(igraph_i_spectral_embedding(graph, no, weights, which,
+                        scaled, X, Y, D, /*cvec=*/ &deg_in,
+			/*deg2=*/ &deg_out, options, callback,
+			callback_right, /*symmetric=*/ 0, /*eigen=*/ 0,
+                        /*zapsmall=*/ 1));
+
+  igraph_vector_destroy(&deg_in);
+  igraph_vector_destroy(&deg_out);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_laplacian_spectral_embedding
+ * Spectral embedding of the Laplacian of a graph
+ *
+ * This function essentially does the same as
+ * \ref igraph_adjacency_spectral_embedding, but works on the Laplacian
+ * of the graph, instead of the adjacncy matrix.
+ * \param graph The input graph.
+ * \param no 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.
+ * \param which Which eigenvalues (or singular values, for directed
+ *        graphs) to use, possible values:
+ *        <code>IGRAPH_EIGEN_LM</code>: the ones with the largest magnitude,
+ *        <code>IGRAPH_EIGEN_LA</code>: the (algebraic) largest ones, or
+ *        <code>IGRAPH_EIGEN_SA</code>: the (algebraic) smallest ones.
+ *        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 type The type of the Laplacian to use. Various definitions
+ *        exist for the Laplacian of a graph, and one can choose
+ *        between them with this argument. Possible values:
+ *        <code>IGRAPH_EMBEDDING_D_A</code> means D - A where D is the
+ *        degree matrix and A is the adjacency matrix;
+ *        <code>IGRAPH_EMBEDDING_DAD<code> means Di times A times Di,
+ *        where Di is the inverse of the square root of the degree matrix;
+ *        <code>IGRAPH_EMBEDDING_I_DAD</code> means I - Di A Di, where I
+ *        is the identity matrix.
+ * \param scaled Whether to return X and Y (if scaled is non-zero), or
+ *        U and V.
+ * \param X Initialized matrix, the estimated latent positions are
+ *        stored here.
+ * \param Y Initialized matrix or a null pointer. If not a null
+ *        pointer, then the second half of the latent positions are
+ *        stored here. (For undirected graphs, this always equals X.)
+ * \param D Initialized vector or a null pointer. If not a null
+ *        pointer, then the eigenvalues (for undirected graphs) or the
+ *        singular values (for directed graphs) are stored here.
+ * \param options Options to ARPACK. See \ref igraph_arpack_options_t
+ *        for details. Note that the function overwrites the
+ *        <code>n</code> (number of vertices), <code>nev</code> and
+ *        <code>which</code> parameters and it always starts the
+ *        calculation from a random start vector.
+ * \return Error code.
+ *
+ * \sa \ref igraph_adjacency_spectral_embedding to embed the adjacency
+ * matrix.
+ */
+
+int igraph_laplacian_spectral_embedding(const igraph_t *graph,
+			igraph_integer_t no,
+			const igraph_vector_t *weights,
+			igraph_eigen_which_position_t which,
+			igraph_neimode_t degmode,
+			igraph_laplacian_spectral_embedding_type_t type,
+			igraph_bool_t scaled,
+			igraph_matrix_t *X,
+			igraph_matrix_t *Y,
+			igraph_vector_t *D,
+			igraph_arpack_options_t *options) {
+
+  if (igraph_is_directed(graph)) {
+    return igraph_i_lse_dir(graph, no, weights, which, degmode, type, scaled,
+                            X, Y, D, options);
+  } else {
+    return igraph_i_lse_und(graph, no, weights, which, degmode, type, scaled,
+                            X, Y, D, options);
+  }
+}
+
+/**
+ * \function igraph_dim_select
+ * Dimensionality selection
+ *
+ * Dimensionality selection for singular values using
+ * profile likelihood.
+ *
+ * </para><para>
+ * The input of the function is a numeric vector which contains
+ * the measure of "importance" for each dimension.
+ *
+ * </para><para>
+ * For spectral embedding, these are the singular values of the adjacency
+ * matrix. The singular values are assumed to be generated from a
+ * Gaussian mixture distribution with two components that have different
+ * means and same variance. The dimensionality d is chosen to
+ * maximize the likelihood when the d largest singular values are
+ * assigned to one component of the mixture and the rest of the singular
+ * values assigned to the other component.
+ *
+ * </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
+ * to know their border.
+ *
+ * \param sv A numeric vector, the ordered singular values.
+ * \param dim The result is stored here.
+ * \return Error code.
+ *
+ * Time complexity: O(n), n is the number of values in sv.
+ *
+ * \sa \ref igraph_adjacency_spectral_embedding().
+ */
+
+int igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *dim) {
+
+  int i, n=igraph_vector_size(sv);
+  igraph_real_t x, x2, sum1=0.0, sum2=igraph_vector_sum(sv);
+  igraph_real_t sumsq1=0.0, sumsq2=0.0; /* to be set */
+  igraph_real_t oldmean1, oldmean2, mean1=0.0, mean2=sum2/n;
+  igraph_real_t varsq1=0.0, varsq2=0.0; /* to be set */
+  igraph_real_t var1, var2, sd, profile, max=IGRAPH_NEGINFINITY;
+
+  if (n==0) {
+    IGRAPH_ERROR("Need at least one singular value for dimensionality "
+		 "selection", IGRAPH_EINVAL);
+  }
+
+  if (n==1) { *dim=1; return 0; }
+
+  for (i=0; i<n; i++) {
+    x=VECTOR(*sv)[i];
+    sumsq2 += x*x;
+    varsq2 += (mean2-x) * (mean2-x);
+  }
+
+  for (i = 0; i < n-1; i++) {
+    int n1 = i+1, n2 = n-i-1, n1m1 = n1 - 1, n2m1 = n2-1;
+    x = VECTOR(*sv)[i]; x2 = x*x;
+    sum1 += x; sum2 -= x;
+    sumsq1 += x2; sumsq2 -= x2;
+    oldmean1 = mean1; oldmean2 = mean2;
+    mean1 = sum1 / n1; mean2 = sum2 / n2;
+    varsq1 += (x-oldmean1) * (x-mean1);
+    varsq2 -= (x-oldmean2) * (x-mean2);
+    var1 = i==0 ? 0 : varsq1 / n1m1;
+    var2 = i==n-2 ? 0 : varsq2 / n2m1;
+    sd = sqrt(( n1m1 * var1 + n2m1 * var2) / (n-2));
+    profile = /* - n * log(2.0*M_PI)/2.0 */ /* This is redundant */
+      - n * log(sd) -
+      ((sumsq1 - 2*mean1*sum1 + n1*mean1*mean1) +
+       (sumsq2 - 2*mean2*sum2 + n2*mean2*mean2)) / 2.0 / sd / sd;
+    if (profile > max) {
+      max=profile;
+      *dim=n1;
+    }
+  }
+
+  /* Plus the last case, all elements in one group */
+  x = VECTOR(*sv)[n-1];
+  sum1 += x;
+  oldmean1 = mean1;
+  mean1 = sum1 / n;
+  sumsq1 += x * x;
+  varsq1 += (x-oldmean1) * (x-mean1);
+  var1 = varsq1 / (n-1);
+  sd=sqrt(var1);
+  profile= /* - n * log(2.0*M_PI)/2.0 */ /* This is redundant */
+    - n * log(sd) -
+    (sumsq1 - 2*mean1*sum1 + n*mean1*mean1) / 2.0 / sd / sd;
+  if (profile > max) {
+    max=profile;
+    *dim=n;
+  }
+
+  return 0;
+}
diff --git a/src/evolver_cit.c b/src/evolver_cit.c
deleted file mode 100644
index 4b30e4b..0000000
--- a/src/evolver_cit.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph R package.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-#include "igraph_revolver.h"
-#include "igraph_memory.h"
-#include "igraph_random.h"
-#include "igraph_constructors.h"
-#include "igraph_psumtree.h"
-#include "config.h"
-
-#include <math.h>
-
-/* This file contains the method for creating citation networks */
-
-int igraph_i_create_outseq(igraph_vector_t *real_outseq,
-			   igraph_integer_t nodes,
-			   const igraph_vector_t *outseq,
-			   const igraph_vector_t *outdist,
-			   igraph_integer_t m,
-			   igraph_integer_t *edges) {
-  
-  long int no_of_edges=0;
-
-  if (outseq && nodes != igraph_vector_size(outseq)) {
-    IGRAPH_ERROR("Invalid out-degree sequence length", IGRAPH_EINVAL);
-  }
-  if (!outseq && outdist && igraph_vector_size(outdist)==0) {
-    IGRAPH_ERROR("Invalid out-degree distribution length", IGRAPH_EINVAL);
-  }
-  if (!outseq && !outdist && m<0) {
-    IGRAPH_ERROR("Invalid constant out-degree", IGRAPH_EINVAL);
-  }
-
-  if (outseq) {
-    igraph_vector_clear(real_outseq);
-    igraph_vector_append(real_outseq, outseq);    
-    no_of_edges=(long int) (igraph_vector_sum(real_outseq) - 
-			    VECTOR(*real_outseq)[0]);
-  } else if (outdist) {    
-    igraph_vector_t cumsum;
-    long int i, n=igraph_vector_size(outdist);   
-    IGRAPH_VECTOR_INIT_FINALLY(&cumsum, n+1);
-    IGRAPH_CHECK(igraph_vector_resize(real_outseq, nodes));
-    VECTOR(cumsum)[0]=0;
-    for (i=0; i<n; i++) {
-      VECTOR(cumsum)[i+1] = VECTOR(cumsum)[i] + VECTOR(*outdist)[i];
-    }
-    RNG_BEGIN();
-    VECTOR(*real_outseq)[0]=0;
-    for (i=1; i<nodes; i++) {
-      long int deg;
-      igraph_vector_binsearch(&cumsum, RNG_UNIF(0, VECTOR(cumsum)[n]), &deg);
-      VECTOR(*real_outseq)[0]=deg;
-      no_of_edges += deg;
-    }
-    RNG_END();
-    igraph_vector_destroy(&cumsum);
-    IGRAPH_FINALLY_CLEAN(1);
-  } else {
-    long int i;
-    for (i=0; i<nodes; i++) {
-      VECTOR(*real_outseq)[i]=m;
-    }
-    no_of_edges=(nodes-1)*m;
-  }
-  
-  if (edges) {
-    *edges=(igraph_integer_t) no_of_edges;
-  }
-  
-  return 0;
-}
-
-int igraph_evolver_d(igraph_t *graph,
-		     igraph_integer_t nodes,
-		     igraph_vector_t *kernel,
-		     const igraph_vector_t *outseq,
-		     const igraph_vector_t *outdist,
-		     igraph_integer_t m,
-		     igraph_bool_t directed) {
-
-  igraph_vector_t real_outseq;
-  long int no_of_nodes=nodes;
-  igraph_integer_t no_of_edges;
-  igraph_vector_t edges;
-  long int kernel_size=igraph_vector_size(kernel);
-  long int edgeptr=0;
-  igraph_psumtree_t sumtree;
-  igraph_vector_t degree;
-  long int i, j;
-  
-  if (no_of_nodes<0) {
-    IGRAPH_ERROR("Invalid number of vertices", IGRAPH_EINVAL);
-  }
-  if (kernel_size==0) {
-    IGRAPH_ERROR("Zero length kernel", IGRAPH_EINVAL);
-  }
-  if (VECTOR(*kernel)[0]==0) {
-    IGRAPH_ERROR("Zero attractivity for zero degree vertices no allowed", 
-		 IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
-
-  IGRAPH_VECTOR_INIT_FINALLY(&real_outseq, no_of_nodes);
-  IGRAPH_CHECK(igraph_i_create_outseq(&real_outseq, nodes, outseq, 
-				      outdist, m, &no_of_edges));
-  
-  IGRAPH_CHECK(igraph_vector_resize(&edges, no_of_edges*2));
-  IGRAPH_CHECK(igraph_psumtree_init(&sumtree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_psumtree_destroy, &sumtree);
-  IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);
-  
-  RNG_BEGIN();
-  
-  /* first node */
-  igraph_psumtree_update(&sumtree, 0, VECTOR(*kernel)[0]);
-  
-  for (i=1; i<no_of_nodes; i++) {
-    igraph_real_t sum=igraph_psumtree_sum(&sumtree);
-    long int no_of_neighbors=(long int) VECTOR(real_outseq)[i];
-    long int edgeptr_save;
-    long int to;
-    
-    /* Add edges */
-    edgeptr_save=edgeptr;
-    for (j=0; j<no_of_neighbors; j++) {
-      igraph_psumtree_search(&sumtree, &to, RNG_UNIF(0, sum));
-      VECTOR(degree)[to] += 1;
-      VECTOR(edges)[edgeptr++] = i;
-      VECTOR(edges)[edgeptr++] = to;
-    }     
- 
-    /* Update probabilities */
-    for (j=0; j<no_of_neighbors; j++) {
-      long int to=(long int) VECTOR(edges)[edgeptr_save+j*2+1];
-      long int deg=(long int) VECTOR(degree)[to];
-      long int a= deg < kernel_size ? (long int) VECTOR(*kernel)[deg] : 
-	(long int) VECTOR(*kernel)[kernel_size-1];
-      igraph_psumtree_update(&sumtree, to, a);
-    }
-			     
-    /* New vertex */
-    igraph_psumtree_update(&sumtree, i, VECTOR(*kernel)[0]);
-  }
-  
-  RNG_END();
-  
-  igraph_vector_destroy(&degree);
-  igraph_psumtree_destroy(&sumtree);
-  igraph_vector_destroy(&real_outseq);
-  IGRAPH_FINALLY_CLEAN(3);
-  
-  IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));
-  igraph_vector_destroy(&edges);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
diff --git a/src/f2c.h b/src/f2c.h
deleted file mode 100644
index 5f367fd..0000000
--- a/src/f2c.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/* f2c.h  --  Standard Fortran to C header file */
-
-/**  barf  [ba:rf]  2.  "He suggested using FORTRAN, and everybody barfed."
-
-	- From The Shogakukan DICTIONARY OF NEW ENGLISH (Second edition) */
-
-#ifndef F2C_INCLUDE
-#define F2C_INCLUDE
-
-#include "igraph_blas_internal.h"
-#include "igraph_lapack_internal.h"
-#include "igraph_arpack_internal.h"
-
-typedef int integer;
-typedef unsigned int uinteger;
-typedef char *address;
-typedef short int shortint;
-typedef float real;
-typedef double doublereal;
-typedef struct { real r, i; } f2c_complex;
-typedef struct { doublereal r, i; } doublecomplex;
-typedef int logical;
-typedef short int shortlogical;
-typedef char logical1;
-typedef char integer1;
-#ifdef INTEGER_STAR_8	/* Adjust for integer*8. */
-typedef long longint;		/* system-dependent */
-typedef unsigned long ulongint;	/* system-dependent */
-#define qbit_clear(a,b)	((a) & ~((ulongint)1 << (b)))
-#define qbit_set(a,b)	((a) |  ((ulongint)1 << (b)))
-#endif
-
-#define TRUE_ (1)
-#define FALSE_ (0)
-
-/* Extern is for use with -E */
-#ifndef Extern
-#define Extern extern
-#endif
-
-/* I/O stuff */
-
-#ifdef f2c_i2
-/* for -i2 */
-typedef short flag;
-typedef short ftnlen;
-typedef short ftnint;
-#else
-typedef int flag;
-typedef int ftnlen;
-typedef int ftnint;
-#endif
-
-/*external read, write*/
-typedef struct
-{	flag cierr;
-	ftnint ciunit;
-	flag ciend;
-	char *cifmt;
-	ftnint cirec;
-} cilist;
-
-/*internal read, write*/
-typedef struct
-{	flag icierr;
-	char *iciunit;
-	flag iciend;
-	char *icifmt;
-	ftnint icirlen;
-	ftnint icirnum;
-} icilist;
-
-/*open*/
-typedef struct
-{	flag oerr;
-	ftnint ounit;
-	char *ofnm;
-	ftnlen ofnmlen;
-	char *osta;
-	char *oacc;
-	char *ofm;
-	ftnint orl;
-	char *oblnk;
-} olist;
-
-/*close*/
-typedef struct
-{	flag cerr;
-	ftnint cunit;
-	char *csta;
-} cllist;
-
-/*rewind, backspace, endfile*/
-typedef struct
-{	flag aerr;
-	ftnint aunit;
-} alist;
-
-/* inquire */
-typedef struct
-{	flag inerr;
-	ftnint inunit;
-	char *infile;
-	ftnlen infilen;
-	ftnint	*inex;	/*parameters in standard's order*/
-	ftnint	*inopen;
-	ftnint	*innum;
-	ftnint	*innamed;
-	char	*inname;
-	ftnlen	innamlen;
-	char	*inacc;
-	ftnlen	inacclen;
-	char	*inseq;
-	ftnlen	inseqlen;
-	char 	*indir;
-	ftnlen	indirlen;
-	char	*infmt;
-	ftnlen	infmtlen;
-	char	*inform;
-	ftnint	informlen;
-	char	*inunf;
-	ftnlen	inunflen;
-	ftnint	*inrecl;
-	ftnint	*innrec;
-	char	*inblank;
-	ftnlen	inblanklen;
-} inlist;
-
-#define VOID void
-
-union Multitype {	/* for multiple entry points */
-	integer1 g;
-	shortint h;
-	integer i;
-	/* longint j; */
-	real r;
-	doublereal d;
-	f2c_complex c;
-	doublecomplex z;
-	};
-
-typedef union Multitype Multitype;
-
-/*typedef long int Long;*/	/* No longer used; formerly in Namelist */
-
-struct Vardesc {	/* for Namelist */
-	char *name;
-	char *addr;
-	ftnlen *dims;
-	int  type;
-	};
-typedef struct Vardesc Vardesc;
-
-struct Namelist {
-	char *name;
-	Vardesc **vars;
-	int nvars;
-	};
-typedef struct Namelist Namelist;
-
-#define abs(x) ((x) >= 0 ? (x) : -(x))
-#define dabs(x) (doublereal)abs(x)
-#define min(a,b) ((a) <= (b) ? (a) : (b))
-#define max(a,b) ((a) >= (b) ? (a) : (b))
-#define dmin(a,b) (doublereal)min(a,b)
-#define dmax(a,b) (doublereal)max(a,b)
-#define bit_test(a,b)	((a) >> (b) & 1)
-#define bit_clear(a,b)	((a) & ~((uinteger)1 << (b)))
-#define bit_set(a,b)	((a) |  ((uinteger)1 << (b)))
-
-/* procedure parameter types for -A and -C++ */
-
-#define F2C_proc_par_types 1
-#ifdef __cplusplus
-typedef int /* Unknown procedure type */ (*U_fp)(...);
-typedef shortint (*J_fp)(...);
-typedef integer (*I_fp)(...);
-typedef real (*R_fp)(...);
-typedef doublereal (*D_fp)(...), (*E_fp)(...);
-typedef /* Complex */ VOID (*C_fp)(...);
-typedef /* Double Complex */ VOID (*Z_fp)(...);
-typedef logical (*L_fp)(...);
-typedef shortlogical (*K_fp)(...);
-typedef /* Character */ VOID (*H_fp)(...);
-typedef /* Subroutine */ int (*S_fp)(...);
-#else
-typedef int /* Unknown procedure type */ (*U_fp)();
-typedef shortint (*J_fp)();
-typedef integer (*I_fp)();
-typedef real (*R_fp)();
-typedef doublereal (*D_fp)(), (*E_fp)();
-typedef /* Complex */ VOID (*C_fp)();
-typedef /* Double Complex */ VOID (*Z_fp)();
-typedef logical (*L_fp)();
-typedef shortlogical (*K_fp)();
-typedef /* Character */ VOID (*H_fp)();
-typedef /* Subroutine */ int (*S_fp)();
-#endif
-/* E_fp is for real functions when -R is not specified */
-typedef VOID C_f;	/* complex function */
-typedef VOID H_f;	/* character function */
-typedef VOID Z_f;	/* double complex function */
-typedef doublereal E_f;	/* real function with -R not specified */
-
-/* undef any lower-case symbols that your C compiler predefines, e.g.: */
-
-#ifndef Skip_f2c_Undefs
-#undef cray
-#undef gcos
-#undef mc68010
-#undef mc68020
-#undef mips
-#undef pdp11
-#undef sgi
-#undef sparc
-#undef sun
-#undef sun2
-#undef sun3
-#undef sun4
-#undef u370
-#undef u3b
-#undef u3b2
-#undef u3b5
-#undef unix
-#undef vax
-#endif
-
-#include "config.h"
-
-#endif
diff --git a/src/f2c_dummy.c b/src/f2c_dummy.c
deleted file mode 100644
index 438ddb2..0000000
--- a/src/f2c_dummy.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-int MAIN__(void) { return 0; }
-
diff --git a/src/flow.c b/src/flow.c
index a266aa7..e506ddd 100644
--- a/src/flow.c
+++ b/src/flow.c
@@ -1277,7 +1277,7 @@ int igraph_i_mincut_undirected(const igraph_t *graph,
     igraph_real_t acut;
     long int a, n;
 
-    igraph_vector_t *edges, *edges2;
+    igraph_vector_int_t *edges, *edges2;
     igraph_vector_int_t *neis, *neis2;
    
     do {
@@ -1286,7 +1286,7 @@ int igraph_i_mincut_undirected(const igraph_t *graph,
       /* update the weights of the active vertices connected to a */
       edges=igraph_inclist_get(&inclist, a);
       neis=igraph_adjlist_get(&adjlist, a);
-      n=igraph_vector_size(edges);
+      n=igraph_vector_int_size(edges);
       for (i=0; i<n; i++) {
 	igraph_integer_t edge=(igraph_integer_t) VECTOR(*edges)[i];
 	igraph_integer_t to=(igraph_integer_t) VECTOR(*neis)[i];
@@ -1321,13 +1321,13 @@ int igraph_i_mincut_undirected(const igraph_t *graph,
        last deactivated vertex */
     edges=igraph_inclist_get(&inclist, a);
     neis=igraph_adjlist_get(&adjlist, a);
-    n=igraph_vector_size(edges);
+    n=igraph_vector_int_size(edges);
     for (i=0; i<n; ) {
       if (VECTOR(*neis)[i]==last) {
 	VECTOR(*neis)[i] = VECTOR(*neis)[n-1];
 	VECTOR(*edges)[i] = VECTOR(*edges)[n-1];
 	igraph_vector_int_pop_back(neis);
-	igraph_vector_pop_back(edges);
+	igraph_vector_int_pop_back(edges);
 	n--;
       } else {
 	i++;
@@ -1336,13 +1336,13 @@ int igraph_i_mincut_undirected(const igraph_t *graph,
     
     edges=igraph_inclist_get(&inclist, last);
     neis=igraph_adjlist_get(&adjlist, last);
-    n=igraph_vector_size(edges);
+    n=igraph_vector_int_size(edges);
     for (i=0; i<n; ) {
       if (VECTOR(*neis)[i] == a) {
 	VECTOR(*neis)[i] = VECTOR(*neis)[n-1];
 	VECTOR(*edges)[i] = VECTOR(*edges)[n-1];
 	igraph_vector_int_pop_back(neis);
-	igraph_vector_pop_back(edges);
+	igraph_vector_int_pop_back(edges);
 	n--;
       } else {
 	i++;
@@ -1369,9 +1369,9 @@ int igraph_i_mincut_undirected(const igraph_t *graph,
     neis=igraph_adjlist_get(&adjlist, a);
     edges2=igraph_inclist_get(&inclist, last);
     neis2=igraph_adjlist_get(&adjlist, last);
-    IGRAPH_CHECK(igraph_vector_append(edges, edges2));
+    IGRAPH_CHECK(igraph_vector_int_append(edges, edges2));
     IGRAPH_CHECK(igraph_vector_int_append(neis, neis2));
-    igraph_vector_clear(edges2); /* TODO: free it */
+    igraph_vector_int_clear(edges2); /* TODO: free it */
     igraph_vector_int_clear(neis2);	 /* TODO: free it */
 
     /* Remove the deleted vertex from the heap entirely */
diff --git a/src/foreign-dl-lexer.c b/src/foreign-dl-lexer.c
index 6b13563..b9ec6f0 100644
--- a/src/foreign-dl-lexer.c
+++ b/src/foreign-dl-lexer.c
@@ -537,7 +537,7 @@ static yyconst flex_int16_t yy_chk[318] =
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "igraph/src/foreign-dl-lexer.l"
+#line 1 "src/foreign-dl-lexer.l"
 /* 
    IGraph library.
    Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
@@ -559,7 +559,7 @@ static yyconst flex_int16_t yy_chk[318] =
    02110-1301 USA
 
 */
-#line 24 "igraph/src/foreign-dl-lexer.l"
+#line 24 "src/foreign-dl-lexer.l"
 
 /* 
    IGraph library.
@@ -849,7 +849,7 @@ YY_DECL
 	register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 84 "igraph/src/foreign-dl-lexer.l"
+#line 84 "src/foreign-dl-lexer.l"
 
 
 #line 856 "lex.yy.c"
@@ -942,28 +942,28 @@ do_action:	/* This label is used only to access EOF actions. */
 case 1:
 /* rule 1 can match eol */
 YY_RULE_SETUP
-#line 86 "igraph/src/foreign-dl-lexer.l"
+#line 86 "src/foreign-dl-lexer.l"
 { return NEWLINE; }
 	YY_BREAK
 case 2:
 YY_RULE_SETUP
-#line 88 "igraph/src/foreign-dl-lexer.l"
+#line 88 "src/foreign-dl-lexer.l"
 { return DL; }
 	YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 89 "igraph/src/foreign-dl-lexer.l"
+#line 89 "src/foreign-dl-lexer.l"
 {
   return NEQ; }
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 91 "igraph/src/foreign-dl-lexer.l"
+#line 91 "src/foreign-dl-lexer.l"
 { return NUM; }
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 93 "igraph/src/foreign-dl-lexer.l"
+#line 93 "src/foreign-dl-lexer.l"
 { 
   switch (yyextra->mode) { 
   case 0: BEGIN(FULLMATRIX); 
@@ -977,91 +977,91 @@ YY_RULE_SETUP
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 104 "igraph/src/foreign-dl-lexer.l"
+#line 104 "src/foreign-dl-lexer.l"
 { BEGIN(LABELM); return LABELS; }
 	YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 105 "igraph/src/foreign-dl-lexer.l"
+#line 105 "src/foreign-dl-lexer.l"
 {
   return LABELSEMBEDDED; }
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 107 "igraph/src/foreign-dl-lexer.l"
+#line 107 "src/foreign-dl-lexer.l"
 {
   yyextra->mode=0; return FORMATFULLMATRIX; }
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 109 "igraph/src/foreign-dl-lexer.l"
+#line 109 "src/foreign-dl-lexer.l"
 {
   yyextra->mode=1; return FORMATEDGELIST1; }
 	YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 111 "igraph/src/foreign-dl-lexer.l"
+#line 111 "src/foreign-dl-lexer.l"
 {
   yyextra->mode=2; return FORMATNODELIST1; }
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 114 "igraph/src/foreign-dl-lexer.l"
+#line 114 "src/foreign-dl-lexer.l"
 { /* eaten up */ }
 	YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 115 "igraph/src/foreign-dl-lexer.l"
+#line 115 "src/foreign-dl-lexer.l"
 { return LABEL; }
 	YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 117 "igraph/src/foreign-dl-lexer.l"
+#line 117 "src/foreign-dl-lexer.l"
 { return DIGIT; }
 	YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 118 "igraph/src/foreign-dl-lexer.l"
+#line 118 "src/foreign-dl-lexer.l"
 { return LABEL; }
 	YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 119 "igraph/src/foreign-dl-lexer.l"
+#line 119 "src/foreign-dl-lexer.l"
 { }
 	YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 121 "igraph/src/foreign-dl-lexer.l"
+#line 121 "src/foreign-dl-lexer.l"
 { return NUM; }
 	YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 122 "igraph/src/foreign-dl-lexer.l"
+#line 122 "src/foreign-dl-lexer.l"
 { return LABEL; }
 	YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 123 "igraph/src/foreign-dl-lexer.l"
+#line 123 "src/foreign-dl-lexer.l"
 { }
 	YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 125 "igraph/src/foreign-dl-lexer.l"
+#line 125 "src/foreign-dl-lexer.l"
 { return NUM; }
 	YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 126 "igraph/src/foreign-dl-lexer.l"
+#line 126 "src/foreign-dl-lexer.l"
 { return LABEL; }
 	YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 127 "igraph/src/foreign-dl-lexer.l"
+#line 127 "src/foreign-dl-lexer.l"
 { }
 	YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 129 "igraph/src/foreign-dl-lexer.l"
+#line 129 "src/foreign-dl-lexer.l"
 { /* eaten up */ }
 	YY_BREAK
 case YY_STATE_EOF(INITIAL):
@@ -1069,7 +1069,7 @@ case YY_STATE_EOF(LABELM):
 case YY_STATE_EOF(FULLMATRIX):
 case YY_STATE_EOF(EDGELIST):
 case YY_STATE_EOF(NODELIST):
-#line 131 "igraph/src/foreign-dl-lexer.l"
+#line 131 "src/foreign-dl-lexer.l"
 { 
                           if (yyextra->eof) {
 			    yyterminate();
@@ -1082,12 +1082,12 @@ case YY_STATE_EOF(NODELIST):
 	YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 141 "igraph/src/foreign-dl-lexer.l"
+#line 141 "src/foreign-dl-lexer.l"
 { return 0; }
 	YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 143 "igraph/src/foreign-dl-lexer.l"
+#line 143 "src/foreign-dl-lexer.l"
 ECHO;
 	YY_BREAK
 #line 1094 "lex.yy.c"
@@ -2228,4 +2228,4 @@ void igraph_dl_yyfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 143 "igraph/src/foreign-dl-lexer.l"
+#line 143 "src/foreign-dl-lexer.l"
diff --git a/src/foreign-dl-parser.c b/src/foreign-dl-parser.c
index 8164b87..6078cb7 100644
--- a/src/foreign-dl-parser.c
+++ b/src/foreign-dl-parser.c
@@ -108,7 +108,7 @@
 
 
 /* Copy the first part of user declarations.  */
-#line 23 "igraph/src/foreign-dl-parser.y"
+#line 23 "src/foreign-dl-parser.y"
 
 
 /* 
@@ -188,7 +188,7 @@ extern igraph_real_t igraph_pajek_get_number(const char *str, long int len);
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 91 "igraph/src/foreign-dl-parser.y"
+#line 91 "src/foreign-dl-parser.y"
 {
   long int integer;
   igraph_real_t real;
@@ -1554,57 +1554,57 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 115 "igraph/src/foreign-dl-parser.y"
+#line 115 "src/foreign-dl-parser.y"
     { context->n=(yyvsp[(3) - (7)].integer); ;}
     break;
 
   case 7:
-#line 121 "igraph/src/foreign-dl-parser.y"
+#line 121 "src/foreign-dl-parser.y"
     { context->type=IGRAPH_DL_MATRIX; ;}
     break;
 
   case 8:
-#line 122 "igraph/src/foreign-dl-parser.y"
+#line 122 "src/foreign-dl-parser.y"
     { context->type=IGRAPH_DL_EDGELIST1; ;}
     break;
 
   case 9:
-#line 123 "igraph/src/foreign-dl-parser.y"
+#line 123 "src/foreign-dl-parser.y"
     { context->type=IGRAPH_DL_NODELIST1; ;}
     break;
 
   case 10:
-#line 126 "igraph/src/foreign-dl-parser.y"
+#line 126 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 11:
-#line 126 "igraph/src/foreign-dl-parser.y"
+#line 126 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 14:
-#line 130 "igraph/src/foreign-dl-parser.y"
+#line 130 "src/foreign-dl-parser.y"
     { ;}
     break;
 
   case 15:
-#line 131 "igraph/src/foreign-dl-parser.y"
+#line 131 "src/foreign-dl-parser.y"
     { ;}
     break;
 
   case 16:
-#line 132 "igraph/src/foreign-dl-parser.y"
+#line 132 "src/foreign-dl-parser.y"
     { ;}
     break;
 
   case 17:
-#line 135 "igraph/src/foreign-dl-parser.y"
+#line 135 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 18:
-#line 136 "igraph/src/foreign-dl-parser.y"
+#line 136 "src/foreign-dl-parser.y"
     { 
 	      igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), 
                                   igraph_dl_yyget_leng(scanner), 
@@ -1612,12 +1612,12 @@ yyreduce:
     break;
 
   case 19:
-#line 142 "igraph/src/foreign-dl-parser.y"
+#line 142 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 20:
-#line 142 "igraph/src/foreign-dl-parser.y"
+#line 142 "src/foreign-dl-parser.y"
     {
   context->from += 1;
   context->to = 0;
@@ -1625,12 +1625,12 @@ yyreduce:
     break;
 
   case 22:
-#line 147 "igraph/src/foreign-dl-parser.y"
+#line 147 "src/foreign-dl-parser.y"
     { ;}
     break;
 
   case 23:
-#line 149 "igraph/src/foreign-dl-parser.y"
+#line 149 "src/foreign-dl-parser.y"
     {
   if (igraph_dl_yyget_text(scanner)[0]=='1') {
     IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
@@ -1643,24 +1643,24 @@ yyreduce:
     break;
 
   case 24:
-#line 159 "igraph/src/foreign-dl-parser.y"
+#line 159 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 25:
-#line 161 "igraph/src/foreign-dl-parser.y"
+#line 161 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 28:
-#line 165 "igraph/src/foreign-dl-parser.y"
+#line 165 "src/foreign-dl-parser.y"
     { igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), 
                                    igraph_dl_yyget_leng(scanner), 
 				   context); ;}
     break;
 
   case 29:
-#line 169 "igraph/src/foreign-dl-parser.y"
+#line 169 "src/foreign-dl-parser.y"
     {
 	         context->from += 1; 
 		 context->to = 0;
@@ -1668,7 +1668,7 @@ yyreduce:
     break;
 
   case 30:
-#line 173 "igraph/src/foreign-dl-parser.y"
+#line 173 "src/foreign-dl-parser.y"
     { 
 	         context->from += 1; 
 		 context->to = 0;
@@ -1676,100 +1676,100 @@ yyreduce:
     break;
 
   case 31:
-#line 178 "igraph/src/foreign-dl-parser.y"
+#line 178 "src/foreign-dl-parser.y"
     { ;}
     break;
 
   case 32:
-#line 182 "igraph/src/foreign-dl-parser.y"
+#line 182 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 33:
-#line 184 "igraph/src/foreign-dl-parser.y"
+#line 184 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 34:
-#line 185 "igraph/src/foreign-dl-parser.y"
+#line 185 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 35:
-#line 186 "igraph/src/foreign-dl-parser.y"
+#line 186 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 36:
-#line 187 "igraph/src/foreign-dl-parser.y"
+#line 187 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 37:
-#line 188 "igraph/src/foreign-dl-parser.y"
+#line 188 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 38:
-#line 191 "igraph/src/foreign-dl-parser.y"
+#line 191 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 39:
-#line 192 "igraph/src/foreign-dl-parser.y"
+#line 192 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 40:
-#line 195 "igraph/src/foreign-dl-parser.y"
+#line 195 "src/foreign-dl-parser.y"
     {
                    igraph_i_dl_add_edge_w((yyvsp[(1) - (4)].integer)-1, (yyvsp[(2) - (4)].integer)-1, (yyvsp[(3) - (4)].real), context); ;}
     break;
 
   case 41:
-#line 197 "igraph/src/foreign-dl-parser.y"
+#line 197 "src/foreign-dl-parser.y"
     {
 		   igraph_i_dl_add_edge((yyvsp[(1) - (3)].integer)-1, (yyvsp[(2) - (3)].integer)-1, context);
 ;}
     break;
 
   case 42:
-#line 201 "igraph/src/foreign-dl-parser.y"
+#line 201 "src/foreign-dl-parser.y"
     { (yyval.integer)=igraph_pajek_get_number(igraph_dl_yyget_text(scanner), 
 					  igraph_dl_yyget_leng(scanner)); ;}
     break;
 
   case 43:
-#line 204 "igraph/src/foreign-dl-parser.y"
+#line 204 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 44:
-#line 205 "igraph/src/foreign-dl-parser.y"
+#line 205 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 45:
-#line 208 "igraph/src/foreign-dl-parser.y"
+#line 208 "src/foreign-dl-parser.y"
     {
                           igraph_i_dl_add_edge_w((yyvsp[(1) - (4)].integer), (yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].real), context); ;}
     break;
 
   case 46:
-#line 210 "igraph/src/foreign-dl-parser.y"
+#line 210 "src/foreign-dl-parser.y"
     {
 			  igraph_i_dl_add_edge((yyvsp[(1) - (3)].integer), (yyvsp[(2) - (3)].integer), context);
  ;}
     break;
 
   case 47:
-#line 214 "igraph/src/foreign-dl-parser.y"
+#line 214 "src/foreign-dl-parser.y"
     { (yyval.real)=igraph_pajek_get_number(igraph_dl_yyget_text(scanner), 
 					 igraph_dl_yyget_leng(scanner)); ;}
     break;
 
   case 48:
-#line 217 "igraph/src/foreign-dl-parser.y"
+#line 217 "src/foreign-dl-parser.y"
     {
   /* Copy label list to trie, if needed */
   if (igraph_strvector_size(&context->labels) != 0) {
@@ -1786,63 +1786,63 @@ yyreduce:
     break;
 
   case 49:
-#line 233 "igraph/src/foreign-dl-parser.y"
+#line 233 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 50:
-#line 235 "igraph/src/foreign-dl-parser.y"
+#line 235 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 51:
-#line 236 "igraph/src/foreign-dl-parser.y"
+#line 236 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 52:
-#line 237 "igraph/src/foreign-dl-parser.y"
+#line 237 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 53:
-#line 238 "igraph/src/foreign-dl-parser.y"
+#line 238 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 54:
-#line 239 "igraph/src/foreign-dl-parser.y"
+#line 239 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 55:
-#line 242 "igraph/src/foreign-dl-parser.y"
+#line 242 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 56:
-#line 243 "igraph/src/foreign-dl-parser.y"
+#line 243 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 57:
-#line 246 "igraph/src/foreign-dl-parser.y"
+#line 246 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 58:
-#line 248 "igraph/src/foreign-dl-parser.y"
+#line 248 "src/foreign-dl-parser.y"
     { context->from=igraph_pajek_get_number(igraph_dl_yyget_text(scanner),
 							  igraph_dl_yyget_leng(scanner)); ;}
     break;
 
   case 59:
-#line 251 "igraph/src/foreign-dl-parser.y"
+#line 251 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 60:
-#line 251 "igraph/src/foreign-dl-parser.y"
+#line 251 "src/foreign-dl-parser.y"
     { 
   IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
 				       context->from-1)); 
@@ -1851,29 +1851,29 @@ yyreduce:
     break;
 
   case 61:
-#line 257 "igraph/src/foreign-dl-parser.y"
+#line 257 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 62:
-#line 258 "igraph/src/foreign-dl-parser.y"
+#line 258 "src/foreign-dl-parser.y"
     {;}
     break;
 
   case 63:
-#line 261 "igraph/src/foreign-dl-parser.y"
+#line 261 "src/foreign-dl-parser.y"
     { ;}
     break;
 
   case 64:
-#line 263 "igraph/src/foreign-dl-parser.y"
+#line 263 "src/foreign-dl-parser.y"
     {
   context->from=(yyvsp[(1) - (1)].integer);
  ;}
     break;
 
   case 66:
-#line 267 "igraph/src/foreign-dl-parser.y"
+#line 267 "src/foreign-dl-parser.y"
     {
   IGRAPH_CHECK(igraph_vector_push_back(&context->edges, 
 				       context->from));
@@ -2103,7 +2103,7 @@ yyreturn:
 }
 
 
-#line 273 "igraph/src/foreign-dl-parser.y"
+#line 273 "src/foreign-dl-parser.y"
 
 
 int igraph_dl_yyerror(YYLTYPE* locp, igraph_i_dl_parsedata_t* context, 
diff --git a/src/foreign-dl-parser.h b/src/foreign-dl-parser.h
index 90ef312..329ad31 100644
--- a/src/foreign-dl-parser.h
+++ b/src/foreign-dl-parser.h
@@ -74,7 +74,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 91 "igraph/src/foreign-dl-parser.y"
+#line 91 "src/foreign-dl-parser.y"
 {
   long int integer;
   igraph_real_t real;
diff --git a/src/foreign-gml-lexer.c b/src/foreign-gml-lexer.c
index 43624ef..d8ea53f 100644
--- a/src/foreign-gml-lexer.c
+++ b/src/foreign-gml-lexer.c
@@ -447,7 +447,7 @@ static yyconst flex_int16_t yy_chk[58] =
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "igraph/src/foreign-gml-lexer.l"
+#line 1 "src/foreign-gml-lexer.l"
 /* 
    IGraph library.
    Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
@@ -469,7 +469,7 @@ static yyconst flex_int16_t yy_chk[58] =
    02110-1301 USA
 
 */
-#line 24 "igraph/src/foreign-gml-lexer.l"
+#line 24 "src/foreign-gml-lexer.l"
 
 /* 
    IGraph library.
@@ -756,7 +756,7 @@ YY_DECL
 	register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 81 "igraph/src/foreign-gml-lexer.l"
+#line 81 "src/foreign-gml-lexer.l"
 
 
 #line 763 "lex.yy.c"
@@ -850,49 +850,49 @@ do_action:	/* This label is used only to access EOF actions. */
 case 1:
 /* rule 1 can match eol */
 YY_RULE_SETUP
-#line 83 "igraph/src/foreign-gml-lexer.l"
+#line 83 "src/foreign-gml-lexer.l"
 { /* comments ignored */ }
 	YY_BREAK
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 85 "igraph/src/foreign-gml-lexer.l"
+#line 85 "src/foreign-gml-lexer.l"
 { return STRING; }
 	YY_BREAK
 case 3:
 YY_RULE_SETUP
-#line 86 "igraph/src/foreign-gml-lexer.l"
+#line 86 "src/foreign-gml-lexer.l"
 { return NUM; }
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 87 "igraph/src/foreign-gml-lexer.l"
+#line 87 "src/foreign-gml-lexer.l"
 { return KEYWORD; }
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 88 "igraph/src/foreign-gml-lexer.l"
+#line 88 "src/foreign-gml-lexer.l"
 { return LISTOPEN; }
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 89 "igraph/src/foreign-gml-lexer.l"
+#line 89 "src/foreign-gml-lexer.l"
 { return LISTCLOSE; }
 	YY_BREAK
 case 7:
 /* rule 7 can match eol */
 YY_RULE_SETUP
-#line 90 "igraph/src/foreign-gml-lexer.l"
+#line 90 "src/foreign-gml-lexer.l"
 { }
 	YY_BREAK
 case 8:
 /* rule 8 can match eol */
 YY_RULE_SETUP
-#line 91 "igraph/src/foreign-gml-lexer.l"
+#line 91 "src/foreign-gml-lexer.l"
 { /* other whitespace ignored */ }
 	YY_BREAK
 case YY_STATE_EOF(INITIAL):
-#line 93 "igraph/src/foreign-gml-lexer.l"
+#line 93 "src/foreign-gml-lexer.l"
 { 
                           if (yyextra->eof) {
 			    yyterminate();
@@ -904,7 +904,7 @@ case YY_STATE_EOF(INITIAL):
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 102 "igraph/src/foreign-gml-lexer.l"
+#line 102 "src/foreign-gml-lexer.l"
 ECHO;
 	YY_BREAK
 #line 911 "lex.yy.c"
@@ -2048,7 +2048,7 @@ void igraph_gml_yyfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 102 "igraph/src/foreign-gml-lexer.l"
+#line 102 "src/foreign-gml-lexer.l"
 
 
 
diff --git a/src/foreign-gml-parser.c b/src/foreign-gml-parser.c
index 0c6a5aa..6c63a11 100644
--- a/src/foreign-gml-parser.c
+++ b/src/foreign-gml-parser.c
@@ -94,7 +94,7 @@
 
 
 /* Copy the first part of user declarations.  */
-#line 23 "igraph/src/foreign-gml-parser.y"
+#line 23 "src/foreign-gml-parser.y"
 
 
 /* 
@@ -181,7 +181,7 @@ igraph_gml_tree_t *igraph_i_gml_merge(igraph_gml_tree_t *t1, igraph_gml_tree_t*
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 98 "igraph/src/foreign-gml-parser.y"
+#line 98 "src/foreign-gml-parser.y"
 {
    struct {
       char *s;
@@ -1118,27 +1118,27 @@ yydestruct (yymsg, yytype, yyvaluep, yylocationp, context)
   switch (yytype)
     {
       case 5: /* "KEYWORD" */
-#line 120 "igraph/src/foreign-gml-parser.y"
+#line 120 "src/foreign-gml-parser.y"
 	{ igraph_Free((yyvaluep->str).s); };
 #line 1124 "y.tab.c"
 	break;
       case 11: /* "list" */
-#line 121 "igraph/src/foreign-gml-parser.y"
+#line 121 "src/foreign-gml-parser.y"
 	{ igraph_gml_tree_destroy((yyvaluep->tree)); };
 #line 1129 "y.tab.c"
 	break;
       case 12: /* "keyvalue" */
-#line 121 "igraph/src/foreign-gml-parser.y"
+#line 121 "src/foreign-gml-parser.y"
 	{ igraph_gml_tree_destroy((yyvaluep->tree)); };
 #line 1134 "y.tab.c"
 	break;
       case 13: /* "key" */
-#line 120 "igraph/src/foreign-gml-parser.y"
+#line 120 "src/foreign-gml-parser.y"
 	{ igraph_Free((yyvaluep->str).s); };
 #line 1139 "y.tab.c"
 	break;
       case 15: /* "string" */
-#line 120 "igraph/src/foreign-gml-parser.y"
+#line 120 "src/foreign-gml-parser.y"
 	{ igraph_Free((yyvaluep->str).s); };
 #line 1144 "y.tab.c"
 	break;
@@ -1463,60 +1463,60 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 125 "igraph/src/foreign-gml-parser.y"
+#line 125 "src/foreign-gml-parser.y"
     { context->tree=(yyvsp[(1) - (1)].tree); ;}
     break;
 
   case 3:
-#line 126 "igraph/src/foreign-gml-parser.y"
+#line 126 "src/foreign-gml-parser.y"
     { context->tree=(yyvsp[(1) - (2)].tree); ;}
     break;
 
   case 4:
-#line 129 "igraph/src/foreign-gml-parser.y"
+#line 129 "src/foreign-gml-parser.y"
     { (yyval.tree)=(yyvsp[(1) - (1)].tree); ;}
     break;
 
   case 5:
-#line 130 "igraph/src/foreign-gml-parser.y"
+#line 130 "src/foreign-gml-parser.y"
     { (yyval.tree)=igraph_i_gml_merge((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)); ;}
     break;
 
   case 6:
-#line 133 "igraph/src/foreign-gml-parser.y"
+#line 133 "src/foreign-gml-parser.y"
     { (yyval.tree)=igraph_i_gml_make_numeric((yyvsp[(1) - (2)].str).s, (yyvsp[(1) - (2)].str).len, (yyvsp[(2) - (2)].real)); ;}
     break;
 
   case 7:
-#line 135 "igraph/src/foreign-gml-parser.y"
+#line 135 "src/foreign-gml-parser.y"
     { (yyval.tree)=igraph_i_gml_make_string((yyvsp[(1) - (2)].str).s, (yyvsp[(1) - (2)].str).len, (yyvsp[(2) - (2)].str).s, (yyvsp[(2) - (2)].str).len); ;}
     break;
 
   case 8:
-#line 137 "igraph/src/foreign-gml-parser.y"
+#line 137 "src/foreign-gml-parser.y"
     { (yyval.tree)=igraph_i_gml_make_list((yyvsp[(1) - (4)].str).s, (yyvsp[(1) - (4)].str).len, (yyvsp[(3) - (4)].tree)); ;}
     break;
 
   case 9:
-#line 139 "igraph/src/foreign-gml-parser.y"
+#line 139 "src/foreign-gml-parser.y"
     { (yyval.tree)=igraph_i_gml_make_numeric2((yyvsp[(1) - (2)].str).s, (yyvsp[(1) - (2)].str).len, (yyvsp[(2) - (2)].str).s, (yyvsp[(2) - (2)].str).len); ;}
     break;
 
   case 10:
-#line 142 "igraph/src/foreign-gml-parser.y"
+#line 142 "src/foreign-gml-parser.y"
     { igraph_i_gml_get_keyword(igraph_gml_yyget_text(scanner), 
 					igraph_gml_yyget_leng(scanner), 
 					&(yyval.str)); USE((yyvsp[(1) - (1)].str)) ;}
     break;
 
   case 11:
-#line 145 "igraph/src/foreign-gml-parser.y"
+#line 145 "src/foreign-gml-parser.y"
     { (yyval.real)=igraph_i_gml_get_real(igraph_gml_yyget_text(scanner), 
 				     igraph_gml_yyget_leng(scanner)); ;}
     break;
 
   case 12:
-#line 148 "igraph/src/foreign-gml-parser.y"
+#line 148 "src/foreign-gml-parser.y"
     { igraph_i_gml_get_string(igraph_gml_yyget_text(scanner), 
 					 igraph_gml_yyget_leng(scanner), 
 					 &(yyval.str)); ;}
@@ -1744,7 +1744,7 @@ yyreturn:
 }
 
 
-#line 152 "igraph/src/foreign-gml-parser.y"
+#line 152 "src/foreign-gml-parser.y"
 
 
 int igraph_gml_yyerror(YYLTYPE* locp, igraph_i_gml_parsedata_t *context, 
diff --git a/src/foreign-gml-parser.h b/src/foreign-gml-parser.h
index bff0d80..f54c9a2 100644
--- a/src/foreign-gml-parser.h
+++ b/src/foreign-gml-parser.h
@@ -60,7 +60,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 98 "igraph/src/foreign-gml-parser.y"
+#line 98 "src/foreign-gml-parser.y"
 {
    struct {
       char *s;
diff --git a/src/foreign-graphml.c b/src/foreign-graphml.c
index e7ac529..84c7855 100644
--- a/src/foreign-graphml.c
+++ b/src/foreign-graphml.c
@@ -38,6 +38,7 @@
 #include <libxml/encoding.h>
 #include <libxml/parser.h>
 
+#define GRAPHML_NAMESPACE_URI "http://graphml.graphdrawing.org/xmlns"
 
 xmlEntity blankEntityStruct = {
 #ifndef XML_WITHOUT_CORBA
@@ -65,19 +66,20 @@ xmlEntity blankEntityStruct = {
 
 xmlEntityPtr blankEntity = &blankEntityStruct;
 
-#define GRAPHML_PARSE_ERROR(state, msg) do {                  \
-  if (state->successful) {                                    \
-    igraph_error(msg, __FILE__, __LINE__, IGRAPH_PARSEERROR); \
-    igraph_i_graphml_sax_handler_error(state, msg);           \
-  }                                                           \
-  return;                                                     \
-} while (1)
-
 #define GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, code) do {  \
   if (state->successful) {                                    \
     igraph_error(msg, __FILE__, __LINE__, code);              \
     igraph_i_graphml_sax_handler_error(state, msg);           \
   }                                                           \
+} while (0)
+#define GRAPHML_PARSE_ERROR(state, msg) \
+  GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, IGRAPH_PARSEERROR)
+#define RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, code) do {  \
+  GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, code);            \
+  return;                                                     \
+} while (1)
+#define RETURN_GRAPHML_PARSE_ERROR(state, msg) do {           \
+  GRAPHML_PARSE_ERROR(state, msg);                            \
   return;                                                     \
 } while (1)
 
@@ -88,6 +90,11 @@ typedef struct igraph_i_graphml_attribute_record_t {
   enum { I_GRAPHML_BOOLEAN, I_GRAPHML_INTEGER, I_GRAPHML_LONG,
 	 I_GRAPHML_FLOAT, I_GRAPHML_DOUBLE, I_GRAPHML_STRING,
 	 I_GRAPHML_UNKNOWN_TYPE } type;	/* GraphML type */
+  union {
+    igraph_real_t as_numeric;
+    igraph_bool_t as_boolean;
+    char* as_string;
+  } default_value;   /* Default value of the attribute, if any */
   igraph_attribute_record_t record;
 } igraph_i_graphml_attribute_record_t;
 
@@ -108,10 +115,12 @@ struct igraph_i_graphml_parser_state {
   igraph_vector_ptr_t e_attrs;
   igraph_trie_t g_names;
   igraph_vector_ptr_t g_attrs;
+  igraph_i_graphml_attribute_record_t* current_attr_record;
   xmlChar *data_key;
   igraph_attribute_elemtype_t data_type;
   char *error_message;
   char *data_char;
+  long int act_node;
 };
 
 static void igraph_i_report_unhandled_attribute_target(const char* target,
@@ -120,10 +129,24 @@ static void igraph_i_report_unhandled_attribute_target(const char* target,
       "attribute specifications", file, line, 0, target);
 }
 
-igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data) {
+igraph_real_t igraph_i_graphml_parse_numeric(const char* char_data,
+    igraph_real_t default_value) {
+  double result;
+
+  if (char_data == 0)
+    return default_value;
+
+  if (sscanf(char_data, "%lf", &result) == 0)
+    return default_value;
+
+  return result;
+}
+
+igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data,
+    igraph_bool_t default_value) {
   int value;
   if (char_data == 0)
-    return 0;
+    return default_value;
   if (!strcasecmp("true", char_data))
     return 1;
   if (!strcasecmp("yes", char_data))
@@ -133,18 +156,43 @@ igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data) {
   if (!strcasecmp("no", char_data))
     return 0;
   if (sscanf(char_data, "%d", &value) == 0)
-    return 0;
+    return default_value;
   return value != 0;
 }
 
-void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
-  long int i;
+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);
+      igraph_Free(rec->record.value);
+    }
+  } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
+    if (rec->record.value != 0) {
+      igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
+      if (rec->default_value.as_string != 0) {
+	igraph_Free(rec->default_value.as_string);
+      }
+      igraph_Free(rec->record.value);
+    }
+  } else if (rec->record.type==IGRAPH_ATTRIBUTE_BOOLEAN) {
+    if (rec->record.value != 0) {
+      igraph_vector_bool_destroy((igraph_vector_bool_t*)rec->record.value);
+      igraph_Free(rec->record.value);
+    }
+  }
+  if (rec->id != 0) {
+    igraph_Free(rec->id);
+  }
+  if (rec->record.name != 0) {
+    igraph_Free(rec->record.name);
+  }
+}
 
+void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {
   if (state->destroyed)
     return;
   state->destroyed=1;
 
-  /* this is the easy part */
   igraph_trie_destroy(&state->node_trie);
   igraph_strvector_destroy(&state->edgeids);
   igraph_trie_destroy(&state->v_names);
@@ -156,79 +204,10 @@ void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state)
   if (state->error_message) { free(state->error_message); }
   if (state->data_key) { free(state->data_key); }
   if (state->data_char) { free(state->data_char); }
-  
-  for (i=0; i<igraph_vector_ptr_size(&state->v_attrs); i++) {
-    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->v_attrs)[i];
-    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
-      if (rec->record.value != 0) {
-	igraph_vector_destroy((igraph_vector_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
-      if (rec->record.value != 0) {
-	igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    } else if (rec->record.type==IGRAPH_ATTRIBUTE_BOOLEAN) {
-      if (rec->record.value != 0) {
-	igraph_vector_bool_destroy((igraph_vector_bool_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    }
-    if (rec->id != 0) igraph_Free(rec->id);
-    if (rec->record.name != 0) igraph_Free(rec->record.name);
-    igraph_Free(rec);
-  }	 
-
-  for (i=0; i<igraph_vector_ptr_size(&state->e_attrs); i++) {
-    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->e_attrs)[i];
-    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
-      if (rec->record.value != 0) {
-	igraph_vector_destroy((igraph_vector_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
-      if (rec->record.value != 0) {
-	igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    } else if (rec->record.type==IGRAPH_ATTRIBUTE_BOOLEAN) {
-      if (rec->record.value != 0) {
-	igraph_vector_bool_destroy((igraph_vector_bool_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    }
-    if (rec->id != 0) igraph_Free(rec->id);
-    if (rec->record.name != 0) igraph_Free(rec->record.name);
-    igraph_Free(rec);
-  }
-
-  for (i=0; i<igraph_vector_ptr_size(&state->g_attrs); i++) {
-    igraph_i_graphml_attribute_record_t *rec=VECTOR(state->g_attrs)[i];
-    if (rec->record.type==IGRAPH_ATTRIBUTE_NUMERIC) {
-      if (rec->record.value != 0) {
-	igraph_vector_destroy((igraph_vector_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    } else if (rec->record.type==IGRAPH_ATTRIBUTE_STRING) {
-      if (rec->record.value != 0) {
-	igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    } else if (rec->record.type==IGRAPH_ATTRIBUTE_BOOLEAN) {
-      if (rec->record.value != 0) {
-	igraph_vector_bool_destroy((igraph_vector_bool_t*)rec->record.value);
-	igraph_Free(rec->record.value);
-      }
-    }
-    if (rec->id != 0) igraph_Free(rec->id);
-    if (rec->record.name != 0) igraph_Free(rec->record.name);
-    igraph_Free(rec);
-  }
 
-  igraph_vector_ptr_destroy(&state->v_attrs);
-  igraph_vector_ptr_destroy(&state->e_attrs);
-  igraph_vector_ptr_destroy(&state->g_attrs);
+  igraph_vector_ptr_destroy_all(&state->v_attrs);
+  igraph_vector_ptr_destroy_all(&state->e_attrs);
+  igraph_vector_ptr_destroy_all(&state->g_attrs);
   
   IGRAPH_FINALLY_CLEAN(1);
 }
@@ -285,65 +264,71 @@ void igraph_i_graphml_sax_handler_start_document(void *state0) {
 
   ret=igraph_vector_int_init(&state->prev_state_stack, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   ret=igraph_vector_int_reserve(&state->prev_state_stack, 32);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_vector_int_destroy, &state->prev_state_stack);
   
   ret=igraph_vector_ptr_init(&state->v_attrs, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
+  IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&state->v_attrs,
+      igraph_i_graphml_attribute_record_destroy);
   IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->v_attrs);
 
   ret=igraph_vector_ptr_init(&state->e_attrs, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
+  IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&state->e_attrs,
+      igraph_i_graphml_attribute_record_destroy);
   IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->e_attrs);
 
   ret=igraph_vector_ptr_init(&state->g_attrs, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
+  IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&state->g_attrs,
+      igraph_i_graphml_attribute_record_destroy);
   IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->g_attrs);
 
   ret=igraph_vector_init(&state->edgelist, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_vector_destroy, &state->edgelist);
 
   ret=igraph_trie_init(&state->node_trie, 1);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_trie_destroy, &state->node_trie);
 
   ret=igraph_strvector_init(&state->edgeids, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_strvector_destroy, &state->edgeids);
 
   ret=igraph_trie_init(&state->v_names, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_trie_destroy, &state->v_names);
 
   ret=igraph_trie_init(&state->e_names, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_trie_destroy, &state->e_names);
 
   ret=igraph_trie_init(&state->g_names, 0);
   if (ret) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
   }
   IGRAPH_FINALLY(igraph_trie_destroy, &state->g_names);
   
@@ -410,7 +395,7 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int nodes=igraph_trie_size(&state->node_trie);
 	igraph_vector_resize(vec, nodes);
 	for (l=origsize; l<nodes; l++) {
-	  VECTOR(*vec)[l]=IGRAPH_NAN;
+	  VECTOR(*vec)[l] = graphmlrec->default_value.as_numeric;
 	}
       } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
@@ -418,7 +403,7 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int nodes=igraph_trie_size(&state->node_trie);
 	igraph_strvector_resize(strvec, nodes);
 	for (l=origsize; l<nodes; l++) {
-	  igraph_strvector_set(strvec, l, "");
+	  igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string);
 	}
       } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
 	igraph_vector_bool_t *boolvec=(igraph_vector_bool_t*)rec->value;
@@ -426,7 +411,7 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int nodes=igraph_trie_size(&state->node_trie);
 	igraph_vector_bool_resize(boolvec, nodes);
 	for (l=origsize; l<nodes; l++) {
-	  VECTOR(*boolvec)[l]=0;
+	  VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean;
 	}
       }
       VECTOR(vattr)[i]=rec;
@@ -439,8 +424,6 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
       VECTOR(vattr)[i]=&idrec;
     } else {
       igraph_vector_ptr_pop_back(&vattr);
-      IGRAPH_WARNING("Could not add vertex ids, "
-		     "there is already an 'id' vertex attribute");
     }
 
     for (i=0; i<igraph_vector_ptr_size(&state->e_attrs); i++) {
@@ -458,7 +441,7 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int edges=igraph_vector_size(&state->edgelist)/2;
 	igraph_vector_resize(vec, edges);
 	for (l=origsize; l<edges; l++) {
-	  VECTOR(*vec)[l]=IGRAPH_NAN;
+	  VECTOR(*vec)[l] = graphmlrec->default_value.as_numeric;
 	}
       } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
@@ -466,7 +449,7 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int edges=igraph_vector_size(&state->edgelist)/2;
 	igraph_strvector_resize(strvec, edges);
 	for (l=origsize; l<edges; l++) {
-	  igraph_strvector_set(strvec, l, "");
+	  igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string);
 	}
       } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
 	igraph_vector_bool_t *boolvec=(igraph_vector_bool_t*)rec->value;
@@ -474,7 +457,7 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int edges=igraph_vector_size(&state->edgelist)/2;
 	igraph_vector_bool_resize(boolvec, edges);
 	for (l=origsize; l<edges; l++) {
-	  VECTOR(*boolvec)[l]=0;
+	  VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean;
 	}
       }
       VECTOR(eattr)[i]=rec;
@@ -507,21 +490,21 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 	long int origsize=igraph_vector_size(vec);
 	igraph_vector_resize(vec, 1);
 	for (l=origsize; l<1; l++) {
-	  VECTOR(*vec)[l]=IGRAPH_NAN;
+	  VECTOR(*vec)[l] = graphmlrec->default_value.as_numeric;
 	}
       } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {
 	igraph_strvector_t *strvec=(igraph_strvector_t*)rec->value;
 	long int origsize=igraph_strvector_size(strvec);
 	igraph_strvector_resize(strvec, 1);
 	for (l=origsize; l<1; l++) {
-	  igraph_strvector_set(strvec, l, "");
+	  igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string);
 	}
       } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {
 	igraph_vector_bool_t *boolvec=(igraph_vector_bool_t*)rec->value;
 	long int origsize=igraph_vector_bool_size(boolvec);
 	igraph_vector_bool_resize(boolvec, 1);
 	for (l=origsize; l<1; l++) {
-	  VECTOR(*boolvec)[l]=0;
+	  VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean;
 	}
       }
       VECTOR(gattr)[i]=rec;
@@ -544,86 +527,109 @@ void igraph_i_graphml_sax_handler_end_document(void *state0) {
 #define toXmlChar(a)   (BAD_CAST(a))
 #define fromXmlChar(a) ((char *)(a)) /* not the most elegant way... */
 
-void igraph_i_graphml_add_attribute_key(const xmlChar** attrs, 
-					struct igraph_i_graphml_parser_state *state) {
+#define XML_ATTR_LOCALNAME(it) (*(it))
+#define XML_ATTR_PREFIX(it) (*(it+1))
+#define XML_ATTR_URI(it) (*(it+2))
+#define XML_ATTR_VALUE_START(it) (*(it+3))
+#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) {
   xmlChar **it;
+  xmlChar *localname;
   igraph_trie_t *trie=0;
   igraph_vector_ptr_t *ptrvector=0;
   long int id;
   unsigned short int skip=0;
-  int ret;
+  int i, ret;
   igraph_i_graphml_attribute_record_t *rec;
 
-  if (!state->successful) return;
+  if (!state->successful)
+    return 0;
    
   rec = igraph_Calloc(1, igraph_i_graphml_attribute_record_t);
   if (rec==0) {
     GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+    return 0;
   }
   IGRAPH_FINALLY(igraph_free, rec);
 
   rec->type = I_GRAPHML_UNKNOWN_TYPE;
 
-  for (it=(xmlChar**)attrs; *it; it+=2) {
-    if (xmlStrEqual(*it, toXmlChar("id"))) {
-      const char *id=(const char*)(*(it+1));
-      rec->id=strdup(id);
-    } else if (xmlStrEqual(*it, toXmlChar("attr.name"))) {
-      const char *name=fromXmlChar(*(it+1));
-      rec->record.name=strdup(name);
-    } else if (xmlStrEqual(*it, toXmlChar("attr.type"))) {
-      if (xmlStrEqual(*(it+1), (xmlChar*)"boolean")) { 
+  for (i=0, it=(xmlChar**)attrs; i < nb_attrs; i++, it+=5) {
+    if (XML_ATTR_URI(it) != 0 &&
+	!xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it)))
+      continue;
+
+    localname = XML_ATTR_LOCALNAME(it);
+
+    if (xmlStrEqual(localname, toXmlChar("id"))) {
+      rec->id=fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));
+    } else if (xmlStrEqual(localname, toXmlChar("attr.name"))) {
+      rec->record.name=fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));
+    } else if (xmlStrEqual(localname, toXmlChar("attr.type"))) {
+      if (!xmlStrncmp(toXmlChar("boolean"), XML_ATTR_VALUE(it))) {
 	rec->type=I_GRAPHML_BOOLEAN;
-	rec->record.type=IGRAPH_ATTRIBUTE_BOOLEAN;	    
-      } else if (xmlStrEqual(*(it+1), toXmlChar("string"))) {
+	rec->record.type=IGRAPH_ATTRIBUTE_BOOLEAN;
+	rec->default_value.as_boolean=0;
+      } else if (!xmlStrncmp(toXmlChar("string"), XML_ATTR_VALUE(it))) {
 	rec->type=I_GRAPHML_STRING;
 	rec->record.type=IGRAPH_ATTRIBUTE_STRING;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("float"))) { 
+	rec->default_value.as_string=strdup("");
+      } else if (!xmlStrncmp(toXmlChar("float"), XML_ATTR_VALUE(it))) {
 	rec->type=I_GRAPHML_FLOAT;
 	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("double"))) { 
+	rec->default_value.as_numeric=IGRAPH_NAN;
+      } else if (!xmlStrncmp(toXmlChar("double"), XML_ATTR_VALUE(it))) {
 	rec->type=I_GRAPHML_DOUBLE;
 	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("int"))) {
+	rec->default_value.as_numeric=IGRAPH_NAN;
+      } else if (!xmlStrncmp(toXmlChar("int"), XML_ATTR_VALUE(it))) {
 	rec->type=I_GRAPHML_INTEGER;
 	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("long"))) {
+	rec->default_value.as_numeric=IGRAPH_NAN;
+      } else if (!xmlStrncmp(toXmlChar("long"), XML_ATTR_VALUE(it))) {
 	rec->type=I_GRAPHML_LONG;
 	rec->record.type=IGRAPH_ATTRIBUTE_NUMERIC;
+	rec->default_value.as_numeric=IGRAPH_NAN;
       } else {
         GRAPHML_PARSE_ERROR(state,
             "Cannot parse GraphML file, unknown attribute type");
+        return 0;
       }
     } else if (xmlStrEqual(*it, toXmlChar("for"))) {
       /* graph, vertex or edge attribute? */
-      if (xmlStrEqual(*(it+1), toXmlChar("graph"))) { 
+      if (!xmlStrncmp(toXmlChar("graph"), XML_ATTR_VALUE(it))) {
 	trie=&state->g_names;
 	ptrvector=&state->g_attrs;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("node"))) {
+      } else if (!xmlStrncmp(toXmlChar("node"), XML_ATTR_VALUE(it))) {
 	trie=&state->v_names;
 	ptrvector=&state->v_attrs;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("edge"))) {
+      } else if (!xmlStrncmp(toXmlChar("edge"), XML_ATTR_VALUE(it))) {
 	trie=&state->e_names;
 	ptrvector=&state->e_attrs;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("graphml"))) {
+      } else if (!xmlStrncmp(toXmlChar("graphml"), XML_ATTR_VALUE(it))) {
         igraph_i_report_unhandled_attribute_target("graphml", __FILE__, __LINE__);
         skip=1;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("hyperedge"))) {
+      } else if (!xmlStrncmp(toXmlChar("hyperedge"), XML_ATTR_VALUE(it))) {
         igraph_i_report_unhandled_attribute_target("hyperedge", __FILE__, __LINE__);
         skip=1;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("port"))) {
+      } else if (!xmlStrncmp(toXmlChar("port"), XML_ATTR_VALUE(it))) {
         igraph_i_report_unhandled_attribute_target("port", __FILE__, __LINE__);
         skip=1;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("endpoint"))) {
+      } else if (!xmlStrncmp(toXmlChar("endpoint"), XML_ATTR_VALUE(it))) {
         igraph_i_report_unhandled_attribute_target("endpoint", __FILE__, __LINE__);
         skip=1;
-      } else if (xmlStrEqual(*(it+1), toXmlChar("all"))) {
+      } else if (!xmlStrncmp(toXmlChar("all"), XML_ATTR_VALUE(it))) {
         /* TODO: we should handle this */
         igraph_i_report_unhandled_attribute_target("all", __FILE__, __LINE__);
         skip=1;
       } else {
 	GRAPHML_PARSE_ERROR(state,
             "Cannot parse GraphML file, unknown value in the 'for' attribute of a <key> tag");
+	return 0;
       }
     }
   }
@@ -632,6 +638,7 @@ void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
    * DTD */
   if (rec->id == 0) {
     GRAPHML_PARSE_ERROR(state, "Found <key> tag with no 'id' attribute");
+    return 0;
   }
 
   /* in case of a missing attr.name attribute, use the id as the attribute name */
@@ -649,6 +656,7 @@ void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
   if (!skip && trie == 0) {
     GRAPHML_PARSE_ERROR(state,
         "Cannot parse GraphML file, missing 'for' attribute in a <key> tag");
+    return 0;
   }
 	
   /* if the code above requested skipping the attribute, free everything and
@@ -656,18 +664,20 @@ void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
   if (skip) {
     igraph_free(rec);
     IGRAPH_FINALLY_CLEAN(1);
-    return;
+    return 0;
   }
 
   /* add to trie, attribues */
   igraph_trie_get(trie, rec->id, &id);
   if (id != igraph_trie_size(trie)-1) {
     GRAPHML_PARSE_ERROR(state, "Cannot parse GraphML file, duplicate attribute");
+    return 0;
   }
 
   ret=igraph_vector_ptr_push_back(ptrvector, rec);
   if (ret) {
     GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot read GraphML file", ret);
+    return 0;
   }
 
   /* Ownership of 'rec' is now taken by ptrvector so we can clean the
@@ -683,6 +693,7 @@ void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
     boolvec=igraph_Calloc(1, igraph_vector_bool_t);
     if (boolvec==0) {
       GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+      return 0;
     }
     rec->record.value=boolvec;
     igraph_vector_bool_init(boolvec, 0);    
@@ -691,6 +702,7 @@ void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
     vec=igraph_Calloc(1, igraph_vector_t);
     if (vec==0) {
       GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+      return 0;
     }
     rec->record.value=vec;
     igraph_vector_init(vec, 0);    
@@ -699,28 +711,37 @@ void igraph_i_graphml_add_attribute_key(const xmlChar** attrs,
     strvec=igraph_Calloc(1, igraph_strvector_t);
     if (strvec==0) {
       GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+      return 0;
     }
     rec->record.value=strvec;
     igraph_strvector_init(strvec, 0);
     break;
   default: break;
   }
+
+  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) {
   xmlChar **it;
+  int i;
 
   if (!state->successful)
     return;
 
-  for (it=(xmlChar**)attrs; *it; it+=2) {
+  for (i=0, it=(xmlChar**)attrs; i < nb_attrs; i++, it+=5) {
+    if (XML_ATTR_URI(it) != 0 &&
+	!xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it)))
+      continue;
+
     if (xmlStrEqual(*it, toXmlChar("key"))) {
       if (state->data_key) {
 	free(state->data_key);
       }
-      state->data_key=xmlStrdup(*(it+1));
+      state->data_key=xmlStrndup(XML_ATTR_VALUE(it));
       if (state->data_char) {
         free(state->data_char);
       }
@@ -732,8 +753,8 @@ void igraph_i_graphml_attribute_data_setup(struct igraph_i_graphml_parser_state
   }
 }
 
-void igraph_i_graphml_attribute_data_add(struct igraph_i_graphml_parser_state *state,
-					 const xmlChar *data, int len) {
+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) return;
@@ -746,7 +767,7 @@ void igraph_i_graphml_attribute_data_add(struct igraph_i_graphml_parser_state *s
     state->data_char=igraph_Calloc((size_t) len+1, char);
   }
   if (state->data_char==0) {
-    GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
+    RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);
   }
   memcpy(state->data_char+data_char_new_start, data, 
 	 (size_t) len*sizeof(xmlChar));
@@ -772,7 +793,7 @@ void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state
   case IGRAPH_ATTRIBUTE_VERTEX:
     trie=&state->v_names;
     ptrvector=&state->v_attrs;
-    id=igraph_trie_size(&state->node_trie)-1; /* hack */
+    id=state->act_node;
     break;
   case IGRAPH_ATTRIBUTE_EDGE:
     trie=&state->e_names;
@@ -803,21 +824,22 @@ void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state
     igraph_vector_bool_t *boolvec;
     igraph_vector_t *vec;
     igraph_strvector_t *strvec;
-    igraph_real_t num;
     long int s, i;
+    const char* strvalue;
   case IGRAPH_ATTRIBUTE_BOOLEAN:
     boolvec=(igraph_vector_bool_t *)rec->value;
     s=igraph_vector_bool_size(boolvec);
     if (id >= s) {
       ret=igraph_vector_bool_resize(boolvec, id+1);
       if (ret) {
-        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
       }
       for (i=s; i<id; i++) {
-	VECTOR(*boolvec)[i]=0;
+	VECTOR(*boolvec)[i] = graphmlrec->default_value.as_boolean;
       }
     }
-    VECTOR(*boolvec)[id] = igraph_i_graphml_parse_boolean(state->data_char);
+    VECTOR(*boolvec)[id] = igraph_i_graphml_parse_boolean(state->data_char,
+	graphmlrec->default_value.as_boolean);
     break;
   case IGRAPH_ATTRIBUTE_NUMERIC:
     vec=(igraph_vector_t *)rec->value;
@@ -825,17 +847,14 @@ void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state
     if (id >= s) {
       ret=igraph_vector_resize(vec, id+1);
       if (ret) {
-        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
       }
       for (i=s; i<id; i++) {
-	VECTOR(*vec)[i]=IGRAPH_NAN;
+	VECTOR(*vec)[i] = graphmlrec->default_value.as_numeric;
       }
     }
-    if (state->data_char)
-      sscanf(state->data_char, "%lf", &num);
-    else
-      num=0;
-    VECTOR(*vec)[id]=num;
+    VECTOR(*vec)[id] = igraph_i_graphml_parse_numeric(state->data_char,
+	graphmlrec->default_value.as_numeric);
     break;
   case IGRAPH_ATTRIBUTE_STRING:
     strvec=(igraph_strvector_t *)rec->value;
@@ -843,18 +862,61 @@ void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state
     if (id >= s) {
       ret=igraph_strvector_resize(strvec, id+1);
       if (ret) {
-        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
       }
+      strvalue = graphmlrec->default_value.as_string;
       for (i=s;i<id;i++) {
-	igraph_strvector_set(strvec, i, "");
+	igraph_strvector_set(strvec, i, strvalue);
       }
     }
-    if (state->data_char)
-      ret=igraph_strvector_set(strvec, id, (char*)state->data_char);
-    else
-      ret=igraph_strvector_set(strvec, id, "");
+    if (state->data_char) {
+      strvalue = state->data_char;
+    } else {
+      strvalue = graphmlrec->default_value.as_string;
+    }
+    ret=igraph_strvector_set(strvec, id, strvalue);
     if (ret) {
-      GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+      RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);
+    }
+    break;
+  default:
+    break;
+  }
+
+  if (state->data_char) {
+    igraph_Free(state->data_char);
+  }
+}
+
+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) {
+    igraph_warning("state->current_attr_record was null where it should have been "
+	"non-null; this is probably a bug. Please notify the developers!",
+	__FILE__, __LINE__, 0);
+    return;
+  }
+
+  if (state->data_char == 0)
+    return;
+
+  switch (graphmlrec->record.type) {
+  case IGRAPH_ATTRIBUTE_BOOLEAN:
+    graphmlrec->default_value.as_boolean = igraph_i_graphml_parse_boolean(
+	state->data_char, 0);
+    break;
+  case IGRAPH_ATTRIBUTE_NUMERIC:
+    graphmlrec->default_value.as_numeric = igraph_i_graphml_parse_numeric(
+	state->data_char, IGRAPH_NAN);
+    break;
+  case IGRAPH_ATTRIBUTE_STRING:
+    if (state->data_char) {
+      if (graphmlrec->default_value.as_string != 0) {
+	free(graphmlrec->default_value.as_string);
+      }
+      graphmlrec->default_value.as_string = strdup(state->data_char);
     }
     break;
   default:
@@ -866,22 +928,33 @@ void igraph_i_graphml_attribute_data_finish(struct igraph_i_graphml_parser_state
   }
 }
 
-void igraph_i_graphml_sax_handler_start_element(void *state0,
-						const xmlChar* name,
-						const xmlChar** attrs) {
+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;
+  char* attr_value;
   long int id1, id2;
+  int i;
 
   if (!state->successful)
     return;
 
+  if (!xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), uri)) {
+    /* Tag is in a different namespace, so treat it as an unknown start
+     * tag irrespectively of our state */
+    igraph_i_graphml_handle_unknown_start_tag(state);
+    return;
+  }
+
+
   switch (state->st) {
   case START:
     /* If we are in the START state and received a graphml tag,
      * change to INSIDE_GRAPHML state. Otherwise, change to UNKNOWN. */
-    if (xmlStrEqual(name, toXmlChar("graphml")))
+    if (xmlStrEqual(localname, toXmlChar("graphml")))
       state->st=INSIDE_GRAPHML;
     else
       igraph_i_graphml_handle_unknown_start_tag(state);
@@ -892,27 +965,37 @@ void igraph_i_graphml_sax_handler_start_element(void *state0,
      * change to INSIDE_GRAPH state if the state->index counter reached
      * zero (this is to handle multiple graphs in the same file).
      * Otherwise, change to UNKNOWN. */
-    if (xmlStrEqual(name, toXmlChar("graph"))) {
+    if (xmlStrEqual(localname, toXmlChar("graph"))) {
       if (state->index==0) {
 	state->st=INSIDE_GRAPH;
-	for (it=(xmlChar**)attrs; *it; it+=2) {
+	for (i=0, it=(xmlChar**)attributes; i < nb_attributes; i++, it+=5) {
+	  if (XML_ATTR_URI(it) != 0 &&
+	      !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {
+	    /* Attribute is from a different namespace, so skip it */
+	    continue;
+	  }
 	  if (xmlStrEqual(*it, toXmlChar("edgedefault"))) {
-	    if (xmlStrEqual(*(it+1), toXmlChar("directed"))) state->edges_directed=1;
-	    else if (xmlStrEqual(*(it+1), toXmlChar("undirected"))) state->edges_directed=0;
+            if (!xmlStrncmp(toXmlChar("directed"), XML_ATTR_VALUE(it))) {
+	      state->edges_directed=1;
+	    } else if (!xmlStrncmp(toXmlChar("undirected"), XML_ATTR_VALUE(it))) {
+	      state->edges_directed=0;
+	    }
 	  }
 	}
       }
       state->index--;
-    } else if (xmlStrEqual(name, toXmlChar("key"))) {
-      igraph_i_graphml_add_attribute_key(attrs, state);
+    } else if (xmlStrEqual(localname, toXmlChar("key"))) {
+      state->current_attr_record =
+	igraph_i_graphml_add_attribute_key(attributes, nb_attributes, state);
       state->st=INSIDE_KEY;
-    } else
+    } else {
       igraph_i_graphml_handle_unknown_start_tag(state);
+    }
     break;
 
   case INSIDE_KEY:
     /* If we are in the INSIDE_KEY state, check for default tag */
-    if (xmlStrEqual(name, toXmlChar("default"))) state->st=INSIDE_DEFAULT;
+    if (xmlStrEqual(localname, toXmlChar("default"))) state->st=INSIDE_DEFAULT;
     else igraph_i_graphml_handle_unknown_start_tag(state);
     break;
 
@@ -923,23 +1006,32 @@ void igraph_i_graphml_sax_handler_start_element(void *state0,
     
   case INSIDE_GRAPH:
     /* If we are in the INSIDE_GRAPH state, check for node and edge tags */
-    if (xmlStrEqual(name, toXmlChar("edge"))) {
+    if (xmlStrEqual(localname, toXmlChar("edge"))) {
       id1=-1; id2=-1; 
-      for (it=(xmlChar**)attrs; *it; it+=2) {
-	if (xmlStrEqual(*it, toXmlChar("source"))) {
-	  igraph_trie_get(&state->node_trie, fromXmlChar(*(it+1)), &id1);
-	}
-	if (xmlStrEqual(*it, toXmlChar("target"))) {
-	  igraph_trie_get(&state->node_trie, fromXmlChar(*(it+1)), &id2);
+      for (i=0, it=(xmlChar**)attributes; i < nb_attributes; i++, it+=5) {
+	if (XML_ATTR_URI(it) != 0 &&
+	    !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {
+	  /* Attribute is from a different namespace, so skip it */
+	  continue;
 	}
-	if (xmlStrEqual(*it, toXmlChar("id"))) {
+	if (xmlStrEqual(*it, toXmlChar("source"))) {
+	  attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));
+	  igraph_trie_get(&state->node_trie, attr_value, &id1);
+	  free(attr_value);
+	} else if (xmlStrEqual(*it, toXmlChar("target"))) {
+	  attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));
+	  igraph_trie_get(&state->node_trie, attr_value, &id2);
+	  free(attr_value);
+	} else if (xmlStrEqual(*it, toXmlChar("id"))) {
 	  long int edges=igraph_vector_size(&state->edgelist)/2+1;
 	  long int origsize=igraph_strvector_size(&state->edgeids);
+	  attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));
 	  igraph_strvector_resize(&state->edgeids, edges);
 	  for (;origsize < edges-1; origsize++) {
 	    igraph_strvector_set(&state->edgeids, origsize, "");
 	  }
-	  igraph_strvector_set(&state->edgeids, edges-1, fromXmlChar(*(it+1)));
+	  igraph_strvector_set(&state->edgeids, edges-1, attr_value);
+	  free(attr_value);
 	}
       }
       if (id1>=0 && id2>=0) {
@@ -950,17 +1042,25 @@ void igraph_i_graphml_sax_handler_start_element(void *state0,
 	return;
       }
       state->st=INSIDE_EDGE;
-    } else if (xmlStrEqual(name, toXmlChar("node"))) {
-      for (it=(xmlChar**)attrs; *it; it+=2) {
-	if (xmlStrEqual(*it, toXmlChar("id"))) {
-	  it++;
-	  igraph_trie_get(&state->node_trie, fromXmlChar(*it), &id1);
+    } else if (xmlStrEqual(localname, toXmlChar("node"))) {
+      for (i=0, it=(xmlChar**)attributes; i < nb_attributes; i++, it+=5) {
+	if (XML_ATTR_URI(it) != 0 &&
+	    !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {
+	  /* Attribute is from a different namespace, so skip it */
+	  continue;
+	}
+	if (xmlStrEqual(XML_ATTR_LOCALNAME(it), toXmlChar("id"))) {
+	  attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));
+	  igraph_trie_get(&state->node_trie, attr_value, &id1);
+	  free(attr_value);
 	  break;
 	}
       }
       state->st=INSIDE_NODE;
-    } else if (xmlStrEqual(name, toXmlChar("data"))) {
-      igraph_i_graphml_attribute_data_setup(state, attrs, IGRAPH_ATTRIBUTE_GRAPH);
+      state->act_node = id1;
+    } else if (xmlStrEqual(localname, toXmlChar("data"))) {
+      igraph_i_graphml_attribute_data_setup(state, attributes, nb_attributes,
+	  IGRAPH_ATTRIBUTE_GRAPH);
       igraph_vector_int_push_back(&state->prev_state_stack, state->st);
       state->st=INSIDE_DATA;
     } else
@@ -968,8 +1068,8 @@ void igraph_i_graphml_sax_handler_start_element(void *state0,
     break;
     
   case INSIDE_NODE:
-    if (xmlStrEqual(name, toXmlChar("data"))) {
-      igraph_i_graphml_attribute_data_setup(state, attrs,
+    if (xmlStrEqual(localname, toXmlChar("data"))) {
+      igraph_i_graphml_attribute_data_setup(state, attributes, nb_attributes,
 					    IGRAPH_ATTRIBUTE_VERTEX);
       igraph_vector_int_push_back(&state->prev_state_stack, state->st);
       state->st=INSIDE_DATA;
@@ -977,8 +1077,8 @@ void igraph_i_graphml_sax_handler_start_element(void *state0,
     break;
     
   case INSIDE_EDGE:
-    if (xmlStrEqual(name, toXmlChar("data"))) {
-      igraph_i_graphml_attribute_data_setup(state, attrs, 
+    if (xmlStrEqual(localname, toXmlChar("data"))) {
+      igraph_i_graphml_attribute_data_setup(state, attributes, nb_attributes,
 					    IGRAPH_ATTRIBUTE_EDGE);
       igraph_vector_int_push_back(&state->prev_state_stack, state->st);
       state->st=INSIDE_DATA;
@@ -999,15 +1099,18 @@ void igraph_i_graphml_sax_handler_start_element(void *state0,
   }
 }
 
-void igraph_i_graphml_sax_handler_end_element(void *state0,
-						const xmlChar* name) {
+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=
     (struct igraph_i_graphml_parser_state*)state0;
 
   if (!state->successful)
     return;
 
-  IGRAPH_UNUSED(name);
+  IGRAPH_UNUSED(localname);
+  IGRAPH_UNUSED(prefix);
+  IGRAPH_UNUSED(uri);
 
   switch (state->st) {
   case INSIDE_GRAPHML:
@@ -1019,10 +1122,12 @@ void igraph_i_graphml_sax_handler_end_element(void *state0,
     break;
     
   case INSIDE_KEY:
+    state->current_attr_record = 0;
     state->st=INSIDE_GRAPHML;
     break;
 
   case INSIDE_DEFAULT:
+    igraph_i_graphml_attribute_default_value_finish(state);
     state->st=INSIDE_KEY;
     break;
     
@@ -1060,11 +1165,11 @@ void igraph_i_graphml_sax_handler_chars(void* state0, const xmlChar* ch, int len
 
   switch (state->st) {
   case INSIDE_KEY:
-  case INSIDE_DEFAULT:
     break;
     
   case INSIDE_DATA:
-    igraph_i_graphml_attribute_data_add(state, ch, len);
+  case INSIDE_DEFAULT:
+    igraph_i_graphml_append_to_data_char(state, ch, len);
     break;
     
   default:
@@ -1074,38 +1179,68 @@ void igraph_i_graphml_sax_handler_chars(void* state0, const xmlChar* ch, int len
 }
 
 static xmlSAXHandler igraph_i_graphml_sax_handler={
-  NULL, NULL, NULL, NULL, NULL,
-    igraph_i_graphml_sax_handler_get_entity,
-    NULL, NULL, NULL, NULL, NULL, NULL,
-    igraph_i_graphml_sax_handler_start_document,
-    igraph_i_graphml_sax_handler_end_document,
-    igraph_i_graphml_sax_handler_start_element,
-    igraph_i_graphml_sax_handler_end_element,
-    NULL,
-    igraph_i_graphml_sax_handler_chars,
-    NULL, NULL, NULL,
-    igraph_i_graphml_sax_handler_error,
-    igraph_i_graphml_sax_handler_error,
-    igraph_i_graphml_sax_handler_error,
-    NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL
+  /* internalSubset = */ 0,
+  /* isStandalone = */ 0,
+  /* hasInternalSubset = */ 0,
+  /* hasExternalSubset = */ 0,
+  /* resolveEntity = */ 0,
+  /* getEntity = */ igraph_i_graphml_sax_handler_get_entity,
+  /* entityDecl = */ 0,
+  /* notationDecl = */ 0,
+  /* attributeDecl = */ 0,
+  /* elementDecl = */ 0,
+  /* unparsedEntityDecl = */ 0,
+  /* setDocumentLocator = */ 0,
+  /* startDocument = */ igraph_i_graphml_sax_handler_start_document,
+  /* endDocument = */ igraph_i_graphml_sax_handler_end_document,
+  /* startElement = */ 0,
+  /* endElement = */ 0,
+  /* reference = */ 0,
+  /* characters = */ igraph_i_graphml_sax_handler_chars,
+  /* ignorableWhitespaceFunc = */ 0,
+  /* processingInstruction = */ 0,
+  /* comment = */ 0,
+  /* warning = */ igraph_i_graphml_sax_handler_error,
+  /* error = */ igraph_i_graphml_sax_handler_error,
+  /* fatalError = */ igraph_i_graphml_sax_handler_error,
+  /* getParameterEntity = */ 0,
+  /* cdataBlock = */ 0,
+  /* externalSubset = */ 0,
+  /* initialized = */ XML_SAX2_MAGIC,
+  /* _private = */ 0,
+  /* startElementNs = */ igraph_i_graphml_sax_handler_start_element_ns,
+  /* endElementNs = */ igraph_i_graphml_sax_handler_end_element_ns,
+  /* serror = */ 0
 };
 
 #endif
 
+#define IS_FORBIDDEN_CONTROL_CHAR(x) ((x) < ' ' && (x) != '\t' && (x) != '\r' && (x) != '\n')
+
 int igraph_i_xml_escape(char* src, char** dest) {
   long int destlen=0;
   char *s, *d;
+  unsigned char ch;
+
   for (s=src; *s; s++, destlen++) {
-    if (*s == '&') destlen += 4;
-    else if (*s == '<') destlen += 3;
-    else if (*s == '>') destlen += 3;
-    else if (*s == '"') destlen += 5;
-    else if (*s == '\'') destlen += 5;
+    ch = (unsigned char)(*s);
+    if (ch == '&') destlen += 4;
+    else if (ch == '<') destlen += 3;
+    else if (ch == '>') destlen += 3;
+    else if (ch == '"') destlen += 5;
+    else if (ch == '\'') destlen += 5;
+    else if (IS_FORBIDDEN_CONTROL_CHAR(ch)) {
+      char msg[4096];
+      snprintf(msg, 4096, "Forbidden control character 0x%02X found in igraph_i_xml_escape",
+	  ch);
+      IGRAPH_ERROR(msg, IGRAPH_EINVAL);
+    }
   }
   *dest=igraph_Calloc(destlen+1, char);
   if (!*dest) IGRAPH_ERROR("Not enough memory", IGRAPH_ENOMEM);
   for (s=src, d=*dest; *s; s++, d++) {
-    switch (*s) {
+    ch = (unsigned char)(*s);
+    switch (ch) {
     case '&':
       strcpy(d, "&"); d+=4; break;
     case '<':
@@ -1117,7 +1252,7 @@ int igraph_i_xml_escape(char* src, char** dest) {
     case '\'':
       strcpy(d, "'"); d+=5; break;
     default:
-      *d = *s;
+      *d = ch;
     }
   }
   *d=0;
@@ -1188,6 +1323,14 @@ int igraph_read_graph_graphml(igraph_t *graph, FILE *instream,
   if (ctxt==NULL)
     IGRAPH_ERROR("Can't create progressive parser context", IGRAPH_PARSEERROR);
 
+  /* Set parsing options */
+  if (xmlCtxtUseOptions(ctxt,
+	XML_PARSE_NOENT | XML_PARSE_NOBLANKS |
+	XML_PARSE_NONET | XML_PARSE_NSCLEAN |
+	XML_PARSE_NOCDATA | XML_PARSE_HUGE
+	))
+    IGRAPH_ERROR("Cannot set options for the parser context", IGRAPH_EINVAL);
+
   /* Parse the file */
   while ((res=(int) fread(buffer, 1, 4096, instream))>0) {
     xmlParseChunk(ctxt, buffer, res, 0);
@@ -1349,10 +1492,13 @@ int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream,
       IGRAPH_CHECK(igraph_i_attribute_get_numeric_graph_attr(graph, name, &numv));
       if (!isnan(VECTOR(numv)[0])) {
         IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
-        ret=fprintf(outstream, "    <data key=\"%s%s\">%g</data>\n",
-                    gprefix, name_escaped, VECTOR(numv)[0]);
+        ret=fprintf(outstream, "    <data key=\"%s%s\">", gprefix, name_escaped);
         igraph_Free(name_escaped);
         if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+        ret=igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+        ret=fprintf(outstream, "</data>\n");
+        if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
       }
     } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
       char *s, *s_escaped;
@@ -1395,10 +1541,13 @@ int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream,
                      igraph_vss_1(l), &numv));
         if (!isnan(VECTOR(numv)[0])) {
           IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
-          ret=fprintf(outstream, "      <data key=\"%s%s\">%g</data>\n",
-                      vprefix, name_escaped, VECTOR(numv)[0]);
+          ret=fprintf(outstream, "      <data key=\"%s%s\">", vprefix, name_escaped);
           igraph_Free(name_escaped);
           if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+          ret=igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+          ret=fprintf(outstream, "</data>\n");
+          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
         }
       } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
         char *s, *s_escaped;
@@ -1451,10 +1600,13 @@ int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream,
 			      igraph_ess_1((igraph_integer_t) edge), &numv));
         if (!isnan(VECTOR(numv)[0])) {
           IGRAPH_CHECK(igraph_i_xml_escape(name, &name_escaped));
-          ret=fprintf(outstream, "      <data key=\"%s%s\">%g</data>\n",
-                      eprefix, name_escaped, VECTOR(numv)[0]);
+          ret=fprintf(outstream, "      <data key=\"%s%s\">", eprefix, name_escaped);
           igraph_Free(name_escaped);
           if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+          ret=igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);
+          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
+          ret=fprintf(outstream, "</data>\n");
+          if (ret<0) IGRAPH_ERROR("Write failed", IGRAPH_EFILE);
         }
       } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_STRING) {
         char *s, *s_escaped;
diff --git a/src/foreign-lgl-lexer.c b/src/foreign-lgl-lexer.c
index 4e23115..f36bc7c 100644
--- a/src/foreign-lgl-lexer.c
+++ b/src/foreign-lgl-lexer.c
@@ -433,7 +433,7 @@ static yyconst flex_int16_t yy_chk[17] =
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "igraph/src/foreign-lgl-lexer.l"
+#line 1 "src/foreign-lgl-lexer.l"
 /* 
    IGraph library.
    Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
@@ -455,7 +455,7 @@ static yyconst flex_int16_t yy_chk[17] =
    02110-1301 USA
 
 */
-#line 24 "igraph/src/foreign-lgl-lexer.l"
+#line 24 "src/foreign-lgl-lexer.l"
 
 /* 
    IGraph library.
@@ -739,7 +739,7 @@ YY_DECL
 	register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 80 "igraph/src/foreign-lgl-lexer.l"
+#line 80 "src/foreign-lgl-lexer.l"
 
 
  /* --------------------------------------------------hashmark------*/
@@ -832,30 +832,30 @@ do_action:	/* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 83 "igraph/src/foreign-lgl-lexer.l"
+#line 83 "src/foreign-lgl-lexer.l"
 { return HASH; }
 	YY_BREAK
 /* ------------------------------------------------whitespace------*/
 case 2:
 YY_RULE_SETUP
-#line 86 "igraph/src/foreign-lgl-lexer.l"
+#line 86 "src/foreign-lgl-lexer.l"
 { }
 	YY_BREAK
 /* ---------------------------------------------------newline------*/
 case 3:
 /* rule 3 can match eol */
 YY_RULE_SETUP
-#line 89 "igraph/src/foreign-lgl-lexer.l"
+#line 89 "src/foreign-lgl-lexer.l"
 { return NEWLINE; }
 	YY_BREAK
 /* ----------------------------------------------alphanumeric------*/
 case 4:
 YY_RULE_SETUP
-#line 92 "igraph/src/foreign-lgl-lexer.l"
+#line 92 "src/foreign-lgl-lexer.l"
 { return ALNUM; }
 	YY_BREAK
 case YY_STATE_EOF(INITIAL):
-#line 94 "igraph/src/foreign-lgl-lexer.l"
+#line 94 "src/foreign-lgl-lexer.l"
 { if (yyextra->eof) {
                        yyterminate();
                     } else {
@@ -866,7 +866,7 @@ case YY_STATE_EOF(INITIAL):
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 102 "igraph/src/foreign-lgl-lexer.l"
+#line 102 "src/foreign-lgl-lexer.l"
 ECHO;
 	YY_BREAK
 #line 873 "lex.yy.c"
@@ -2007,7 +2007,7 @@ void igraph_lgl_yyfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 102 "igraph/src/foreign-lgl-lexer.l"
+#line 102 "src/foreign-lgl-lexer.l"
 
 
 
diff --git a/src/foreign-lgl-parser.c b/src/foreign-lgl-parser.c
index 5e070cf..5ff2bd7 100644
--- a/src/foreign-lgl-parser.c
+++ b/src/foreign-lgl-parser.c
@@ -88,7 +88,7 @@
 
 
 /* Copy the first part of user declarations.  */
-#line 23 "igraph/src/foreign-lgl-parser.y"
+#line 23 "src/foreign-lgl-parser.y"
 
 
 /* 
@@ -163,7 +163,7 @@ igraph_real_t igraph_lgl_get_number(const char *str, long int len);
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 86 "igraph/src/foreign-lgl-parser.y"
+#line 86 "src/foreign-lgl-parser.y"
 {
   long int edgenum;
   double weightnum;
@@ -1415,12 +1415,12 @@ yyreduce:
   switch (yyn)
     {
         case 6:
-#line 107 "igraph/src/foreign-lgl-parser.y"
+#line 107 "src/foreign-lgl-parser.y"
     { context->actvertex=(yyvsp[(2) - (3)].edgenum); ;}
     break;
 
   case 9:
-#line 111 "igraph/src/foreign-lgl-parser.y"
+#line 111 "src/foreign-lgl-parser.y"
     { 
              igraph_vector_push_back(context->vector, context->actvertex);
              igraph_vector_push_back(context->vector, (yyvsp[(1) - (2)].edgenum));
@@ -1429,7 +1429,7 @@ yyreduce:
     break;
 
   case 10:
-#line 116 "igraph/src/foreign-lgl-parser.y"
+#line 116 "src/foreign-lgl-parser.y"
     { 
 	     igraph_vector_push_back(context->vector, context->actvertex);
              igraph_vector_push_back(context->vector, (yyvsp[(1) - (3)].edgenum));
@@ -1439,7 +1439,7 @@ yyreduce:
     break;
 
   case 11:
-#line 125 "igraph/src/foreign-lgl-parser.y"
+#line 125 "src/foreign-lgl-parser.y"
     { igraph_trie_get2(context->trie, 
 				   igraph_lgl_yyget_text(scanner), 
 				   igraph_lgl_yyget_leng(scanner), 
@@ -1447,7 +1447,7 @@ yyreduce:
     break;
 
   case 12:
-#line 130 "igraph/src/foreign-lgl-parser.y"
+#line 130 "src/foreign-lgl-parser.y"
     { (yyval.weightnum)=igraph_lgl_get_number(igraph_lgl_yyget_text(scanner), 
 					   igraph_lgl_yyget_leng(scanner)); ;}
     break;
@@ -1674,7 +1674,7 @@ yyreturn:
 }
 
 
-#line 133 "igraph/src/foreign-lgl-parser.y"
+#line 133 "src/foreign-lgl-parser.y"
 
 
 int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, 
diff --git a/src/foreign-lgl-parser.h b/src/foreign-lgl-parser.h
index 0e43b13..2680f24 100644
--- a/src/foreign-lgl-parser.h
+++ b/src/foreign-lgl-parser.h
@@ -54,7 +54,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 86 "igraph/src/foreign-lgl-parser.y"
+#line 86 "src/foreign-lgl-parser.y"
 {
   long int edgenum;
   double weightnum;
diff --git a/src/foreign-ncol-lexer.c b/src/foreign-ncol-lexer.c
index c66ab80..8b3afb2 100644
--- a/src/foreign-ncol-lexer.c
+++ b/src/foreign-ncol-lexer.c
@@ -433,7 +433,7 @@ static yyconst flex_int16_t yy_chk[15] =
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "igraph/src/foreign-ncol-lexer.l"
+#line 1 "src/foreign-ncol-lexer.l"
 /* 
    IGraph library.
    Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
@@ -455,7 +455,7 @@ static yyconst flex_int16_t yy_chk[15] =
    02110-1301 USA
 
 */
-#line 24 "igraph/src/foreign-ncol-lexer.l"
+#line 24 "src/foreign-ncol-lexer.l"
 
 /* 
    IGraph library.
@@ -739,7 +739,7 @@ YY_DECL
 	register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 80 "igraph/src/foreign-ncol-lexer.l"
+#line 80 "src/foreign-ncol-lexer.l"
 
 
  /* ------------------------------------------------whitespace------*/
@@ -832,24 +832,24 @@ do_action:	/* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 83 "igraph/src/foreign-ncol-lexer.l"
+#line 83 "src/foreign-ncol-lexer.l"
 { }
 	YY_BREAK
 /* ---------------------------------------------------newline------*/
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 86 "igraph/src/foreign-ncol-lexer.l"
+#line 86 "src/foreign-ncol-lexer.l"
 { return NEWLINE; }
 	YY_BREAK
 /* ----------------------------------------------alphanumeric------*/
 case 3:
 YY_RULE_SETUP
-#line 89 "igraph/src/foreign-ncol-lexer.l"
+#line 89 "src/foreign-ncol-lexer.l"
 { return ALNUM; }
 	YY_BREAK
 case YY_STATE_EOF(INITIAL):
-#line 91 "igraph/src/foreign-ncol-lexer.l"
+#line 91 "src/foreign-ncol-lexer.l"
 { if (yyextra->eof) {
                        yyterminate();
                     } else {
@@ -860,7 +860,7 @@ case YY_STATE_EOF(INITIAL):
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 99 "igraph/src/foreign-ncol-lexer.l"
+#line 99 "src/foreign-ncol-lexer.l"
 ECHO;
 	YY_BREAK
 #line 867 "lex.yy.c"
@@ -2001,7 +2001,7 @@ void igraph_ncol_yyfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 99 "igraph/src/foreign-ncol-lexer.l"
+#line 99 "src/foreign-ncol-lexer.l"
 
 
 
diff --git a/src/foreign-ncol-parser.c b/src/foreign-ncol-parser.c
index 1d25f5d..56d289f 100644
--- a/src/foreign-ncol-parser.c
+++ b/src/foreign-ncol-parser.c
@@ -86,7 +86,7 @@
 
 
 /* Copy the first part of user declarations.  */
-#line 23 "igraph/src/foreign-ncol-parser.y"
+#line 23 "src/foreign-ncol-parser.y"
 
 
 /* 
@@ -162,7 +162,7 @@ igraph_real_t igraph_ncol_get_number(const char *str, long int len);
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 87 "igraph/src/foreign-ncol-parser.y"
+#line 87 "src/foreign-ncol-parser.y"
 {
   long int edgenum;
   double weightnum;
@@ -1408,7 +1408,7 @@ yyreduce:
   switch (yyn)
     {
         case 5:
-#line 105 "igraph/src/foreign-ncol-parser.y"
+#line 105 "src/foreign-ncol-parser.y"
     { 
            igraph_vector_push_back(context->vector, (yyvsp[(1) - (3)].edgenum));
            igraph_vector_push_back(context->vector, (yyvsp[(2) - (3)].edgenum));
@@ -1417,7 +1417,7 @@ yyreduce:
     break;
 
   case 6:
-#line 110 "igraph/src/foreign-ncol-parser.y"
+#line 110 "src/foreign-ncol-parser.y"
     { 
            igraph_vector_push_back(context->vector, (yyvsp[(1) - (4)].edgenum));
            igraph_vector_push_back(context->vector, (yyvsp[(2) - (4)].edgenum));
@@ -1427,7 +1427,7 @@ yyreduce:
     break;
 
   case 7:
-#line 118 "igraph/src/foreign-ncol-parser.y"
+#line 118 "src/foreign-ncol-parser.y"
     { igraph_trie_get2(context->trie, 
 				   igraph_ncol_yyget_text(scanner),
 				   igraph_ncol_yyget_leng(scanner), 
@@ -1435,7 +1435,7 @@ yyreduce:
     break;
 
   case 8:
-#line 123 "igraph/src/foreign-ncol-parser.y"
+#line 123 "src/foreign-ncol-parser.y"
     { (yyval.weightnum)=igraph_ncol_get_number(igraph_ncol_yyget_text(scanner), 
 					    igraph_ncol_yyget_leng(scanner)); ;}
     break;
@@ -1662,7 +1662,7 @@ yyreturn:
 }
 
 
-#line 126 "igraph/src/foreign-ncol-parser.y"
+#line 126 "src/foreign-ncol-parser.y"
 
 
 int igraph_ncol_yyerror(YYLTYPE* locp, 
diff --git a/src/foreign-ncol-parser.h b/src/foreign-ncol-parser.h
index 4833d97..f104e12 100644
--- a/src/foreign-ncol-parser.h
+++ b/src/foreign-ncol-parser.h
@@ -52,7 +52,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 87 "igraph/src/foreign-ncol-parser.y"
+#line 87 "src/foreign-ncol-parser.y"
 {
   long int edgenum;
   double weightnum;
diff --git a/src/foreign-pajek-lexer.c b/src/foreign-pajek-lexer.c
index eca1c33..f3f0d21 100644
--- a/src/foreign-pajek-lexer.c
+++ b/src/foreign-pajek-lexer.c
@@ -552,7 +552,7 @@ static yyconst flex_int16_t yy_chk[331] =
 #define yymore() yymore_used_but_not_detected
 #define YY_MORE_ADJ 0
 #define YY_RESTORE_YY_MORE_OFFSET
-#line 1 "igraph/src/foreign-pajek-lexer.l"
+#line 1 "src/foreign-pajek-lexer.l"
 /* 
    IGraph library.
    Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
@@ -574,7 +574,7 @@ static yyconst flex_int16_t yy_chk[331] =
    02110-1301 USA
 
 */
-#line 24 "igraph/src/foreign-pajek-lexer.l"
+#line 24 "src/foreign-pajek-lexer.l"
 
 /* 
    IGraph library.
@@ -858,7 +858,7 @@ YY_DECL
 	register int yy_act;
     struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
 
-#line 81 "igraph/src/foreign-pajek-lexer.l"
+#line 81 "src/foreign-pajek-lexer.l"
 
 
 #line 865 "lex.yy.c"
@@ -950,82 +950,82 @@ do_action:	/* This label is used only to access EOF actions. */
 
 case 1:
 YY_RULE_SETUP
-#line 83 "igraph/src/foreign-pajek-lexer.l"
+#line 83 "src/foreign-pajek-lexer.l"
 { }
 	YY_BREAK
 case 2:
 /* rule 2 can match eol */
 YY_RULE_SETUP
-#line 84 "igraph/src/foreign-pajek-lexer.l"
+#line 84 "src/foreign-pajek-lexer.l"
 { }
 	YY_BREAK
 case 3:
 /* rule 3 can match eol */
 YY_RULE_SETUP
-#line 85 "igraph/src/foreign-pajek-lexer.l"
+#line 85 "src/foreign-pajek-lexer.l"
 { }
 	YY_BREAK
 case 4:
 YY_RULE_SETUP
-#line 86 "igraph/src/foreign-pajek-lexer.l"
+#line 86 "src/foreign-pajek-lexer.l"
 { return NETWORKLINE; }
 	YY_BREAK
 case 5:
 YY_RULE_SETUP
-#line 87 "igraph/src/foreign-pajek-lexer.l"
+#line 87 "src/foreign-pajek-lexer.l"
 { return NETWORKLINE; }
 	YY_BREAK
 case 6:
 YY_RULE_SETUP
-#line 88 "igraph/src/foreign-pajek-lexer.l"
+#line 88 "src/foreign-pajek-lexer.l"
 { return VERTICESLINE; }
 	YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 89 "igraph/src/foreign-pajek-lexer.l"
+#line 89 "src/foreign-pajek-lexer.l"
 { return ARCSLINE; }
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 90 "igraph/src/foreign-pajek-lexer.l"
+#line 90 "src/foreign-pajek-lexer.l"
 { return EDGESLINE; }
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 91 "igraph/src/foreign-pajek-lexer.l"
+#line 91 "src/foreign-pajek-lexer.l"
 { return ARCSLISTLINE; }
 	YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 92 "igraph/src/foreign-pajek-lexer.l"
+#line 92 "src/foreign-pajek-lexer.l"
 { return EDGESLISTLINE; }
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 93 "igraph/src/foreign-pajek-lexer.l"
+#line 93 "src/foreign-pajek-lexer.l"
 { return MATRIXLINE; }
 	YY_BREAK
 case 12:
 /* rule 12 can match eol */
 YY_RULE_SETUP
-#line 94 "igraph/src/foreign-pajek-lexer.l"
+#line 94 "src/foreign-pajek-lexer.l"
 { yyextra->mode=0; return NEWLINE; }
 	YY_BREAK
 case 13:
 /* rule 13 can match eol */
 YY_RULE_SETUP
-#line 95 "igraph/src/foreign-pajek-lexer.l"
+#line 95 "src/foreign-pajek-lexer.l"
 { return QSTR; }
 	YY_BREAK
 case 14:
 /* rule 14 can match eol */
 YY_RULE_SETUP
-#line 96 "igraph/src/foreign-pajek-lexer.l"
+#line 96 "src/foreign-pajek-lexer.l"
 { return PSTR; }
 	YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 97 "igraph/src/foreign-pajek-lexer.l"
+#line 97 "src/foreign-pajek-lexer.l"
 { 
                     return NUM; }
 	YY_BREAK
@@ -1035,7 +1035,7 @@ case 16:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 6;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 100 "igraph/src/foreign-pajek-lexer.l"
+#line 100 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_X_FACT; } else { return ALNUM; } }
 	YY_BREAK
 case 17:
@@ -1044,7 +1044,7 @@ case 17:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 6;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 101 "igraph/src/foreign-pajek-lexer.l"
+#line 101 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_Y_FACT; } else { return ALNUM; } }
 	YY_BREAK
 case 18:
@@ -1053,7 +1053,7 @@ case 18:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 102 "igraph/src/foreign-pajek-lexer.l"
+#line 102 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_IC; } else { return ALNUM; } }
 	YY_BREAK
 case 19:
@@ -1062,7 +1062,7 @@ case 19:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 103 "igraph/src/foreign-pajek-lexer.l"
+#line 103 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_BC; } else { return ALNUM; } }
 	YY_BREAK
 case 20:
@@ -1071,7 +1071,7 @@ case 20:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 104 "igraph/src/foreign-pajek-lexer.l"
+#line 104 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_BW; } else { return ALNUM; } }
 	YY_BREAK
 case 21:
@@ -1080,7 +1080,7 @@ case 21:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 3;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 105 "igraph/src/foreign-pajek-lexer.l"
+#line 105 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_PHI; } else { return ALNUM; } }
 	YY_BREAK
 case 22:
@@ -1089,7 +1089,7 @@ case 22:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 106 "igraph/src/foreign-pajek-lexer.l"
+#line 106 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_R; } else { return ALNUM; } }
 	YY_BREAK
 case 23:
@@ -1098,7 +1098,7 @@ case 23:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 107 "igraph/src/foreign-pajek-lexer.l"
+#line 107 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_Q; } else { return ALNUM; } }
 	YY_BREAK
 case 24:
@@ -1107,7 +1107,7 @@ case 24:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 108 "igraph/src/foreign-pajek-lexer.l"
+#line 108 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_FONT; } else { return ALNUM; } }
 	YY_BREAK
 case 25:
@@ -1116,7 +1116,7 @@ case 25:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 3;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 109 "igraph/src/foreign-pajek-lexer.l"
+#line 109 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_URL; } else { return ALNUM; } }
 	YY_BREAK
 case 26:
@@ -1125,7 +1125,7 @@ case 26:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 111 "igraph/src/foreign-pajek-lexer.l"
+#line 111 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_C; } else { return ALNUM; } }
 	YY_BREAK
 case 27:
@@ -1134,7 +1134,7 @@ case 27:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 112 "igraph/src/foreign-pajek-lexer.l"
+#line 112 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_P; } else { return ALNUM; } }
 	YY_BREAK
 case 28:
@@ -1143,7 +1143,7 @@ case 28:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 113 "igraph/src/foreign-pajek-lexer.l"
+#line 113 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_S; } else { return ALNUM; } }
 	YY_BREAK
 case 29:
@@ -1152,7 +1152,7 @@ case 29:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 114 "igraph/src/foreign-pajek-lexer.l"
+#line 114 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_A; } else { return ALNUM; } }
 	YY_BREAK
 case 30:
@@ -1161,7 +1161,7 @@ case 30:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 115 "igraph/src/foreign-pajek-lexer.l"
+#line 115 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_W; } else { return ALNUM; } }
 	YY_BREAK
 case 31:
@@ -1170,7 +1170,7 @@ case 31:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 116 "igraph/src/foreign-pajek-lexer.l"
+#line 116 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_H1; } else { return ALNUM; } }
 	YY_BREAK
 case 32:
@@ -1179,7 +1179,7 @@ case 32:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 117 "igraph/src/foreign-pajek-lexer.l"
+#line 117 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_H2; } else { return ALNUM; } }
 	YY_BREAK
 case 33:
@@ -1188,7 +1188,7 @@ case 33:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 118 "igraph/src/foreign-pajek-lexer.l"
+#line 118 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_A1; } else { return ALNUM; } }
 	YY_BREAK
 case 34:
@@ -1197,7 +1197,7 @@ case 34:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 119 "igraph/src/foreign-pajek-lexer.l"
+#line 119 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_A2; } else { return ALNUM; } }
 	YY_BREAK
 case 35:
@@ -1206,7 +1206,7 @@ case 35:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 120 "igraph/src/foreign-pajek-lexer.l"
+#line 120 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_K1; } else { return ALNUM; } }
 	YY_BREAK
 case 36:
@@ -1215,7 +1215,7 @@ case 36:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 121 "igraph/src/foreign-pajek-lexer.l"
+#line 121 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_K2; } else { return ALNUM; } }
 	YY_BREAK
 case 37:
@@ -1224,7 +1224,7 @@ case 37:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 122 "igraph/src/foreign-pajek-lexer.l"
+#line 122 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_AP; } else { return ALNUM; } }
 	YY_BREAK
 case 38:
@@ -1233,7 +1233,7 @@ case 38:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 123 "igraph/src/foreign-pajek-lexer.l"
+#line 123 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_L; } else { return ALNUM; } }
 	YY_BREAK
 case 39:
@@ -1242,7 +1242,7 @@ case 39:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 124 "igraph/src/foreign-pajek-lexer.l"
+#line 124 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==2) { return EP_LP; } else { return ALNUM; } }
 	YY_BREAK
 case 40:
@@ -1251,7 +1251,7 @@ case 40:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 126 "igraph/src/foreign-pajek-lexer.l"
+#line 126 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_LPHI; } else
                              if (yyextra->mode==2) { return EP_LPHI; } else { return ALNUM; } }
 	YY_BREAK
@@ -1261,7 +1261,7 @@ case 41:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 128 "igraph/src/foreign-pajek-lexer.l"
+#line 128 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_LC; } else
                              if (yyextra->mode==2) { return EP_LC; } else { return ALNUM; } }
 	YY_BREAK
@@ -1271,7 +1271,7 @@ case 42:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 130 "igraph/src/foreign-pajek-lexer.l"
+#line 130 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_LR; } else
                              if (yyextra->mode==2) { return EP_LR; } else { return ALNUM; } }
 	YY_BREAK
@@ -1281,7 +1281,7 @@ case 43:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 2;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 132 "igraph/src/foreign-pajek-lexer.l"
+#line 132 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_LA; } else
                              if (yyextra->mode==2) { return EP_LA; } else { return ALNUM; } }
 	YY_BREAK
@@ -1291,7 +1291,7 @@ case 44:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 4;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 134 "igraph/src/foreign-pajek-lexer.l"
+#line 134 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_SIZE; } else 
                              if (yyextra->mode==2) { return EP_SIZE; } else { return ALNUM; } }
 	YY_BREAK
@@ -1301,17 +1301,17 @@ case 45:
 yyg->yy_c_buf_p = yy_cp = yy_bp + 3;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 136 "igraph/src/foreign-pajek-lexer.l"
+#line 136 "src/foreign-pajek-lexer.l"
 { if (yyextra->mode==1) { return VP_FOS; } else 
                              if (yyextra->mode==2) { return EP_FOS; } else { return ALNUM; } }
 	YY_BREAK
 case 46:
 YY_RULE_SETUP
-#line 139 "igraph/src/foreign-pajek-lexer.l"
+#line 139 "src/foreign-pajek-lexer.l"
 { return ALNUM; }
 	YY_BREAK
 case YY_STATE_EOF(INITIAL):
-#line 141 "igraph/src/foreign-pajek-lexer.l"
+#line 141 "src/foreign-pajek-lexer.l"
 { if (yyextra->eof) {
                        yyterminate();
                     } else {
@@ -1322,7 +1322,7 @@ case YY_STATE_EOF(INITIAL):
 	YY_BREAK
 case 47:
 YY_RULE_SETUP
-#line 148 "igraph/src/foreign-pajek-lexer.l"
+#line 148 "src/foreign-pajek-lexer.l"
 ECHO;
 	YY_BREAK
 #line 1329 "lex.yy.c"
@@ -2463,7 +2463,7 @@ void igraph_pajek_yyfree (void * ptr , yyscan_t yyscanner)
 
 #define YYTABLES_NAME "yytables"
 
-#line 148 "igraph/src/foreign-pajek-lexer.l"
+#line 148 "src/foreign-pajek-lexer.l"
 
 
 
diff --git a/src/foreign-pajek-parser.c b/src/foreign-pajek-parser.c
index 88a07f5..a90c01e 100644
--- a/src/foreign-pajek-parser.c
+++ b/src/foreign-pajek-parser.c
@@ -178,7 +178,7 @@
 
 
 /* Copy the first part of user declarations.  */
-#line 23 "igraph/src/foreign-pajek-parser.y"
+#line 23 "src/foreign-pajek-parser.y"
 
 
 /* 
@@ -290,7 +290,7 @@ extern long int igraph_i_pajek_actedge;
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 123 "igraph/src/foreign-pajek-parser.y"
+#line 123 "src/foreign-pajek-parser.y"
 {
   long int intnum;
   double   realnum;  
@@ -1770,14 +1770,14 @@ yyreduce:
   switch (yyn)
     {
         case 2:
-#line 196 "igraph/src/foreign-pajek-parser.y"
+#line 196 "src/foreign-pajek-parser.y"
     {
   if (context->vcount2 > 0) { igraph_i_pajek_check_bipartite(context); }
  ;}
     break;
 
   case 6:
-#line 204 "igraph/src/foreign-pajek-parser.y"
+#line 204 "src/foreign-pajek-parser.y"
     { 
   context->vcount=(yyvsp[(2) - (2)].intnum); 
   context->vcount2=0;
@@ -1785,7 +1785,7 @@ yyreduce:
     break;
 
   case 7:
-#line 208 "igraph/src/foreign-pajek-parser.y"
+#line 208 "src/foreign-pajek-parser.y"
     { 
   context->vcount=(yyvsp[(2) - (3)].intnum);
   context->vcount2=(yyvsp[(3) - (3)].intnum);
@@ -1794,29 +1794,29 @@ yyreduce:
     break;
 
   case 12:
-#line 218 "igraph/src/foreign-pajek-parser.y"
+#line 218 "src/foreign-pajek-parser.y"
     { context->actvertex=(yyvsp[(1) - (1)].intnum); ;}
     break;
 
   case 13:
-#line 218 "igraph/src/foreign-pajek-parser.y"
+#line 218 "src/foreign-pajek-parser.y"
     { ;}
     break;
 
   case 14:
-#line 221 "igraph/src/foreign-pajek-parser.y"
+#line 221 "src/foreign-pajek-parser.y"
     { (yyval.intnum)=(yyvsp[(1) - (1)].intnum); context->mode=1; ;}
     break;
 
   case 15:
-#line 223 "igraph/src/foreign-pajek-parser.y"
+#line 223 "src/foreign-pajek-parser.y"
     {
   igraph_i_pajek_add_string_vertex_attribute("id", (yyvsp[(1) - (1)].string).str, (yyvsp[(1) - (1)].string).len, context);
 ;}
     break;
 
   case 17:
-#line 228 "igraph/src/foreign-pajek-parser.y"
+#line 228 "src/foreign-pajek-parser.y"
     { 
   igraph_i_pajek_add_numeric_vertex_attribute("x", (yyvsp[(1) - (2)].realnum), context);
   igraph_i_pajek_add_numeric_vertex_attribute("y", (yyvsp[(2) - (2)].realnum), context);
@@ -1824,7 +1824,7 @@ yyreduce:
     break;
 
   case 18:
-#line 232 "igraph/src/foreign-pajek-parser.y"
+#line 232 "src/foreign-pajek-parser.y"
     { 
   igraph_i_pajek_add_numeric_vertex_attribute("x", (yyvsp[(1) - (3)].realnum), context);
   igraph_i_pajek_add_numeric_vertex_attribute("y", (yyvsp[(2) - (3)].realnum), context);
@@ -1833,28 +1833,28 @@ yyreduce:
     break;
 
   case 20:
-#line 238 "igraph/src/foreign-pajek-parser.y"
+#line 238 "src/foreign-pajek-parser.y"
     { 
   igraph_i_pajek_add_string_vertex_attribute("shape", (yyvsp[(1) - (1)].string).str, (yyvsp[(1) - (1)].string).len, context);
 ;}
     break;
 
   case 24:
-#line 246 "igraph/src/foreign-pajek-parser.y"
+#line 246 "src/foreign-pajek-parser.y"
     {
 	 igraph_i_pajek_add_numeric_vertex_attribute("xfact", (yyvsp[(2) - (2)].realnum), context);
        ;}
     break;
 
   case 25:
-#line 249 "igraph/src/foreign-pajek-parser.y"
+#line 249 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("yfact", (yyvsp[(2) - (2)].realnum), context);
        ;}
     break;
 
   case 26:
-#line 252 "igraph/src/foreign-pajek-parser.y"
+#line 252 "src/foreign-pajek-parser.y"
     { /* RGB color */
          igraph_i_pajek_add_numeric_vertex_attribute("color-red", (yyvsp[(2) - (4)].realnum), context);
 	 igraph_i_pajek_add_numeric_vertex_attribute("color-green", (yyvsp[(3) - (4)].realnum), context);
@@ -1863,7 +1863,7 @@ yyreduce:
     break;
 
   case 27:
-#line 257 "igraph/src/foreign-pajek-parser.y"
+#line 257 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("framecolor-red", (yyvsp[(2) - (4)].realnum), context);
 	 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-green", (yyvsp[(3) - (4)].realnum), context);
@@ -1872,7 +1872,7 @@ yyreduce:
     break;
 
   case 28:
-#line 262 "igraph/src/foreign-pajek-parser.y"
+#line 262 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-red", (yyvsp[(2) - (4)].realnum), context);
 	 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-green", (yyvsp[(3) - (4)].realnum), context);
@@ -1881,75 +1881,75 @@ yyreduce:
     break;
 
   case 29:
-#line 267 "igraph/src/foreign-pajek-parser.y"
+#line 267 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("labeldist", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 30:
-#line 270 "igraph/src/foreign-pajek-parser.y"
+#line 270 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("labeldegree2", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 31:
-#line 273 "igraph/src/foreign-pajek-parser.y"
+#line 273 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("framewidth", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 32:
-#line 276 "igraph/src/foreign-pajek-parser.y"
+#line 276 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("fontsize", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 33:
-#line 279 "igraph/src/foreign-pajek-parser.y"
+#line 279 "src/foreign-pajek-parser.y"
     {       
          igraph_i_pajek_add_numeric_vertex_attribute("rotation", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 34:
-#line 282 "igraph/src/foreign-pajek-parser.y"
+#line 282 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("radius", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 35:
-#line 285 "igraph/src/foreign-pajek-parser.y"
+#line 285 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("diamondratio", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 36:
-#line 288 "igraph/src/foreign-pajek-parser.y"
+#line 288 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("labeldegree", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 37:
-#line 291 "igraph/src/foreign-pajek-parser.y"
+#line 291 "src/foreign-pajek-parser.y"
     {
          igraph_i_pajek_add_numeric_vertex_attribute("vertexsize", (yyvsp[(2) - (2)].realnum), context);
      ;}
     break;
 
   case 38:
-#line 296 "igraph/src/foreign-pajek-parser.y"
+#line 296 "src/foreign-pajek-parser.y"
     { context->mode=3; ;}
     break;
 
   case 39:
-#line 296 "igraph/src/foreign-pajek-parser.y"
+#line 296 "src/foreign-pajek-parser.y"
     { 
          context->mode=1;
 	 igraph_i_pajek_add_string_vertex_attribute("font", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -1957,12 +1957,12 @@ yyreduce:
     break;
 
   case 40:
-#line 300 "igraph/src/foreign-pajek-parser.y"
+#line 300 "src/foreign-pajek-parser.y"
     { context->mode=3; ;}
     break;
 
   case 41:
-#line 300 "igraph/src/foreign-pajek-parser.y"
+#line 300 "src/foreign-pajek-parser.y"
     {
          context->mode=1;
 	 igraph_i_pajek_add_string_vertex_attribute("url", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -1970,12 +1970,12 @@ yyreduce:
     break;
 
   case 42:
-#line 304 "igraph/src/foreign-pajek-parser.y"
+#line 304 "src/foreign-pajek-parser.y"
     { context->mode=3; ;}
     break;
 
   case 43:
-#line 304 "igraph/src/foreign-pajek-parser.y"
+#line 304 "src/foreign-pajek-parser.y"
     {
          context->mode=1;
 	 igraph_i_pajek_add_string_vertex_attribute("color", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -1983,12 +1983,12 @@ yyreduce:
     break;
 
   case 44:
-#line 308 "igraph/src/foreign-pajek-parser.y"
+#line 308 "src/foreign-pajek-parser.y"
     { context->mode=3; ;}
     break;
 
   case 45:
-#line 308 "igraph/src/foreign-pajek-parser.y"
+#line 308 "src/foreign-pajek-parser.y"
     {
          context->mode=1;
 	 igraph_i_pajek_add_string_vertex_attribute("framecolor", 
@@ -1997,12 +1997,12 @@ yyreduce:
     break;
 
   case 46:
-#line 313 "igraph/src/foreign-pajek-parser.y"
+#line 313 "src/foreign-pajek-parser.y"
     { context->mode=3; ;}
     break;
 
   case 47:
-#line 313 "igraph/src/foreign-pajek-parser.y"
+#line 313 "src/foreign-pajek-parser.y"
     {
          context->mode=1;
 	 igraph_i_pajek_add_string_vertex_attribute("labelcolor", 
@@ -2011,65 +2011,65 @@ yyreduce:
     break;
 
   case 48:
-#line 320 "igraph/src/foreign-pajek-parser.y"
+#line 320 "src/foreign-pajek-parser.y"
     { (yyval.string)=(yyvsp[(1) - (1)].string); ;}
     break;
 
   case 55:
-#line 324 "igraph/src/foreign-pajek-parser.y"
+#line 324 "src/foreign-pajek-parser.y"
     { context->directed=1; ;}
     break;
 
   case 56:
-#line 325 "igraph/src/foreign-pajek-parser.y"
+#line 325 "src/foreign-pajek-parser.y"
     { context->directed=1; ;}
     break;
 
   case 60:
-#line 330 "igraph/src/foreign-pajek-parser.y"
+#line 330 "src/foreign-pajek-parser.y"
     { context->actedge++;
 	                  context->mode=2; ;}
     break;
 
   case 61:
-#line 331 "igraph/src/foreign-pajek-parser.y"
+#line 331 "src/foreign-pajek-parser.y"
     { 
   igraph_vector_push_back(context->vector, (yyvsp[(1) - (6)].intnum)-1);
   igraph_vector_push_back(context->vector, (yyvsp[(2) - (6)].intnum)-1); ;}
     break;
 
   case 64:
-#line 340 "igraph/src/foreign-pajek-parser.y"
+#line 340 "src/foreign-pajek-parser.y"
     { context->directed=0; ;}
     break;
 
   case 65:
-#line 341 "igraph/src/foreign-pajek-parser.y"
+#line 341 "src/foreign-pajek-parser.y"
     { context->directed=0; ;}
     break;
 
   case 69:
-#line 346 "igraph/src/foreign-pajek-parser.y"
+#line 346 "src/foreign-pajek-parser.y"
     { context->actedge++; 
 	                    context->mode=2; ;}
     break;
 
   case 70:
-#line 347 "igraph/src/foreign-pajek-parser.y"
+#line 347 "src/foreign-pajek-parser.y"
     { 
   igraph_vector_push_back(context->vector, (yyvsp[(1) - (6)].intnum)-1);
   igraph_vector_push_back(context->vector, (yyvsp[(2) - (6)].intnum)-1); ;}
     break;
 
   case 74:
-#line 356 "igraph/src/foreign-pajek-parser.y"
+#line 356 "src/foreign-pajek-parser.y"
     {
   igraph_i_pajek_add_numeric_edge_attribute("weight", (yyvsp[(1) - (1)].realnum), context);
 ;}
     break;
 
   case 78:
-#line 364 "igraph/src/foreign-pajek-parser.y"
+#line 364 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("color-red", (yyvsp[(2) - (4)].realnum), context);
        igraph_i_pajek_add_numeric_edge_attribute("color-green", (yyvsp[(3) - (4)].realnum), context);
@@ -2078,117 +2078,117 @@ yyreduce:
     break;
 
   case 79:
-#line 369 "igraph/src/foreign-pajek-parser.y"
+#line 369 "src/foreign-pajek-parser.y"
     { 
        igraph_i_pajek_add_numeric_edge_attribute("arrowsize", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 80:
-#line 372 "igraph/src/foreign-pajek-parser.y"
+#line 372 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("edgewidth", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 81:
-#line 375 "igraph/src/foreign-pajek-parser.y"
+#line 375 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("hook1", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 82:
-#line 378 "igraph/src/foreign-pajek-parser.y"
+#line 378 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("hook2", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 83:
-#line 381 "igraph/src/foreign-pajek-parser.y"
+#line 381 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("angle1", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 84:
-#line 384 "igraph/src/foreign-pajek-parser.y"
+#line 384 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("angle2", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 85:
-#line 387 "igraph/src/foreign-pajek-parser.y"
+#line 387 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("velocity1", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 86:
-#line 390 "igraph/src/foreign-pajek-parser.y"
+#line 390 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("velocity2", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 87:
-#line 393 "igraph/src/foreign-pajek-parser.y"
+#line 393 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("arrowpos", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 88:
-#line 396 "igraph/src/foreign-pajek-parser.y"
+#line 396 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("labelpos", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 89:
-#line 399 "igraph/src/foreign-pajek-parser.y"
+#line 399 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("labelangle", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 90:
-#line 402 "igraph/src/foreign-pajek-parser.y"
+#line 402 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("labelangle2", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 91:
-#line 405 "igraph/src/foreign-pajek-parser.y"
+#line 405 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("labeldegree", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 92:
-#line 408 "igraph/src/foreign-pajek-parser.y"
+#line 408 "src/foreign-pajek-parser.y"
     {		/* what is this??? */
        igraph_i_pajek_add_numeric_edge_attribute("arrowsize", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 93:
-#line 411 "igraph/src/foreign-pajek-parser.y"
+#line 411 "src/foreign-pajek-parser.y"
     {
        igraph_i_pajek_add_numeric_edge_attribute("fontsize", (yyvsp[(2) - (2)].realnum), context);
    ;}
     break;
 
   case 94:
-#line 416 "igraph/src/foreign-pajek-parser.y"
+#line 416 "src/foreign-pajek-parser.y"
     { context->mode=4; ;}
     break;
 
   case 95:
-#line 416 "igraph/src/foreign-pajek-parser.y"
+#line 416 "src/foreign-pajek-parser.y"
     {
       context->mode=2;
       igraph_i_pajek_add_string_edge_attribute("arrowtype", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -2196,12 +2196,12 @@ yyreduce:
     break;
 
   case 96:
-#line 420 "igraph/src/foreign-pajek-parser.y"
+#line 420 "src/foreign-pajek-parser.y"
     { context->mode=4; ;}
     break;
 
   case 97:
-#line 420 "igraph/src/foreign-pajek-parser.y"
+#line 420 "src/foreign-pajek-parser.y"
     {
       context->mode=2;
       igraph_i_pajek_add_string_edge_attribute("linepattern", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -2209,12 +2209,12 @@ yyreduce:
     break;
 
   case 98:
-#line 424 "igraph/src/foreign-pajek-parser.y"
+#line 424 "src/foreign-pajek-parser.y"
     { context->mode=4; ;}
     break;
 
   case 99:
-#line 424 "igraph/src/foreign-pajek-parser.y"
+#line 424 "src/foreign-pajek-parser.y"
     {
       context->mode=2;
       igraph_i_pajek_add_string_edge_attribute("label", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -2222,12 +2222,12 @@ yyreduce:
     break;
 
   case 100:
-#line 428 "igraph/src/foreign-pajek-parser.y"
+#line 428 "src/foreign-pajek-parser.y"
     { context->mode=4; ;}
     break;
 
   case 101:
-#line 428 "igraph/src/foreign-pajek-parser.y"
+#line 428 "src/foreign-pajek-parser.y"
     {
       context->mode=2;
       igraph_i_pajek_add_string_edge_attribute("labelcolor", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -2235,12 +2235,12 @@ yyreduce:
     break;
 
   case 102:
-#line 432 "igraph/src/foreign-pajek-parser.y"
+#line 432 "src/foreign-pajek-parser.y"
     { context->mode=4; ;}
     break;
 
   case 103:
-#line 432 "igraph/src/foreign-pajek-parser.y"
+#line 432 "src/foreign-pajek-parser.y"
     {
       context->mode=2;
       igraph_i_pajek_add_string_edge_attribute("color", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);
@@ -2248,22 +2248,22 @@ yyreduce:
     break;
 
   case 104:
-#line 438 "igraph/src/foreign-pajek-parser.y"
+#line 438 "src/foreign-pajek-parser.y"
     { context->mode=2; (yyval.string)=(yyvsp[(1) - (1)].string); ;}
     break;
 
   case 105:
-#line 440 "igraph/src/foreign-pajek-parser.y"
+#line 440 "src/foreign-pajek-parser.y"
     { context->directed=1; ;}
     break;
 
   case 112:
-#line 448 "igraph/src/foreign-pajek-parser.y"
+#line 448 "src/foreign-pajek-parser.y"
     { context->mode=0; context->actfrom=fabs((yyvsp[(1) - (1)].intnum))-1; ;}
     break;
 
   case 113:
-#line 450 "igraph/src/foreign-pajek-parser.y"
+#line 450 "src/foreign-pajek-parser.y"
     { 
   igraph_vector_push_back(context->vector, context->actfrom); 
   igraph_vector_push_back(context->vector, fabs((yyvsp[(1) - (1)].intnum))-1); 
@@ -2271,17 +2271,17 @@ yyreduce:
     break;
 
   case 114:
-#line 455 "igraph/src/foreign-pajek-parser.y"
+#line 455 "src/foreign-pajek-parser.y"
     { context->directed=0; ;}
     break;
 
   case 121:
-#line 463 "igraph/src/foreign-pajek-parser.y"
+#line 463 "src/foreign-pajek-parser.y"
     { context->mode=0; context->actfrom=fabs((yyvsp[(1) - (1)].intnum))-1; ;}
     break;
 
   case 122:
-#line 465 "igraph/src/foreign-pajek-parser.y"
+#line 465 "src/foreign-pajek-parser.y"
     { 
   igraph_vector_push_back(context->vector, context->actfrom); 
   igraph_vector_push_back(context->vector, fabs((yyvsp[(1) - (1)].intnum))-1); 
@@ -2289,7 +2289,7 @@ yyreduce:
     break;
 
   case 124:
-#line 474 "igraph/src/foreign-pajek-parser.y"
+#line 474 "src/foreign-pajek-parser.y"
     { context->actfrom=0; 
                          context->actto=0; 
                          context->directed=(context->vcount2==0);
@@ -2297,12 +2297,12 @@ yyreduce:
     break;
 
   case 127:
-#line 481 "igraph/src/foreign-pajek-parser.y"
+#line 481 "src/foreign-pajek-parser.y"
     { context->actfrom++; context->actto=0; ;}
     break;
 
   case 130:
-#line 485 "igraph/src/foreign-pajek-parser.y"
+#line 485 "src/foreign-pajek-parser.y"
     {
   if ((yyvsp[(1) - (1)].realnum) != 0) {
     if (context->vcount2==0) {
@@ -2323,31 +2323,31 @@ yyreduce:
     break;
 
   case 131:
-#line 505 "igraph/src/foreign-pajek-parser.y"
+#line 505 "src/foreign-pajek-parser.y"
     { (yyval.intnum)=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),
 					  igraph_pajek_yyget_leng(scanner)); ;}
     break;
 
   case 132:
-#line 508 "igraph/src/foreign-pajek-parser.y"
+#line 508 "src/foreign-pajek-parser.y"
     { (yyval.realnum)=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),
 					  igraph_pajek_yyget_leng(scanner)); ;}
     break;
 
   case 135:
-#line 513 "igraph/src/foreign-pajek-parser.y"
+#line 513 "src/foreign-pajek-parser.y"
     { (yyval.string).str=igraph_pajek_yyget_text(scanner); 
               (yyval.string).len=igraph_pajek_yyget_leng(scanner); ;}
     break;
 
   case 136:
-#line 515 "igraph/src/foreign-pajek-parser.y"
+#line 515 "src/foreign-pajek-parser.y"
     { (yyval.string).str=igraph_pajek_yyget_text(scanner); 
               (yyval.string).len=igraph_pajek_yyget_leng(scanner); ;}
     break;
 
   case 137:
-#line 517 "igraph/src/foreign-pajek-parser.y"
+#line 517 "src/foreign-pajek-parser.y"
     { (yyval.string).str=igraph_pajek_yyget_text(scanner)+1; 
                (yyval.string).len=igraph_pajek_yyget_leng(scanner)-2; ;}
     break;
@@ -2574,7 +2574,7 @@ yyreturn:
 }
 
 
-#line 520 "igraph/src/foreign-pajek-parser.y"
+#line 520 "src/foreign-pajek-parser.y"
 
 
 int igraph_pajek_yyerror(YYLTYPE* locp, 
diff --git a/src/foreign-pajek-parser.h b/src/foreign-pajek-parser.h
index e783d6f..0770ba4 100644
--- a/src/foreign-pajek-parser.h
+++ b/src/foreign-pajek-parser.h
@@ -144,7 +144,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 123 "igraph/src/foreign-pajek-parser.y"
+#line 123 "src/foreign-pajek-parser.y"
 {
   long int intnum;
   double   realnum;  
diff --git a/src/foreign.c b/src/foreign.c
index d5b2767..738ad5f 100644
--- a/src/foreign.c
+++ b/src/foreign.c
@@ -198,6 +198,7 @@ int igraph_read_graph_ncol(igraph_t *graph, FILE *instream,
   
   igraph_vector_t edges, ws;
   igraph_trie_t trie=IGRAPH_TRIE_NULL;
+  igraph_integer_t no_of_nodes;
   long int no_predefined=0;
   igraph_vector_ptr_t name, weight;
   igraph_vector_ptr_t *pname=0, *pweight=0;
@@ -272,8 +273,13 @@ int igraph_read_graph_ncol(igraph_t *graph, FILE *instream,
     VECTOR(weight)[0]=&weightrec;
   }
 
-  IGRAPH_CHECK(igraph_add_vertices(graph, (igraph_integer_t) 
-				   igraph_vector_max(&edges)+1, pname));
+  if (igraph_vector_empty(&edges)) {
+    no_of_nodes = 0;
+  } else {
+    no_of_nodes = igraph_vector_max(&edges)+1;
+  }
+
+  IGRAPH_CHECK(igraph_add_vertices(graph, no_of_nodes, pname));
   IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight));
 
   if (pname) {
@@ -3047,7 +3053,11 @@ int igraph_read_graph_dl(igraph_t *graph, FILE *instream,
   }
 
   /* Check number of vertices */
-  n=(long int) igraph_vector_max(&context.edges);
+  if (n2 > 0) {
+    n = (long int) igraph_vector_max(&context.edges);
+  } else {
+    n = 0;
+  }
   if (n >= context.n) {
     IGRAPH_WARNING("More vertices than specified in `DL' file");
     context.n=n;
diff --git a/src/games.c b/src/games.c
index 406c1be..413c233 100644
--- a/src/games.c
+++ b/src/games.c
@@ -99,6 +99,10 @@ int igraph_i_barabasi_game_bag(igraph_t *graph, igraph_integer_t n,
   long int i,j,k;
   long int bagsize, start_nodes, start_edges, new_edges, no_of_edges;
 
+  if (!directed) {
+    outpref = 1;
+  }
+
   start_nodes= start_from ? igraph_vcount(start_from) : 1;
   start_edges= start_from ? igraph_ecount(start_from) : 0;
   if (outseq) { 
@@ -203,6 +207,10 @@ int igraph_i_barabasi_game_psumtree_multiple(igraph_t *graph,
   igraph_vector_t degree;
   long int start_nodes, start_edges, new_edges, no_of_edges;
 
+  if (!directed) {
+    outpref = 1;
+  }
+
   start_nodes= start_from ? igraph_vcount(start_from) : 1;
   start_edges= start_from ? igraph_ecount(start_from) : 0;
   if (outseq) { 
@@ -305,6 +313,10 @@ int igraph_i_barabasi_game_psumtree(igraph_t *graph,
   igraph_vector_t degree;
   long int start_nodes, start_edges, new_edges, no_of_edges;
 
+  if (!directed) {
+    outpref = 1;
+  }
+
   start_nodes= start_from ? igraph_vcount(start_from) : 1;
   start_edges= start_from ? igraph_ecount(start_from) : 0;
   if (outseq) { 
@@ -425,7 +437,8 @@ int igraph_i_barabasi_game_psumtree(igraph_t *graph,
  * \param outpref Boolean, if true not only the in- but also the out-degree
  *        of a vertex increases its citation probability. Ie. the
  *        citation probability is determined by the total degree of
- *        the vertices.
+ *        the vertices. Ignored and assumed to be true if the graph
+ *        being generated is undirected.
  * \param A The probability that a vertex is cited is proportional to
  *        d^power+A, where d is its degree (see also the \p outpref
  *        argument), power and A are given by arguments. In the
@@ -483,10 +496,13 @@ int igraph_barabasi_game(igraph_t *graph, igraph_integer_t n,
   long int start_nodes= start_from ? igraph_vcount(start_from) : 0;
   long int newn= start_from ? n-start_nodes : n;
 
-  /* Fix an obscure parameterization */
+  /* Fix obscure parameterizations */
   if (outseq && igraph_vector_size(outseq) == 0) {
     outseq=0;
   }
+  if (!directed) {
+    outpref=1;
+  }
   
   /* Check arguments */
 
@@ -3863,4 +3879,254 @@ int igraph_k_regular_game(igraph_t *graph,
   return IGRAPH_SUCCESS;
 }
 
+/**
+ * \function igraph_correlated_game
+ * Generate pairs of correlated random graphs
+ *
+ * Sample a new graph by perturbing the adjacency matrix of a
+ * given graph and shuffling its vertices.
+ *
+ * \param old_graph The original graph.
+ * \param new_graph The new graph will be stored here.
+ * \param corr A scalar in the unit interval, the target Pearson
+ *        correlation between the adjacency matrices of the original the
+ *        generated graph (the adjacency matrix being used as a vector).
+ * \param p A numeric scalar, the probability of an edge between two
+ *        vertices, it must in the open (0,1) interval.
+ * \param permutation A permutation to apply to the vertices of the
+ *        generated graph. It can also be a null pointer, in which case
+ *        the vertices will not be permuted.
+ * \return Error code
+ *
+ * \sa \ref igraph_correlated_pair_game() for generating a pair
+ * of correlated random graphs in one go.
+ */
+
+int igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_graph,
+			   igraph_real_t corr, igraph_real_t p,
+			   const igraph_vector_t *permutation) {
+
+  int no_of_nodes=igraph_vcount(old_graph);
+  int no_of_edges=igraph_ecount(old_graph);
+  igraph_bool_t directed=igraph_is_directed(old_graph);
+  igraph_real_t no_of_all=directed ? no_of_nodes * (no_of_nodes-1) :
+    no_of_nodes * (no_of_nodes-1) / 2;
+  igraph_real_t no_of_missing=no_of_all - no_of_edges;
+  igraph_real_t q= p + corr * (1 - p);
+  igraph_real_t p_del= 1 - q;
+  igraph_real_t p_add= ((1 - q) * (p / (1 - p)));
+  igraph_vector_t add, delete, edges, newedges;
+  igraph_real_t last;
+  int p_e=0, p_a=0, p_d=0, no_add, no_del;
+  igraph_real_t inf=IGRAPH_INFINITY;
+  igraph_real_t next_e, next_a, next_d;
+  int i;
+
+  if (corr < -1 || corr > 1) {
+    IGRAPH_ERROR("Correlation must be in [-1,1] in correlated "
+		 "Erdos-Renyi game", IGRAPH_EINVAL);
+  }
+  if (p <= 0 || p >= 1) {
+    IGRAPH_ERROR("Edge probability must be in (0,1) in correlated "
+		 "Erdos-Renyi game", IGRAPH_EINVAL);
+  }
+  if (permutation) {
+    if (igraph_vector_size(permutation) != no_of_nodes) {
+      IGRAPH_ERROR("Invalid permutation length in correlated Erdos-Renyi game",
+		   IGRAPH_EINVAL);
+    }
+  }
+
+  /* Special cases */
+
+  if (corr == 0) {
+    return igraph_erdos_renyi_game(new_graph, IGRAPH_ERDOS_RENYI_GNP,
+				   no_of_nodes, p, directed,
+				   IGRAPH_NO_LOOPS);
+  }
+  if (corr == 1) {
+    /* We don't copy, because we don't need the attributes.... */
+    IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+    IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0));
+    if (permutation) {
+      int newec=igraph_vector_size(&edges);
+      for (i=0; i<newec; i++) {
+	int tmp=VECTOR(edges)[i];
+	VECTOR(edges)[i] = VECTOR(*permutation)[tmp];
+      }
+    }
+    IGRAPH_CHECK(igraph_create(new_graph, &edges, no_of_nodes, directed));
+    igraph_vector_destroy(&edges);
+    IGRAPH_FINALLY_CLEAN(1);
+    return 0;
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&newedges, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&add, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&delete, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges*2);
+
+  IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0));
+
+  RNG_BEGIN();
+
+  if (p_del > 0) {
+    last=RNG_GEOM(p_del);
+    while (last < no_of_edges) {
+      IGRAPH_CHECK(igraph_vector_push_back(&delete, last));
+      last += RNG_GEOM(p_del);
+      last += 1;
+    }
+  }
+  no_del=igraph_vector_size(&delete);
+
+  if (p_add > 0) {
+    last=RNG_GEOM(p_add);
+    while (last < no_of_missing) {
+      IGRAPH_CHECK(igraph_vector_push_back(&add, last));
+      last += RNG_GEOM(p_add);
+      last += 1;
+    }
+  }
+  no_add=igraph_vector_size(&add);
+
+  RNG_END();
+
+  IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0));
+
+  /* Now we are merging the original edges, the edges that are removed,
+     and the new edges. We have the following pointers:
+     - p_a: the next edge to add
+     - p_d: the next edge to delete
+     - p_e: the next original edge
+     - next_e: the code of the next edge in 'edges'
+     - next_a: the code of the next edge to add
+     - next_d: the code of the next edge to delete */
+
+#define D_CODE(f,t) (((t)==no_of_nodes-1 ? f : t) * no_of_nodes + (f))
+#define U_CODE(f,t) ((t) * ((t)-1) / 2 + (f))
+#define CODE(f,t) (directed ? D_CODE(f,t) : U_CODE(f,t))
+#define CODEE() (CODE(VECTOR(edges)[2*p_e], VECTOR(edges)[2*p_e+1]))
 
+  /* First we (re)code the edges to delete */
+
+  for (i=0; i<no_del; i++) {
+    int td=VECTOR(delete)[i];
+    int from=VECTOR(edges)[2*td];
+    int to=VECTOR(edges)[2*td+1];
+    VECTOR(delete)[i] = CODE(from, to);
+  }
+
+  IGRAPH_CHECK(igraph_vector_reserve(&newedges,
+				     (no_of_edges - no_del + no_add) * 2));
+
+  /* Now we can do the merge. Additional edges are tricky, because
+     the code must be shifted by the edges in the original graph. */
+
+#define UPD_E()								\
+  { if (p_e < no_of_edges) { next_e=CODEE(); } else { next_e = inf; } }
+#define UPD_A()								\
+  { if (p_a < no_add) { \
+      next_a = VECTOR(add)[p_a] + p_e; } else { next_a = inf; } }
+#define UPD_D()								\
+  { if (p_d < no_del) { \
+      next_d = VECTOR(delete)[p_d]; } else { next_d = inf; } }
+
+  UPD_E(); UPD_A(); UPD_D();
+
+  while (next_e != inf || next_a != inf || next_d != inf) {
+    if (next_e <= next_a && next_e < next_d) {
+
+      /* keep an edge */
+      IGRAPH_CHECK(igraph_vector_push_back(&newedges, VECTOR(edges)[2*p_e]));
+      IGRAPH_CHECK(igraph_vector_push_back(&newedges, VECTOR(edges)[2*p_e+1]));
+      p_e ++; UPD_E(); UPD_A()
+
+    } else if (next_e <= next_a && next_e == next_d) {
+
+      /* delete an edge */
+      p_e ++; UPD_E(); UPD_A();
+      p_d++; UPD_D();
+
+    } else {
+
+      /* add an edge */
+      int to, from;
+      if (directed) {
+	to = (int) floor(next_a / no_of_nodes);
+	from = (int) (next_a - ((igraph_real_t)to)*no_of_nodes);
+	if (from == to) { to=no_of_nodes-1; }
+      } else {
+	to = (int) floor((sqrt(8*next_a+1)+1)/2);
+	from = (int) (next_a-(((igraph_real_t)to)*(to-1))/2);
+      }
+      IGRAPH_CHECK(igraph_vector_push_back(&newedges, from));
+      IGRAPH_CHECK(igraph_vector_push_back(&newedges, to));
+      p_a++; UPD_A();
+
+    }
+  }
+
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&add);
+  igraph_vector_destroy(&delete);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  if (permutation) {
+    int newec=igraph_vector_size(&newedges);
+    for (i=0; i<newec; i++) {
+      int tmp=VECTOR(newedges)[i];
+      VECTOR(newedges)[i] = VECTOR(*permutation)[tmp];
+    }
+  }
+
+  IGRAPH_CHECK(igraph_create(new_graph, &newedges, no_of_nodes, directed));
+
+  igraph_vector_destroy(&newedges);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+#undef D_CODE
+#undef U_CODE
+#undef CODE
+#undef CODEE
+#undef UPD_E
+#undef UPD_A
+#undef UPD_D
+
+/**
+ * \function igraph_correlated_pair_game
+ * Generate pairs of correlated random graphs
+ *
+ * Sample two random graphs, with given correlation.
+ *
+ * \param graph1 The first graph will be stored here.
+ * \param graph2 The second graph will be stored here.
+ * \param n The number of vertices in both graphs.
+ * \param corr A scalar in the unit interval, the target Pearson
+ *        correlation between the adjacency matrices of the original the
+ *        generated graph (the adjacency matrix being used as a vector).
+ * \param p A numeric scalar, the probability of an edge between two
+ *        vertices, it must in the open (0,1) interval.
+ * \param directed Whether to generate directed graphs.
+ * \param permutation A permutation to apply to the vertices of the
+ *        second graph. It can also be a null pointer, in which case
+ *        the vertices will not be permuted.
+ * \return Error code
+ *
+ * \sa \ref igraph_correlated_game() for generating a correlated pair
+ * to a given graph.
+ */
+
+int igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2,
+				int n, igraph_real_t corr, igraph_real_t p,
+				igraph_bool_t directed,
+				const igraph_vector_t *permutation) {
+
+  IGRAPH_CHECK(igraph_erdos_renyi_game(graph1, IGRAPH_ERDOS_RENYI_GNP, n, p,
+				       directed, IGRAPH_NO_LOOPS));
+  IGRAPH_CHECK(igraph_correlated_game(graph1, graph2, corr, p, permutation));
+  return 0;
+}
diff --git a/src/gengraph_box_list.h b/src/gengraph_box_list.h
index 0711a07..b3bc4f1 100644
--- a/src/gengraph_box_list.h
+++ b/src/gengraph_box_list.h
@@ -28,6 +28,8 @@
 #ifndef _BOX_LIST_H
 #define _BOX_LIST_H
 
+#define register
+
 namespace gengraph {
 
 class box_list {
diff --git a/src/gengraph_definitions.h b/src/gengraph_definitions.h
index a0209bf..80e177a 100644
--- a/src/gengraph_definitions.h
+++ b/src/gengraph_definitions.h
@@ -21,6 +21,10 @@
 #ifndef DEFINITIONS_H
 #define DEFINITIONS_H
 
+#ifndef register
+#define register
+#endif
+
 #include <stdio.h>
 #include <math.h>
 #include <string.h>
diff --git a/src/gengraph_graph_molloy_hash.cpp b/src/gengraph_graph_molloy_hash.cpp
index b1825e0..0d2dd18 100644
--- a/src/gengraph_graph_molloy_hash.cpp
+++ b/src/gengraph_graph_molloy_hash.cpp
@@ -906,9 +906,9 @@ bool graph_molloy_hash::make_connected() {
   return(trees == ffub);
 }
 
-long long graph_molloy_hash::slow_connected_shuffle(long long times) {
+int64_t graph_molloy_hash::slow_connected_shuffle(int64_t times) {
   assert(verify());
-  long long nb_swaps = 0;
+  int64_t nb_swaps = 0;
   int T = 1;
 
   while(times>nb_swaps) {
diff --git a/src/gengraph_graph_molloy_optimized.cpp b/src/gengraph_graph_molloy_optimized.cpp
index ab5be90..4c4ed1e 100644
--- a/src/gengraph_graph_molloy_optimized.cpp
+++ b/src/gengraph_graph_molloy_optimized.cpp
@@ -34,6 +34,10 @@
 #include "igraph_statusbar.h"
 #include "igraph_progress.h"
 
+#ifndef register
+#define register
+#endif
+
 using namespace std;
 
 namespace gengraph {
@@ -1879,12 +1883,12 @@ double graph_molloy_opt::effective_K(int K, int quality) {
 
 /***** NOT USED ANYMORE (Modif 22/04/2005) ******
 
-long long *graph_molloy_opt::vertex_betweenness_usp(bool trivial_paths) {
+int64_t *graph_molloy_opt::vertex_betweenness_usp(bool trivial_paths) {
   if(VERBOSE()) fprintf(stderr,"Computing vertex betweenness USP...");
   int i;
   unsigned char *dist = new unsigned char[n];
   int *buff = new int[n];
-  long long *b = new long long[n];
+  int64_t *b = new int64_t[n];
   int *bb = new int[n];
   int *dd = new int[max_degree()];
   for(i=0; i<n; i++) b[i]=0;
@@ -1907,7 +1911,7 @@ long long *graph_molloy_opt::vertex_betweenness_usp(bool trivial_paths) {
       if(trivial_paths || w!=v0) bb[w] += bb[v]+1;
       if(trivial_paths) bb[v]++;
     }
-    for(i=0; i<nb_vertices; i++) b[buff[i]]+=(long long)(bb[buff[i]]);
+    for(i=0; i<nb_vertices; i++) b[buff[i]]+=(int64_t)(bb[buff[i]]);
   }
   delete[] dist;
   delete[] buff;
@@ -1916,12 +1920,12 @@ long long *graph_molloy_opt::vertex_betweenness_usp(bool trivial_paths) {
   return b;
 }
 
-long long *graph_molloy_opt::vertex_betweenness_rsp(bool trivial_paths) {
+int64_t *graph_molloy_opt::vertex_betweenness_rsp(bool trivial_paths) {
   if(VERBOSE()) fprintf(stderr,"Computing vertex betweenness RSP...");
   int i;
   unsigned char *dist = new unsigned char[n];
   int *buff = new int[n];
-  long long *b = new long long[n];
+  int64_t *b = new int64_t[n];
   int *bb = new int[n];
   int *dd = new int[max_degree()];
   for(i=0; i<n; i++) b[i]=0;
@@ -1957,7 +1961,7 @@ long long *graph_molloy_opt::vertex_betweenness_rsp(bool trivial_paths) {
       }
       if(trivial_paths) bb[v]++;
     }
-    for(i=0; i<nb_vertices; i++) b[buff[i]]+=(long long)(bb[buff[i]]);
+    for(i=0; i<nb_vertices; i++) b[buff[i]]+=(int64_t)(bb[buff[i]]);
   }
   delete[] dist;
   delete[] buff;
diff --git a/src/gengraph_qsort.h b/src/gengraph_qsort.h
index 7996a37..66ee4b2 100644
--- a/src/gengraph_qsort.h
+++ b/src/gengraph_qsort.h
@@ -24,6 +24,10 @@
 #include <assert.h>
 #include <stdio.h>
 
+#ifndef register
+#define register
+#endif
+
 namespace gengraph {
 
 //___________________________________________________________________________
diff --git a/src/gengraph_vertex_cover.h b/src/gengraph_vertex_cover.h
index 314915b..cf09e87 100644
--- a/src/gengraph_vertex_cover.h
+++ b/src/gengraph_vertex_cover.h
@@ -29,6 +29,10 @@
 
 #include "gengraph_box_list.h"
 
+#ifndef register
+#define register
+#endif
+
 namespace gengraph { 
 
 void vertex_cover(int n, int *links, int *deg, int **neigh = NULL) {
diff --git a/src/glpenv01.c b/src/glpenv01.c
deleted file mode 100644
index d1afbe4..0000000
--- a/src/glpenv01.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/* glpenv01.c (environment initialization/termination) */
-
-/***********************************************************************
-*  This code is part of GLPK (GNU Linear Programming Kit).
-*
-*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
-*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
-*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
-*  E-mail: <mao at gnu.org>.
-*
-*  GLPK 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.
-*
-*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>.
-***********************************************************************/
-
-#ifdef __clang__
-#pragma clang diagnostic ignored "-Wsign-conversion"
-#pragma clang diagnostic ignored "-Wint-conversion"
-#endif
-
-#include "glpapi.h"
-#include "igraph_error.h"
-
-/***********************************************************************
-*  NAME
-*
-*  glp_init_env - initialize GLPK environment
-*
-*  SYNOPSIS
-*
-*  int glp_init_env(void);
-*
-*  DESCRIPTION
-*
-*  The routine glp_init_env initializes the GLPK environment. Normally
-*  the application program does not need to call this routine, because
-*  it is called automatically on the first call to any API routine.
-*
-*  RETURNS
-*
-*  The routine glp_init_env returns one of the following codes:
-*
-*  0 - initialization successful;
-*  1 - environment has been already initialized;
-*  2 - initialization failed (insufficient memory);
-*  3 - initialization failed (unsupported programming model). */
-
-int glp_init_env(void)
-{     ENV *env;
-      int ok;
-      /* check if the programming model is supported */
-      ok = (CHAR_BIT == 8 && sizeof(char) == 1 &&
-         sizeof(short) == 2 && sizeof(int) == 4 &&
-         (sizeof(void *) == 4 || sizeof(void *) == 8));
-      if (!ok) return 3;
-      /* check if the environment is already initialized */
-      if (tls_get_ptr() != NULL) return 1;
-      /* allocate and initialize the environment block */
-      env = malloc(sizeof(ENV));
-      if (env == NULL) return 2;
-      env->magic = ENV_MAGIC;
-      sprintf(env->version, "%d.%d",
-         GLP_MAJOR_VERSION, GLP_MINOR_VERSION);
-      env->term_buf = malloc(TERM_BUF_SIZE);
-      if (env->term_buf == NULL)
-      {  free(env);
-         return 2;
-      }
-      env->term_out = GLP_ON;
-      env->term_hook = NULL;
-      env->term_info = NULL;
-      env->tee_file = NULL;
-      env->err_file = "";
-      env->err_line = 0;
-      env->err_hook = NULL;
-      env->err_info = NULL;
-      env->mem_limit.hi = 0x7FFFFFFF, env->mem_limit.lo = 0xFFFFFFFF;
-      env->mem_ptr = NULL;
-      env->mem_count = env->mem_cpeak = 0;
-      env->mem_total = env->mem_tpeak = xlset(0);
-      env->file_ptr = NULL;
-      env->ioerr_msg = malloc(IOERR_MSG_SIZE);
-      if (env->ioerr_msg == NULL)
-      {  free(env->term_buf);
-         free(env);
-         return 2;
-      }
-      strcpy(env->ioerr_msg, "No error");
-      env->h_odbc = env->h_mysql = NULL;
-      /* save pointer to the environment block */
-      tls_set_ptr(env);
-      /* initialization successful */
-      return 0;
-}
-
-/***********************************************************************
-*  NAME
-*
-*  get_env_ptr - retrieve pointer to environment block
-*
-*  SYNOPSIS
-*
-*  #include "glpenv.h"
-*  ENV *get_env_ptr(void);
-*
-*  DESCRIPTION
-*
-*  The routine get_env_ptr retrieves and returns a pointer to the GLPK
-*  environment block.
-*
-*  If the GLPK environment has not been initialized yet, the routine
-*  performs initialization. If initialization fails, the routine prints
-*  an error message to stderr and terminates the program.
-*
-*  RETURNS
-*
-*  The routine returns a pointer to the environment block. */
-
-ENV *get_env_ptr(void)
-{     ENV *env = tls_get_ptr();
-      /* check if the environment has been initialized */
-      if (env == NULL)
-      {  /* not initialized yet; perform initialization */
-         if (glp_init_env() != 0)
-         {  /* initialization failed; display an error message */
-	   IGRAPH_ERROR("GLPK initialization failed", IGRAPH_EGLP);
-         }
-         /* initialization successful; retrieve the pointer */
-         env = tls_get_ptr();
-      }
-      /* check if the environment block is valid */
-      if (env->magic != ENV_MAGIC)
-      {  
-	IGRAPH_ERROR("Invalid GLPK environment", IGRAPH_EGLP);
-      }
-      return env;
-}
-
-/***********************************************************************
-*  NAME
-*
-*  glp_version - determine library version
-*
-*  SYNOPSIS
-*
-*  const char *glp_version(void);
-*
-*  RETURNS
-*
-*  The routine glp_version returns a pointer to a null-terminated
-*  character string, which specifies the version of the GLPK library in
-*  the form "X.Y", where X is the major version number, and Y is the
-*  minor version number, for example, "4.16". */
-
-const char *glp_version(void)
-{     ENV *env = get_env_ptr();
-      return env->version;
-}
-
-/***********************************************************************
-*  NAME
-*
-*  glp_free_env - free GLPK environment
-*
-*  SYNOPSIS
-*
-*  int glp_free_env(void);
-*
-*  DESCRIPTION
-*
-*  The routine glp_free_env frees all resources used by GLPK routines
-*  (memory blocks, etc.) which are currently still in use.
-*
-*  Normally the application program does not need to call this routine,
-*  because GLPK routines always free all unused resources. However, if
-*  the application program even has deleted all problem objects, there
-*  will be several memory blocks still allocated for the library needs.
-*  For some reasons the application program may want GLPK to free this
-*  memory, in which case it should call glp_free_env.
-*
-*  Note that a call to glp_free_env invalidates all problem objects as
-*  if no GLPK routine were called.
-*
-*  RETURNS
-*
-*  0 - termination successful;
-*  1 - environment is inactive (was not initialized). */
-
-int glp_free_env(void)
-{     ENV *env = tls_get_ptr();
-      MEM *desc;
-      /* check if the environment is active */
-      if (env == NULL) return 1;
-      /* check if the environment block is valid */
-      if (env->magic != ENV_MAGIC)
-      {  
-	 IGRAPH_ERROR("Invalid GLPK environment", IGRAPH_EGLP);
-      }
-      /* close handles to shared libraries */
-      if (env->h_odbc != NULL)
-         xdlclose(env->h_odbc);
-      if (env->h_mysql != NULL)
-         xdlclose(env->h_mysql);
-      /* close streams which are still open */
-      while (env->file_ptr != NULL)
-         xfclose(env->file_ptr);
-      /* free memory blocks which are still allocated */
-      while (env->mem_ptr != NULL)
-      {  desc = env->mem_ptr;
-         env->mem_ptr = desc->next;
-         free(desc);
-      }
-      /* invalidate the environment block */
-      env->magic = -1;
-      /* free memory allocated to the environment block */
-      free(env->term_buf);
-      free(env->ioerr_msg);
-      free(env);
-      /* reset a pointer to the environment block */
-      tls_set_ptr(NULL);
-      /* termination successful */
-      return 0;
-}
-
-/* eof */
diff --git a/src/glpk/COPYING b/src/glpk/COPYING
new file mode 100644
index 0000000..35ca8a5
--- /dev/null
+++ b/src/glpk/COPYING
@@ -0,0 +1,676 @@
+
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
diff --git a/src/glpk/README b/src/glpk/README
new file mode 100644
index 0000000..c60e48f
--- /dev/null
+++ b/src/glpk/README
@@ -0,0 +1,39 @@
+                                                     Olga K. gewidmet
+
+GLPK (GNU Linear Programming Kit) Version 4.45
+
+Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+E-mail: <mao at gnu.org>.
+
+GLPK is part of the GNU Project released under the aegis of GNU.
+
+GLPK 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.
+
+See the file COPYING for the GNU General Public License.
+
+See the file INSTALL for compilation and installation instructions.
+
+The GLPK package is a set of routines written in ANSI C and organized
+in the form of a callable library. This package is intended for solving
+large-scale linear programming (LP), mixed integer linear programming
+(MIP), and other related problems.
+
+The GLPK package includes the following main components:
+
+* implementation of the simplex method;
+* implementation of the exact simplex method based on bignum (rational)
+  arithmetic;
+* implementation of the primal-dual interior-point method;
+* implementation of the branch-and-cut method;
+* application program interface (API);
+* GNU MathProg modeling language (a subset of AMPL);
+* GLPSOL, a stand-alone LP/MIP solver.
+
+See GLPK webpage <http://www.gnu.org/software/glpk/glpk.html>.
+
+Please report bugs to <bug-glpk at gnu.org>.
diff --git a/src/glpk/amd/COPYING b/src/glpk/amd/COPYING
new file mode 100644
index 0000000..84bba36
--- /dev/null
+++ b/src/glpk/amd/COPYING
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/glpk/amd/README b/src/glpk/amd/README
new file mode 100644
index 0000000..de950eb
--- /dev/null
+++ b/src/glpk/amd/README
@@ -0,0 +1,58 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+      are used with GLPK.
+
+      The original code was modified according to GLPK requirements by
+      Andrew Makhorin <mao at gnu.org>.
+************************************************************************
+AMD Version 2.2, Copyright (C) 2007 by Timothy A. Davis,
+Patrick R. Amestoy, and Iain S. Duff.  All Rights Reserved.
+
+Description:
+
+   AMD is a set of routines for pre-ordering sparse matrices prior to
+   Cholesky or LU factorization, using the approximate minimum degree
+   ordering algorithm.  Written in ANSI/ISO C with a MATLAB interface,
+   and in Fortran 77.
+
+Authors:
+
+   Timothy A. Davis (davis at cise.ufl.edu), University of Florida.
+   Patrick R. Amestoy, ENSEEIHT, Toulouse, France.
+   Iain S. Duff, Rutherford Appleton Laboratory, UK.
+
+AMD License:
+
+   Your use or distribution of AMD or any modified version of AMD
+   implies that you agree to this License.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+   USA.
+
+   Permission is hereby granted to use or copy this program under the
+   terms of the GNU LGPL, provided that the Copyright, this License,
+   and the Availability of the original version is retained on all
+   copies.  User documentation of any code that uses this code or any
+   modified version of this code must cite the Copyright, this License,
+   the Availability note, and "Used by permission."  Permission to
+   modify the code and to distribute modified code is granted, provided
+   the Copyright, this License, and the Availability note are retained,
+   and a notice that the code was modified is included.
+
+   AMD is available under alternate licences; contact T. Davis for
+   details.
+
+Availability:
+
+    http://www.cise.ufl.edu/research/sparse/amd
diff --git a/src/amd_1.c b/src/glpk/amd/amd_1.c
similarity index 100%
rename from src/amd_1.c
rename to src/glpk/amd/amd_1.c
diff --git a/src/amd_2.c b/src/glpk/amd/amd_2.c
similarity index 100%
rename from src/amd_2.c
rename to src/glpk/amd/amd_2.c
diff --git a/src/amd_aat.c b/src/glpk/amd/amd_aat.c
similarity index 100%
rename from src/amd_aat.c
rename to src/glpk/amd/amd_aat.c
diff --git a/src/amd_control.c b/src/glpk/amd/amd_control.c
similarity index 100%
rename from src/amd_control.c
rename to src/glpk/amd/amd_control.c
diff --git a/src/amd_defaults.c b/src/glpk/amd/amd_defaults.c
similarity index 100%
rename from src/amd_defaults.c
rename to src/glpk/amd/amd_defaults.c
diff --git a/src/amd_dump.c b/src/glpk/amd/amd_dump.c
similarity index 100%
rename from src/amd_dump.c
rename to src/glpk/amd/amd_dump.c
diff --git a/src/amd_info.c b/src/glpk/amd/amd_info.c
similarity index 100%
rename from src/amd_info.c
rename to src/glpk/amd/amd_info.c
diff --git a/src/amd_order.c b/src/glpk/amd/amd_order.c
similarity index 100%
rename from src/amd_order.c
rename to src/glpk/amd/amd_order.c
diff --git a/src/amd_post_tree.c b/src/glpk/amd/amd_post_tree.c
similarity index 100%
rename from src/amd_post_tree.c
rename to src/glpk/amd/amd_post_tree.c
diff --git a/src/amd_postorder.c b/src/glpk/amd/amd_postorder.c
similarity index 100%
rename from src/amd_postorder.c
rename to src/glpk/amd/amd_postorder.c
diff --git a/src/amd_preprocess.c b/src/glpk/amd/amd_preprocess.c
similarity index 100%
rename from src/amd_preprocess.c
rename to src/glpk/amd/amd_preprocess.c
diff --git a/src/amd_valid.c b/src/glpk/amd/amd_valid.c
similarity index 100%
rename from src/amd_valid.c
rename to src/glpk/amd/amd_valid.c
diff --git a/src/glpk/colamd/COPYING b/src/glpk/colamd/COPYING
new file mode 100644
index 0000000..84bba36
--- /dev/null
+++ b/src/glpk/colamd/COPYING
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library 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
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/glpk/colamd/README b/src/glpk/colamd/README
new file mode 100644
index 0000000..a365059
--- /dev/null
+++ b/src/glpk/colamd/README
@@ -0,0 +1,98 @@
+NOTE: Files in this subdirectory are NOT part of the GLPK package, but
+      are used with GLPK.
+
+      The original code was modified according to GLPK requirements by
+      Andrew Makhorin <mao at gnu.org>.
+************************************************************************
+COLAMD/SYMAMD Version 2.7, Copyright (C) 1998-2007, Timothy A. Davis,
+All Rights Reserved.
+
+Description:
+
+   colamd:  an approximate minimum degree column ordering algorithm,
+            for LU factorization of symmetric or unsymmetric matrices,
+            QR factorization, least squares, interior point methods for
+            linear programming problems, and other related problems.
+
+   symamd:  an approximate minimum degree ordering algorithm for
+            Cholesky factorization of symmetric matrices.
+
+Purpose:
+
+   Colamd computes a permutation Q such that the Cholesky factorization
+   of (AQ)'(AQ) has less fill-in and requires fewer floating point
+   operations than A'A.  This also provides a good ordering for sparse
+   partial pivoting methods, P(AQ) = LU, where Q is computed prior to
+   numerical factorization, and P is computed during numerical
+   factorization via conventional partial pivoting with row
+   interchanges.  Colamd is the column ordering method used in SuperLU,
+   part of the ScaLAPACK library.  It is also available as built-in
+   function in MATLAB Version 6, available from MathWorks, Inc.
+   (http://www.mathworks.com).  This routine can be used in place of
+   colmmd in MATLAB.
+
+   Symamd computes a permutation P of a symmetric matrix A such that
+   the Cholesky factorization of PAP' has less fill-in and requires
+   fewer floating point operations than A.  Symamd constructs a matrix
+   M such that M'M has the same nonzero pattern of A, and then orders
+   the columns of M using colmmd.  The column ordering of M is then
+   returned as the row and column ordering P of A.
+
+Authors:
+
+   The authors of the code itself are Stefan I. Larimore and Timothy A.
+   Davis (davis at cise.ufl.edu), University of Florida.  The algorithm
+   was developed in collaboration with John Gilbert, Xerox PARC, and
+   Esmond Ng, Oak Ridge National Laboratory.
+
+Acknowledgements:
+
+   This work was supported by the National Science Foundation, under
+   grants DMS-9504974 and DMS-9803599.
+
+License:
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   This library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+   USA.
+
+   Permission is hereby granted to use or copy this program under the
+   terms of the GNU LGPL, provided that the Copyright, this License,
+   and the Availability of the original version is retained on all
+   copies.  User documentation of any code that uses this code or any
+   modified version of this code must cite the Copyright, this License,
+   the Availability note, and "Used by permission."  Permission to
+   modify the code and to distribute modified code is granted, provided
+   the Copyright, this License, and the Availability note are retained,
+   and a notice that the code was modified is included.
+
+   COLAMD is also available under alternate licenses, contact T. Davis
+   for details.
+
+Availability:
+
+   The colamd/symamd library is available at:
+
+   http://www.cise.ufl.edu/research/sparse/colamd/
+
+References:
+
+   T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, An approximate
+   column minimum degree ordering algorithm, ACM Transactions on
+   Mathematical Software, vol. 30, no. 3., pp. 353-376, 2004.
+
+   T. A. Davis, J. R. Gilbert, S. Larimore, E. Ng, Algorithm 836:
+   COLAMD, an approximate column minimum degree ordering algorithm, ACM
+   Transactions on Mathematical Software, vol. 30, no. 3., pp. 377-380,
+   2004.
diff --git a/src/colamd.c b/src/glpk/colamd/colamd.c
similarity index 100%
rename from src/colamd.c
rename to src/glpk/colamd/colamd.c
diff --git a/src/glpapi01.c b/src/glpk/glpapi01.c
similarity index 100%
rename from src/glpapi01.c
rename to src/glpk/glpapi01.c
diff --git a/src/glpapi02.c b/src/glpk/glpapi02.c
similarity index 100%
rename from src/glpapi02.c
rename to src/glpk/glpapi02.c
diff --git a/src/glpapi03.c b/src/glpk/glpapi03.c
similarity index 100%
rename from src/glpapi03.c
rename to src/glpk/glpapi03.c
diff --git a/src/glpapi04.c b/src/glpk/glpapi04.c
similarity index 100%
rename from src/glpapi04.c
rename to src/glpk/glpapi04.c
diff --git a/src/glpapi05.c b/src/glpk/glpapi05.c
similarity index 100%
rename from src/glpapi05.c
rename to src/glpk/glpapi05.c
diff --git a/src/glpapi06.c b/src/glpk/glpapi06.c
similarity index 100%
rename from src/glpapi06.c
rename to src/glpk/glpapi06.c
diff --git a/src/glpapi07.c b/src/glpk/glpapi07.c
similarity index 100%
rename from src/glpapi07.c
rename to src/glpk/glpapi07.c
diff --git a/src/glpapi08.c b/src/glpk/glpapi08.c
similarity index 100%
rename from src/glpapi08.c
rename to src/glpk/glpapi08.c
diff --git a/src/glpapi09.c b/src/glpk/glpapi09.c
similarity index 100%
rename from src/glpapi09.c
rename to src/glpk/glpapi09.c
diff --git a/src/glpapi10.c b/src/glpk/glpapi10.c
similarity index 100%
rename from src/glpapi10.c
rename to src/glpk/glpapi10.c
diff --git a/src/glpapi11.c b/src/glpk/glpapi11.c
similarity index 100%
rename from src/glpapi11.c
rename to src/glpk/glpapi11.c
diff --git a/src/glpapi12.c b/src/glpk/glpapi12.c
similarity index 100%
rename from src/glpapi12.c
rename to src/glpk/glpapi12.c
diff --git a/src/glpapi13.c b/src/glpk/glpapi13.c
similarity index 100%
rename from src/glpapi13.c
rename to src/glpk/glpapi13.c
diff --git a/src/glpapi14.c b/src/glpk/glpapi14.c
similarity index 100%
rename from src/glpapi14.c
rename to src/glpk/glpapi14.c
diff --git a/src/glpapi15.c b/src/glpk/glpapi15.c
similarity index 100%
rename from src/glpapi15.c
rename to src/glpk/glpapi15.c
diff --git a/src/glpapi16.c b/src/glpk/glpapi16.c
similarity index 100%
rename from src/glpapi16.c
rename to src/glpk/glpapi16.c
diff --git a/src/glpapi17.c b/src/glpk/glpapi17.c
similarity index 100%
rename from src/glpapi17.c
rename to src/glpk/glpapi17.c
diff --git a/src/glpapi18.c b/src/glpk/glpapi18.c
similarity index 100%
rename from src/glpapi18.c
rename to src/glpk/glpapi18.c
diff --git a/src/glpapi19.c b/src/glpk/glpapi19.c
similarity index 100%
rename from src/glpapi19.c
rename to src/glpk/glpapi19.c
diff --git a/src/glpavl.c b/src/glpk/glpavl.c
similarity index 100%
rename from src/glpavl.c
rename to src/glpk/glpavl.c
diff --git a/src/glpbfd.c b/src/glpk/glpbfd.c
similarity index 100%
rename from src/glpbfd.c
rename to src/glpk/glpbfd.c
diff --git a/src/glpbfx.c b/src/glpk/glpbfx.c
similarity index 100%
rename from src/glpbfx.c
rename to src/glpk/glpbfx.c
diff --git a/src/glpcpx.c b/src/glpk/glpcpx.c
similarity index 100%
rename from src/glpcpx.c
rename to src/glpk/glpcpx.c
diff --git a/src/glpdmp.c b/src/glpk/glpdmp.c
similarity index 100%
rename from src/glpdmp.c
rename to src/glpk/glpdmp.c
diff --git a/src/glpdmx.c b/src/glpk/glpdmx.c
similarity index 100%
rename from src/glpdmx.c
rename to src/glpk/glpdmx.c
diff --git a/src/glpk/glpenv01.c b/src/glpk/glpenv01.c
new file mode 100644
index 0000000..a2833a3
--- /dev/null
+++ b/src/glpk/glpenv01.c
@@ -0,0 +1,238 @@
+/* glpenv01.c (environment initialization/termination) */
+
+/***********************************************************************
+*  This code is part of GLPK (GNU Linear Programming Kit).
+*
+*  Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+*  2009, 2010 Andrew Makhorin, Department for Applied Informatics,
+*  Moscow Aviation Institute, Moscow, Russia. All rights reserved.
+*  E-mail: <mao at gnu.org>.
+*
+*  GLPK 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.
+*
+*  GLPK 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 GLPK. If not, see <http://www.gnu.org/licenses/>.
+***********************************************************************/
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wsign-conversion"
+#pragma clang diagnostic ignored "-Wint-conversion"
+#endif
+
+#include "glpapi.h"
+#include "igraph_error.h"
+
+/***********************************************************************
+*  NAME
+*
+*  glp_init_env - initialize GLPK environment
+*
+*  SYNOPSIS
+*
+*  int glp_init_env(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_init_env initializes the GLPK environment. Normally
+*  the application program does not need to call this routine, because
+*  it is called automatically on the first call to any API routine.
+*
+*  RETURNS
+*
+*  The routine glp_init_env returns one of the following codes:
+*
+*  0 - initialization successful;
+*  1 - environment has been already initialized;
+*  2 - initialization failed (insufficient memory);
+*  3 - initialization failed (unsupported programming model). */
+
+int glp_init_env(void)
+{     ENV *env;
+      int ok;
+      /* check if the programming model is supported */
+      ok = (CHAR_BIT == 8 && sizeof(char) == 1 &&
+         sizeof(short) == 2 && sizeof(int) == 4 &&
+         (sizeof(void *) == 4 || sizeof(void *) == 8));
+      if (!ok) return 3;
+      /* check if the environment is already initialized */
+      if (tls_get_ptr() != NULL) return 1;
+      /* allocate and initialize the environment block */
+      env = malloc(sizeof(ENV));
+      if (env == NULL) return 2;
+      env->magic = ENV_MAGIC;
+      sprintf(env->version, "%d.%d",
+         GLP_MAJOR_VERSION, GLP_MINOR_VERSION);
+      env->term_buf = malloc(TERM_BUF_SIZE);
+      if (env->term_buf == NULL)
+      {  free(env);
+         return 2;
+      }
+      env->term_out = GLP_ON;
+      env->term_hook = NULL;
+      env->term_info = NULL;
+      env->tee_file = NULL;
+      env->err_file = "";
+      env->err_line = 0;
+      env->err_hook = NULL;
+      env->err_info = NULL;
+      env->mem_limit.hi = 0x7FFFFFFF, env->mem_limit.lo = 0xFFFFFFFF;
+      env->mem_ptr = NULL;
+      env->mem_count = env->mem_cpeak = 0;
+      env->mem_total = env->mem_tpeak = xlset(0);
+      env->file_ptr = NULL;
+      env->ioerr_msg = malloc(IOERR_MSG_SIZE);
+      if (env->ioerr_msg == NULL)
+      {  free(env->term_buf);
+         free(env);
+         return 2;
+      }
+      strcpy(env->ioerr_msg, "No error");
+      env->h_odbc = env->h_mysql = NULL;
+      /* save pointer to the environment block */
+      tls_set_ptr(env);
+      /* initialization successful */
+      return 0;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  get_env_ptr - retrieve pointer to environment block
+*
+*  SYNOPSIS
+*
+*  #include "glpenv.h"
+*  ENV *get_env_ptr(void);
+*
+*  DESCRIPTION
+*
+*  The routine get_env_ptr retrieves and returns a pointer to the GLPK
+*  environment block.
+*
+*  If the GLPK environment has not been initialized yet, the routine
+*  performs initialization. If initialization fails, the routine prints
+*  an error message to stderr and terminates the program.
+*
+*  RETURNS
+*
+*  The routine returns a pointer to the environment block. */
+
+ENV *get_env_ptr(void)
+{     ENV *env = tls_get_ptr();
+      /* check if the environment has been initialized */
+      if (env == NULL)
+      {  /* not initialized yet; perform initialization */
+         if (glp_init_env() != 0)
+         {  /* initialization failed; display an error message */
+	   igraph_error("GLPK initialization failed", __FILE__, __LINE__,
+			IGRAPH_EGLP);
+	   return NULL;
+         }
+         /* initialization successful; retrieve the pointer */
+         env = tls_get_ptr();
+      }
+      /* check if the environment block is valid */
+      if (env->magic != ENV_MAGIC)
+      {  
+	igraph_error("Invalid GLPK environment", __FILE__, __LINE__,
+		     IGRAPH_EGLP);
+	return NULL;
+      }
+      return env;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_version - determine library version
+*
+*  SYNOPSIS
+*
+*  const char *glp_version(void);
+*
+*  RETURNS
+*
+*  The routine glp_version returns a pointer to a null-terminated
+*  character string, which specifies the version of the GLPK library in
+*  the form "X.Y", where X is the major version number, and Y is the
+*  minor version number, for example, "4.16". */
+
+const char *glp_version(void)
+{     ENV *env = get_env_ptr();
+      return env->version;
+}
+
+/***********************************************************************
+*  NAME
+*
+*  glp_free_env - free GLPK environment
+*
+*  SYNOPSIS
+*
+*  int glp_free_env(void);
+*
+*  DESCRIPTION
+*
+*  The routine glp_free_env frees all resources used by GLPK routines
+*  (memory blocks, etc.) which are currently still in use.
+*
+*  Normally the application program does not need to call this routine,
+*  because GLPK routines always free all unused resources. However, if
+*  the application program even has deleted all problem objects, there
+*  will be several memory blocks still allocated for the library needs.
+*  For some reasons the application program may want GLPK to free this
+*  memory, in which case it should call glp_free_env.
+*
+*  Note that a call to glp_free_env invalidates all problem objects as
+*  if no GLPK routine were called.
+*
+*  RETURNS
+*
+*  0 - termination successful;
+*  1 - environment is inactive (was not initialized). */
+
+int glp_free_env(void)
+{     ENV *env = tls_get_ptr();
+      MEM *desc;
+      /* check if the environment is active */
+      if (env == NULL) return 1;
+      /* check if the environment block is valid */
+      if (env->magic != ENV_MAGIC)
+      {  
+	 IGRAPH_ERROR("Invalid GLPK environment", IGRAPH_EGLP);
+      }
+      /* close handles to shared libraries */
+      if (env->h_odbc != NULL)
+         xdlclose(env->h_odbc);
+      if (env->h_mysql != NULL)
+         xdlclose(env->h_mysql);
+      /* close streams which are still open */
+      while (env->file_ptr != NULL)
+         xfclose(env->file_ptr);
+      /* free memory blocks which are still allocated */
+      while (env->mem_ptr != NULL)
+      {  desc = env->mem_ptr;
+         env->mem_ptr = desc->next;
+         free(desc);
+      }
+      /* invalidate the environment block */
+      env->magic = -1;
+      /* free memory allocated to the environment block */
+      free(env->term_buf);
+      free(env->ioerr_msg);
+      free(env);
+      /* reset a pointer to the environment block */
+      tls_set_ptr(NULL);
+      /* termination successful */
+      return 0;
+}
+
+/* eof */
diff --git a/src/glpenv02.c b/src/glpk/glpenv02.c
similarity index 100%
rename from src/glpenv02.c
rename to src/glpk/glpenv02.c
diff --git a/src/glpenv03.c b/src/glpk/glpenv03.c
similarity index 100%
rename from src/glpenv03.c
rename to src/glpk/glpenv03.c
diff --git a/src/glpenv04.c b/src/glpk/glpenv04.c
similarity index 100%
rename from src/glpenv04.c
rename to src/glpk/glpenv04.c
diff --git a/src/glpenv05.c b/src/glpk/glpenv05.c
similarity index 100%
rename from src/glpenv05.c
rename to src/glpk/glpenv05.c
diff --git a/src/glpenv06.c b/src/glpk/glpenv06.c
similarity index 100%
rename from src/glpenv06.c
rename to src/glpk/glpenv06.c
diff --git a/src/glpenv07.c b/src/glpk/glpenv07.c
similarity index 100%
rename from src/glpenv07.c
rename to src/glpk/glpenv07.c
diff --git a/src/glpenv08.c b/src/glpk/glpenv08.c
similarity index 100%
rename from src/glpenv08.c
rename to src/glpk/glpenv08.c
diff --git a/src/glpfhv.c b/src/glpk/glpfhv.c
similarity index 100%
rename from src/glpfhv.c
rename to src/glpk/glpfhv.c
diff --git a/src/glpgmp.c b/src/glpk/glpgmp.c
similarity index 100%
rename from src/glpgmp.c
rename to src/glpk/glpgmp.c
diff --git a/src/glphbm.c b/src/glpk/glphbm.c
similarity index 100%
rename from src/glphbm.c
rename to src/glpk/glphbm.c
diff --git a/src/glpini01.c b/src/glpk/glpini01.c
similarity index 100%
rename from src/glpini01.c
rename to src/glpk/glpini01.c
diff --git a/src/glpini02.c b/src/glpk/glpini02.c
similarity index 100%
rename from src/glpini02.c
rename to src/glpk/glpini02.c
diff --git a/src/glpios01.c b/src/glpk/glpios01.c
similarity index 100%
rename from src/glpios01.c
rename to src/glpk/glpios01.c
diff --git a/src/glpios02.c b/src/glpk/glpios02.c
similarity index 100%
rename from src/glpios02.c
rename to src/glpk/glpios02.c
diff --git a/src/glpios03.c b/src/glpk/glpios03.c
similarity index 100%
rename from src/glpios03.c
rename to src/glpk/glpios03.c
diff --git a/src/glpios04.c b/src/glpk/glpios04.c
similarity index 100%
rename from src/glpios04.c
rename to src/glpk/glpios04.c
diff --git a/src/glpios05.c b/src/glpk/glpios05.c
similarity index 100%
rename from src/glpios05.c
rename to src/glpk/glpios05.c
diff --git a/src/glpios06.c b/src/glpk/glpios06.c
similarity index 100%
rename from src/glpios06.c
rename to src/glpk/glpios06.c
diff --git a/src/glpios07.c b/src/glpk/glpios07.c
similarity index 100%
rename from src/glpios07.c
rename to src/glpk/glpios07.c
diff --git a/src/glpios08.c b/src/glpk/glpios08.c
similarity index 100%
rename from src/glpios08.c
rename to src/glpk/glpios08.c
diff --git a/src/glpios09.c b/src/glpk/glpios09.c
similarity index 100%
rename from src/glpios09.c
rename to src/glpk/glpios09.c
diff --git a/src/glpios10.c b/src/glpk/glpios10.c
similarity index 100%
rename from src/glpios10.c
rename to src/glpk/glpios10.c
diff --git a/src/glpios11.c b/src/glpk/glpios11.c
similarity index 100%
rename from src/glpios11.c
rename to src/glpk/glpios11.c
diff --git a/src/glpios12.c b/src/glpk/glpios12.c
similarity index 100%
rename from src/glpios12.c
rename to src/glpk/glpios12.c
diff --git a/src/glpipm.c b/src/glpk/glpipm.c
similarity index 100%
rename from src/glpipm.c
rename to src/glpk/glpipm.c
diff --git a/src/glpk/glpk.inc b/src/glpk/glpk.inc
new file mode 100644
index 0000000..7a48b81
--- /dev/null
+++ b/src/glpk/glpk.inc
@@ -0,0 +1 @@
+GLPK = ../optional/glpk/glpapi.h ../optional/glpk/glpapi01.c ../optional/glpk/glpapi02.c ../optional/glpk/glpapi03.c ../optional/glpk/glpapi04.c ../optional/glpk/glpapi05.c ../optional/glpk/glpapi06.c ../optional/glpk/glpapi07.c ../optional/glpk/glpapi08.c ../optional/glpk/glpapi09.c ../optional/glpk/glpapi10.c ../optional/glpk/glpapi11.c ../optional/glpk/glpapi12.c ../optional/glpk/glpapi13.c ../optional/glpk/glpapi14.c ../optional/glpk/glpapi15.c ../optional/glpk/glpapi16.c ../optional [...]
\ No newline at end of file
diff --git a/src/glplib01.c b/src/glpk/glplib01.c
similarity index 100%
rename from src/glplib01.c
rename to src/glpk/glplib01.c
diff --git a/src/glplib02.c b/src/glpk/glplib02.c
similarity index 100%
rename from src/glplib02.c
rename to src/glpk/glplib02.c
diff --git a/src/glplib03.c b/src/glpk/glplib03.c
similarity index 100%
rename from src/glplib03.c
rename to src/glpk/glplib03.c
diff --git a/src/glplpf.c b/src/glpk/glplpf.c
similarity index 100%
rename from src/glplpf.c
rename to src/glpk/glplpf.c
diff --git a/src/glplpx01.c b/src/glpk/glplpx01.c
similarity index 100%
rename from src/glplpx01.c
rename to src/glpk/glplpx01.c
diff --git a/src/glplpx02.c b/src/glpk/glplpx02.c
similarity index 100%
rename from src/glplpx02.c
rename to src/glpk/glplpx02.c
diff --git a/src/glplpx03.c b/src/glpk/glplpx03.c
similarity index 100%
rename from src/glplpx03.c
rename to src/glpk/glplpx03.c
diff --git a/src/glpluf.c b/src/glpk/glpluf.c
similarity index 100%
rename from src/glpluf.c
rename to src/glpk/glpluf.c
diff --git a/src/glplux.c b/src/glpk/glplux.c
similarity index 100%
rename from src/glplux.c
rename to src/glpk/glplux.c
diff --git a/src/glpmat.c b/src/glpk/glpmat.c
similarity index 100%
rename from src/glpmat.c
rename to src/glpk/glpmat.c
diff --git a/src/glpmpl01.c b/src/glpk/glpmpl01.c
similarity index 100%
rename from src/glpmpl01.c
rename to src/glpk/glpmpl01.c
diff --git a/src/glpmpl02.c b/src/glpk/glpmpl02.c
similarity index 100%
rename from src/glpmpl02.c
rename to src/glpk/glpmpl02.c
diff --git a/src/glpmpl03.c b/src/glpk/glpmpl03.c
similarity index 100%
rename from src/glpmpl03.c
rename to src/glpk/glpmpl03.c
diff --git a/src/glpmpl04.c b/src/glpk/glpmpl04.c
similarity index 100%
rename from src/glpmpl04.c
rename to src/glpk/glpmpl04.c
diff --git a/src/glpmpl05.c b/src/glpk/glpmpl05.c
similarity index 100%
rename from src/glpmpl05.c
rename to src/glpk/glpmpl05.c
diff --git a/src/glpmpl06.c b/src/glpk/glpmpl06.c
similarity index 100%
rename from src/glpmpl06.c
rename to src/glpk/glpmpl06.c
diff --git a/src/glpmps.c b/src/glpk/glpmps.c
similarity index 100%
rename from src/glpmps.c
rename to src/glpk/glpmps.c
diff --git a/src/glpnet01.c b/src/glpk/glpnet01.c
similarity index 100%
rename from src/glpnet01.c
rename to src/glpk/glpnet01.c
diff --git a/src/glpnet02.c b/src/glpk/glpnet02.c
similarity index 100%
rename from src/glpnet02.c
rename to src/glpk/glpnet02.c
diff --git a/src/glpnet03.c b/src/glpk/glpnet03.c
similarity index 100%
rename from src/glpnet03.c
rename to src/glpk/glpnet03.c
diff --git a/src/glpnet04.c b/src/glpk/glpnet04.c
similarity index 100%
rename from src/glpnet04.c
rename to src/glpk/glpnet04.c
diff --git a/src/glpnet05.c b/src/glpk/glpnet05.c
similarity index 100%
rename from src/glpnet05.c
rename to src/glpk/glpnet05.c
diff --git a/src/glpnet06.c b/src/glpk/glpnet06.c
similarity index 100%
rename from src/glpnet06.c
rename to src/glpk/glpnet06.c
diff --git a/src/glpnet07.c b/src/glpk/glpnet07.c
similarity index 100%
rename from src/glpnet07.c
rename to src/glpk/glpnet07.c
diff --git a/src/glpnet08.c b/src/glpk/glpnet08.c
similarity index 100%
rename from src/glpnet08.c
rename to src/glpk/glpnet08.c
diff --git a/src/glpnet09.c b/src/glpk/glpnet09.c
similarity index 100%
rename from src/glpnet09.c
rename to src/glpk/glpnet09.c
diff --git a/src/glpnpp01.c b/src/glpk/glpnpp01.c
similarity index 100%
rename from src/glpnpp01.c
rename to src/glpk/glpnpp01.c
diff --git a/src/glpnpp02.c b/src/glpk/glpnpp02.c
similarity index 100%
rename from src/glpnpp02.c
rename to src/glpk/glpnpp02.c
diff --git a/src/glpnpp03.c b/src/glpk/glpnpp03.c
similarity index 100%
rename from src/glpnpp03.c
rename to src/glpk/glpnpp03.c
diff --git a/src/glpnpp04.c b/src/glpk/glpnpp04.c
similarity index 100%
rename from src/glpnpp04.c
rename to src/glpk/glpnpp04.c
diff --git a/src/glpnpp05.c b/src/glpk/glpnpp05.c
similarity index 100%
rename from src/glpnpp05.c
rename to src/glpk/glpnpp05.c
diff --git a/src/glpqmd.c b/src/glpk/glpqmd.c
similarity index 100%
rename from src/glpqmd.c
rename to src/glpk/glpqmd.c
diff --git a/src/glprgr.c b/src/glpk/glprgr.c
similarity index 100%
rename from src/glprgr.c
rename to src/glpk/glprgr.c
diff --git a/src/glprng01.c b/src/glpk/glprng01.c
similarity index 100%
rename from src/glprng01.c
rename to src/glpk/glprng01.c
diff --git a/src/glprng02.c b/src/glpk/glprng02.c
similarity index 100%
rename from src/glprng02.c
rename to src/glpk/glprng02.c
diff --git a/src/glpscf.c b/src/glpk/glpscf.c
similarity index 100%
rename from src/glpscf.c
rename to src/glpk/glpscf.c
diff --git a/src/glpscl.c b/src/glpk/glpscl.c
similarity index 100%
rename from src/glpscl.c
rename to src/glpk/glpscl.c
diff --git a/src/glpsdf.c b/src/glpk/glpsdf.c
similarity index 100%
rename from src/glpsdf.c
rename to src/glpk/glpsdf.c
diff --git a/src/glpspm.c b/src/glpk/glpspm.c
similarity index 100%
rename from src/glpspm.c
rename to src/glpk/glpspm.c
diff --git a/src/glpspx01.c b/src/glpk/glpspx01.c
similarity index 100%
rename from src/glpspx01.c
rename to src/glpk/glpspx01.c
diff --git a/src/glpspx02.c b/src/glpk/glpspx02.c
similarity index 100%
rename from src/glpspx02.c
rename to src/glpk/glpspx02.c
diff --git a/src/glpsql.c b/src/glpk/glpsql.c
similarity index 100%
rename from src/glpsql.c
rename to src/glpk/glpsql.c
diff --git a/src/glpssx01.c b/src/glpk/glpssx01.c
similarity index 100%
rename from src/glpssx01.c
rename to src/glpk/glpssx01.c
diff --git a/src/glpssx02.c b/src/glpk/glpssx02.c
similarity index 100%
rename from src/glpssx02.c
rename to src/glpk/glpssx02.c
diff --git a/src/glptsp.c b/src/glpk/glptsp.c
similarity index 100%
rename from src/glptsp.c
rename to src/glpk/glptsp.c
diff --git a/src/heap.pmt b/src/heap.pmt
index 5460a28..8d35551 100644
--- a/src/heap.pmt
+++ b/src/heap.pmt
@@ -22,7 +22,6 @@
 */
 
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_error.h"
 #include "config.h"
 
diff --git a/src/igraph.h b/src/igraph.h
deleted file mode 100644
index f5848d0..0000000
--- a/src/igraph.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_H
-#define IGRAPH_H
-
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE 1
-#endif
-
-#include "igraph_version.h"
-#include "igraph_memory.h"
-#include "igraph_error.h"
-#include "igraph_random.h"
-#include "igraph_progress.h"
-#include "igraph_statusbar.h"
-
-#include "igraph_types.h"
-#include "igraph_complex.h"
-#include "igraph_vector.h"
-#include "igraph_matrix.h"
-#include "igraph_array.h"
-#include "igraph_dqueue.h"
-#include "igraph_stack.h"
-#include "igraph_heap.h"
-#include "igraph_psumtree.h"
-#include "igraph_strvector.h"
-#include "igraph_vector_ptr.h"
-#include "igraph_spmatrix.h"
-#include "igraph_sparsemat.h"
-#include "igraph_qsort.h"
-
-#include "igraph_constants.h"
-#include "igraph_datatype.h"
-#include "igraph_iterators.h"
-#include "igraph_interface.h"
-#include "igraph_constructors.h"
-#include "igraph_games.h"
-#include "igraph_microscopic_update.h"
-#include "igraph_centrality.h"
-#include "igraph_paths.h"
-#include "igraph_components.h"
-#include "igraph_structural.h"
-#include "igraph_transitivity.h"
-#include "igraph_neighborhood.h"
-#include "igraph_topology.h"
-#include "igraph_bipartite.h"
-#include "igraph_cliques.h"
-#include "igraph_layout.h"
-#include "igraph_visitor.h"
-#include "igraph_community.h"
-#include "igraph_conversion.h"
-#include "igraph_foreign.h"
-#include "igraph_motifs.h"
-#include "igraph_operators.h"
-#include "igraph_flow.h"
-#include "igraph_revolver.h"
-#include "igraph_nongraph.h"
-#include "igraph_cocitation.h"
-#include "igraph_adjlist.h"
-#include "igraph_attributes.h"
-#include "igraph_blas.h"
-#include "igraph_lapack.h"
-#include "igraph_arpack.h"
-#include "igraph_mixing.h"
-#include "igraph_separators.h"
-#include "igraph_cohesive_blocks.h"
-#include "igraph_eigen.h"
-#include "igraph_hrg.h"
-#include "igraph_threading.h"
-#include "igraph_interrupt.h"
-#include "igraph_scg.h"
-#include "igraph_matching.h"
-#include "igraph_graphlets.h"
-#include "igraph_epidemics.h"
-
-#endif
diff --git a/src/igraph_adjlist.h b/src/igraph_adjlist.h
deleted file mode 100644
index 2e5caf8..0000000
--- a/src/igraph_adjlist.h
+++ /dev/null
@@ -1,238 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_ADJLIST_H
-#define IGRAPH_ADJLIST_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
-
-#include "igraph_constants.h"
-#include "igraph_types.h"
-#include "igraph_datatype.h"
-
-__BEGIN_DECLS
-
-typedef struct igraph_adjlist_t { 
-  igraph_integer_t length;
-  igraph_vector_int_t *adjs;
-} igraph_adjlist_t;
-
-int igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, 
-			  igraph_neimode_t mode);
-int igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes);
-igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al); 
-int igraph_adjlist_init_complementer(const igraph_t *graph,
-				     igraph_adjlist_t *al, 
-				     igraph_neimode_t mode,
-				     igraph_bool_t loops);
-void igraph_adjlist_destroy(igraph_adjlist_t *al);
-void igraph_adjlist_clear(igraph_adjlist_t *al);
-void igraph_adjlist_sort(igraph_adjlist_t *al);
-int igraph_adjlist_simplify(igraph_adjlist_t *al);
-int igraph_adjlist_remove_duplicate(const igraph_t *graph, 
-				    igraph_adjlist_t *al);
-int igraph_adjlist_print(const igraph_adjlist_t *al);
-int igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile);
-/* igraph_vector_int_t *igraph_adjlist_get(const igraph_adjlist_t *al,  */
-/* 			       igraph_integer_t no); */
-/**
- * \define igraph_adjlist_get
- * Query a vector in an adjlist
- * 
- * 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.
- * \return Pointer to the <type>igraph_vector_int_t</type> object.
- * 
- * Time complexity: O(1).
- */
-#define igraph_adjlist_get(al,no) (&(al)->adjs[(long int)(no)])
-
-int igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist,
-		   igraph_neimode_t mode, igraph_bool_t duplicate);
-
-typedef struct igraph_inclist_t {
-  igraph_integer_t length;
-  igraph_vector_t *incs;
-} igraph_inclist_t;
-
-int igraph_inclist_init(const igraph_t *graph, 
-			    igraph_inclist_t *il, 
-			    igraph_neimode_t mode);
-int igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n);
-void igraph_inclist_destroy(igraph_inclist_t *il);
-void igraph_inclist_clear(igraph_inclist_t *il);
-int igraph_inclist_remove_duplicate(const igraph_t *graph,
-					igraph_inclist_t *il);
-int igraph_inclist_print(const igraph_inclist_t *il);
-int igraph_inclist_fprint(const igraph_inclist_t *il, FILE *outfile);
-
-/**
- * \define igraph_inclist_get
- * Query a vector in an incidence list
- *
- * Returns a pointer to an <type>igraph_vector_t</type> object from an
- * incidence list containing edge ids. The vector can be modified,
- * resized, etc. as desired. 
- * \param graph il The incidence list.
- * \param no The vertex for which the incident edges are returned.
- * \return Pointer to an <type>igraph_vector_t</type> object.
- * 
- * Time complexity: O(1).
- */
-#define igraph_inclist_get(il,no) (&(il)->incs[(long int)(no)])
-
-typedef struct igraph_lazy_adjlist_t {
-  const igraph_t *graph;
-  igraph_integer_t length;
-  igraph_vector_t **adjs;
-  igraph_neimode_t mode;
-  igraph_lazy_adlist_simplify_t simplify;
-} igraph_lazy_adjlist_t;
-
-int igraph_lazy_adjlist_init(const igraph_t *graph,
-			       igraph_lazy_adjlist_t *al,
-			       igraph_neimode_t mode,
-			       igraph_lazy_adlist_simplify_t simplify);
-void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al);
-void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al);
-/* igraph_vector_t *igraph_lazy_adjlist_get(igraph_lazy_adjlist_t *al, */
-/* 					   igraph_integer_t no); */
-/**
- * \define igraph_lazy_adjlist_get
- * 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.
- * \return Pointer to a vector. It is allowed to modify it and
- *   modification does not affect the original graph.
- * 
- * Time complexity: O(d), the number of neighbor vertices for the
- * first time, O(1) for subsequent calls.
- */
-#define igraph_lazy_adjlist_get(al,no) \
-  ((al)->adjs[(long int)(no)] != 0 ? ((al)->adjs[(long int)(no)]) : \
-   (igraph_lazy_adjlist_get_real(al, no)))
-igraph_vector_t *igraph_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al,
-						igraph_integer_t no);
-
-typedef struct igraph_lazy_inclist_t {
-  const igraph_t *graph;
-  igraph_integer_t length;
-  igraph_vector_t **incs;
-  igraph_neimode_t mode;
-} igraph_lazy_inclist_t;
-
-int igraph_lazy_inclist_init(const igraph_t *graph,
-				   igraph_lazy_inclist_t *il,
-				   igraph_neimode_t mode);
-void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il);
-void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il);
-
-/**
- * \define igraph_lazy_inclist_get
- * 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
- * operations are needed when the incident edges of the same vertex are
- * queried again.
- * \param al The lazy incidence list object.
- * \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.
- * 
- * Time complexity: O(d), the number of incident edges for the first
- * time, O(1) for subsequent calls with the same \p no argument.
- */
-#define igraph_lazy_inclist_get(al,no) \
-  ((al)->incs[(long int)(no)] != 0 ? ((al)->incs[(long int)(no)]) : \
-   (igraph_lazy_inclist_get_real(al, no)))
-igraph_vector_t *igraph_lazy_inclist_get_real(igraph_lazy_inclist_t *al,
-						    igraph_integer_t no);
-
-/************************************************************************* 
- * DEPRECATED TYPES AND FUNCTIONS
- */
-
-typedef igraph_inclist_t igraph_adjedgelist_t;
-
-int igraph_adjedgelist_init(const igraph_t *graph, 
-			    igraph_inclist_t *il, 
-			    igraph_neimode_t mode);
-void igraph_adjedgelist_destroy(igraph_inclist_t *il);
-int igraph_adjedgelist_remove_duplicate(const igraph_t *graph,
-					igraph_inclist_t *il);
-int igraph_adjedgelist_print(const igraph_inclist_t *il, FILE *outfile);
-
-/**
- * \define igraph_adjedgelist_get
- * 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.
- *
- * </para><para>
- * Deprecated in version 0.6.
- */
-#define igraph_adjedgelist_get(ael,no) (&(ael)->incs[(long int)(no)])
-
-typedef igraph_lazy_inclist_t igraph_lazy_adjedgelist_t;
-
-int igraph_lazy_adjedgelist_init(const igraph_t *graph,
-				   igraph_lazy_inclist_t *il,
-				   igraph_neimode_t mode);
-void igraph_lazy_adjedgelist_destroy(igraph_lazy_inclist_t *il);
-
-/**
- * \define igraph_lazy_adjedgelist_get
- * 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.
- *
- * </para><para>
- * Deprecated in version 0.6.
- */
-#define igraph_lazy_adjedgelist_get(al,no) \
-  ((al)->incs[(long int)(no)] != 0 ? ((al)->incs[(long int)(no)]) : \
-   (igraph_lazy_adjedgelist_get_real(al, no)))
-igraph_vector_t *igraph_lazy_adjedgelist_get_real(igraph_lazy_inclist_t *al,
-						    igraph_integer_t no);
-__END_DECLS
-
-#endif
diff --git a/src/igraph_blas.h b/src/igraph_blas.h
deleted file mode 100644
index 7742720..0000000
--- a/src/igraph_blas.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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 BLAS_H
-#define BLAS_H
-
-#include "igraph_types.h"
-#include "igraph_vector.h"
-#include "igraph_matrix.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
-
-/**
- * \section about_blas BLAS interface in igraph
- * 
- * <para>
- * BLAS is a highly optimized library for basic linear algebra operations
- * such as vector-vector, matrix-vector and matrix-matrix product.
- * Please see http://www.netlib.org/blas/ for details and a reference
- * implementation in Fortran. igraph contains some wrapper functions
- * that can be used to call BLAS routines in a somewhat more
- * user-friendly way. Not all BLAS routines are included in igraph,
- * and even those which are included might not have wrappers;
- * the extension of the set of wrapped functions will probably be driven
- * by igraph's internal requirements. The wrapper functions usually
- * substitute double-precision floating point arrays used by BLAS with
- * \type igraph_vector_t and \type igraph_matrix_t instances and also
- * remove those parameters (such as the number of rows/columns) that
- * can be inferred from the passed arguments directly.
- * </para>
- */
-
-void igraph_blas_dgemv(igraph_bool_t transpose, igraph_real_t alpha,
-        const igraph_matrix_t* a, const igraph_vector_t* x,
-        igraph_real_t beta, igraph_vector_t* y);
-void igraph_blas_dgemv_array(igraph_bool_t transpose, igraph_real_t alpha,
-        const igraph_matrix_t* a, const igraph_real_t* x,
-        igraph_real_t beta, igraph_real_t* y);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_blas_internal.h b/src/igraph_blas_internal.h
index 06fa4a9..4cd0eff 100644
--- a/src/igraph_blas_internal.h
+++ b/src/igraph_blas_internal.h
@@ -38,6 +38,7 @@
 #define igraphdcopy_	dcopy_
 #define igraphdscal_	dscal_
 #define igraphdswap_	dswap_
+#define igraphdgemm_	dgemm_
 #define igraphdgemv_	dgemv_
 #define igraphddot_	ddot_
 #define igraphdnrm2_	dnrm2_
@@ -46,10 +47,19 @@
 #define igraphidamax_   idamax_
 #define igraphdtrmm_    dtrmm_
 #define igraphdasum_    dasum_
+#define igraphdtrsm_    dtrsm_
+#define igraphdtrsv_    dtrsv_
+#define igraphdnrm2_    dnrm2_
 #endif
 
 int igraphdgemv_(char *trans, int *m, int *n, igraph_real_t *alpha,
     igraph_real_t *a, int *lda, igraph_real_t *x, int *incx,
     igraph_real_t *beta, igraph_real_t *y, int *incy);
 
+int igraphdgemm_(char *transa, char *transb, int *m, int *n, int *k,
+    double *alpha, double *a, int *lda, double *b, int *ldb,
+    double *beta, double *c__, int *ldc);
+
+double igraphdnrm2_(int *n, double *x, int *incx);
+
 #endif
diff --git a/src/igraph_constants.h b/src/igraph_constants.h
deleted file mode 100644
index 8c1694b..0000000
--- a/src/igraph_constants.h
+++ /dev/null
@@ -1,159 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_CONSTANTS_H
-#define IGRAPH_CONSTANTS_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
-
-#include "igraph_types.h"
-#include "igraph_datatype.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Constants                                          */
-/* -------------------------------------------------- */
-
-typedef enum { IGRAPH_UNDIRECTED=0, IGRAPH_DIRECTED=1 } igraph_i_directed_t;
-
-typedef enum { IGRAPH_NO_LOOPS=0, IGRAPH_LOOPS=1 } igraph_i_loops_t;
-
-typedef enum { IGRAPH_NO_MULTIPLE=0, IGRAPH_MULTIPLE=1 } igraph_i_multiple_t;
-
-typedef enum { IGRAPH_ASCENDING=0, IGRAPH_DESCENDING=1 } igraph_order_t;
-
-typedef enum { IGRAPH_MINIMUM=0, IGRAPH_MAXIMUM=1 } igraph_optimal_t;
-
-typedef enum { IGRAPH_OUT=1, IGRAPH_IN=2, IGRAPH_ALL=3,
-	       IGRAPH_TOTAL=3 } igraph_neimode_t;
-
-typedef enum { IGRAPH_WEAK=1, IGRAPH_STRONG=2 } igraph_connectedness_t;
-
-typedef enum { IGRAPH_RECIPROCITY_DEFAULT=0, 
-	       IGRAPH_RECIPROCITY_RATIO=1 } igraph_reciprocity_t;
-
-typedef enum { IGRAPH_ADJ_DIRECTED=0, 
-	       IGRAPH_ADJ_UNDIRECTED=1, IGRAPH_ADJ_MAX=1,
-               IGRAPH_ADJ_UPPER, IGRAPH_ADJ_LOWER, IGRAPH_ADJ_MIN,
-	       IGRAPH_ADJ_PLUS } igraph_adjacency_t;
-
-typedef enum { IGRAPH_STAR_OUT=0, IGRAPH_STAR_IN,
-	       IGRAPH_STAR_UNDIRECTED, 
-	       IGRAPH_STAR_MUTUAL } igraph_star_mode_t;
-
-typedef enum { IGRAPH_TREE_OUT=0, IGRAPH_TREE_IN,
-	       IGRAPH_TREE_UNDIRECTED } igraph_tree_mode_t;
-
-typedef enum { IGRAPH_ERDOS_RENYI_GNP=0, 
-	       IGRAPH_ERDOS_RENYI_GNM } igraph_erdos_renyi_t;
-
-typedef enum { IGRAPH_GET_ADJACENCY_UPPER=0,
-	       IGRAPH_GET_ADJACENCY_LOWER,
-	       IGRAPH_GET_ADJACENCY_BOTH } igraph_get_adjacency_t;
-
-typedef enum { IGRAPH_DEGSEQ_SIMPLE=0,
-	       IGRAPH_DEGSEQ_VL,
-	       IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE } igraph_degseq_t;
-
-typedef enum { IGRAPH_FILEFORMAT_EDGELIST=0,
-	       IGRAPH_FILEFORMAT_NCOL,
-	       IGRAPH_FILEFORMAT_PAJEK,
-               IGRAPH_FILEFORMAT_LGL,
-               IGRAPH_FILEFORMAT_GRAPHML } igraph_fileformat_type_t;
-
-typedef enum { IGRAPH_REWIRING_SIMPLE=0,
-	       IGRAPH_REWIRING_SIMPLE_LOOPS } igraph_rewiring_t;
-
-typedef enum { IGRAPH_EDGEORDER_ID=0,
-	       IGRAPH_EDGEORDER_FROM,
-	       IGRAPH_EDGEORDER_TO } igraph_edgeorder_type_t;
-
-typedef enum { IGRAPH_TO_DIRECTED_ARBITRARY=0,
-	       IGRAPH_TO_DIRECTED_MUTUAL } igraph_to_directed_t;
-
-typedef enum { IGRAPH_TO_UNDIRECTED_EACH=0,
-	       IGRAPH_TO_UNDIRECTED_COLLAPSE,
-               IGRAPH_TO_UNDIRECTED_MUTUAL} igraph_to_undirected_t;
-
-typedef enum { IGRAPH_VCONN_NEI_ERROR=0,
-	       IGRAPH_VCONN_NEI_NUMBER_OF_NODES,
-	       IGRAPH_VCONN_NEI_IGNORE, 
-	       IGRAPH_VCONN_NEI_NEGATIVE } igraph_vconn_nei_t;
-
-typedef enum { IGRAPH_SPINCOMM_UPDATE_SIMPLE=0,
-	       IGRAPH_SPINCOMM_UPDATE_CONFIG } igraph_spincomm_update_t; 
-
-typedef enum { IGRAPH_DONT_SIMPLIFY=0,
-	       IGRAPH_SIMPLIFY } igraph_lazy_adlist_simplify_t;
-
-typedef enum { IGRAPH_TRANSITIVITY_NAN=0,
-               IGRAPH_TRANSITIVITY_ZERO } igraph_transitivity_mode_t;
-
-typedef enum { IGRAPH_SPINCOMM_IMP_ORIG=0, 
-	       IGRAPH_SPINCOMM_IMP_NEG } igraph_spinglass_implementation_t;
-
-typedef enum { IGRAPH_COMMCMP_VI = 0,
-               IGRAPH_COMMCMP_NMI,
-               IGRAPH_COMMCMP_SPLIT_JOIN,
-               IGRAPH_COMMCMP_RAND,
-               IGRAPH_COMMCMP_ADJUSTED_RAND } igraph_community_comparison_t;
-
-typedef enum { IGRAPH_ADD_WEIGHTS_NO = 0,
-               IGRAPH_ADD_WEIGHTS_YES,
-               IGRAPH_ADD_WEIGHTS_IF_PRESENT } igraph_add_weights_t;
-
-typedef enum { IGRAPH_BARABASI_BAG = 0,
-	       IGRAPH_BARABASI_PSUMTREE, 
-	       IGRAPH_BARABASI_PSUMTREE_MULTIPLE} igraph_barabasi_algorithm_t;
-
-typedef enum { IGRAPH_FAS_EXACT_IP = 0,
-	       IGRAPH_FAS_APPROX_EADES } igraph_fas_algorithm_t;
-
-typedef enum { IGRAPH_SUBGRAPH_AUTO = 0,
-	           IGRAPH_SUBGRAPH_COPY_AND_DELETE,
-			   IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH
-			 } igraph_subgraph_implementation_t;
-
-typedef enum { IGRAPH_IMITATE_AUGMENTED = 0,
-               IGRAPH_IMITATE_BLIND,
-               IGRAPH_IMITATE_CONTRACTED } igraph_imitate_algorithm_t;
-
-typedef igraph_real_t  igraph_scalar_function_t(const igraph_vector_t *var, 
-						const igraph_vector_t *par,
-						void* extra);
-typedef void igraph_vector_function_t(const igraph_vector_t *var, 
-				      const igraph_vector_t *par,
-				      igraph_vector_t* res, void* extra);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_dqueue.h b/src/igraph_dqueue.h
deleted file mode 100644
index d7146ba..0000000
--- a/src/igraph_dqueue.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_DQUEUE_H
-#define IGRAPH_DQUEUE_H
-
-#include "igraph_types.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
-
-/* -------------------------------------------------- */
-/* double ended queue, very useful                    */
-/* -------------------------------------------------- */
-
-#define BASE_IGRAPH_REAL
-#include "igraph_pmt.h"
-#include "igraph_dqueue_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_IGRAPH_REAL
-
-#define BASE_LONG
-#include "igraph_pmt.h"
-#include "igraph_dqueue_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_LONG
-
-#define BASE_CHAR
-#include "igraph_pmt.h"
-#include "igraph_dqueue_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_CHAR
-
-#define BASE_BOOL
-#include "igraph_pmt.h"
-#include "igraph_dqueue_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_BOOL
-
-#define IGRAPH_DQUEUE_NULL { 0,0,0,0 }
-#define IGRAPH_DQUEUE_INIT_FINALLY(v, size) \
-  do { IGRAPH_CHECK(igraph_dqueue_init(v, size)); \
-  IGRAPH_FINALLY(igraph_dqueue_destroy, v); } while (0)
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_eigen.h b/src/igraph_eigen.h
deleted file mode 100644
index c3712a2..0000000
--- a/src/igraph_eigen.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-#include "igraph_arpack.h"
-#include "igraph_lapack.h"
-#include "igraph_sparsemat.h"
-
-#ifndef IGRAPH_EIGEN_H
-#define IGRAPH_EIGEN_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
-
-typedef enum { IGRAPH_EIGEN_AUTO=0,
-	       IGRAPH_EIGEN_LAPACK,
-	       IGRAPH_EIGEN_ARPACK, 
-	       IGRAPH_EIGEN_COMP_AUTO,
-	       IGRAPH_EIGEN_COMP_LAPACK,
-	       IGRAPH_EIGEN_COMP_ARPACK } igraph_eigen_algorithm_t;
-
-typedef enum { IGRAPH_EIGEN_LM=0,
-	       IGRAPH_EIGEN_SM,
-	       IGRAPH_EIGEN_LA,
-	       IGRAPH_EIGEN_SA,
-	       IGRAPH_EIGEN_BE,
-	       IGRAPH_EIGEN_LR,
-	       IGRAPH_EIGEN_SR,
-	       IGRAPH_EIGEN_LI,
-	       IGRAPH_EIGEN_SI,
-	       IGRAPH_EIGEN_ALL,
-	       IGRAPH_EIGEN_INTERVAL,
-	       IGRAPH_EIGEN_SELECT } igraph_eigen_which_position_t;
-
-typedef struct igraph_eigen_which_t {
-  igraph_eigen_which_position_t pos;
-  int howmany;
-  int il, iu;
-  igraph_real_t vl, vu;
-  int vestimate;
-  igraph_lapack_dgeevx_balance_t balance;
-} igraph_eigen_which_t;
-    
-
-int igraph_eigen_matrix_symmetric(const igraph_matrix_t *A,
-				  const igraph_sparsemat_t *sA,
-				  igraph_arpack_function_t *fun, int n,
-				  void *extra,
-				  igraph_eigen_algorithm_t algorithm,
-				  const igraph_eigen_which_t *which,
-				  igraph_arpack_options_t *options,
-				  igraph_arpack_storage_t *storage,
-				  igraph_vector_t *values, 
-				  igraph_matrix_t *vectors);
-
-int igraph_eigen_matrix(const igraph_matrix_t *A,
-			const igraph_sparsemat_t *sA,
-			igraph_arpack_function_t *fun, int n,
-			void *extra,
-			igraph_eigen_algorithm_t algorithm,
-			const igraph_eigen_which_t *which,
-			igraph_arpack_options_t *options,
-			igraph_arpack_storage_t *storage,
-			igraph_vector_complex_t *values,
-			igraph_matrix_complex_t *vectors);
-
-int igraph_eigen_adjacency(const igraph_t *graph,
-			   igraph_eigen_algorithm_t algorithm,
-			   const igraph_eigen_which_t *which,
-			   igraph_arpack_options_t *options,
-			   igraph_arpack_storage_t *storage,
-			   igraph_vector_t *values,
-			   igraph_matrix_t *vectors,
-			   igraph_vector_complex_t *cmplxvalues,
-			   igraph_matrix_complex_t *cmplxvectors);
-
-int igraph_eigen_laplacian(const igraph_t *graph,
-			   igraph_eigen_algorithm_t algorithm,
-			   const igraph_eigen_which_t *which,
-			   igraph_arpack_options_t *options,
-			   igraph_arpack_storage_t *storage,
-			   igraph_vector_t *values,
-			   igraph_matrix_t *vectors,
-			   igraph_vector_complex_t *cmplxvalues,
-			   igraph_matrix_complex_t *cmplxvectors);
-
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_error.h b/src/igraph_error.h
deleted file mode 100644
index 718084d..0000000
--- a/src/igraph_error.h
+++ /dev/null
@@ -1,721 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_ERROR_H
-#define IGRAPH_ERROR_H
-
-#include <stdarg.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
-
-/* This file contains the igraph error handling.
- * Most bits are taken literally from the GSL library (with the GSL_
- * prefix renamed to IGRAPH_), as I couldn't find a better way to do
- * them. */
-
-/**
- * \section errorhandlingbasics Error handling basics
- * 
- * <para>\a igraph functions can run into various problems preventing them 
- * from normal operation. The user might have supplied invalid arguments,
- * e.g. a non-square matrix when a square-matrix was expected, or the program 
- * has run out of memory while some more memory allocation is required, etc.
- * </para>
- * 
- * <para>By default \a igraph aborts the program when it runs into an 
- * error. While this behavior might be good enough for smaller programs, 
- * it is without doubt avoidable in larger projects. Please read further
- * if your project requires more sophisticated error handling. You can 
- * safely skip the rest of this chapter otherwise.
- * </para>
- */
-
-/**
- * \section errorhandlers Error handlers
- *
- * <para>
- * If \a igraph runs into an error - an invalid argument was supplied
- * to a function, or we've ran out of memory - the control is
- * transferred to the \emb error handler \eme function.
- * </para><para>
- * The default error handler is \ref igraph_error_handler_abort which
- * prints an error message and aborts the program.
- * </para>
- * <para>
- * The \ref igraph_set_error_handler() function can be used to set a new
- * error handler function of type \ref igraph_error_handler_t; see the
- * documentation of this type for details.
- * </para>
- * <para>
- * There are two other predefined error handler functions,
- * \ref igraph_error_handler_ignore and \ref igraph_error_handler_printignore.
- * These deallocate the temporarily allocated memory (more about this
- * later) and return with the error code. The latter also prints an
- * error message. If you use these error handlers you need to take
- * care about possible errors yourself by checking the return value of
- * (almost) every non-void \a igraph function.
- * </para><para>
- * Independently of the error handler installed, all functions in the
- * library do their best to leave their arguments
- * \em semantically unchanged if an error
- * happens. By semantically we mean that the implementation of an
- * object supplied as an argument might change, but its
- * \quote meaning \endquote in most cases does not. The rare occasions
- * when this rule is violated are documented in this manual.
- * </para>
- */
-
-/**
- * \section errorcodes Error codes
- * 
- * <para>Every \a igraph function which can fail return a
- * single integer error code. Some functions are very simple and
- * cannot run into any error, these may return other types, or
- * \type void as well. The error codes are defined by the
- * \ref igraph_error_type_t enumeration.
- * </para>
- */
-
-/**
- * \section writing_error_handlers Writing error handlers
- *
- * <para>
- * The contents of the rest of this chapter might be useful only
- * for those who want to create an interface to \a igraph from another
- * language. Most readers can safely skip to the next chapter.
- * </para>
- * 
- * <para>
- * You can write and install error handlers simply by defining a
- * 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
- * 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.
- * </para>
- * <para> 
- * If you want to write an error handler, your error handler should
- * call \ref IGRAPH_FINALLY_FREE() to deallocate all temporary memory to
- * prevent memory leaks.
- * </para>
- */
-
-/**
- * \section error_handling_internals Error handling internals
- *
- * <para>
- * If an error happens, the functions in the library call the
- * \ref IGRAPH_ERROR macro with a textual description of the error and an
- * \a igraph error code. This macro calls (through the \ref
- * igraph_error() function) the installed error handler. Another useful
- * macro is \ref IGRAPH_CHECK(). This checks the return value of its
- * argument, which is normally a function call, and calls \ref
- * IGRAPH_ERROR if it is not \c IGRAPH_SUCCESS. 
- * </para>
- */
-
-/** 
- * \section deallocating_memory Deallocating memory
- *
- * <para>
- * If a function runs into an error (and the program is not aborted)
- * the error handler should deallocate all temporary memory. This is
- * done by storing the address and the destroy function of all temporary
- * objects in a stack. The \ref IGRAPH_FINALLY function declares an object as
- * temporary by placing its address in the stack. If an \a igraph function returns
- * with success it calls \ref IGRAPH_FINALLY_CLEAN() with the
- * number of objects to remove from the stack. If an error happens
- * however, the error handler should call \ref IGRAPH_FINALLY_FREE() to
- * deallocate each object added to the stack. This means that the
- * temporary objects allocated in the calling function (and etc.) will
- * be freed as well.
- * </para>
- */
-
-/**
- * \section writing_functions_error_handling Writing \a igraph functions with
- * proper error handling
- *
- * <para>
- * There are some simple rules to keep in order to have functions
- * behaving well in erroneous situations. First, check the arguments
- * of the functions and call \ref IGRAPH_ERROR if they are invalid. Second,
- * call \ref IGRAPH_FINALLY on each dynamically allocated object and call
- * \ref IGRAPH_FINALLY_CLEAN() with the proper argument before returning. Third, use
- * \ref IGRAPH_CHECK on all \a igraph function calls which can generate errors.
- * </para>
- * <para>
- * The size of the stack used for this bookkeeping is fixed, and
- * small. If you want to allocate several objects, write a destroy
- * function which can deallocate all of these. See the
- * <filename>adjlist.c</filename> file in the
- * \a igraph source for an example.
- * </para>
- * <para> 
- * For some functions these mechanisms are simply not flexible
- * enough. These functions should define their own error handlers and
- * restore the error handler before they return.
- * </para>
- */
-
-/**
- * \section error_handling_threads Error handling and threads
- *
- * <para>
- * It is likely that the \a igraph error handling
- * method is \em not thread-safe, mainly because of
- * the static global stack which is used to store the address of the
- * temporarily allocated objects. This issue might be addressed in a
- * later version of \a igraph.
- * </para>
- */
-
-/**
- * \typedef igraph_error_handler_t
- * \brief Type of error handler functions.
- * 
- * This is the type of the error handler functions.
- * \param reason Textual description of the error.
- * \param file The source file in which the error is noticed.
- * \param line The number of the line in the source file which triggered
- *   the error
- * \param igraph_errno The \a igraph error code.
- */
-
-typedef void igraph_error_handler_t (const char * reason, const char * file,
-				     int line, int igraph_errno);
-
-/**
- * \var igraph_error_handler_abort
- * \brief Abort program in case of error.
- *
- * The default error handler, prints an error message and aborts the
- * program. 
- */
-
-extern igraph_error_handler_t igraph_error_handler_abort;
-
-/**
- * \var igraph_error_handler_ignore
- * \brief Ignore errors.
- *
- * This error handler frees the temporarily allocated memory and returns
- * with the error code. 
- */
-
-extern igraph_error_handler_t igraph_error_handler_ignore;
-
-/**
- * \var igraph_error_handler_printignore
- * \brief Print and ignore errors.
- * 
- * Frees temporarily allocated memory, prints an error message to the
- * standard error and returns with the error code. 
- */
-
-extern igraph_error_handler_t igraph_error_handler_printignore;
-
-/**
- * \function igraph_set_error_handler
- * \brief Set a new error handler.
- *
- * Installs a new error handler. If called with 0, it installs the
- * default error handler (which is currently
- * \ref igraph_error_handler_abort). 
- * \param new_handler The error handler function to install.
- * \return The old error handler function. This should be saved and
- *   restored if \p new_handler is not needed any
- *   more.
- */
-
-igraph_error_handler_t*
-igraph_set_error_handler(igraph_error_handler_t* new_handler);
-
-/**
- * \typedef igraph_error_type_t
- * \brief Error code type.
- * These are the possible values returned by \a igraph functions.
- * Note that these are interesting only if you defined an error handler
- * with \ref igraph_set_error_handler(). Otherwise the program is aborted 
- * and the function causing the error never returns.
- * 
- * \enumval IGRAPH_SUCCESS The function successfully completed its task.
- * \enumval IGRAPH_FAILURE Something went wrong. You'll almost never
- *    meet this error as normally more specific error codes are used.
- * \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
- *    number was specified as the number of vertices.
- * \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already
- *    installed with the given name.
- * \enumval IGRAPH_EINVEVECTOR Invalid vector of vertex ids. A vertex id
- *    is either negative or bigger than the number of vertices minus one.
- * \enumval IGRAPH_EINVVID Invalid vertex id, negative or too big.
- * \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,
- *   or the user has no rights to open it.
- * \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or
- *   disabled (at compile-time) function.
- * \enumval IGRAPH_DIVERGED A numeric algorithm failed to converge.
- * \enumval IGRAPH_ARPACK_PROD Matrix-vector product failed.
- * \enumval IGRAPH_ARPACK_NPOS N must be positive.
- * \enumval IGRAPH_ARPACK_NEVNPOS NEV must be positive.
- * \enumval IGRAPH_ARPACK_NCVSMALL NCV must be bigger.
- * \enumval IGRAPH_ARPACK_NONPOSI Maximum number of iterations should be positive.
- * \enumval IGRAPH_ARPACK_WHICHINV Invalid WHICH parameter.
- * \enumval IGRAPH_ARPACK_BMATINV Invalid BMAT parameter.
- * \enumval IGRAPH_ARPACK_WORKLSMALL WORKL is too small.
- * \enumval IGRAPH_ARPACK_TRIDERR LAPACK error in tridiagonal eigenvalue calculation.
- * \enumval IGRAPH_ARPACK_ZEROSTART Starting vector is zero.
- * \enumval IGRAPH_ARPACK_MODEINV MODE is invalid.
- * \enumval IGRAPH_ARPACK_MODEBMAT MODE and BMAT are not compatible.
- * \enumval IGRAPH_ARPACK_ISHIFT ISHIFT must be 0 or 1.
- * \enumval IGRAPH_ARPACK_NEVBE NEV and WHICH='BE' are incompatible.
- * \enumval IGRAPH_ARPACK_NOFACT Could not build an Arnoldi factorization.
- * \enumval IGRAPH_ARPACK_FAILED No eigenvalues to sufficient accuracy.
- * \enumval IGRAPH_ARPACK_HOWMNY HOWMNY is invalid.
- * \enumval IGRAPH_ARPACK_HOWMNYS HOWMNY='S' is not implemented.
- * \enumval IGRAPH_ARPACK_EVDIFF Different number of converged Ritz values.
- * \enumval IGRAPH_ARPACK_SHUR Error from calculation of a real Schur form.
- * \enumval IGRAPH_ARPACK_LAPACK LAPACK (dtrevc) error for calculating eigenvectors.
- * \enumval IGRAPH_ARPACK_UNKNOWN Unknown ARPACK error.
- * \enumval IGRAPH_ENEGLOOP Negative loop detected while calculating shortest paths.
- * \enumval IGRAPH_EINTERNAL Internal error, likely a bug in igraph.
- * \enumval IGRAPH_EDIVZERO Big integer division by zero.
- * \enumval IGARPH_GLP_EBOUND GLPK error (GLP_EBOUND).
- * \enumval IGARPH_GLP_EROOT GLPK error (GLP_EROOT).
- * \enumval IGARPH_GLP_ENOPFS GLPK error (GLP_ENOPFS).
- * \enumval IGARPH_GLP_ENODFS GLPK error (GLP_ENODFS).
- * \enumval IGARPH_GLP_EFAIL GLPK error (GLP_EFAIL).
- * \enumval IGARPH_GLP_EMIPGAP GLPK error (GLP_EMIPGAP).
- * \enumval IGARPH_GLP_ETMLIM GLPK error (GLP_ETMLIM).
- * \enumval IGARPH_GLP_ESTOP GLPK error (GLP_ESTOP).
- * \enumval IGRAPH_EATTRIBUTES Attribute handler error. The user is not 
- *   expected to find this; it is signalled if some igraph function is
- *   not using the attribute handler interface properly.
- * \enumval IGRAPH_EATTRCOMBINE Unimplemented attribute combination 
- *   method for the given attribute type.
- * \enumval IGRAPH_ELAPACK A LAPACK call resulted an error.
- * \enumval IGRAPH_EDRL Internal error in the DrL layout generator.
- * \enumval IGRAPH_EOVERFLOW Integer or double overflow.
- * \enumval IGRAPH_EGLP Internal GLPK error.
- * \enumval IGRAPH_CPUTIME CPU time exceeded.
- * \enumval IGRAPH_EUNDERFLOW Integer or double underflow.
- */
-
-typedef enum {
-  IGRAPH_SUCCESS       = 0,
-  IGRAPH_FAILURE       = 1,
-  IGRAPH_ENOMEM        = 2,
-  IGRAPH_PARSEERROR    = 3,
-  IGRAPH_EINVAL        = 4,
-  IGRAPH_EXISTS        = 5,
-  IGRAPH_EINVEVECTOR   = 6,
-  IGRAPH_EINVVID       = 7,
-  IGRAPH_NONSQUARE     = 8,
-  IGRAPH_EINVMODE      = 9,
-  IGRAPH_EFILE         = 10,
-  IGRAPH_UNIMPLEMENTED = 12,
-  IGRAPH_INTERRUPTED   = 13,
-  IGRAPH_DIVERGED      = 14,
-  IGRAPH_ARPACK_PROD      = 15,
-  IGRAPH_ARPACK_NPOS      = 16,
-  IGRAPH_ARPACK_NEVNPOS   = 17,
-  IGRAPH_ARPACK_NCVSMALL  = 18,
-  IGRAPH_ARPACK_NONPOSI   = 19,
-  IGRAPH_ARPACK_WHICHINV  = 20,
-  IGRAPH_ARPACK_BMATINV   = 21,
-  IGRAPH_ARPACK_WORKLSMALL= 22,
-  IGRAPH_ARPACK_TRIDERR   = 23,
-  IGRAPH_ARPACK_ZEROSTART = 24,
-  IGRAPH_ARPACK_MODEINV   = 25,
-  IGRAPH_ARPACK_MODEBMAT  = 26,
-  IGRAPH_ARPACK_ISHIFT    = 27,
-  IGRAPH_ARPACK_NEVBE     = 28,
-  IGRAPH_ARPACK_NOFACT    = 29,
-  IGRAPH_ARPACK_FAILED    = 30,
-  IGRAPH_ARPACK_HOWMNY    = 31,
-  IGRAPH_ARPACK_HOWMNYS   = 32,
-  IGRAPH_ARPACK_EVDIFF    = 33,
-  IGRAPH_ARPACK_SHUR      = 34,
-  IGRAPH_ARPACK_LAPACK    = 35,
-  IGRAPH_ARPACK_UNKNOWN   = 36,
-  IGRAPH_ENEGLOOP         = 37,
-  IGRAPH_EINTERNAL        = 38,
-  IGRAPH_ARPACK_MAXIT     = 39,
-  IGRAPH_ARPACK_NOSHIFT   = 40,
-  IGRAPH_ARPACK_REORDER   = 41,
-  IGRAPH_EDIVZERO         = 42,
-  IGRAPH_GLP_EBOUND       = 43,
-  IGRAPH_GLP_EROOT        = 44,
-  IGRAPH_GLP_ENOPFS       = 45,
-  IGRAPH_GLP_ENODFS       = 46,
-  IGRAPH_GLP_EFAIL        = 47, 
-  IGRAPH_GLP_EMIPGAP      = 48,
-  IGRAPH_GLP_ETMLIM       = 49,
-  IGRAPH_GLP_ESTOP        = 50,
-  IGRAPH_EATTRIBUTES      = 51,
-  IGRAPH_EATTRCOMBINE     = 52,
-  IGRAPH_ELAPACK          = 53,
-  IGRAPH_EDRL             = 54,
-  IGRAPH_EOVERFLOW        = 55,
-  IGRAPH_EGLP             = 56,
-  IGRAPH_CPUTIME          = 57,
-  IGRAPH_EUNDERFLOW       = 58
-} igraph_error_type_t;
-
-/**
- * \define IGRAPH_ERROR
- * \brief Trigger an error.
- * 
- * \a igraph functions usually use this macro when they notice an error.
- * It calls
- * \ref igraph_error() with the proper parameters and if that returns 
- * the macro returns the "calling" function as well, with the error
- * code. If for some (suspicious) reason you want to call the error
- * handler without returning from the current function, call
- * \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,
- *   its associated text (see  \ref igraph_strerror()) is "Invalid
- *   value" and this string should explain which parameter was invalid
- *   and maybe why. 
- * \param igraph_errno The \a igraph error code.
- */
-
-#define IGRAPH_ERROR(reason,igraph_errno) \
-       do { \
-       igraph_error (reason, __FILE__, __LINE__, igraph_errno) ; \
-       return igraph_errno ; \
-       } while (0)
-
-/**
- * \function igraph_error
- * \brief Trigger an error.
- *
- * \a igraph functions usually call this function (most often via the 
- * \ref IGRAPH_ERROR macro) if they notice an error.
- * It calls the currently installed error handler function with the
- * supplied arguments. 
- *
- * \param reason Textual description of the error.
- * \param file The source file in which the error was noticed.
- * \param line The number of line in the source file which triggered the
- *   error.
- * \param igraph_errno The \a igraph error code.
- * \return the error code (if it returns)
- * 
- * \sa igraph_errorf().
- */
-
-int igraph_error(const char *reason, const char *file, int line,
-		 int igraph_errno);
-
-/**
- * \function igraph_errorf
- * \brief Trigger an error, printf-like version.
- * 
- * \param reason Textual description of the error, interpreted as 
- *               a 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.
- * \param ... Additional parameters, the values to substitute into the
- *            format string.
- * 
- * \sa igraph_error().
- */
-
-int igraph_errorf(const char *reason, const char *file, int line, 
-		  int igraph_errno, ...);
-
-int igraph_errorvf(const char *reason, const char *file, int line,
-		   int igraph_errno, va_list ap);
-
-/**
- * \function igraph_strerror
- * \brief Textual description of an error.
- * 
- * This is a simple utility function, it gives a short general textual
- * description for an \a igraph error code.
- * 
- * \param igraph_errno The \a igraph error code.
- * \return pointer to the textual description of the error code.
- */
-
-const char* igraph_strerror(const int igraph_errno);
-
-#define IGRAPH_ERROR_SELECT_2(a,b)       ((a) != IGRAPH_SUCCESS ? (a) : ((b) != IGRAPH_SUCCESS ? (b) : IGRAPH_SUCCESS))
-#define IGRAPH_ERROR_SELECT_3(a,b,c)     ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_2(b,c))
-#define IGRAPH_ERROR_SELECT_4(a,b,c,d)   ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_3(b,c,d))
-#define IGRAPH_ERROR_SELECT_5(a,b,c,d,e) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_4(b,c,d,e))
-
-/* Now comes the more convenient error handling macro arsenal.
- * Ideas taken from exception.{h,c} by Laurent Deniau see
- * http://cern.ch/Laurent.Deniau/html/oopc/oopc.html#Exceptions for more 
- * information. We don't use the exception handling code though.  */
-
-struct igraph_i_protectedPtr {
-  int all;
-  void *ptr;
-  void (*func)(void*);
-};
-
-typedef void igraph_finally_func_t (void*);
-
-void IGRAPH_FINALLY_REAL(void (*func)(void*), void* ptr);
-
-/**
- * \function IGRAPH_FINALLY_CLEAN
- * \brief Signal clean deallocation of objects.
- * 
- * Removes the specified number of objects from the stack of
- * temporarily allocated objects. Most often this is called just
- * before returning from a function.
- * \param num The number of objects to remove from the bookkeeping
- *   stack. 
- */
-
-void IGRAPH_FINALLY_CLEAN(int num); 
-
-/**
- * \function IGRAPH_FINALLY_FREE
- * \brief Deallocate all registered objects.
- *
- * Calls the destroy function for all objects in the stack of
- * temporarily allocated objects. This is usually called only from an
- * error handler. It is \em not appropriate to use it
- * instead of destroying each unneeded object of a function, as it
- * destroys the temporary objects of the caller function (and so on)
- * as well.
- */
-
-void IGRAPH_FINALLY_FREE(void);
-
-/**
- * \function IGRAPH_FINALLY_STACK_SIZE
- * \brief Returns the number of registered objects.
- *
- * Returns the number of objects in the stack of temporarily allocated
- * objects. This function is handy if you write an own igraph routine and
- * you want to make sure it handles errors properly. A properly written
- * igraph routine should not leave pointers to temporarily allocated objects
- * in the finally stack, because otherwise an \ref IGRAPH_FINALLY_FREE call
- * in another igraph function would result in freeing these objects as well
- * (and this is really hard to debug, since the error will be not in that
- * function that shows erroneous behaviour). Therefore, it is advised to
- * write your own test cases and examine \ref IGRAPH_FINALLY_STACK_SIZE
- * before and after your test cases - the numbers should be equal.
- */
-int IGRAPH_FINALLY_STACK_SIZE(void);
-
-/**
- * \define IGRAPH_FINALLY_STACK_EMPTY
- * \brief Returns true if there are no registered objects, false otherwise.
- *
- * This is just a shorthand notation for checking that
- * \ref IGRAPH_FINALLY_STACK_SIZE is zero.
- */
-#define IGRAPH_FINALLY_STACK_EMPTY (IGRAPH_FINALLY_STACK_SIZE() == 0)
-
-/**
- * \define IGRAPH_FINALLY
- * \brief Register an object for deallocation.
- * \param func The address of the function which is normally called to
- *   destroy the object.
- * \param ptr Pointer to the object itself.
- * 
- * This macro places the address of an object, together with the
- * address of its destructor in a stack. This stack is used if an
- * error happens to deallocate temporarily allocated objects to
- * prevent memory leaks.
- */
-
-#define IGRAPH_FINALLY(func,ptr) \
-  IGRAPH_FINALLY_REAL((igraph_finally_func_t*)(func), (ptr))
-
-#if (defined(__GNUC__) && GCC_VERSION_MAJOR >= 3)
-#  define IGRAPH_UNLIKELY(a) __builtin_expect((a), 0)
-#  define IGRAPH_LIKELY(a)   __builtin_expect((a), 1)
-#else
-#  define IGRAPH_UNLIKELY(a) a
-#  define IGRAPH_LIKELY(a)   a
-#endif
-
-/**
- * \define IGRAPH_CHECK
- * \brief Check the return value of a function call.
- *
- * \param a An expression, usually a function call.
- * 
- * Executes the expression and checks its value. If this is not
- * \c IGRAPH_SUCCESS, it calls \ref IGRAPH_ERROR with
- * the value as the error code. Here is an example usage:
- * \verbatim IGRAPH_CHECK(vector_push_back(&v, 100)); \endverbatim
- * 
- * </para><para>There is only one reason to use this macro when writing 
- * \a igraph functions. If the user installs an error handler which
- * returns to the auxiliary calling code (like \ref
- * igraph_error_handler_ignore and \ref
- * 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
- * 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)
-
-
-/**
- * \section about_igraph_warnings Warning messages
- * 
- * <para>
- * Igraph also supports warning messages in addition to error 
- * messages. Warning messages typically do not terminate the 
- * program, but they are usually crucial to the user.
- * </para>
- * 
- * <para>
- * Igraph warning are handled similarly to errors. There is a 
- * separate warning handler function that is called whenever
- * an igraph function triggers a warning. This handler can be 
- * set by the \ref igraph_set_warning_handler() function. There are 
- * two predefined simple warning handlers, 
- * \ref igraph_warning_handler_ignore() and 
- * \ref igraph_warning_handler_print(), the latter being the default.
- * </para>
- * 
- * <para>
- * To trigger a warning, igraph functions typically use the 
- * \ref IGRAPH_WARNING() macro, the \ref igraph_warning() function, 
- * or if more flexibility is needed, \ref igraph_warningf().
- * </para>
- */
-
-/**
- * \typedef igraph_warning_handler_t
- * Type of igraph warning handler functions
- * 
- * Currently it is defined to have the same type as 
- * \ref igraph_error_handler_t, although the last (error code)
- * argument is not used.
- */
-
-typedef igraph_error_handler_t igraph_warning_handler_t;
-
-/**
- * \function igraph_set_warning_handler
- * Install a warning handler
- * 
- * Install the supplied warning handler function.
- * \param new_handler The new warning handler function to install.
- *        Supply a null pointer here to uninstall the current 
- *        warning handler, without installing a new one.
- * \return The current warning handler function.
- */
-
-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;
-
-/**
- * \function igraph_warning
- * Trigger a warning
- * 
- * Call this function if you want to trigger a warning from within 
- * a function that uses igraph.
- * \param reason Textual description of the warning.
- * \param file The source file in which the warning was noticed.
- * \param line The number of line in the source file which triggered the
- *         warning.
- * \param igraph_errno Warnings could have potentially error codes as well, 
- *        but this is currently not used in igraph.
- * \return The supplied error code.
- */
-
-int igraph_warning(const char *reason, const char *file, int line,
-		   int igraph_errno);
-
-/**
- * \function igraph_warningf
- * Trigger a warning, more flexible printf-like syntax
- * 
- * This function is similar to \ref igraph_warning(), but
- * uses a printf-like syntax. It substitutes the additional arguments 
- * into the \p reason template string and calls \ref igraph_warning().
- * \param reason Textual description of the warning, a template string
- *        with the same syntax as the standard printf C library function.
- * \param file The source file in which the warning was noticed.
- * \param line The number of line in the source file which triggered the
- *         warning.
- * \param igraph_errno Warnings could have potentially error codes as well, 
- *        but this is currently not used in igraph.
- * \param ... The additional arguments to be substituted into the 
- *        template string.
- * \return The supplied error code.
- */
-
-int igraph_warningf(const char *reason, const char *file, int line, 
-		    int igraph_errno, ...);
-
-/**
- * \define IGRAPH_WARNING
- * Trigger a warning.
- * 
- * This is the usual way of triggering a warning from an igraph
- * function. It calls \ref igraph_warning().
- * \param reason The warning message.
- */
-
-#define IGRAPH_WARNING(reason) \
-       do { \
-         igraph_warning(reason, __FILE__, __LINE__, -1); \
-       } while (0)
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_games.h b/src/igraph_games.h
deleted file mode 100644
index 08bd483..0000000
--- a/src/igraph_games.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_GAMES_H
-#define IGRAPH_GAMES_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
-
-#include "igraph_constants.h"
-#include "igraph_types.h"
-#include "igraph_matrix.h"
-#include "igraph_vector.h"
-#include "igraph_datatype.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Constructors, games (=stochastic)                  */
-/* -------------------------------------------------- */
-
-int igraph_barabasi_game(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,
-			 igraph_barabasi_algorithm_t algo,
-			 const igraph_t *start_from);
-int igraph_nonlinear_barabasi_game(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 zeroappeal,
-				   igraph_bool_t directed);
-int igraph_erdos_renyi_game(igraph_t *graph, igraph_erdos_renyi_t type,
-			    igraph_integer_t n, igraph_real_t p,
-			    igraph_bool_t directed, igraph_bool_t loops);
-int igraph_erdos_renyi_game_gnp(igraph_t *graph, igraph_integer_t n, igraph_real_t p,
-				igraph_bool_t directed, igraph_bool_t loops);
-int igraph_erdos_renyi_game_gnm(igraph_t *graph, igraph_integer_t n, igraph_real_t m,
-				igraph_bool_t directed, igraph_bool_t loops);
-int igraph_degree_sequence_game(igraph_t *graph, const igraph_vector_t *out_deg,
-				const igraph_vector_t *in_deg, 
-				igraph_degseq_t method);
-int igraph_growing_random_game(igraph_t *graph, igraph_integer_t n, 
-			       igraph_integer_t m, igraph_bool_t directed, igraph_bool_t citation);
-int igraph_barabasi_aging_game(igraph_t *graph, 
-			       igraph_integer_t nodes,
-			       igraph_integer_t m,
-			       const igraph_vector_t *outseq,
-			       igraph_bool_t outpref,
-			       igraph_real_t pa_exp,
-			       igraph_real_t aging_exp,
-			       igraph_integer_t aging_bin,
-			       igraph_real_t zero_deg_appeal,
-			       igraph_real_t zero_age_appeal,
-			       igraph_real_t deg_coef,
-			       igraph_real_t age_coef,
-			       igraph_bool_t directed);
-int igraph_recent_degree_game(igraph_t *graph, igraph_integer_t n,
-			      igraph_real_t power,
-			      igraph_integer_t window,
-			      igraph_integer_t m,  
-			      const igraph_vector_t *outseq,
-			      igraph_bool_t outpref,
-			      igraph_real_t zero_appeal,
-			      igraph_bool_t directed);
-int igraph_recent_degree_aging_game(igraph_t *graph,
-				    igraph_integer_t nodes,
-				    igraph_integer_t m, 
-				    const igraph_vector_t *outseq,
-				    igraph_bool_t outpref,
-				    igraph_real_t pa_exp,
-				    igraph_real_t aging_exp,
-				    igraph_integer_t aging_bin,
-				    igraph_integer_t window,
-				    igraph_real_t zero_appeal,
-				    igraph_bool_t directed);
-int igraph_callaway_traits_game (igraph_t *graph, igraph_integer_t nodes, 
-				 igraph_integer_t types, igraph_integer_t edges_per_step, 
-				 igraph_vector_t *type_dist,
-				 igraph_matrix_t *pref_matrix,
-				 igraph_bool_t directed);
-int igraph_establishment_game(igraph_t *graph, igraph_integer_t nodes,
-			      igraph_integer_t types, igraph_integer_t k,
-			      igraph_vector_t *type_dist,
-			      igraph_matrix_t *pref_matrix,
-			      igraph_bool_t directed);
-int igraph_grg_game(igraph_t *graph, igraph_integer_t nodes,
-		    igraph_real_t radius, igraph_bool_t torus,
-		    igraph_vector_t *x, igraph_vector_t *y);
-int igraph_preference_game(igraph_t *graph, igraph_integer_t nodes,
-			   igraph_integer_t types, 
-			   const igraph_vector_t *type_dist,
-			   igraph_bool_t fixed_sizes,
-			   const igraph_matrix_t *pref_matrix,
-			   igraph_vector_t *node_type_vec,
-			   igraph_bool_t directed, igraph_bool_t loops);
-int igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer_t nodes,
-				      igraph_integer_t types,
-				      igraph_matrix_t *type_dist_matrix,
-				      igraph_matrix_t *pref_matrix,
-				      igraph_vector_t *node_type_in_vec,
-				      igraph_vector_t *node_type_out_vec,
-				      igraph_bool_t loops);
-
-int igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, 
-			igraph_bool_t loops, igraph_bool_t multiple);
-int igraph_watts_strogatz_game(igraph_t *graph, igraph_integer_t dim,
-			       igraph_integer_t size, igraph_integer_t nei,
-			       igraph_real_t p, igraph_bool_t loops, 
-			       igraph_bool_t multiple);
-
-int igraph_lastcit_game(igraph_t *graph, 
-			igraph_integer_t nodes, igraph_integer_t edges_per_node, 
-			igraph_integer_t agebins,
-			const igraph_vector_t *preference, igraph_bool_t directed);
-
-int igraph_cited_type_game(igraph_t *graph, igraph_integer_t nodes,
-			   const igraph_vector_t *types,
-			   const igraph_vector_t *pref,
-			   igraph_integer_t edges_per_step,
-			   igraph_bool_t directed);
-
-int igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t nodes,
-				  const igraph_vector_t *types,
-				  const igraph_matrix_t *pref,
-				  igraph_integer_t edges_per_step,
-				  igraph_bool_t directed);
-
-int igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes,
-			    igraph_real_t fw_prob, igraph_real_t bw_factor,
-			    igraph_integer_t ambs, igraph_bool_t directed);
-
-
-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);
-
-int igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_of_edges,
-                igraph_vector_t* fitness_out, igraph_vector_t* fitness_in,
-                igraph_bool_t loops, igraph_bool_t multiple);
-
-int igraph_static_power_law_game(igraph_t *graph,
-    igraph_integer_t no_of_nodes, igraph_integer_t no_of_edges,
-    igraph_real_t exponent_out, igraph_real_t exponent_in,
-    igraph_bool_t loops, igraph_bool_t multiple,
-    igraph_bool_t finite_size_correction);
-
-int igraph_k_regular_game(igraph_t *graph,
-    igraph_integer_t no_of_nodes, igraph_integer_t k,
-    igraph_bool_t directed, igraph_bool_t multiple);
-
-int igraph_sbm_game(igraph_t *graph, igraph_integer_t n, 
-		    const igraph_matrix_t *pref_matrix,
-		    const igraph_vector_int_t *block_sizes,
-		    igraph_bool_t directed, igraph_bool_t loops);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_lapack.h b/src/igraph_lapack.h
deleted file mode 100644
index 90ea388..0000000
--- a/src/igraph_lapack.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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 LAPACK_H
-#define LAPACK_H
-
-#include "igraph_vector.h"
-#include "igraph_matrix.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
-
-/**
- * \section about_lapack LAPACK interface in igraph
- * 
- * <para>
- * LAPACK is written in Fortran90 and provides routines for solving
- * systems of simultaneous linear equations, least-squares solutions
- * of linear systems of equations, eigenvalue problems, and singular
- * value problems. The associated matrix factorizations (LU, Cholesky,
- * QR, SVD, Schur, generalized Schur) are also provided, as are
- * related computations such as reordering of the Schur factorizations
- * and estimating condition numbers. Dense and banded matrices are
- * handled, but not general sparse matrices. In all areas, similar
- * functionality is provided for real and complex matrices, in both
- * single and double precision.
- * </para>
- * 
- * <para>
- * igraph provides an interface to a very limited set of LAPACK
- * functions, using the regular igraph data structures.
- * </para>
- * 
- * <para>
- * See more about LAPACK at http://www.netlib.org/lapack/
- * </para>
- */
-
-int igraph_lapack_dgetrf(igraph_matrix_t *a, igraph_vector_int_t *ipiv,
-			 int *info);
-int igraph_lapack_dgetrs(igraph_bool_t transpose, const igraph_matrix_t *a,
-			 igraph_vector_int_t *ipiv, igraph_matrix_t *b);
-int igraph_lapack_dgesv(igraph_matrix_t *a, igraph_vector_int_t *ipiv,
-			igraph_matrix_t *b, int *info);
-
-typedef enum { IGRAPH_LAPACK_DSYEV_ALL,
-	       IGRAPH_LAPACK_DSYEV_INTERVAL,
-	       IGRAPH_LAPACK_DSYEV_SELECT } igraph_lapack_dsyev_which_t;
-
-int igraph_lapack_dsyevr(const igraph_matrix_t *A, 
-			 igraph_lapack_dsyev_which_t which,
-			 igraph_real_t vl, igraph_real_t vu, int vestimate, 
-			 int il, int iu, igraph_real_t abstol,
-			 igraph_vector_t *values, igraph_matrix_t *vectors,
-			 igraph_vector_int_t *support);
-
-/* TODO: should we use complex vectors/matrices? */
-
-int igraph_lapack_dgeev(const igraph_matrix_t *A, 
-			igraph_vector_t *valuesreal,
-			igraph_vector_t *valuesimag, 
-			igraph_matrix_t *vectorsleft,
-			igraph_matrix_t *vectorsright, int *info);
-
-typedef enum { IGRAPH_LAPACK_DGEEVX_BALANCE_NONE=0, 
-	       IGRAPH_LAPACK_DGEEVX_BALANCE_PERM,
-	       IGRAPH_LAPACK_DGEEVX_BALANCE_SCALE,
-	       IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH } 
-  igraph_lapack_dgeevx_balance_t;
-
-int igraph_lapack_dgeevx(igraph_lapack_dgeevx_balance_t balance,
-			 const igraph_matrix_t *A,
-			 igraph_vector_t *valuesreal,
-			 igraph_vector_t *valuesimag,
-			 igraph_matrix_t *vectorsleft,
-			 igraph_matrix_t *vectorsright,
-			 int *ilo, int *ihi, igraph_vector_t *scale,
-			 igraph_real_t *abnrm,
-			 igraph_vector_t *rconde,
-			 igraph_vector_t *rcondv,
-			 int *info);
-
-int igraph_lapack_dgehrd(const igraph_matrix_t *A, 
-			 int ilo, int ihi,
-			 igraph_matrix_t *result);
-			
-__END_DECLS
-
-#endif
diff --git a/src/igraph_lapack_internal.h b/src/igraph_lapack_internal.h
index 1466b9a..e0331d5 100644
--- a/src/igraph_lapack_internal.h
+++ b/src/igraph_lapack_internal.h
@@ -83,6 +83,7 @@
 #define igraphdlaln2_	dlaln2_
 #define igraphdladiv_	dladiv_
 #define igraphdsyevr_	dsyevr_
+#define igraphdsyrk_    dsyrk_
 #define igraphdlansy_	dlansy_
 #define igraphdormtr_	dormtr_
 #define igraphdormql_	dormql_
@@ -116,6 +117,7 @@
 #define igraphdlarrv_	dlarrv_
 #define igraphdlar1v_	dlar1v_
 #define igraphdlarrf_	dlarrf_
+#define igraphdpotrf_   dpotrf_
 #define igraphdsterf_	dsterf_
 #define igraphdsytrd_	dsytrd_
 #define igraphdlatrd_	dlatrd_
@@ -138,6 +140,7 @@
 #define igraph_dlamc3_  dlamc3_
 #define igraph_dlamc4_  dlamc4_
 #define igraph_dlamc5_  dlamc5_
+#define igraphddot_     ddot_
 #endif
 
 int igraphdgetrf_(int *m, int *n, igraph_real_t *a, int *lda, int *ipiv,
@@ -175,4 +178,7 @@ int igraphdgehrd_(int *n, int *ilo, int *ihi, igraph_real_t *A, int *lda,
 		  igraph_real_t *tau, igraph_real_t *work, int *lwork,
 		  int *info);
 
+igraph_real_t igraphddot_(int *n, igraph_real_t *dx, int *incx, 
+			  igraph_real_t *dy, int *incy);
+
 #endif
diff --git a/src/igraph_layout.h b/src/igraph_layout.h
deleted file mode 100644
index aa87e5b..0000000
--- a/src/igraph_layout.h
+++ /dev/null
@@ -1,253 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_LAYOUT_H
-#define IGRAPH_LAYOUT_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
-
-#include "igraph_constants.h"
-#include "igraph_types.h"
-#include "igraph_vector.h"
-#include "igraph_vector_ptr.h"
-#include "igraph_matrix.h"
-#include "igraph_datatype.h"
-#include "igraph_arpack.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Layouts                                            */
-/* -------------------------------------------------- */
-
-int igraph_layout_random(const igraph_t *graph, igraph_matrix_t *res);
-int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res);
-int igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res,
-		       igraph_integer_t center, const igraph_vector_t *order);
-int igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, long int width);
-int igraph_layout_fruchterman_reingold(const igraph_t *graph, igraph_matrix_t *res,
-				       igraph_integer_t niter, igraph_real_t maxdelta,
-				       igraph_real_t area, igraph_real_t coolexp, 
-				       igraph_real_t repulserad, igraph_bool_t use_seed,
-				       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);
-int igraph_layout_grid_fruchterman_reingold(const igraph_t *graph, 
-					    igraph_matrix_t *res,
-					    igraph_integer_t niter, igraph_real_t maxdelta, 
-					    igraph_real_t area, igraph_real_t coolexp,
-					    igraph_real_t repulserad, 
-					    igraph_real_t cellsize, igraph_bool_t use_seed,
-                        const igraph_vector_t *weight);
-int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res,
-			       igraph_integer_t niter, igraph_real_t sigma, 
-			       igraph_real_t initemp, igraph_real_t coolexp,
-			       igraph_real_t kkconst, igraph_bool_t use_seed,
-			       const igraph_vector_t *minx,
-			       const igraph_vector_t *maxx,
-			       const igraph_vector_t *miny,
-			       const igraph_vector_t *maxy);
-int igraph_layout_springs(const igraph_t *graph, igraph_matrix_t *res,
-			  igraph_real_t mass, igraph_real_t equil, igraph_real_t k,
-			  igraph_real_t repeqdis, igraph_real_t kfr, igraph_bool_t repulse);
-int igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res,
-		      igraph_integer_t maxiter, igraph_real_t maxdelta, 
-		      igraph_real_t area, igraph_real_t coolexp,
-		      igraph_real_t repulserad, igraph_real_t cellsize, igraph_integer_t root);
-int igraph_layout_reingold_tilford(const igraph_t *graph, igraph_matrix_t *res,
-				   igraph_neimode_t mode,
-				   const igraph_vector_t *roots,
-				   const igraph_vector_t *rootlevel);
-int igraph_layout_reingold_tilford_circular(const igraph_t *graph,
-					    igraph_matrix_t *res, 
-					    igraph_neimode_t mode,
-					    const igraph_vector_t *roots,
-					    const igraph_vector_t *rootlevel);
-int igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *res,
-        igraph_t *extd_graph, igraph_vector_t *extd_to_orig_eids,
-        const igraph_vector_t* layers, igraph_real_t hgap,
-        igraph_real_t vgap, long int maxiter, const igraph_vector_t *weights);
-
-int igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res);
-int igraph_layout_sphere(const igraph_t *graph, igraph_matrix_t *res);
-int igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res,
-        long int width, long int height);
-int igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, 
-					  igraph_matrix_t *res,
-					  igraph_integer_t niter, igraph_real_t maxdelta,
-					  igraph_real_t volume, igraph_real_t coolexp,
-					  igraph_real_t repulserad,
-					  igraph_bool_t use_seed,
-					  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,
-					  const igraph_vector_t *minz,
-					  const igraph_vector_t *maxz);
-
-int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res,
-				  igraph_integer_t niter, igraph_real_t sigma, 
-				  igraph_real_t initemp, igraph_real_t coolexp, 
-				  igraph_real_t kkconst, igraph_bool_t use_seed,
-				  igraph_bool_t fixz, 
-				  const igraph_vector_t *minx,
-				  const igraph_vector_t *maxx,
-				  const igraph_vector_t *miny,
-				  const igraph_vector_t *maxy,
-				  const igraph_vector_t *minz,
-				  const igraph_vector_t *maxz);
-
-int igraph_layout_graphopt(const igraph_t *graph, 
-			   igraph_matrix_t *res, igraph_integer_t niter,
-			   igraph_real_t node_charge, igraph_real_t node_mass,
-			   igraph_real_t spring_length,
-			   igraph_real_t spring_constant, 
-			   igraph_real_t max_sa_movement,
-			   igraph_bool_t use_seed);
-
-int igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, 
-                      const igraph_matrix_t *dist, long int dim,
-                      igraph_arpack_options_t *options);
-
-int igraph_layout_bipartite(const igraph_t *graph, 
-			    const igraph_vector_bool_t *types,
-			    igraph_matrix_t *res, igraph_real_t hgap, 
-			    igraph_real_t vgap, long int maxiter);
-
-/** 
- * \struct igraph_layout_drl_options_t
- * Parameters for the DrL layout generator
- *
- * \member edge_cut The edge cutting parameter.
- *    Edge cutting is done in the late stages of the
- *    algorithm in order to achieve less dense layouts.  Edges are cut
- *    if there is a lot of stress on them (a large value in the
- *    objective function sum).  The edge cutting parameter is a value
- *    between 0 and 1 with 0 representing no edge cutting and 1
- *    representing maximal edge cutting. The default value is 32/40.
- * \member init_iterations Number of iterations, initial phase.
- * \member init_temperature Start temperature, initial phase.
- * \member init_attraction Attraction, initial phase.
- * \member init_damping_mult Damping factor, initial phase.
- * \member liquid_iterations Number of iterations in the liquid phase.
- * \member liquid_temperature Start temperature in the liquid phase.
- * \member liquid_attraction Attraction in the liquid phase.
- * \member liquid_damping_mult Multiplicatie damping factor, liquid phase.
- * \member expansion_iterations Number of iterations in the expansion phase.
- * \member expansion_temperature Start temperature in the expansion phase.
- * \member expansion_attraction Attraction, expansion phase.
- * \member expansion_damping_mult Damping factor, expansion phase.
- * \member cooldown_iterations Number of iterations in the cooldown phase.
- * \member cooldown_temperature Start temperature in the cooldown phase.
- * \member cooldown_attraction Attraction in the cooldown phase.
- * \member cooldown_damping_mult Damping fact int the cooldown phase.
- * \member crunch_iterations Number of iterations in the crunch phase.
- * \member crunch_temperature Start temperature in the crunch phase.
- * \member crunch_attraction Attraction in the crunch phase.
- * \member crunch_damping_mult Damping factor in the crunch phase.
- * \member simmer_iterations Number of iterations in the simmer phase.
- * \member simmer_temperature Start temperature in te simmer phase.
- * \member simmer_attraction Attraction in the simmer phase.
- * \member simmer_damping_mult Multiplicative damping factor in the simmer phase.
- */
-
-typedef struct igraph_layout_drl_options_t {
-  igraph_real_t    edge_cut;
-  igraph_integer_t init_iterations;
-  igraph_real_t    init_temperature;
-  igraph_real_t    init_attraction;
-  igraph_real_t    init_damping_mult;
-  igraph_integer_t liquid_iterations;
-  igraph_real_t    liquid_temperature;
-  igraph_real_t    liquid_attraction;
-  igraph_real_t    liquid_damping_mult;
-  igraph_integer_t expansion_iterations;
-  igraph_real_t    expansion_temperature;
-  igraph_real_t    expansion_attraction;
-  igraph_real_t    expansion_damping_mult;
-  igraph_integer_t cooldown_iterations;
-  igraph_real_t    cooldown_temperature;
-  igraph_real_t    cooldown_attraction;
-  igraph_real_t    cooldown_damping_mult;
-  igraph_integer_t crunch_iterations;
-  igraph_real_t    crunch_temperature;
-  igraph_real_t    crunch_attraction;
-  igraph_real_t    crunch_damping_mult;
-  igraph_integer_t simmer_iterations;
-  igraph_real_t    simmer_temperature;
-  igraph_real_t    simmer_attraction;
-  igraph_real_t    simmer_damping_mult;
-} igraph_layout_drl_options_t;
-
-/**
- * \typedef igraph_layout_drl_default_t 
- * Predefined parameter templates for the DrL layout generator
- * 
- * These constants can be used to initialize a set of DrL parameters. 
- * These can then be modified according to the user's needs.
- * \enumval IGRAPH_LAYOUT_DRL_DEFAULT The deafult parameters.
- * \enumval IGRAPH_LAYOUT_DRL_COARSEN Slightly modified parameters to
- *      get a coarser layout.  
- * \enumval IGRAPH_LAYOUT_DRL_COARSEST An even coarser layout.
- * \enumval IGRAPH_LAYOUT_DRL_REFINE Refine an already calculated layout.
- * \enumval IGRAPH_LAYOUT_DRL_FINAL Finalize an already refined layout.
- */
-
-typedef enum { IGRAPH_LAYOUT_DRL_DEFAULT=0, 
-	       IGRAPH_LAYOUT_DRL_COARSEN,
-	       IGRAPH_LAYOUT_DRL_COARSEST,
-	       IGRAPH_LAYOUT_DRL_REFINE,
-	       IGRAPH_LAYOUT_DRL_FINAL } igraph_layout_drl_default_t;
-
-int igraph_layout_drl_options_init(igraph_layout_drl_options_t *options,
-				   igraph_layout_drl_default_t templ);
-int igraph_layout_drl(const igraph_t *graph, igraph_matrix_t *res, 
-		      igraph_bool_t use_seed,
-		      igraph_layout_drl_options_t *options,
-		      const igraph_vector_t *weights, 
-		      const igraph_vector_bool_t *fixed);
-
-int igraph_layout_drl_3d(const igraph_t *graph, igraph_matrix_t *res, 
-			 igraph_bool_t use_seed,
-			 igraph_layout_drl_options_t *options,
-			 const igraph_vector_t *weights,
-			 const igraph_vector_bool_t *fixed);
-
-int igraph_layout_merge_dla(igraph_vector_ptr_t *graphs,
-			    igraph_vector_ptr_t *coords, 
-			    igraph_matrix_t *res);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_math.h b/src/igraph_math.h
index 4d33329..538d4bf 100644
--- a/src/igraph_math.h
+++ b/src/igraph_math.h
@@ -75,6 +75,10 @@ double igraph_fmin(double a, double b);
 #ifndef M_SQRT2
 #  define M_SQRT2 1.4142135623730950488016887
 #endif
+#ifndef M_LN_SQRT_2PI
+#define M_LN_SQRT_2PI   0.918938533204672741780329736406 /* log(sqrt(2*pi))
+							    == log(2*pi)/2 */
+#endif
 
 __END_DECLS
 
diff --git a/src/igraph_matrix.h b/src/igraph_matrix.h
deleted file mode 100644
index a17431a..0000000
--- a/src/igraph_matrix.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_MATRIX_H
-#define IGRAPH_MATRIX_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
-
-#include "igraph_vector.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Matrix, very similar to vector                     */
-/* -------------------------------------------------- */
-
-#define BASE_IGRAPH_REAL
-#include "igraph_pmt.h"
-#include "igraph_matrix_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_IGRAPH_REAL
-
-#define BASE_INT
-#include "igraph_pmt.h"
-#include "igraph_matrix_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_INT
-
-#define BASE_LONG
-#include "igraph_pmt.h"
-#include "igraph_matrix_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_LONG
-
-#define BASE_CHAR
-#include "igraph_pmt.h"
-#include "igraph_matrix_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_CHAR
-
-#define BASE_BOOL
-#include "igraph_pmt.h"
-#include "igraph_matrix_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_BOOL
-
-#define BASE_COMPLEX
-#include "igraph_pmt.h"
-#include "igraph_matrix_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_COMPLEX
-
-#define IGRAPH_MATRIX_NULL { IGRAPH_VECTOR_NULL, 0, 0 }
-#define IGRAPH_MATRIX_INIT_FINALLY(m, nr, nc) \
-  do { IGRAPH_CHECK(igraph_matrix_init(m, nr, nc)); \
-  IGRAPH_FINALLY(igraph_matrix_destroy, m); } while (0)
-
-/**
- * \ingroup matrix
- * \define MATRIX
- * \brief Accessing an element of a matrix.
- *
- * Note that there are no range checks right now. 
- * This functionality might be redefined as a proper function later. 
- * \param m The matrix object.
- * \param i The index of the row, starting with zero.
- * \param j The index of the column, starting with zero.
- *
- * Time complexity: O(1).
- */
-#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,
-				      const igraph_matrix_t *rhs,
-				      igraph_real_t tol);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_matrix_pmt.h b/src/igraph_matrix_pmt.h
deleted file mode 100644
index e8a4097..0000000
--- a/src/igraph_matrix_pmt.h
+++ /dev/null
@@ -1,234 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-typedef struct TYPE(igraph_matrix) {
-  TYPE(igraph_vector) data;
-  long int nrow, ncol;
-} TYPE(igraph_matrix);
-
-/*---------------*/
-/* Allocation    */
-/*---------------*/
-
-int FUNCTION(igraph_matrix,init)(TYPE(igraph_matrix) *m, 
-				 long int nrow, long int ncol);
-int FUNCTION(igraph_matrix,copy)(TYPE(igraph_matrix) *to, 
-				 const TYPE(igraph_matrix) *from);
-void FUNCTION(igraph_matrix,destroy)(TYPE(igraph_matrix) *m);
-long int FUNCTION(igraph_matrix,capacity)(const TYPE(igraph_matrix) *m);
-
-/*--------------------*/
-/* Accessing elements */
-/*--------------------*/
-
-/* MATRIX */
-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,
-				    long int row, long int col);
-void FUNCTION(igraph_matrix,set)(TYPE(igraph_matrix)* m, long int row, long int col,
-				 BASE value);
-
-/*------------------------------*/
-/* Initializing matrix elements */
-/*------------------------------*/
-
-void FUNCTION(igraph_matrix,null)(TYPE(igraph_matrix) *m);
-void FUNCTION(igraph_matrix,fill)(TYPE(igraph_matrix) *m, BASE e);
-
-/*------------------*/
-/* Copying matrices */
-/*------------------*/
-
-void FUNCTION(igraph_matrix,copy_to)(const TYPE(igraph_matrix) *m, BASE *to);
-int FUNCTION(igraph_matrix,update)(TYPE(igraph_matrix) *to, 
-				   const TYPE(igraph_matrix) *from);
-int FUNCTION(igraph_matrix,rbind)(TYPE(igraph_matrix) *to,
-				  const TYPE(igraph_matrix) *from);
-int FUNCTION(igraph_matrix,cbind)(TYPE(igraph_matrix) *to,
-				  const TYPE(igraph_matrix) *from);
-int FUNCTION(igraph_matrix,swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2);
-
-/*--------------------------*/
-/* Copying rows and columns */
-/*--------------------------*/
-
-int FUNCTION(igraph_matrix,get_row)(const TYPE(igraph_matrix) *m, 
-				    TYPE(igraph_vector) *res, long int index);
-int FUNCTION(igraph_matrix,get_col)(const TYPE(igraph_matrix) *m, 
-				    TYPE(igraph_vector) *res, long int index);
-int FUNCTION(igraph_matrix,set_row)(TYPE(igraph_matrix) *m,
-				     const TYPE(igraph_vector) *v, long int index);
-int FUNCTION(igraph_matrix,set_col)(TYPE(igraph_matrix) *m,
-				    const TYPE(igraph_vector) *v, long int index);
-int FUNCTION(igraph_matrix,select_rows)(const TYPE(igraph_matrix) *m,
-					TYPE(igraph_matrix) *res, 
-					const igraph_vector_t *rows);
-int FUNCTION(igraph_matrix,select_cols)(const TYPE(igraph_matrix) *m,
-					TYPE(igraph_matrix) *res, 
-					const igraph_vector_t *cols);
-int FUNCTION(igraph_matrix,select_rows_cols)(const TYPE(igraph_matrix) *m,
-					TYPE(igraph_matrix) *res, 
-					const igraph_vector_t *rows,
-					const igraph_vector_t *cols);
-
-/*-----------------------------*/
-/* Exchanging rows and columns */
-/*-----------------------------*/
-
-int FUNCTION(igraph_matrix,swap_rows)(TYPE(igraph_matrix) *m, 
-				      long int i, long int j);
-int FUNCTION(igraph_matrix,swap_cols)(TYPE(igraph_matrix) *m, 
-				      long int i, long int j);
-int FUNCTION(igraph_matrix,swap_rowcol)(TYPE(igraph_matrix) *m,
-				       long int i, long int j);
-int FUNCTION(igraph_matrix,transpose)(TYPE(igraph_matrix) *m);
-
-/*-----------------------------*/
-/* Matrix operations           */
-/*-----------------------------*/
-
-int FUNCTION(igraph_matrix,add)(TYPE(igraph_matrix) *m1, 
-				const TYPE(igraph_matrix) *m2);
-int FUNCTION(igraph_matrix,sub)(TYPE(igraph_matrix) *m1, 
-				const TYPE(igraph_matrix) *m2);
-int FUNCTION(igraph_matrix,mul_elements)(TYPE(igraph_matrix) *m1, 
-					 const TYPE(igraph_matrix) *m2);
-int FUNCTION(igraph_matrix,div_elements)(TYPE(igraph_matrix) *m1, 
-					 const TYPE(igraph_matrix) *m2);
-void FUNCTION(igraph_matrix,scale)(TYPE(igraph_matrix) *m, BASE by);
-void FUNCTION(igraph_matrix,add_constant)(TYPE(igraph_matrix) *m, BASE plus);
-
-/*-----------------------------*/
-/* Finding minimum and maximum */
-/*-----------------------------*/
-
-igraph_real_t FUNCTION(igraph_matrix,min)(const TYPE(igraph_matrix) *m);
-igraph_real_t FUNCTION(igraph_matrix,max)(const TYPE(igraph_matrix) *m);
-int FUNCTION(igraph_matrix,which_min)(const TYPE(igraph_matrix) *m,
-				      long int *i, long int *j);
-int FUNCTION(igraph_matrix,which_max)(const TYPE(igraph_matrix) *m,
-				      long int *i, long int *j);
-int FUNCTION(igraph_matrix,minmax)(const TYPE(igraph_matrix) *m,
-				   BASE *min, BASE *max);
-int FUNCTION(igraph_matrix,which_minmax)(const TYPE(igraph_matrix) *m,
-					 long int *imin, long int *jmin,
-					 long int *imax, long int *jmax);
-
-/*------------------------------*/
-/* Comparison                   */
-/*------------------------------*/
-
-igraph_bool_t FUNCTION(igraph_matrix,all_e)(const TYPE(igraph_matrix) *lhs, 
-					    const TYPE(igraph_matrix) *rhs);
-igraph_bool_t FUNCTION(igraph_matrix,all_l)(const TYPE(igraph_matrix) *lhs, 
-					    const TYPE(igraph_matrix) *rhs);
-igraph_bool_t FUNCTION(igraph_matrix,all_g)(const TYPE(igraph_matrix) *lhs, 
-					    const TYPE(igraph_matrix) *rhs);
-igraph_bool_t FUNCTION(igraph_matrix,all_le)(const TYPE(igraph_matrix) *lhs, 
-					     const TYPE(igraph_matrix) *rhs);
-igraph_bool_t FUNCTION(igraph_matrix,all_ge)(const TYPE(igraph_matrix) *lhs, 
-					     const TYPE(igraph_matrix) *rhs);
-
-/*-------------------*/
-/* Matrix properties */
-/*-------------------*/
-
-igraph_bool_t FUNCTION(igraph_matrix,isnull)(const TYPE(igraph_matrix) *m);
-igraph_bool_t FUNCTION(igraph_matrix,empty)(const TYPE(igraph_matrix) *m);
-long int FUNCTION(igraph_matrix,size)(const TYPE(igraph_matrix) *m);
-long int FUNCTION(igraph_matrix,nrow)(const TYPE(igraph_matrix) *m);
-long int FUNCTION(igraph_matrix,ncol)(const TYPE(igraph_matrix) *m);
-igraph_bool_t FUNCTION(igraph_matrix,is_symmetric)(const TYPE(igraph_matrix) *m);
-BASE FUNCTION(igraph_matrix,sum)(const TYPE(igraph_matrix) *m);
-BASE FUNCTION(igraph_matrix,prod)(const TYPE(igraph_matrix) *m);
-int FUNCTION(igraph_matrix,rowsum)(const TYPE(igraph_matrix) *m,
-				   TYPE(igraph_vector) *res);
-int FUNCTION(igraph_matrix,colsum)(const TYPE(igraph_matrix) *m,
-				   TYPE(igraph_vector) *res);
-igraph_bool_t FUNCTION(igraph_matrix,is_equal)(const TYPE(igraph_matrix) *m1, 
-					       const TYPE(igraph_matrix) *m2);
-BASE FUNCTION(igraph_matrix,maxdifference)(const TYPE(igraph_matrix) *m1,
-						    const TYPE(igraph_matrix) *m2);
-
-/*------------------------*/
-/* Searching for elements */
-/*------------------------*/
-
-igraph_bool_t FUNCTION(igraph_matrix,contains)(const TYPE(igraph_matrix) *m,
-					       BASE e);
-igraph_bool_t FUNCTION(igraph_matrix,search)(const TYPE(igraph_matrix) *m,
-					     long int from, BASE what, 
-					     long int *pos, 
-					     long int *row, long int *col);
-
-/*------------------------*/
-/* Resizing operations    */
-/*------------------------*/
-
-int FUNCTION(igraph_matrix,resize)(TYPE(igraph_matrix) *m, 
-				   long int nrow, long int ncol);
-int FUNCTION(igraph_matrix,resize_min)(TYPE(igraph_matrix) *m);
-int FUNCTION(igraph_matrix,add_cols)(TYPE(igraph_matrix) *m, long int n);
-int FUNCTION(igraph_matrix,add_rows)(TYPE(igraph_matrix) *m, long int n);
-int FUNCTION(igraph_matrix,remove_col)(TYPE(igraph_matrix) *m, long int col);
-int FUNCTION(igraph_matrix,remove_row)(TYPE(igraph_matrix) *m, long int row);
-
-/*------------------------*/
-/* Print as text          */
-/*------------------------*/
-
-int FUNCTION(igraph_matrix,print)(const TYPE(igraph_matrix) *m);
-int FUNCTION(igraph_matrix,printf)(const TYPE(igraph_matrix) *m,
-																	 const char *format);
-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, 
-			       igraph_matrix_t *real);
-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, 
-				   igraph_matrix_t *real, 
-				   igraph_matrix_t *imag);
-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,
-				       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, 
-					    long int *index, long int nremove);
-int FUNCTION(igraph_matrix,delete_rows_neg)(TYPE(igraph_matrix) *m, 
-					    const igraph_vector_t *neg, 
-					    long int nremove);
-
diff --git a/src/igraph_motifs.h b/src/igraph_motifs.h
deleted file mode 100644
index 8494536..0000000
--- a/src/igraph_motifs.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_MOTIFS_H
-#define IGRAPH_MOTIFS_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
-
-#include "igraph_types.h"
-#include "igraph_datatype.h"
-#include "igraph_iterators.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Graph motifs                                       */
-/* -------------------------------------------------- */
-
-/**
- * \typedef igraph_motifs_handler_t
- * Callback type for \c igraph_motifs_randesu_callback
- * 
- * \ref igraph_motifs_randesu_callback() calls a specified callback
- * function whenever a new motif is found during a motif search. This
- * callback function must be of type \c igraph_motifs_handler_t. It has
- * the following arguments:
- * \param graph The graph that that algorithm is working on. Of course
- *   this must not be modified.
- * \param vids The IDs of the vertices in the motif that has just been
- *   found. This vector is owned by the motif search algorithm, so do not
- *   modify or destroy it; make a copy of it if you need it later.
- * \param isoclass The isomorphism class of the motif that has just been
- *   found. Use \ref igraph_isoclass or \ref igraph_isoclass_subgraph to find
- *   out which isomorphism class belongs to a given motif.
- * \param extra The extra argument that was passed to \ref
- *   igraph_motifs_randesu_callback().
- * \return A logical value, if TRUE (=non-zero), that is interpreted
- *    as a request to stop the motif search and return to the caller.
- * 
- * \sa \ref igraph_motifs_randesu_callback()
- */
-
-typedef igraph_bool_t igraph_motifs_handler_t(const igraph_t *graph,
-					      igraph_vector_t *vids,
-					      int isoclass,
-					      void* extra);
-
-int igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *hist, 
-			  int size, const igraph_vector_t *cut_prob);
-
-int igraph_motifs_randesu_callback(const igraph_t *graph, int size,
-				   const igraph_vector_t *cut_prob,
-				   igraph_motifs_handler_t *callback,
-				   void* extra);
-
-int igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_integer_t *est,
-				   int size, const igraph_vector_t *cut_prob, 
-				   igraph_integer_t sample_size, 
-				   const igraph_vector_t *sample);
-int igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no,
-			     int size, const igraph_vector_t *cut_prob);
-
-int igraph_dyad_census(const igraph_t *graph, igraph_integer_t *mut,
-		       igraph_integer_t *asym, igraph_integer_t *null);
-int igraph_triad_census(const igraph_t *igraph, igraph_vector_t *res);
-int igraph_triad_census_24(const igraph_t *graph, igraph_integer_t *res2,
-			   igraph_integer_t *res4);
-
-int igraph_adjacent_triangles(const igraph_t *graph,
-			      igraph_vector_t *res,
-			      const igraph_vs_t vids);
-
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_neighborhood.h b/src/igraph_neighborhood.h
deleted file mode 100644
index 7e2a261..0000000
--- a/src/igraph_neighborhood.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_NEIGHBORHOOD_H
-#define IGRAPH_NEIGHBORHOOD_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
-
-int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
-			     igraph_vs_t vids, igraph_integer_t order, 
-			     igraph_neimode_t mode);
-int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
-			igraph_vs_t vids, igraph_integer_t order,
-			igraph_neimode_t mode);
-int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
-			       igraph_vs_t vids, igraph_integer_t order,
-			       igraph_neimode_t mode);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_paths.h b/src/igraph_paths.h
deleted file mode 100644
index 41cc310..0000000
--- a/src/igraph_paths.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_PATHS_H
-#define IGRAPH_PATHS_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
-
-#include "igraph_constants.h"
-#include "igraph_types.h"
-#include "igraph_vector.h"
-#include "igraph_vector_ptr.h"
-#include "igraph_matrix.h"
-
-__BEGIN_DECLS
-
-int igraph_diameter(const igraph_t *graph, igraph_integer_t *res, 
-		    igraph_integer_t *from, igraph_integer_t *to,
-		    igraph_vector_t *path,
-		    igraph_bool_t directed, igraph_bool_t unconn);
-int igraph_diameter_dijkstra(const igraph_t *graph,
-			     const igraph_vector_t *weights,
-			     igraph_real_t *pres,
-			     igraph_integer_t *pfrom,
-			     igraph_integer_t *pto,
-			     igraph_vector_t *path,
-			     igraph_bool_t directed,
-			     igraph_bool_t unconn);
-
-int igraph_shortest_paths(const igraph_t *graph, igraph_matrix_t *res, 
-			  const igraph_vs_t from, const igraph_vs_t to, 
-			  igraph_neimode_t mode);
-int igraph_get_shortest_paths(const igraph_t *graph, 
-			      igraph_vector_ptr_t *vertices,
-			      igraph_vector_ptr_t *edges,
-			      igraph_integer_t from, const igraph_vs_t to, 
-			      igraph_neimode_t mode,
-			      igraph_vector_long_t *predecessors,
-			      igraph_vector_long_t *inbound_edges);
-int igraph_get_shortest_path(const igraph_t *graph, 
-			     igraph_vector_t *vertices,
-			     igraph_vector_t *edges, 
-			     igraph_integer_t from,
-			     igraph_integer_t to,
-			     igraph_neimode_t mode);
-
-int igraph_get_all_shortest_paths(const igraph_t *graph,
-				  igraph_vector_ptr_t *res, 
-				  igraph_vector_t *nrgeo,
-				  igraph_integer_t from, const igraph_vs_t to, 
-				  igraph_neimode_t mode);
-int igraph_shortest_paths_dijkstra(const igraph_t *graph,
-				   igraph_matrix_t *res,
-				   const igraph_vs_t from,
-				   const igraph_vs_t to,
-				   const igraph_vector_t *weights, 
-				   igraph_neimode_t mode);
-int igraph_shortest_paths_bellman_ford(const igraph_t *graph,
-				   igraph_matrix_t *res,
-				   const igraph_vs_t from,
-				   const igraph_vs_t to,
-				   const igraph_vector_t *weights, 
-				   igraph_neimode_t mode);
-int igraph_get_shortest_paths_dijkstra(const igraph_t *graph,
-                                       igraph_vector_ptr_t *vertices,
-				       igraph_vector_ptr_t *edges,
-				       igraph_integer_t from,
-				       igraph_vs_t to,
-				       const igraph_vector_t *weights,
-				       igraph_neimode_t mode,
-				       igraph_vector_long_t *predecessors,
-				       igraph_vector_long_t *inbound_edges);
-int igraph_get_shortest_path_dijkstra(const igraph_t *graph,
-				      igraph_vector_t *vertices,
-				      igraph_vector_t *edges,
-				      igraph_integer_t from,
-				      igraph_integer_t to,
-				      const igraph_vector_t *weights,
-				      igraph_neimode_t mode);
-int igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph,
-               igraph_vector_ptr_t *res, 
-               igraph_vector_t *nrgeo,
-               igraph_integer_t from, igraph_vs_t to,
-               const igraph_vector_t *weights,
-               igraph_neimode_t mode);
-int igraph_shortest_paths_johnson(const igraph_t *graph,
-				  igraph_matrix_t *res,
-				  const igraph_vs_t from,
-				  const igraph_vs_t to,
-				  const igraph_vector_t *weights);
-
-int igraph_average_path_length(const igraph_t *graph, igraph_real_t *res,
-			       igraph_bool_t directed, igraph_bool_t unconn);
-int igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res,
-			    igraph_real_t *unconnected, igraph_bool_t directed);
-
-int igraph_eccentricity(const igraph_t *graph, 
-			igraph_vector_t *res,
-			igraph_vs_t vids,
-			igraph_neimode_t mode);
-
-int igraph_radius(const igraph_t *graph, igraph_real_t *radius, 
-		  igraph_neimode_t mode);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_pmt.h b/src/igraph_pmt.h
deleted file mode 100644
index b01c7b1..0000000
--- a/src/igraph_pmt.h
+++ /dev/null
@@ -1,142 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-#define CONCAT2x(a,b) a ## _ ## b 
-#define CONCAT2(a,b) CONCAT2x(a,b)
-#define CONCAT3x(a,b,c) a ## _ ## b ## _ ## c
-#define CONCAT3(a,b,c) CONCAT3x(a,b,c)
-#define CONCAT4x(a,b,c,d) a ## _ ## b ## _ ## c ## _ ## d
-#define CONCAT4(a,b,c,d) CONCAT4x(a,b,c,d)
-
-#if defined(BASE_IGRAPH_REAL)
-#define BASE igraph_real_t
-#define SHORT
-#define OUT_FORMAT "%G"
-#define PRINTFUNC(val) igraph_real_printf(val)
-#define FPRINTFUNC(file, val) igraph_real_fprintf(file, val)
-#define ZERO 0.0
-#define ONE 1.0
-#define MULTIPLICITY 1
-
-#elif defined(BASE_LONG)
-#define BASE long
-#define SHORT long
-#define OUT_FORMAT "%ld"
-#define ZERO 0L
-#define ONE 1L
-#define MULTIPLICITY 1
-
-#elif defined(BASE_CHAR)
-#define BASE char
-#define SHORT char
-#define OUT_FORMAT "%d"
-#define ZERO 0
-#define ONE 1
-#define MULTIPLICITY 1
-
-#elif defined(BASE_BOOL)
-#define BASE igraph_bool_t
-#define SHORT bool
-#define OUT_FORMAT "%d"
-#define ZERO 0
-#define ONE 1
-#define MULTIPLICITY 1
-
-#elif defined(BASE_INT)
-#define BASE int
-#define SHORT int
-#define OUT_FORMAT "%d"
-#define ZERO 0
-#define ONE 1
-#define MULTIPLICITY 1
-
-#elif defined(BASE_LIMB)
-#define BASE limb_t
-#define SHORT limb
-#define ZERO 0
-#define ONE 1
-#define MULTIPLICITY 1
-#define UNSIGNED 1
-
-#elif defined(BASE_PTR)
-#define BASE void*
-#define SHORT ptr
-#define ZERO 0
-#define MULTIPLICITY 1
-
-#elif defined(BASE_COMPLEX)
-#undef complex
-#define BASE igraph_complex_t
-#define SHORT complex
-#define ZERO igraph_complex(0,0)
-#define ONE {{1.0,0.0}}
-#define MULTIPLICITY 2
-#define NOTORDERED 1
-#define NOABS 1
-#define SUM(a,b,c) ((a) = igraph_complex_add((b),(c)))
-#define DIFF(a,b,c) ((a) = igraph_complex_sub((b),(c)))
-#define PROD(a,b,c) ((a) = igraph_complex_mul((b),(c)))
-#define DIV(a,b,c) ((a) = igraph_complex_div((b),(c)))
-#define EQ(a,b) IGRAPH_COMPLEX_EQ((a),(b))
-#define SQ(a) IGRAPH_REAL(igraph_complex_mul((a),(a)))
-
-#else
-#error unknown BASE_ directive
-#endif
-
-#if defined(BASE_IGRAPH_REAL)
-#  define FUNCTION(dir,name) CONCAT2(dir,name)
-#  define TYPE(dir) CONCAT2(dir,t)
-#elif defined(BASE_BOOL)
-   /* Special case because stdbool.h defines bool as a macro to _Bool which would
-    * screw things up */
-#  define FUNCTION(a,c) CONCAT3x(a,bool,c)
-#  define TYPE(dir) CONCAT3x(dir,bool,t)
-#else
-#  define FUNCTION(a,c) CONCAT3(a,SHORT,c)
-#  define TYPE(dir) CONCAT3(dir,SHORT,t)
-#endif
-
-#if defined(HEAP_TYPE_MIN)
-#define HEAPMORE <
-#define HEAPMOREEQ <=
-#define HEAPLESS >
-#define HEAPLESSEQ >=
-#undef FUNCTION
-#undef TYPE
-#if defined(BASE_IGRAPH_REAL)
-#define FUNCTION(dir,name) CONCAT3(dir,min,name)
-#define TYPE(dir) CONCAT3(dir,min,t)
-#else
-#define FUNCTION(a,c) CONCAT4(a,min,SHORT,c)
-#define TYPE(dir) CONCAT4(dir,min,SHORT,t)
-#endif
-#endif
-
-#if defined(HEAP_TYPE_MAX)
-#define HEAPMORE >
-#define HEAPMOREEQ >=
-#define HEAPLESS <
-#define HEAPLESSEQ <=
-#endif
-
diff --git a/src/igraph_random.h b/src/igraph_random.h
deleted file mode 100644
index 2658248..0000000
--- a/src/igraph_random.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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 REST_RANDOM_H
-#define REST_RANDOM_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
-
-#include "igraph_types.h"
-
-#include <stdlib.h>
-#include <time.h>
-
-/* The new RNG interface is (somewhat) modelled based on the GSL */
-
-typedef struct igraph_rng_type_t {
-  const char *name;
-  unsigned long int min;
-  unsigned long int max;
-  int (*init)(void **state);
-  void (*destroy)(void *state);
-  int (*seed)(void *state, unsigned long int seed);  
-  unsigned long int (*get)(void *state);
-  igraph_real_t (*get_real)(void *state);
-  igraph_real_t (*get_norm)(void *state);
-  igraph_real_t (*get_geom)(void *state, igraph_real_t p);
-  igraph_real_t (*get_binom)(void *state, long int n, igraph_real_t p);
-  igraph_real_t (*get_exp)(void *state, igraph_real_t rate);
-} igraph_rng_type_t;
-
-typedef struct igraph_rng_t {
-  const igraph_rng_type_t *type;
-  void *state;
-  int def;
-} igraph_rng_t;
-
-/* --------------------------------- */
-
-int igraph_rng_init(igraph_rng_t *rng, const igraph_rng_type_t *type);
-void igraph_rng_destroy(igraph_rng_t *rng);
-
-int igraph_rng_seed(igraph_rng_t *rng, unsigned long int seed);
-unsigned long int igraph_rng_max(igraph_rng_t *rng);
-unsigned long int igraph_rng_min(igraph_rng_t *rng);
-const char *igraph_rng_name(igraph_rng_t *rng);
-
-long int igraph_rng_get_integer(igraph_rng_t *rng,
-				long int l, long int h);
-igraph_real_t igraph_rng_get_normal(igraph_rng_t *rng, 
-				    igraph_real_t m, igraph_real_t s);
-igraph_real_t igraph_rng_get_unif(igraph_rng_t *rng, 
-				  igraph_real_t l, igraph_real_t h);
-igraph_real_t igraph_rng_get_unif01(igraph_rng_t *rng);
-igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p);
-igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, long int n, 
-				   igraph_real_t p);
-igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate);
-unsigned long int igraph_rng_get_int31(igraph_rng_t *rng);
-igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate);
-
-/* --------------------------------- */
-
-extern const igraph_rng_type_t igraph_rngtype_glibc2;
-extern const igraph_rng_type_t igraph_rngtype_rand;
-extern const igraph_rng_type_t igraph_rngtype_mt19937;
-
-igraph_rng_t *igraph_rng_default(void);
-void igraph_rng_set_default(igraph_rng_t *rng);
-
-/* --------------------------------- */
-
-#ifdef USING_R
-
-void GetRNGstate(void);
-void PutRNGstate(void);
-#define RNG_BEGIN()    GetRNGstate()
-#define RNG_END()      PutRNGstate()
-
-#else 
-
-#define RNG_BEGIN()      if (igraph_rng_default()->def==1) {	\
-  igraph_rng_seed(igraph_rng_default(), time(0));		\
-  igraph_rng_default()->def=2;					\
-  }
-#define RNG_END()		/* do nothing */
-
-#endif
-
-#define RNG_INTEGER(l,h) (igraph_rng_get_integer(igraph_rng_default(),(l),(h)))
-#define RNG_NORMAL(m,s)  (igraph_rng_get_normal(igraph_rng_default(),(m),(s)))
-#define RNG_UNIF(l,h)    (igraph_rng_get_unif(igraph_rng_default(),(l),(h)))
-#define RNG_UNIF01()     (igraph_rng_get_unif01(igraph_rng_default()))
-#define RNG_GEOM(p)      (igraph_rng_get_geom(igraph_rng_default(),(p)))
-#define RNG_BINOM(n,p)   (igraph_rng_get_binom(igraph_rng_default(),(n),(p)))
-#define RNG_INT31()      (igraph_rng_get_int31(igraph_rng_default()))
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_revolver.h b/src/igraph_revolver.h
deleted file mode 100644
index 8b069cf..0000000
--- a/src/igraph_revolver.h
+++ /dev/null
@@ -1,1200 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_REVOLVER_H
-#define IGRAPH_REVOLVER_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
-
-#include "igraph_constants.h"
-#include "igraph_types.h"
-#include "igraph_datatype.h"
-#include "igraph_adjlist.h"
-#include "igraph_matrix.h"
-#include "igraph_array.h"
-#include "igraph_vector_ptr.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Network evolution measurement, new implementation  */
-/* -------------------------------------------------- */
-
-int igraph_evolver_d(igraph_t *graph,
-		     igraph_integer_t nodes,
-		     igraph_vector_t *kernel,
-		     const igraph_vector_t *outseq,
-		     const igraph_vector_t *outdist,
-		     igraph_integer_t m,
-		     igraph_bool_t directed);
-
-int igraph_revolver_d(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     igraph_vector_t *kernel,		     
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_d(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pmaxind);
-int igraph_revolver_st_d(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel);
-int igraph_revolver_exp_d(const igraph_t *graphm,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pmaxind);
-int igraph_revolver_error_d(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t maxind,
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull);
-int igraph_revolver_error2_d(const igraph_t *graph,
-			     const igraph_vector_t *kernel,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-
-int igraph_revolver_ad(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_ad(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t agebins);
-int igraph_revolver_st_ad(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel);
-int igraph_revolver_exp_ad(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t agebins);
-int igraph_revolver_error_ad(const igraph_t *graph, 
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pmaxind,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_ad(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_ade(const igraph_t *graph,
-		       igraph_integer_t niter,
-		       igraph_integer_t agebins,
-		       const igraph_vector_t *cats,
-		       igraph_array3_t *kernel,
-		       igraph_array3_t *sd,
-		       igraph_array3_t *norm,
-		       igraph_array3_t *cites,
-		       igraph_array3_t *expected,
-		       igraph_real_t *logprob,
-		       igraph_real_t *lognull,
-		       igraph_real_t *logmax,
-		       const igraph_matrix_t *debug,
-		       igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_ade(const igraph_t *graph, 
-			   igraph_array3_t *kernel, 
-			   igraph_array3_t *sd,
-			   igraph_array3_t *norm,
-			   igraph_array3_t *cites,
-			   const igraph_matrix_t *debug,
-			   igraph_vector_ptr_t *debugres,
-			   igraph_real_t *logmax,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebind);
-int igraph_revolver_st_ade(const igraph_t *graph,
-			  igraph_vector_t *st,
-			  const igraph_array3_t *kernel,
-			  const igraph_vector_t *cats);
-int igraph_revolver_exp_ade(const igraph_t *graph, 
-			   igraph_array3_t *expected,
-			   const igraph_array3_t *kernel,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t nocats,
-			   igraph_integer_t maxdegree,
-			   igraph_integer_t agebins);
-int igraph_revolver_error_ade(const igraph_t *graph,
-			     const igraph_array3_t *kernel,
-			     const igraph_vector_t *st,
-			     const igraph_vector_t *cats,
-			     igraph_integer_t pnocats,
-			     igraph_integer_t pmaxdegree,
-			     igraph_integer_t pagebins,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-int igraph_revolver_error2_ade(const igraph_t *graph,
-			       const igraph_array3_t *kernel,
-			       const igraph_vector_t *cats,
-			       igraph_real_t *logprob,
-			       igraph_real_t *lognull);
-
-int igraph_revolver_e(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     const igraph_vector_t *cats,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *st,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_e(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 const igraph_vector_t *cats,
-			 igraph_integer_t pnocats);
-int igraph_revolver_st_e(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel,
-			const igraph_vector_t *cats);
-int igraph_revolver_exp_e(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 const igraph_vector_t *cats,
-			 igraph_integer_t pnocats);
-int igraph_revolver_error_e(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull);
-int igraph_revolver_error2_e(const igraph_t *graph,
-			     const igraph_vector_t *kernel,
-			     const igraph_vector_t *cats,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-
-int igraph_revolver_de(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_de(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_st_de(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats);
-int igraph_revolver_exp_de(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_error_de(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_de(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_l(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     igraph_integer_t agebins,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_l(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pagebins);
-int igraph_revolver_st_l(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel);
-int igraph_revolver_exp_l(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pagebins);
-int igraph_revolver_error_l(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pagebins,
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull);
-int igraph_revolver_error2_l(const igraph_t *graph,
-			     const igraph_vector_t *kernel,			     
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-
-int igraph_revolver_dl(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_dl(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t pagebins);
-int igraph_revolver_st_dl(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel);
-int igraph_revolver_exp_dl(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t pagebins);
-int igraph_revolver_error_dl(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pagebins,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_dl(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_el(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      const igraph_vector_t *cats,
-		      igraph_integer_t agebins,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_el(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pagebins);
-int igraph_revolver_st_el(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats);
-int igraph_revolver_exp_el(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pagebins);
-int igraph_revolver_error_el(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_el(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_r(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     igraph_integer_t window,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_r(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 igraph_integer_t window,
-			 igraph_integer_t maxind);
-int igraph_revolver_st_r(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel,
-			igraph_integer_t window);
-int igraph_revolver_exp_r(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 igraph_integer_t window,
-			 igraph_integer_t pmaxind);
-int igraph_revolver_error_r(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t window,
-			   igraph_integer_t maxind,			   
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull);
-int igraph_revolver_error2_r(const igraph_t *graph,
-			     const igraph_vector_t *kernel,
-			     igraph_integer_t window,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-
-int igraph_revolver_ar(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      igraph_integer_t window,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_ar(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pagebins,
-			  igraph_integer_t pwindow,
-			  igraph_integer_t maxind);
-int igraph_revolver_st_ar(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 igraph_integer_t pwindow);
-int igraph_revolver_exp_ar(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t agebins,
-			  igraph_integer_t window,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_error_ar(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pagebins,
-			    igraph_integer_t pwindow,
-			    igraph_integer_t maxind,			   
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_ar(const igraph_t *graph, 
-			      const igraph_matrix_t *kernel,
-			      igraph_integer_t window, 
-			      igraph_real_t *logprob, 
-			      igraph_real_t *lognull);
-
-int igraph_revolver_di(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_di(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_st_di(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats);
-int igraph_revolver_exp_di(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_error_di(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_di(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_adi(const igraph_t *graph,
-		       igraph_integer_t niter,
-		       igraph_integer_t agebins,
-		       const igraph_vector_t *cats,
-		       igraph_array3_t *kernel,
-		       igraph_array3_t *sd,
-		       igraph_array3_t *norm,
-		       igraph_array3_t *cites,
-		       igraph_array3_t *expected,
-		       igraph_real_t *logprob,
-		       igraph_real_t *lognull,
-		       igraph_real_t *logmax,
-		       const igraph_matrix_t *debug,
-		       igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_adi(const igraph_t *graph,
-			   igraph_array3_t *kernel,
-			   igraph_array3_t *sd,
-			   igraph_array3_t *norm,
-			   igraph_array3_t *cites,
-			   const igraph_matrix_t *debug,
-			   igraph_vector_ptr_t *debugres,
-			   igraph_real_t *logmax,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins);
-int igraph_revolver_st_adi(const igraph_t *graph,
-			  igraph_vector_t *st,
-			  const igraph_array3_t *kernel,
-			  const igraph_vector_t *cats);
-int igraph_revolver_exp_adi(const igraph_t *graph,
-			   igraph_array3_t *expected,
-			   const igraph_array3_t *kernel,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins);
-int igraph_revolver_error_adi(const igraph_t *graph,
-			     const igraph_array3_t *kernel,
-			     const igraph_vector_t *st,
-			     const igraph_vector_t *cats,
-			     igraph_integer_t pnocats,
-			     igraph_integer_t pmaxind,
-			     igraph_integer_t pagebins,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-int igraph_revolver_error2_adi(const igraph_t *graph,
-			       const igraph_array3_t *kernel,
-			       const igraph_vector_t *cats,
-			       igraph_real_t *logprob,
-			       igraph_real_t *lognull);
-
-int igraph_revolver_il(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_il(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pagebins);
-int igraph_revolver_st_il(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats);
-int igraph_revolver_exp_il(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t nocats,
-			  igraph_integer_t pagebins);
-int igraph_revolver_error_il(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t nocats,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_il(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_ir(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t window,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_ir(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pwindow,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_st_ir(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 igraph_integer_t pwindow,
-			 const igraph_vector_t *cats);
-int igraph_revolver_exp_ir(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pwindow,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind);
-int igraph_revolver_error_ir(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pwindow,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull);
-int igraph_revolver_error2_ir(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_integer_t window,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_air(const igraph_t *graph,
-		       igraph_integer_t niter,
-		       igraph_integer_t window,
-		       igraph_integer_t agebins,
-		       const igraph_vector_t *cats,
-		       igraph_array3_t *kernel,
-		       igraph_array3_t *sd,
-		       igraph_array3_t *norm,
-		       igraph_array3_t *cites,
-		       igraph_array3_t *expected,
-		       igraph_real_t *logprob,
-		       igraph_real_t *lognull,
-		       igraph_real_t *logmax,
-		       const igraph_matrix_t *debug,
-		       igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_air(const igraph_t *graph,
-			   igraph_array3_t *kernel,
-			   igraph_array3_t *sd,
-			   igraph_array3_t *norm,
-			   igraph_array3_t *cites,
-			   const igraph_matrix_t *debug,
-			   igraph_vector_ptr_t *debugres,
-			   igraph_real_t *logmax,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pwindow,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins);
-int igraph_revolver_st_air(const igraph_t *graph,
-			  igraph_vector_t *st,
-			  const igraph_array3_t *kernel,
-			  igraph_integer_t pwindow,
-			  const igraph_vector_t *cats);
-int igraph_revolver_exp_air(const igraph_t *graph,
-			   igraph_array3_t *expected,
-			   const igraph_array3_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pwindow,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins);
-int igraph_revolver_error_air(const igraph_t *graph,
-			     const igraph_array3_t *kernel,
-			     const igraph_vector_t *st,
-			     igraph_integer_t pwindow,
-			     const igraph_vector_t *cats,
-			     igraph_integer_t pnocats,
-			     igraph_integer_t pmaxind,
-			     igraph_integer_t pagebins,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull);
-int igraph_revolver_error2_air(const igraph_t *graph,
-			       const igraph_array3_t *kernel,
-			       const igraph_vector_t *cats,
-			       igraph_integer_t window,
-			       igraph_real_t *logprob,
-			       igraph_real_t *lognull);
-
-/* Non-citation networks */
-
-int igraph_revolver_d_d(const igraph_t *graph,
-			igraph_integer_t niter,
-			const igraph_vector_t *vtime,
-			const igraph_vector_t *etime,
-			igraph_matrix_t *kernel,
-			igraph_matrix_t *sd,
-			igraph_matrix_t *norm,
-			igraph_matrix_t *cites,
-			igraph_matrix_t *expected,
-			igraph_real_t *logprob,
-			igraph_real_t *lognull,
-			const igraph_matrix_t *debug,
-			igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_d_d(const igraph_t *graph, 
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *kernel,
-			    igraph_matrix_t *sd,
-			    igraph_matrix_t *norm,
-			    igraph_matrix_t *cites,
-			    const igraph_matrix_t *debug,
-			    igraph_vector_ptr_t *debugres,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    igraph_integer_t pmaxdegree);
-int igraph_revolver_st_d_d(const igraph_t *graph,
-			   igraph_lazy_inclist_t *inclist,
-			   igraph_vector_t *st,
-			   const igraph_matrix_t *kernel,
-			   const igraph_vector_t *vtime,
-			   const igraph_vector_t *vtimeidx,
-			   const igraph_vector_t *etime,
-			   const igraph_vector_t *etimeidx,
-			   igraph_integer_t pno_of_events);
-int igraph_revolver_exp_d_d(const igraph_t *graph,
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *expected,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    igraph_integer_t pmaxdegree);
-int igraph_revolver_error_d_d(const igraph_t *graph,
-			      igraph_lazy_inclist_t *inclist,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *st,
-			      const igraph_vector_t *vtime,
-			      const igraph_vector_t *vtimeidx,
-			      const igraph_vector_t *etime,
-			      const igraph_vector_t *etimeidx,
-			      igraph_integer_t pno_of_events,
-			      igraph_integer_t pmaxdegree, 
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-int igraph_revolver_p_p(const igraph_t *graph,
-			igraph_integer_t niter,
-			const igraph_vector_t *vtime,
-			const igraph_vector_t *etime,
-			const igraph_vector_t *authors,
-			const igraph_vector_t *eventsizes,
-			igraph_matrix_t *kernel,
-			igraph_matrix_t *sd,
-			igraph_matrix_t *norm,
-			igraph_matrix_t *cites,
-			igraph_matrix_t *expected,
-			igraph_real_t *logprob,
-			igraph_real_t *lognull,
-			const igraph_matrix_t *debug,
-			igraph_vector_ptr_t *debugres);
-int igraph_revolver_mes_p_p(const igraph_t *graph,
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *kernel,
-			    igraph_matrix_t *sd,
-			    igraph_matrix_t *norm,
-			    igraph_matrix_t *cites,
-			    const igraph_matrix_t *debug,
-			    igraph_vector_ptr_t *debugres,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    const igraph_vector_t *authors,
-			    const igraph_vector_t *eventsizes,
-			    igraph_integer_t pmaxpapers);
-int igraph_revolver_st_p_p(const igraph_t *graph,
-			   igraph_lazy_inclist_t *inclist,
-			   igraph_vector_t *st,
-			   const igraph_matrix_t *kernel,
-			   const igraph_vector_t *vtime,
-			   const igraph_vector_t *vtimeidx,
-			   const igraph_vector_t *etime,
-			   const igraph_vector_t *etimeidx,
-			   igraph_integer_t pno_of_events,
-			   const igraph_vector_t *authors,
-			   const igraph_vector_t *eventsizes,
-			   igraph_integer_t pmaxpapers);
-int igraph_revolver_exp_p_p(const igraph_t *graph,
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *expected,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    const igraph_vector_t *authors,
-			    const igraph_vector_t *eventsizes,
-			    igraph_integer_t pmaxpapers);
-int igraph_revolver_error_p_p(const igraph_t *graph,
-			      igraph_lazy_inclist_t *inclist,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *st,
-			      const igraph_vector_t *vtime,
-			      const igraph_vector_t *vtimeidx,
-			      const igraph_vector_t *etime,
-			      const igraph_vector_t *etimeidx,
-			      igraph_integer_t pno_of_events,
-			      const igraph_vector_t *authors,
-			      const igraph_vector_t *eventsizes,
-			      igraph_integer_t pmaxpapers,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull);
-
-/* -------------------------------------------------- */
-/* Maximum likelihood revolver                        */
-/* -------------------------------------------------- */
-
-int igraph_revolver_ml_d(const igraph_t *graph,
-			 igraph_integer_t niter,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *cites,
-			 igraph_real_t delta,
-			 const igraph_vector_t *filter,
-			 igraph_real_t *logprob,
-			 igraph_real_t *logmax);
-
-int igraph_revolver_probs_d(const igraph_t *graph,
-			    const igraph_vector_t *kernel,
-			    igraph_vector_t *logprobs,
-			    igraph_vector_t *logcited,
-			    igraph_vector_t *logciting,
-			    igraph_bool_t ntk);
-
-int igraph_revolver_ml_de(const igraph_t *graph,
-			  igraph_integer_t niter,
-			  igraph_matrix_t *kernel,
-			  const igraph_vector_t *cats,
-			  igraph_matrix_t *cites,
-			  igraph_real_t delta,
-			  const igraph_vector_t *filter,
-			  igraph_real_t *logprob,
-			  igraph_real_t *logmax);
-
-int igraph_revolver_probs_de(const igraph_t *graph,
-			     const igraph_matrix_t *kernel,
-			     const igraph_vector_t *cats,
-			     igraph_vector_t *logprobs,
-			     igraph_vector_t *logcited,
-			     igraph_vector_t *logciting);
-
-int igraph_revolver_ml_ade(const igraph_t *graph,
-			   igraph_integer_t niter,
-			   igraph_array3_t *kernel,
-			   const igraph_vector_t *cats,
-			   igraph_array3_t *cites,
-			   igraph_integer_t pagebins,
-			   igraph_real_t delta,
-			   const igraph_vector_t *filter,
-			   igraph_real_t *logprob,
-			   igraph_real_t *logmax);
-
-int igraph_revolver_probs_ade(const igraph_t *graph,
-			      const igraph_array3_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_vector_t *logprobs,
-			      igraph_vector_t *logcited,
-			      igraph_vector_t *logciting);
-
-int igraph_revolver_ml_f(const igraph_t *graph,
-			 igraph_integer_t niter,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *cites,
-			 igraph_real_t delta,
-			 igraph_real_t *logprob,
-			 igraph_real_t *logmax);
-
-int igraph_revolver_ml_df(const igraph_t *graph,
-			  igraph_integer_t niter,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *cites,
-			  igraph_real_t delta,
-			  igraph_real_t *logprob,
-			  igraph_real_t *logmax);
-
-int igraph_revolver_ml_l(const igraph_t *graph,
-			 igraph_integer_t niter,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *cites,
-			 igraph_integer_t pagebins,
-			 igraph_real_t delta,
-			 igraph_real_t *logprob,
-			 igraph_real_t *logmax);
-
-int igraph_revolver_ml_ad(const igraph_t *graph,
-			  igraph_integer_t niter,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *cites,
-			  igraph_integer_t pagebins,
-			  igraph_real_t delta,
-			  const igraph_vector_t *filter,
-			  igraph_real_t *logprob,
-			  igraph_real_t *logmax);
-
-int igraph_revolver_probs_ad(const igraph_t *graph,
-			     const igraph_matrix_t *kernel,
-			     igraph_vector_t *logprobs,
-			     igraph_vector_t *logcited,
-			     igraph_vector_t *logciting,
-			     igraph_bool_t ntk);
-
-int igraph_revolver_ml_D(const igraph_t *graph,
-			 igraph_vector_t *res,
-			 igraph_real_t *Fmin,			 
-			 igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			 igraph_scalar_function_t *A_fun,
-			 igraph_vector_function_t *dA_fun,
-			 const igraph_vector_t *filter,
-			 igraph_integer_t *fncount, igraph_integer_t *grcount);
-
-int igraph_revolver_ml_D_alpha(const igraph_t *graph,
-			       igraph_real_t *alpha, igraph_real_t *Fmin,
-			       igraph_real_t abstol, igraph_real_t reltol, 
-			       int maxit, const igraph_vector_t *filter,
-			       igraph_integer_t *fncount, 
-			       igraph_integer_t *grcount);
-
-int igraph_revolver_ml_D_alpha_a(const igraph_t *graph,
-				 igraph_real_t *alpha, igraph_real_t *a,
-				 igraph_real_t *Fmin,
-				 igraph_real_t abstol, igraph_real_t reltol,
-				 int maxit, const igraph_vector_t *filter,
-				 igraph_integer_t *fncount, 
-				 igraph_integer_t *grcount);
-
-int igraph_revolver_ml_DE(const igraph_t *graph,
-			  const igraph_vector_t *cats,
-			  igraph_vector_t *res,
-			  igraph_real_t *Fmin,
-			  igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			  igraph_scalar_function_t *A_fun,
-			  igraph_vector_function_t *dA_fun,
-			  const igraph_vector_t *filter,
-			  igraph_integer_t *fncount, 
-			  igraph_integer_t *grcount,
-			  igraph_vector_t *lastderiv);
-
-int igraph_revolver_ml_DE_alpha_a(const igraph_t *graph,
-				  const igraph_vector_t *cats,
-				  igraph_real_t *alpha, igraph_real_t *a,
-				  igraph_vector_t *coeffs,
-				  igraph_real_t *Fmin,
-				  igraph_real_t abstol, igraph_real_t reltol,
-				  int maxit, const igraph_vector_t *filter,
-				  igraph_integer_t *fncount,
-				  igraph_integer_t *grcount);
-
-int igraph_revolver_ml_AD(const igraph_t *graph,
-			  igraph_vector_t *res,
-			  igraph_real_t *Fmin,
-			  igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			  igraph_scalar_function_t *A_fun,
-			  igraph_vector_function_t *dA_fun,
-			  int agebins, const igraph_vector_t *filter,
-			  igraph_integer_t *fncount, 
-			  igraph_integer_t *grcount,
-			  igraph_vector_t *lastderiv);
-
-int igraph_revolver_ml_AD_alpha_a_beta(const igraph_t *graph,
-				       igraph_real_t *alpha, igraph_real_t *a,
-				       igraph_real_t *beta, igraph_real_t *Fmin,
-				       igraph_real_t abstol, igraph_real_t reltol,
-				       int maxit, int agebins, 
-				       const igraph_vector_t *filter,
-				       igraph_integer_t *fncount,
-				       igraph_integer_t *grcount);
-
-int igraph_revolver_ml_AD_dpareto(const igraph_t *graph,
-				  igraph_real_t *alpha, igraph_real_t *a,
-				  igraph_real_t *paralpha, igraph_real_t *parbeta,
-				  igraph_real_t *parscale,
-				  igraph_real_t *Fmin,
-				  igraph_real_t abstol, igraph_real_t reltol,
-				  int maxit, int agebins, 
-				  const igraph_vector_t *filter,
-				  igraph_integer_t *fncount,
-				  igraph_integer_t *grcount);
-
-int igraph_revolver_ml_AD_dpareto_eval(const igraph_t *graph,
-				       igraph_real_t alpha, igraph_real_t a,
-				       igraph_real_t paralpha, 
-				       igraph_real_t parbeta,
-				       igraph_real_t parscale,
-				       igraph_real_t *value,
-				       igraph_vector_t *deriv,
-				       int agebins,
-				       const igraph_vector_t *filter);
-
-
-
-int igraph_revolver_ml_ADE(const igraph_t *graph,
-			   const igraph_vector_t *cats,
-			   igraph_vector_t *res,
-			   igraph_real_t *Fmin,
-			   igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			   igraph_scalar_function_t *A_fun,
-			   igraph_vector_function_t *dA_fun,
-			   int agebins, const igraph_vector_t *filter,
-			   igraph_integer_t *fncount, 
-			   igraph_integer_t *grcount,
-			   igraph_vector_t *lastderiv);
-
-int igraph_revolver_probs_ADE(const igraph_t *graph,
-			      igraph_scalar_function_t *A_fun,
-			      const igraph_matrix_t *par,
-			      const igraph_vector_t *cats,
-			      const igraph_vector_t *gcats,
-			      int agebins,
-			      igraph_vector_t *logprobs,
-			      igraph_vector_t *logcited,
-			      igraph_vector_t *logciting);
-
-int igraph_revolver_ml_ADE_alpha_a_beta(const igraph_t *graph,
-					const igraph_vector_t *cats,
-					igraph_real_t *alpha, igraph_real_t *a,
-					igraph_real_t *beta, igraph_vector_t *coeffs,
-					igraph_real_t *Fmin,
-					igraph_real_t abstol, igraph_real_t reltol,
-					int maxit, int agebins, 
-					const igraph_vector_t *filter,
-					igraph_integer_t *fncount,
-					igraph_integer_t *grcount);
-
-int igraph_revolver_ml_ADE_dpareto(const igraph_t *graph,
-				   const igraph_vector_t *cats,
-				   igraph_real_t *alpha, igraph_real_t *a,
-				   igraph_real_t *paralpha, igraph_real_t *parbeta,
-				   igraph_real_t *parscale, igraph_vector_t *coeffs,
-				   igraph_real_t *Fmin,
-				   igraph_real_t abstol, igraph_real_t reltol,
-				   int maxit, int agebins, 
-				   const igraph_vector_t *filter,
-				   igraph_integer_t *fncount,
-				   igraph_integer_t *grcount);
-
-int igraph_revolver_ml_ADE_dpareto_eval(const igraph_t *graph,
-					const igraph_vector_t *cats,
-					igraph_real_t alpha, igraph_real_t a,
-					igraph_real_t paralpha, 
-					igraph_real_t parbeta,
-					igraph_real_t parscale,
-					const igraph_vector_t *coeffs,
-					igraph_real_t *value,
-					igraph_vector_t *deriv,
-					int agebins,
-					const igraph_vector_t *filter);
-
-int igraph_revolver_ml_ADE_dpareto_evalf(const igraph_t *graph,
-					 const igraph_vector_t *cats,
-					 const igraph_matrix_t *par,
-					 igraph_vector_t *value,
-					 int agebins, 
-					 const igraph_vector_t *filter);
-
-int igraph_revolver_probs_ADE_dpareto(const igraph_t *graph,
-				      const igraph_matrix_t *par,
-				      const igraph_vector_t *cats,
-				      const igraph_vector_t *gcats,
-				      int agebins,
-				      igraph_vector_t *logprobs,
-				      igraph_vector_t *logcited,
-				      igraph_vector_t *logciting);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_sparsemat.h b/src/igraph_sparsemat.h
deleted file mode 100644
index add7356..0000000
--- a/src/igraph_sparsemat.h
+++ /dev/null
@@ -1,264 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_SPARSEMAT_H
-#define IGRAPH_SPARSEMAT_H
-
-#include "igraph_types.h"
-#include "igraph_vector.h"
-#include "igraph_datatype.h"
-#include "igraph_arpack.h"
-
-#include <stdio.h>
-
-struct cs_di_sparse;
-struct cs_di_symbolic;
-struct cs_di_numeric;
-
-typedef struct {
-  struct cs_di_sparse *cs;
-} igraph_sparsemat_t;
-
-typedef struct {
-  struct cs_di_symbolic *symbolic;
-} igraph_sparsemat_symbolic_t;
-
-typedef struct {
-  struct cs_di_numeric *numeric;
-} igraph_sparsemat_numeric_t;
-
-typedef enum { IGRAPH_SPARSEMAT_TRIPLET, 
-	       IGRAPH_SPARSEMAT_CC        } igraph_sparsemat_type_t;
-
-typedef struct {
-  igraph_sparsemat_t *mat;
-  int pos;
-  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, 
-			  const igraph_sparsemat_t *from);
-void igraph_sparsemat_destroy(igraph_sparsemat_t *A);
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-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);
-
-int igraph_sparsemat_nzmax(const igraph_sparsemat_t *A);
-
-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);
-
-#endif
diff --git a/src/igraph_stack.c b/src/igraph_stack.c
index 928f748..c63051c 100644
--- a/src/igraph_stack.c
+++ b/src/igraph_stack.c
@@ -36,6 +36,12 @@
 #include "igraph_pmt_off.h"
 #undef BASE_LONG
 
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "stack.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
 #define BASE_CHAR
 #include "igraph_pmt.h"
 #include "stack.pmt"
diff --git a/src/igraph_stack.h b/src/igraph_stack.h
deleted file mode 100644
index c6a821c..0000000
--- a/src/igraph_stack.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_STACK_H
-#define IGRAPH_STACK_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
-
-#include "igraph_types.h"
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Plain stack                                        */
-/* -------------------------------------------------- */
-
-#define BASE_IGRAPH_REAL
-#include "igraph_pmt.h"
-#include "igraph_stack_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_IGRAPH_REAL
-
-#define BASE_LONG
-#include "igraph_pmt.h"
-#include "igraph_stack_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_LONG
-
-#define BASE_CHAR
-#include "igraph_pmt.h"
-#include "igraph_stack_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_CHAR
-
-#define BASE_BOOL
-#include "igraph_pmt.h"
-#include "igraph_stack_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_BOOL
-
-#define BASE_PTR
-#include "igraph_pmt.h"
-#include "igraph_stack_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_PTR
-
-#define IGRAPH_STACK_NULL { 0,0,0 }
-
-void igraph_stack_ptr_free_all(igraph_stack_ptr_t* s);
-void igraph_stack_ptr_destroy_all(igraph_stack_ptr_t* s);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_vector.h b/src/igraph_vector.h
deleted file mode 100644
index 2be3b3c..0000000
--- a/src/igraph_vector.h
+++ /dev/null
@@ -1,174 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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_VECTOR_H
-#define IGRAPH_VECTOR_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
-
-#include "igraph_types.h"
-#include "igraph_complex.h"
-
-#ifdef HAVE_STDINT_H
-#  include <stdint.h>
-#else
-#  if HAVE_SYS_INT_TYPES_H
-#    include <sys/int_types.h>    /* for Solaris */
-#  endif
-#endif
-
-__BEGIN_DECLS
-
-/* -------------------------------------------------- */
-/* Flexible vector                                    */
-/* -------------------------------------------------- */
-
-#define BASE_IGRAPH_REAL
-#include "igraph_pmt.h"
-#include "igraph_vector_type.h"
-#include "igraph_pmt_off.h"
-#undef BASE_IGRAPH_REAL
-
-#define BASE_LONG
-#include "igraph_pmt.h"
-#include "igraph_vector_type.h"
-#include "igraph_pmt_off.h"
-#undef BASE_LONG
-
-#define BASE_CHAR
-#include "igraph_pmt.h"
-#include "igraph_vector_type.h"
-#include "igraph_pmt_off.h"
-#undef BASE_CHAR
-
-#define BASE_BOOL
-#include "igraph_pmt.h"
-#include "igraph_vector_type.h"
-#include "igraph_pmt_off.h"
-#undef BASE_BOOL
-
-#define BASE_INT
-#include "igraph_pmt.h"
-#include "igraph_vector_type.h"
-#include "igraph_pmt_off.h"
-#undef BASE_INT
-
-#define BASE_COMPLEX
-#include "igraph_pmt.h"
-#include "igraph_vector_type.h"
-#include "igraph_pmt_off.h"
-#undef BASE_COMPLEX
-
-#define BASE_IGRAPH_REAL
-#include "igraph_pmt.h"
-#include "igraph_vector_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_IGRAPH_REAL
-
-#define BASE_LONG
-#include "igraph_pmt.h"
-#include "igraph_vector_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_LONG
-
-#define BASE_CHAR
-#include "igraph_pmt.h"
-#include "igraph_vector_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_CHAR
-
-#define BASE_BOOL
-#include "igraph_pmt.h"
-#include "igraph_vector_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_BOOL
-
-#define BASE_INT
-#include "igraph_pmt.h"
-#include "igraph_vector_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_INT
-
-#define BASE_COMPLEX
-#include "igraph_pmt.h"
-#include "igraph_vector_pmt.h"
-#include "igraph_pmt_off.h"
-#undef BASE_COMPLEX
-
-/* -------------------------------------------------- */
-/* Helper macros                                      */
-/* -------------------------------------------------- */
-
-#ifndef IGRAPH_VECTOR_NULL
-#define IGRAPH_VECTOR_NULL { 0,0,0 }
-#endif
-
-#ifndef IGRAPH_VECTOR_INIT_FINALLY
-#define IGRAPH_VECTOR_INIT_FINALLY(v, size) \
-  do { IGRAPH_CHECK(igraph_vector_init(v, size)); \
-  IGRAPH_FINALLY(igraph_vector_destroy, v); } while (0)
-#endif
-#ifndef IGRAPH_VECTOR_BOOL_INIT_FINALLY
-#define IGRAPH_VECTOR_BOOL_INIT_FINALLY(v, size) \
-  do { IGRAPH_CHECK(igraph_vector_bool_init(v, size)); \
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, v); } while (0)
-#endif
-#ifndef IGRAPH_VECTOR_LONG_INIT_FINALLY
-#define IGRAPH_VECTOR_LONG_INIT_FINALLY(v, size) \
-  do { IGRAPH_CHECK(igraph_vector_long_init(v, size)); \
-  IGRAPH_FINALLY(igraph_vector_long_destroy, v); } while (0)
-#endif
-
-/* -------------------------------------------------- */
-/* Type-specific vector functions                     */
-/* -------------------------------------------------- */
-
-int igraph_vector_floor(const igraph_vector_t *from, igraph_vector_long_t *to);
-int igraph_vector_round(const igraph_vector_t *from, igraph_vector_long_t *to);
-
-igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs,
-				  const igraph_vector_t *rhs,
-				  igraph_real_t tol);
-
-/* These are for internal use only */
-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, 
-			 igraph_vector_t* res, igraph_real_t maxval);
-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, 
-		       long int nodes);
-
-__END_DECLS
-
-#endif
diff --git a/src/igraph_version.h b/src/igraph_version.h
index 115951a..4539c61 100644
--- a/src/igraph_version.h
+++ b/src/igraph_version.h
@@ -24,7 +24,11 @@
 #ifndef IGRAPH_VERSION_H
 #define IGRAPH_VERSION_H
 
-#define IGRAPH_VERSION "0.7.1"
+#define IGRAPH_VERSION "1.0.0"
+#define IGRAPH_VERSION_MAJOR @PACKAGE_VERSION_MAJOR@
+#define IGRAPH_VERSION_MINOR @PACKAGE_VERSION_MINOR@
+#define IGRAPH_VERSION_PATCH @PACKAGE_VERSION_PATCH@
+#define IGRAPH_VERSION_PRERELEASE "@PACKAGE_VERSION_PRERELEASE@"
 
 int igraph_version(const char **version_string,
 		   int *major,
diff --git a/src/include/igraph.h b/src/include/igraph.h
new file mode 100644
index 0000000..f7fcd7e
--- /dev/null
+++ b/src/include/igraph.h
@@ -0,0 +1,99 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_H
+#define IGRAPH_H
+
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+
+#include "igraph_version.h"
+#include "igraph_memory.h"
+#include "igraph_error.h"
+#include "igraph_random.h"
+#include "igraph_progress.h"
+#include "igraph_statusbar.h"
+
+#include "igraph_types.h"
+#include "igraph_complex.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.h"
+#include "igraph_array.h"
+#include "igraph_dqueue.h"
+#include "igraph_stack.h"
+#include "igraph_heap.h"
+#include "igraph_psumtree.h"
+#include "igraph_strvector.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_spmatrix.h"
+#include "igraph_sparsemat.h"
+#include "igraph_qsort.h"
+
+#include "igraph_constants.h"
+#include "igraph_datatype.h"
+#include "igraph_iterators.h"
+#include "igraph_interface.h"
+#include "igraph_constructors.h"
+#include "igraph_games.h"
+#include "igraph_microscopic_update.h"
+#include "igraph_centrality.h"
+#include "igraph_paths.h"
+#include "igraph_components.h"
+#include "igraph_structural.h"
+#include "igraph_transitivity.h"
+#include "igraph_neighborhood.h"
+#include "igraph_topology.h"
+#include "igraph_bipartite.h"
+#include "igraph_cliques.h"
+#include "igraph_layout.h"
+#include "igraph_visitor.h"
+#include "igraph_community.h"
+#include "igraph_conversion.h"
+#include "igraph_foreign.h"
+#include "igraph_motifs.h"
+#include "igraph_operators.h"
+#include "igraph_flow.h"
+#include "igraph_nongraph.h"
+#include "igraph_cocitation.h"
+#include "igraph_adjlist.h"
+#include "igraph_attributes.h"
+#include "igraph_blas.h"
+#include "igraph_lapack.h"
+#include "igraph_arpack.h"
+#include "igraph_mixing.h"
+#include "igraph_separators.h"
+#include "igraph_cohesive_blocks.h"
+#include "igraph_eigen.h"
+#include "igraph_hrg.h"
+#include "igraph_threading.h"
+#include "igraph_interrupt.h"
+#include "igraph_scg.h"
+#include "igraph_matching.h"
+#include "igraph_embedding.h"
+#include "igraph_scan.h"
+#include "igraph_graphlets.h"
+#include "igraph_epidemics.h"
+#include "igraph_lsap.h"
+
+#endif
diff --git a/src/include/igraph_adjlist.h b/src/include/igraph_adjlist.h
new file mode 100644
index 0000000..33ee13a
--- /dev/null
+++ b/src/include/igraph_adjlist.h
@@ -0,0 +1,238 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_ADJLIST_H
+#define IGRAPH_ADJLIST_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
+
+#include "igraph_constants.h"
+#include "igraph_types.h"
+#include "igraph_datatype.h"
+
+__BEGIN_DECLS
+
+typedef struct igraph_adjlist_t { 
+  igraph_integer_t length;
+  igraph_vector_int_t *adjs;
+} igraph_adjlist_t;
+
+int igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al, 
+			  igraph_neimode_t mode);
+int igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes);
+igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al); 
+int igraph_adjlist_init_complementer(const igraph_t *graph,
+				     igraph_adjlist_t *al, 
+				     igraph_neimode_t mode,
+				     igraph_bool_t loops);
+void igraph_adjlist_destroy(igraph_adjlist_t *al);
+void igraph_adjlist_clear(igraph_adjlist_t *al);
+void igraph_adjlist_sort(igraph_adjlist_t *al);
+int igraph_adjlist_simplify(igraph_adjlist_t *al);
+int igraph_adjlist_remove_duplicate(const igraph_t *graph, 
+				    igraph_adjlist_t *al);
+int igraph_adjlist_print(const igraph_adjlist_t *al);
+int igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile);
+/* igraph_vector_int_t *igraph_adjlist_get(const igraph_adjlist_t *al,  */
+/* 			       igraph_integer_t no); */
+/**
+ * \define igraph_adjlist_get
+ * Query a vector in an adjlist
+ * 
+ * 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.
+ * \return Pointer to the <type>igraph_vector_int_t</type> object.
+ * 
+ * Time complexity: O(1).
+ */
+#define igraph_adjlist_get(al,no) (&(al)->adjs[(long int)(no)])
+
+int igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist,
+		   igraph_neimode_t mode, igraph_bool_t duplicate);
+
+typedef struct igraph_inclist_t {
+  igraph_integer_t length;
+  igraph_vector_int_t *incs;
+} igraph_inclist_t;
+
+int igraph_inclist_init(const igraph_t *graph, 
+			    igraph_inclist_t *il, 
+			    igraph_neimode_t mode);
+int igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n);
+void igraph_inclist_destroy(igraph_inclist_t *il);
+void igraph_inclist_clear(igraph_inclist_t *il);
+int igraph_inclist_remove_duplicate(const igraph_t *graph,
+					igraph_inclist_t *il);
+int igraph_inclist_print(const igraph_inclist_t *il);
+int igraph_inclist_fprint(const igraph_inclist_t *il, FILE *outfile);
+
+/**
+ * \define igraph_inclist_get
+ * 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,
+ * resized, etc. as desired. 
+ * \param graph il The incidence list.
+ * \param no The vertex for which the incident edges are returned.
+ * \return Pointer to an <type>igraph_vector_int_t</type> object.
+ * 
+ * Time complexity: O(1).
+ */
+#define igraph_inclist_get(il,no) (&(il)->incs[(long int)(no)])
+
+typedef struct igraph_lazy_adjlist_t {
+  const igraph_t *graph;
+  igraph_integer_t length;
+  igraph_vector_t **adjs;
+  igraph_neimode_t mode;
+  igraph_lazy_adlist_simplify_t simplify;
+} igraph_lazy_adjlist_t;
+
+int igraph_lazy_adjlist_init(const igraph_t *graph,
+			       igraph_lazy_adjlist_t *al,
+			       igraph_neimode_t mode,
+			       igraph_lazy_adlist_simplify_t simplify);
+void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al);
+void igraph_lazy_adjlist_clear(igraph_lazy_adjlist_t *al);
+/* igraph_vector_t *igraph_lazy_adjlist_get(igraph_lazy_adjlist_t *al, */
+/* 					   igraph_integer_t no); */
+/**
+ * \define igraph_lazy_adjlist_get
+ * 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.
+ * \return Pointer to a vector. It is allowed to modify it and
+ *   modification does not affect the original graph.
+ * 
+ * Time complexity: O(d), the number of neighbor vertices for the
+ * first time, O(1) for subsequent calls.
+ */
+#define igraph_lazy_adjlist_get(al,no) \
+  ((al)->adjs[(long int)(no)] != 0 ? ((al)->adjs[(long int)(no)]) : \
+   (igraph_lazy_adjlist_get_real(al, no)))
+igraph_vector_t *igraph_lazy_adjlist_get_real(igraph_lazy_adjlist_t *al,
+						igraph_integer_t no);
+
+typedef struct igraph_lazy_inclist_t {
+  const igraph_t *graph;
+  igraph_integer_t length;
+  igraph_vector_t **incs;
+  igraph_neimode_t mode;
+} igraph_lazy_inclist_t;
+
+int igraph_lazy_inclist_init(const igraph_t *graph,
+				   igraph_lazy_inclist_t *il,
+				   igraph_neimode_t mode);
+void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il);
+void igraph_lazy_inclist_clear(igraph_lazy_inclist_t *il);
+
+/**
+ * \define igraph_lazy_inclist_get
+ * 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
+ * operations are needed when the incident edges of the same vertex are
+ * queried again.
+ * \param al The lazy incidence list object.
+ * \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.
+ * 
+ * Time complexity: O(d), the number of incident edges for the first
+ * time, O(1) for subsequent calls with the same \p no argument.
+ */
+#define igraph_lazy_inclist_get(al,no) \
+  ((al)->incs[(long int)(no)] != 0 ? ((al)->incs[(long int)(no)]) : \
+   (igraph_lazy_inclist_get_real(al, no)))
+igraph_vector_t *igraph_lazy_inclist_get_real(igraph_lazy_inclist_t *al,
+						    igraph_integer_t no);
+
+/************************************************************************* 
+ * DEPRECATED TYPES AND FUNCTIONS
+ */
+
+typedef igraph_inclist_t igraph_adjedgelist_t;
+
+int igraph_adjedgelist_init(const igraph_t *graph, 
+			    igraph_inclist_t *il, 
+			    igraph_neimode_t mode);
+void igraph_adjedgelist_destroy(igraph_inclist_t *il);
+int igraph_adjedgelist_remove_duplicate(const igraph_t *graph,
+					igraph_inclist_t *il);
+int igraph_adjedgelist_print(const igraph_inclist_t *il, FILE *outfile);
+
+/**
+ * \define igraph_adjedgelist_get
+ * 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.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+#define igraph_adjedgelist_get(ael,no) (&(ael)->incs[(long int)(no)])
+
+typedef igraph_lazy_inclist_t igraph_lazy_adjedgelist_t;
+
+int igraph_lazy_adjedgelist_init(const igraph_t *graph,
+				   igraph_lazy_inclist_t *il,
+				   igraph_neimode_t mode);
+void igraph_lazy_adjedgelist_destroy(igraph_lazy_inclist_t *il);
+
+/**
+ * \define igraph_lazy_adjedgelist_get
+ * 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.
+ *
+ * </para><para>
+ * Deprecated in version 0.6.
+ */
+#define igraph_lazy_adjedgelist_get(al,no) \
+  ((al)->incs[(long int)(no)] != 0 ? ((al)->incs[(long int)(no)]) : \
+   (igraph_lazy_adjedgelist_get_real(al, no)))
+igraph_vector_t *igraph_lazy_adjedgelist_get_real(igraph_lazy_inclist_t *al,
+						    igraph_integer_t no);
+__END_DECLS
+
+#endif
diff --git a/src/igraph_arpack.h b/src/include/igraph_arpack.h
similarity index 100%
rename from src/igraph_arpack.h
rename to src/include/igraph_arpack.h
diff --git a/src/igraph_array.h b/src/include/igraph_array.h
similarity index 100%
rename from src/igraph_array.h
rename to src/include/igraph_array.h
diff --git a/src/igraph_array_pmt.h b/src/include/igraph_array_pmt.h
similarity index 100%
rename from src/igraph_array_pmt.h
rename to src/include/igraph_array_pmt.h
diff --git a/src/igraph_attributes.h b/src/include/igraph_attributes.h
similarity index 100%
rename from src/igraph_attributes.h
rename to src/include/igraph_attributes.h
diff --git a/src/igraph_bipartite.h b/src/include/igraph_bipartite.h
similarity index 100%
rename from src/igraph_bipartite.h
rename to src/include/igraph_bipartite.h
diff --git a/src/include/igraph_blas.h b/src/include/igraph_blas.h
new file mode 100644
index 0000000..102a6d1
--- /dev/null
+++ b/src/include/igraph_blas.h
@@ -0,0 +1,74 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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 BLAS_H
+#define BLAS_H
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.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
+
+/**
+ * \section about_blas BLAS interface in igraph
+ * 
+ * <para>
+ * BLAS is a highly optimized library for basic linear algebra operations
+ * such as vector-vector, matrix-vector and matrix-matrix product.
+ * Please see http://www.netlib.org/blas/ for details and a reference
+ * implementation in Fortran. igraph contains some wrapper functions
+ * that can be used to call BLAS routines in a somewhat more
+ * user-friendly way. Not all BLAS routines are included in igraph,
+ * and even those which are included might not have wrappers;
+ * the extension of the set of wrapped functions will probably be driven
+ * by igraph's internal requirements. The wrapper functions usually
+ * substitute double-precision floating point arrays used by BLAS with
+ * \type igraph_vector_t and \type igraph_matrix_t instances and also
+ * remove those parameters (such as the number of rows/columns) that
+ * can be inferred from the passed arguments directly.
+ * </para>
+ */
+
+void igraph_blas_dgemv(igraph_bool_t transpose, igraph_real_t alpha,
+        const igraph_matrix_t* a, const igraph_vector_t* x,
+        igraph_real_t beta, igraph_vector_t* y);
+void igraph_blas_dgemv_array(igraph_bool_t transpose, igraph_real_t alpha,
+        const igraph_matrix_t* a, const igraph_real_t* x,
+        igraph_real_t beta, igraph_real_t* y);
+
+igraph_real_t igraph_blas_dnrm2(const igraph_vector_t *v);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_centrality.h b/src/include/igraph_centrality.h
similarity index 100%
rename from src/igraph_centrality.h
rename to src/include/igraph_centrality.h
diff --git a/src/igraph_cliques.h b/src/include/igraph_cliques.h
similarity index 100%
rename from src/igraph_cliques.h
rename to src/include/igraph_cliques.h
diff --git a/src/igraph_cocitation.h b/src/include/igraph_cocitation.h
similarity index 100%
rename from src/igraph_cocitation.h
rename to src/include/igraph_cocitation.h
diff --git a/src/igraph_cohesive_blocks.h b/src/include/igraph_cohesive_blocks.h
similarity index 100%
rename from src/igraph_cohesive_blocks.h
rename to src/include/igraph_cohesive_blocks.h
diff --git a/src/igraph_community.h b/src/include/igraph_community.h
similarity index 100%
rename from src/igraph_community.h
rename to src/include/igraph_community.h
diff --git a/src/igraph_complex.h b/src/include/igraph_complex.h
similarity index 100%
rename from src/igraph_complex.h
rename to src/include/igraph_complex.h
diff --git a/src/igraph_components.h b/src/include/igraph_components.h
similarity index 100%
rename from src/igraph_components.h
rename to src/include/igraph_components.h
diff --git a/src/include/igraph_constants.h b/src/include/igraph_constants.h
new file mode 100644
index 0000000..715f750
--- /dev/null
+++ b/src/include/igraph_constants.h
@@ -0,0 +1,167 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_CONSTANTS_H
+#define IGRAPH_CONSTANTS_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
+
+#include "igraph_types.h"
+#include "igraph_datatype.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Constants                                          */
+/* -------------------------------------------------- */
+
+typedef enum { IGRAPH_UNDIRECTED=0, IGRAPH_DIRECTED=1 } igraph_i_directed_t;
+
+typedef enum { IGRAPH_NO_LOOPS=0, IGRAPH_LOOPS=1 } igraph_i_loops_t;
+
+typedef enum { IGRAPH_NO_MULTIPLE=0, IGRAPH_MULTIPLE=1 } igraph_i_multiple_t;
+
+typedef enum { IGRAPH_ASCENDING=0, IGRAPH_DESCENDING=1 } igraph_order_t;
+
+typedef enum { IGRAPH_MINIMUM=0, IGRAPH_MAXIMUM=1 } igraph_optimal_t;
+
+typedef enum { IGRAPH_OUT=1, IGRAPH_IN=2, IGRAPH_ALL=3,
+	       IGRAPH_TOTAL=3 } igraph_neimode_t;
+
+typedef enum { IGRAPH_WEAK=1, IGRAPH_STRONG=2 } igraph_connectedness_t;
+
+typedef enum { IGRAPH_RECIPROCITY_DEFAULT=0, 
+	       IGRAPH_RECIPROCITY_RATIO=1 } igraph_reciprocity_t;
+
+typedef enum { IGRAPH_ADJ_DIRECTED=0, 
+	       IGRAPH_ADJ_UNDIRECTED=1, IGRAPH_ADJ_MAX=1,
+               IGRAPH_ADJ_UPPER, IGRAPH_ADJ_LOWER, IGRAPH_ADJ_MIN,
+	       IGRAPH_ADJ_PLUS } igraph_adjacency_t;
+
+typedef enum { IGRAPH_STAR_OUT=0, IGRAPH_STAR_IN,
+	       IGRAPH_STAR_UNDIRECTED, 
+	       IGRAPH_STAR_MUTUAL } igraph_star_mode_t;
+
+typedef enum { IGRAPH_TREE_OUT=0, IGRAPH_TREE_IN,
+	       IGRAPH_TREE_UNDIRECTED } igraph_tree_mode_t;
+
+typedef enum { IGRAPH_ERDOS_RENYI_GNP=0, 
+	       IGRAPH_ERDOS_RENYI_GNM } igraph_erdos_renyi_t;
+
+typedef enum { IGRAPH_GET_ADJACENCY_UPPER=0,
+	       IGRAPH_GET_ADJACENCY_LOWER,
+	       IGRAPH_GET_ADJACENCY_BOTH } igraph_get_adjacency_t;
+
+typedef enum { IGRAPH_DEGSEQ_SIMPLE=0,
+	       IGRAPH_DEGSEQ_VL,
+	       IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE } igraph_degseq_t;
+
+typedef enum { IGRAPH_FILEFORMAT_EDGELIST=0,
+	       IGRAPH_FILEFORMAT_NCOL,
+	       IGRAPH_FILEFORMAT_PAJEK,
+               IGRAPH_FILEFORMAT_LGL,
+               IGRAPH_FILEFORMAT_GRAPHML } igraph_fileformat_type_t;
+
+typedef enum { IGRAPH_REWIRING_SIMPLE=0,
+	       IGRAPH_REWIRING_SIMPLE_LOOPS } igraph_rewiring_t;
+
+typedef enum { IGRAPH_EDGEORDER_ID=0,
+	       IGRAPH_EDGEORDER_FROM,
+	       IGRAPH_EDGEORDER_TO } igraph_edgeorder_type_t;
+
+typedef enum { IGRAPH_TO_DIRECTED_ARBITRARY=0,
+	       IGRAPH_TO_DIRECTED_MUTUAL } igraph_to_directed_t;
+
+typedef enum { IGRAPH_TO_UNDIRECTED_EACH=0,
+	       IGRAPH_TO_UNDIRECTED_COLLAPSE,
+               IGRAPH_TO_UNDIRECTED_MUTUAL} igraph_to_undirected_t;
+
+typedef enum { IGRAPH_VCONN_NEI_ERROR=0,
+	       IGRAPH_VCONN_NEI_NUMBER_OF_NODES,
+	       IGRAPH_VCONN_NEI_IGNORE, 
+	       IGRAPH_VCONN_NEI_NEGATIVE } igraph_vconn_nei_t;
+
+typedef enum { IGRAPH_SPINCOMM_UPDATE_SIMPLE=0,
+	       IGRAPH_SPINCOMM_UPDATE_CONFIG } igraph_spincomm_update_t; 
+
+typedef enum { IGRAPH_DONT_SIMPLIFY=0,
+	       IGRAPH_SIMPLIFY } igraph_lazy_adlist_simplify_t;
+
+typedef enum { IGRAPH_TRANSITIVITY_NAN=0,
+               IGRAPH_TRANSITIVITY_ZERO } igraph_transitivity_mode_t;
+
+typedef enum { IGRAPH_SPINCOMM_IMP_ORIG=0, 
+	       IGRAPH_SPINCOMM_IMP_NEG } igraph_spinglass_implementation_t;
+
+typedef enum { IGRAPH_COMMCMP_VI = 0,
+               IGRAPH_COMMCMP_NMI,
+               IGRAPH_COMMCMP_SPLIT_JOIN,
+               IGRAPH_COMMCMP_RAND,
+               IGRAPH_COMMCMP_ADJUSTED_RAND } igraph_community_comparison_t;
+
+typedef enum { IGRAPH_ADD_WEIGHTS_NO = 0,
+               IGRAPH_ADD_WEIGHTS_YES,
+               IGRAPH_ADD_WEIGHTS_IF_PRESENT } igraph_add_weights_t;
+
+typedef enum { IGRAPH_BARABASI_BAG = 0,
+	       IGRAPH_BARABASI_PSUMTREE, 
+	       IGRAPH_BARABASI_PSUMTREE_MULTIPLE} igraph_barabasi_algorithm_t;
+
+typedef enum { IGRAPH_FAS_EXACT_IP = 0,
+	       IGRAPH_FAS_APPROX_EADES } igraph_fas_algorithm_t;
+
+typedef enum { IGRAPH_SUBGRAPH_AUTO = 0,
+	           IGRAPH_SUBGRAPH_COPY_AND_DELETE,
+			   IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH
+			 } igraph_subgraph_implementation_t;
+
+typedef enum { IGRAPH_IMITATE_AUGMENTED = 0,
+               IGRAPH_IMITATE_BLIND,
+               IGRAPH_IMITATE_CONTRACTED } igraph_imitate_algorithm_t;
+
+typedef igraph_real_t  igraph_scalar_function_t(const igraph_vector_t *var, 
+						const igraph_vector_t *par,
+						void* extra);
+typedef void igraph_vector_function_t(const igraph_vector_t *var, 
+				      const igraph_vector_t *par,
+				      igraph_vector_t* res, void* extra);
+
+typedef enum { IGRAPH_LAYOUT_GRID = 0,
+	       IGRAPH_LAYOUT_NOGRID,
+	       IGRAPH_LAYOUT_AUTOGRID } igraph_layout_grid_t;
+
+typedef enum { IGRAPH_RANDOM_WALK_STUCK_ERROR = 0,
+	       IGRAPH_RANDOM_WALK_STUCK_RETURN } igraph_random_walk_stuck_t;
+
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_constructors.h b/src/include/igraph_constructors.h
similarity index 100%
rename from src/igraph_constructors.h
rename to src/include/igraph_constructors.h
diff --git a/src/igraph_conversion.h b/src/include/igraph_conversion.h
similarity index 100%
rename from src/igraph_conversion.h
rename to src/include/igraph_conversion.h
diff --git a/src/igraph_datatype.h b/src/include/igraph_datatype.h
similarity index 100%
rename from src/igraph_datatype.h
rename to src/include/igraph_datatype.h
diff --git a/src/include/igraph_dqueue.h b/src/include/igraph_dqueue.h
new file mode 100644
index 0000000..6cfb88d
--- /dev/null
+++ b/src/include/igraph_dqueue.h
@@ -0,0 +1,82 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_DQUEUE_H
+#define IGRAPH_DQUEUE_H
+
+#include "igraph_types.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
+
+/* -------------------------------------------------- */
+/* double ended queue, very useful                    */
+/* -------------------------------------------------- */
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "igraph_dqueue_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "igraph_dqueue_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "igraph_dqueue_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "igraph_dqueue_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "igraph_dqueue_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define IGRAPH_DQUEUE_NULL { 0,0,0,0 }
+#define IGRAPH_DQUEUE_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_dqueue_init(v, size)); \
+  IGRAPH_FINALLY(igraph_dqueue_destroy, v); } while (0)
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_dqueue_pmt.h b/src/include/igraph_dqueue_pmt.h
similarity index 100%
rename from src/igraph_dqueue_pmt.h
rename to src/include/igraph_dqueue_pmt.h
diff --git a/src/include/igraph_eigen.h b/src/include/igraph_eigen.h
new file mode 100644
index 0000000..d37e3d9
--- /dev/null
+++ b/src/include/igraph_eigen.h
@@ -0,0 +1,119 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_arpack.h"
+#include "igraph_lapack.h"
+#include "igraph_sparsemat.h"
+
+#ifndef IGRAPH_EIGEN_H
+#define IGRAPH_EIGEN_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
+
+typedef enum { IGRAPH_EIGEN_AUTO=0,
+	       IGRAPH_EIGEN_LAPACK,
+	       IGRAPH_EIGEN_ARPACK, 
+	       IGRAPH_EIGEN_COMP_AUTO,
+	       IGRAPH_EIGEN_COMP_LAPACK,
+	       IGRAPH_EIGEN_COMP_ARPACK } igraph_eigen_algorithm_t;
+
+typedef enum { IGRAPH_EIGEN_LM=0,
+	       IGRAPH_EIGEN_SM,	/* 1 */
+	       IGRAPH_EIGEN_LA,	/* 2 */
+	       IGRAPH_EIGEN_SA,	/* 3 */
+	       IGRAPH_EIGEN_BE,	/* 4 */
+	       IGRAPH_EIGEN_LR,	/* 5 */
+	       IGRAPH_EIGEN_SR,	/* 6 */
+	       IGRAPH_EIGEN_LI,	/* 7 */
+	       IGRAPH_EIGEN_SI,	/* 8 */
+	       IGRAPH_EIGEN_ALL, /* 9 */
+	       IGRAPH_EIGEN_INTERVAL, /* 10 */
+	       IGRAPH_EIGEN_SELECT }  /* 11 */
+                 igraph_eigen_which_position_t;
+
+typedef struct igraph_eigen_which_t {
+  igraph_eigen_which_position_t pos;
+  int howmany;
+  int il, iu;
+  igraph_real_t vl, vu;
+  int vestimate;
+  igraph_lapack_dgeevx_balance_t balance;
+} igraph_eigen_which_t;
+    
+
+int igraph_eigen_matrix_symmetric(const igraph_matrix_t *A,
+				  const igraph_sparsemat_t *sA,
+				  igraph_arpack_function_t *fun, int n,
+				  void *extra,
+				  igraph_eigen_algorithm_t algorithm,
+				  const igraph_eigen_which_t *which,
+				  igraph_arpack_options_t *options,
+				  igraph_arpack_storage_t *storage,
+				  igraph_vector_t *values, 
+				  igraph_matrix_t *vectors);
+
+int igraph_eigen_matrix(const igraph_matrix_t *A,
+			const igraph_sparsemat_t *sA,
+			igraph_arpack_function_t *fun, int n,
+			void *extra,
+			igraph_eigen_algorithm_t algorithm,
+			const igraph_eigen_which_t *which,
+			igraph_arpack_options_t *options,
+			igraph_arpack_storage_t *storage,
+			igraph_vector_complex_t *values,
+			igraph_matrix_complex_t *vectors);
+
+int igraph_eigen_adjacency(const igraph_t *graph,
+			   igraph_eigen_algorithm_t algorithm,
+			   const igraph_eigen_which_t *which,
+			   igraph_arpack_options_t *options,
+			   igraph_arpack_storage_t *storage,
+			   igraph_vector_t *values,
+			   igraph_matrix_t *vectors,
+			   igraph_vector_complex_t *cmplxvalues,
+			   igraph_matrix_complex_t *cmplxvectors);
+
+int igraph_eigen_laplacian(const igraph_t *graph,
+			   igraph_eigen_algorithm_t algorithm,
+			   const igraph_eigen_which_t *which,
+			   igraph_arpack_options_t *options,
+			   igraph_arpack_storage_t *storage,
+			   igraph_vector_t *values,
+			   igraph_matrix_t *vectors,
+			   igraph_vector_complex_t *cmplxvalues,
+			   igraph_matrix_complex_t *cmplxvectors);
+
+
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_embedding.h b/src/include/igraph_embedding.h
new file mode 100644
index 0000000..b0e29dc
--- /dev/null
+++ b/src/include/igraph_embedding.h
@@ -0,0 +1,77 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   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_EMBEDDING_H
+#define IGRAPH_EMBEDDING_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
+
+#include "igraph_datatype.h"
+#include "igraph_arpack.h"
+#include "igraph_eigen.h"
+#include "igraph_constants.h"
+
+__BEGIN_DECLS
+
+int igraph_adjacency_spectral_embedding(const igraph_t *graph,
+					igraph_integer_t no,
+					const igraph_vector_t *weights,
+					igraph_eigen_which_position_t which,
+					igraph_bool_t scaled,
+					igraph_matrix_t *X,
+					igraph_matrix_t *Y,
+					igraph_vector_t *D,
+					const igraph_vector_t *cvec,
+					igraph_arpack_options_t *options);
+
+typedef enum {
+  IGRAPH_EMBEDDING_D_A=0,
+  IGRAPH_EMBEDDING_I_DAD,
+  IGRAPH_EMBEDDING_DAD,
+  IGRAPH_EMBEDDING_OAP } igraph_laplacian_spectral_embedding_type_t;
+
+int igraph_laplacian_spectral_embedding(const igraph_t *graph,
+			igraph_integer_t no,
+			const igraph_vector_t *weights,
+			igraph_eigen_which_position_t which,
+			igraph_neimode_t degmode,
+			igraph_laplacian_spectral_embedding_type_t type,
+			igraph_bool_t scaled,
+			igraph_matrix_t *X,
+			igraph_matrix_t *Y,
+			igraph_vector_t *D,
+			igraph_arpack_options_t *options);
+
+int igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *dim);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_epidemics.h b/src/include/igraph_epidemics.h
similarity index 100%
rename from src/igraph_epidemics.h
rename to src/include/igraph_epidemics.h
diff --git a/src/include/igraph_error.h b/src/include/igraph_error.h
new file mode 100644
index 0000000..880b1bf
--- /dev/null
+++ b/src/include/igraph_error.h
@@ -0,0 +1,723 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_ERROR_H
+#define IGRAPH_ERROR_H
+
+#include <stdarg.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
+
+/* This file contains the igraph error handling.
+ * Most bits are taken literally from the GSL library (with the GSL_
+ * prefix renamed to IGRAPH_), as I couldn't find a better way to do
+ * them. */
+
+/**
+ * \section errorhandlingbasics Error handling basics
+ * 
+ * <para>\a igraph functions can run into various problems preventing them 
+ * from normal operation. The user might have supplied invalid arguments,
+ * e.g. a non-square matrix when a square-matrix was expected, or the program 
+ * has run out of memory while some more memory allocation is required, etc.
+ * </para>
+ * 
+ * <para>By default \a igraph aborts the program when it runs into an 
+ * error. While this behavior might be good enough for smaller programs, 
+ * it is without doubt avoidable in larger projects. Please read further
+ * if your project requires more sophisticated error handling. You can 
+ * safely skip the rest of this chapter otherwise.
+ * </para>
+ */
+
+/**
+ * \section errorhandlers Error handlers
+ *
+ * <para>
+ * If \a igraph runs into an error - an invalid argument was supplied
+ * to a function, or we've ran out of memory - the control is
+ * transferred to the \emb error handler \eme function.
+ * </para><para>
+ * The default error handler is \ref igraph_error_handler_abort which
+ * prints an error message and aborts the program.
+ * </para>
+ * <para>
+ * The \ref igraph_set_error_handler() function can be used to set a new
+ * error handler function of type \ref igraph_error_handler_t; see the
+ * documentation of this type for details.
+ * </para>
+ * <para>
+ * There are two other predefined error handler functions,
+ * \ref igraph_error_handler_ignore and \ref igraph_error_handler_printignore.
+ * These deallocate the temporarily allocated memory (more about this
+ * later) and return with the error code. The latter also prints an
+ * error message. If you use these error handlers you need to take
+ * care about possible errors yourself by checking the return value of
+ * (almost) every non-void \a igraph function.
+ * </para><para>
+ * Independently of the error handler installed, all functions in the
+ * library do their best to leave their arguments
+ * \em semantically unchanged if an error
+ * happens. By semantically we mean that the implementation of an
+ * object supplied as an argument might change, but its
+ * \quote meaning \endquote in most cases does not. The rare occasions
+ * when this rule is violated are documented in this manual.
+ * </para>
+ */
+
+/**
+ * \section errorcodes Error codes
+ * 
+ * <para>Every \a igraph function which can fail return a
+ * single integer error code. Some functions are very simple and
+ * cannot run into any error, these may return other types, or
+ * \type void as well. The error codes are defined by the
+ * \ref igraph_error_type_t enumeration.
+ * </para>
+ */
+
+/**
+ * \section writing_error_handlers Writing error handlers
+ *
+ * <para>
+ * The contents of the rest of this chapter might be useful only
+ * for those who want to create an interface to \a igraph from another
+ * language. Most readers can safely skip to the next chapter.
+ * </para>
+ * 
+ * <para>
+ * You can write and install error handlers simply by defining a
+ * 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
+ * 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.
+ * </para>
+ * <para> 
+ * If you want to write an error handler, your error handler should
+ * call \ref IGRAPH_FINALLY_FREE() to deallocate all temporary memory to
+ * prevent memory leaks.
+ * </para>
+ */
+
+/**
+ * \section error_handling_internals Error handling internals
+ *
+ * <para>
+ * If an error happens, the functions in the library call the
+ * \ref IGRAPH_ERROR macro with a textual description of the error and an
+ * \a igraph error code. This macro calls (through the \ref
+ * igraph_error() function) the installed error handler. Another useful
+ * macro is \ref IGRAPH_CHECK(). This checks the return value of its
+ * argument, which is normally a function call, and calls \ref
+ * IGRAPH_ERROR if it is not \c IGRAPH_SUCCESS. 
+ * </para>
+ */
+
+/** 
+ * \section deallocating_memory Deallocating memory
+ *
+ * <para>
+ * If a function runs into an error (and the program is not aborted)
+ * the error handler should deallocate all temporary memory. This is
+ * done by storing the address and the destroy function of all temporary
+ * objects in a stack. The \ref IGRAPH_FINALLY function declares an object as
+ * temporary by placing its address in the stack. If an \a igraph function returns
+ * with success it calls \ref IGRAPH_FINALLY_CLEAN() with the
+ * number of objects to remove from the stack. If an error happens
+ * however, the error handler should call \ref IGRAPH_FINALLY_FREE() to
+ * deallocate each object added to the stack. This means that the
+ * temporary objects allocated in the calling function (and etc.) will
+ * be freed as well.
+ * </para>
+ */
+
+/**
+ * \section writing_functions_error_handling Writing \a igraph functions with
+ * proper error handling
+ *
+ * <para>
+ * There are some simple rules to keep in order to have functions
+ * behaving well in erroneous situations. First, check the arguments
+ * of the functions and call \ref IGRAPH_ERROR if they are invalid. Second,
+ * call \ref IGRAPH_FINALLY on each dynamically allocated object and call
+ * \ref IGRAPH_FINALLY_CLEAN() with the proper argument before returning. Third, use
+ * \ref IGRAPH_CHECK on all \a igraph function calls which can generate errors.
+ * </para>
+ * <para>
+ * The size of the stack used for this bookkeeping is fixed, and
+ * small. If you want to allocate several objects, write a destroy
+ * function which can deallocate all of these. See the
+ * <filename>adjlist.c</filename> file in the
+ * \a igraph source for an example.
+ * </para>
+ * <para> 
+ * For some functions these mechanisms are simply not flexible
+ * enough. These functions should define their own error handlers and
+ * restore the error handler before they return.
+ * </para>
+ */
+
+/**
+ * \section error_handling_threads Error handling and threads
+ *
+ * <para>
+ * It is likely that the \a igraph error handling
+ * method is \em not thread-safe, mainly because of
+ * the static global stack which is used to store the address of the
+ * temporarily allocated objects. This issue might be addressed in a
+ * later version of \a igraph.
+ * </para>
+ */
+
+/**
+ * \typedef igraph_error_handler_t
+ * \brief Type of error handler functions.
+ * 
+ * This is the type of the error handler functions.
+ * \param reason Textual description of the error.
+ * \param file The source file in which the error is noticed.
+ * \param line The number of the line in the source file which triggered
+ *   the error
+ * \param igraph_errno The \a igraph error code.
+ */
+
+typedef void igraph_error_handler_t (const char * reason, const char * file,
+				     int line, int igraph_errno);
+
+/**
+ * \var igraph_error_handler_abort
+ * \brief Abort program in case of error.
+ *
+ * The default error handler, prints an error message and aborts the
+ * program. 
+ */
+
+extern igraph_error_handler_t igraph_error_handler_abort;
+
+/**
+ * \var igraph_error_handler_ignore
+ * \brief Ignore errors.
+ *
+ * This error handler frees the temporarily allocated memory and returns
+ * with the error code. 
+ */
+
+extern igraph_error_handler_t igraph_error_handler_ignore;
+
+/**
+ * \var igraph_error_handler_printignore
+ * \brief Print and ignore errors.
+ * 
+ * Frees temporarily allocated memory, prints an error message to the
+ * standard error and returns with the error code. 
+ */
+
+extern igraph_error_handler_t igraph_error_handler_printignore;
+
+/**
+ * \function igraph_set_error_handler
+ * \brief Set a new error handler.
+ *
+ * Installs a new error handler. If called with 0, it installs the
+ * default error handler (which is currently
+ * \ref igraph_error_handler_abort). 
+ * \param new_handler The error handler function to install.
+ * \return The old error handler function. This should be saved and
+ *   restored if \p new_handler is not needed any
+ *   more.
+ */
+
+igraph_error_handler_t*
+igraph_set_error_handler(igraph_error_handler_t* new_handler);
+
+/**
+ * \typedef igraph_error_type_t
+ * \brief Error code type.
+ * These are the possible values returned by \a igraph functions.
+ * Note that these are interesting only if you defined an error handler
+ * with \ref igraph_set_error_handler(). Otherwise the program is aborted 
+ * and the function causing the error never returns.
+ * 
+ * \enumval IGRAPH_SUCCESS The function successfully completed its task.
+ * \enumval IGRAPH_FAILURE Something went wrong. You'll almost never
+ *    meet this error as normally more specific error codes are used.
+ * \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
+ *    number was specified as the number of vertices.
+ * \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already
+ *    installed with the given name.
+ * \enumval IGRAPH_EINVEVECTOR Invalid vector of vertex ids. A vertex id
+ *    is either negative or bigger than the number of vertices minus one.
+ * \enumval IGRAPH_EINVVID Invalid vertex id, negative or too big.
+ * \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,
+ *   or the user has no rights to open it.
+ * \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or
+ *   disabled (at compile-time) function.
+ * \enumval IGRAPH_DIVERGED A numeric algorithm failed to converge.
+ * \enumval IGRAPH_ARPACK_PROD Matrix-vector product failed.
+ * \enumval IGRAPH_ARPACK_NPOS N must be positive.
+ * \enumval IGRAPH_ARPACK_NEVNPOS NEV must be positive.
+ * \enumval IGRAPH_ARPACK_NCVSMALL NCV must be bigger.
+ * \enumval IGRAPH_ARPACK_NONPOSI Maximum number of iterations should be positive.
+ * \enumval IGRAPH_ARPACK_WHICHINV Invalid WHICH parameter.
+ * \enumval IGRAPH_ARPACK_BMATINV Invalid BMAT parameter.
+ * \enumval IGRAPH_ARPACK_WORKLSMALL WORKL is too small.
+ * \enumval IGRAPH_ARPACK_TRIDERR LAPACK error in tridiagonal eigenvalue calculation.
+ * \enumval IGRAPH_ARPACK_ZEROSTART Starting vector is zero.
+ * \enumval IGRAPH_ARPACK_MODEINV MODE is invalid.
+ * \enumval IGRAPH_ARPACK_MODEBMAT MODE and BMAT are not compatible.
+ * \enumval IGRAPH_ARPACK_ISHIFT ISHIFT must be 0 or 1.
+ * \enumval IGRAPH_ARPACK_NEVBE NEV and WHICH='BE' are incompatible.
+ * \enumval IGRAPH_ARPACK_NOFACT Could not build an Arnoldi factorization.
+ * \enumval IGRAPH_ARPACK_FAILED No eigenvalues to sufficient accuracy.
+ * \enumval IGRAPH_ARPACK_HOWMNY HOWMNY is invalid.
+ * \enumval IGRAPH_ARPACK_HOWMNYS HOWMNY='S' is not implemented.
+ * \enumval IGRAPH_ARPACK_EVDIFF Different number of converged Ritz values.
+ * \enumval IGRAPH_ARPACK_SHUR Error from calculation of a real Schur form.
+ * \enumval IGRAPH_ARPACK_LAPACK LAPACK (dtrevc) error for calculating eigenvectors.
+ * \enumval IGRAPH_ARPACK_UNKNOWN Unknown ARPACK error.
+ * \enumval IGRAPH_ENEGLOOP Negative loop detected while calculating shortest paths.
+ * \enumval IGRAPH_EINTERNAL Internal error, likely a bug in igraph.
+ * \enumval IGRAPH_EDIVZERO Big integer division by zero.
+ * \enumval IGARPH_GLP_EBOUND GLPK error (GLP_EBOUND).
+ * \enumval IGARPH_GLP_EROOT GLPK error (GLP_EROOT).
+ * \enumval IGARPH_GLP_ENOPFS GLPK error (GLP_ENOPFS).
+ * \enumval IGARPH_GLP_ENODFS GLPK error (GLP_ENODFS).
+ * \enumval IGARPH_GLP_EFAIL GLPK error (GLP_EFAIL).
+ * \enumval IGARPH_GLP_EMIPGAP GLPK error (GLP_EMIPGAP).
+ * \enumval IGARPH_GLP_ETMLIM GLPK error (GLP_ETMLIM).
+ * \enumval IGARPH_GLP_ESTOP GLPK error (GLP_ESTOP).
+ * \enumval IGRAPH_EATTRIBUTES Attribute handler error. The user is not 
+ *   expected to find this; it is signalled if some igraph function is
+ *   not using the attribute handler interface properly.
+ * \enumval IGRAPH_EATTRCOMBINE Unimplemented attribute combination 
+ *   method for the given attribute type.
+ * \enumval IGRAPH_ELAPACK A LAPACK call resulted an error.
+ * \enumval IGRAPH_EDRL Internal error in the DrL layout generator.
+ * \enumval IGRAPH_EOVERFLOW Integer or double overflow.
+ * \enumval IGRAPH_EGLP Internal GLPK error.
+ * \enumval IGRAPH_CPUTIME CPU time exceeded.
+ * \enumval IGRAPH_EUNDERFLOW Integer or double underflow.
+ * \enumval IGRAPH_ERWSTUCK Random walk got stuck.
+ */
+
+typedef enum {
+  IGRAPH_SUCCESS       = 0,
+  IGRAPH_FAILURE       = 1,
+  IGRAPH_ENOMEM        = 2,
+  IGRAPH_PARSEERROR    = 3,
+  IGRAPH_EINVAL        = 4,
+  IGRAPH_EXISTS        = 5,
+  IGRAPH_EINVEVECTOR   = 6,
+  IGRAPH_EINVVID       = 7,
+  IGRAPH_NONSQUARE     = 8,
+  IGRAPH_EINVMODE      = 9,
+  IGRAPH_EFILE         = 10,
+  IGRAPH_UNIMPLEMENTED = 12,
+  IGRAPH_INTERRUPTED   = 13,
+  IGRAPH_DIVERGED      = 14,
+  IGRAPH_ARPACK_PROD      = 15,
+  IGRAPH_ARPACK_NPOS      = 16,
+  IGRAPH_ARPACK_NEVNPOS   = 17,
+  IGRAPH_ARPACK_NCVSMALL  = 18,
+  IGRAPH_ARPACK_NONPOSI   = 19,
+  IGRAPH_ARPACK_WHICHINV  = 20,
+  IGRAPH_ARPACK_BMATINV   = 21,
+  IGRAPH_ARPACK_WORKLSMALL= 22,
+  IGRAPH_ARPACK_TRIDERR   = 23,
+  IGRAPH_ARPACK_ZEROSTART = 24,
+  IGRAPH_ARPACK_MODEINV   = 25,
+  IGRAPH_ARPACK_MODEBMAT  = 26,
+  IGRAPH_ARPACK_ISHIFT    = 27,
+  IGRAPH_ARPACK_NEVBE     = 28,
+  IGRAPH_ARPACK_NOFACT    = 29,
+  IGRAPH_ARPACK_FAILED    = 30,
+  IGRAPH_ARPACK_HOWMNY    = 31,
+  IGRAPH_ARPACK_HOWMNYS   = 32,
+  IGRAPH_ARPACK_EVDIFF    = 33,
+  IGRAPH_ARPACK_SHUR      = 34,
+  IGRAPH_ARPACK_LAPACK    = 35,
+  IGRAPH_ARPACK_UNKNOWN   = 36,
+  IGRAPH_ENEGLOOP         = 37,
+  IGRAPH_EINTERNAL        = 38,
+  IGRAPH_ARPACK_MAXIT     = 39,
+  IGRAPH_ARPACK_NOSHIFT   = 40,
+  IGRAPH_ARPACK_REORDER   = 41,
+  IGRAPH_EDIVZERO         = 42,
+  IGRAPH_GLP_EBOUND       = 43,
+  IGRAPH_GLP_EROOT        = 44,
+  IGRAPH_GLP_ENOPFS       = 45,
+  IGRAPH_GLP_ENODFS       = 46,
+  IGRAPH_GLP_EFAIL        = 47, 
+  IGRAPH_GLP_EMIPGAP      = 48,
+  IGRAPH_GLP_ETMLIM       = 49,
+  IGRAPH_GLP_ESTOP        = 50,
+  IGRAPH_EATTRIBUTES      = 51,
+  IGRAPH_EATTRCOMBINE     = 52,
+  IGRAPH_ELAPACK          = 53,
+  IGRAPH_EDRL             = 54,
+  IGRAPH_EOVERFLOW        = 55,
+  IGRAPH_EGLP             = 56,
+  IGRAPH_CPUTIME          = 57,
+  IGRAPH_EUNDERFLOW       = 58,
+  IGRAPH_ERWSTUCK         = 59
+} igraph_error_type_t;
+
+/**
+ * \define IGRAPH_ERROR
+ * \brief Trigger an error.
+ * 
+ * \a igraph functions usually use this macro when they notice an error.
+ * It calls
+ * \ref igraph_error() with the proper parameters and if that returns 
+ * the macro returns the "calling" function as well, with the error
+ * code. If for some (suspicious) reason you want to call the error
+ * handler without returning from the current function, call
+ * \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,
+ *   its associated text (see  \ref igraph_strerror()) is "Invalid
+ *   value" and this string should explain which parameter was invalid
+ *   and maybe why. 
+ * \param igraph_errno The \a igraph error code.
+ */
+
+#define IGRAPH_ERROR(reason,igraph_errno) \
+       do { \
+       igraph_error (reason, __FILE__, __LINE__, igraph_errno) ; \
+       return igraph_errno ; \
+       } while (0)
+
+/**
+ * \function igraph_error
+ * \brief Trigger an error.
+ *
+ * \a igraph functions usually call this function (most often via the 
+ * \ref IGRAPH_ERROR macro) if they notice an error.
+ * It calls the currently installed error handler function with the
+ * supplied arguments. 
+ *
+ * \param reason Textual description of the error.
+ * \param file The source file in which the error was noticed.
+ * \param line The number of line in the source file which triggered the
+ *   error.
+ * \param igraph_errno The \a igraph error code.
+ * \return the error code (if it returns)
+ * 
+ * \sa igraph_errorf().
+ */
+
+int igraph_error(const char *reason, const char *file, int line,
+		 int igraph_errno);
+
+/**
+ * \function igraph_errorf
+ * \brief Trigger an error, printf-like version.
+ * 
+ * \param reason Textual description of the error, interpreted as 
+ *               a 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.
+ * \param ... Additional parameters, the values to substitute into the
+ *            format string.
+ * 
+ * \sa igraph_error().
+ */
+
+int igraph_errorf(const char *reason, const char *file, int line, 
+		  int igraph_errno, ...);
+
+int igraph_errorvf(const char *reason, const char *file, int line,
+		   int igraph_errno, va_list ap);
+
+/**
+ * \function igraph_strerror
+ * \brief Textual description of an error.
+ * 
+ * This is a simple utility function, it gives a short general textual
+ * description for an \a igraph error code.
+ * 
+ * \param igraph_errno The \a igraph error code.
+ * \return pointer to the textual description of the error code.
+ */
+
+const char* igraph_strerror(const int igraph_errno);
+
+#define IGRAPH_ERROR_SELECT_2(a,b)       ((a) != IGRAPH_SUCCESS ? (a) : ((b) != IGRAPH_SUCCESS ? (b) : IGRAPH_SUCCESS))
+#define IGRAPH_ERROR_SELECT_3(a,b,c)     ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_2(b,c))
+#define IGRAPH_ERROR_SELECT_4(a,b,c,d)   ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_3(b,c,d))
+#define IGRAPH_ERROR_SELECT_5(a,b,c,d,e) ((a) != IGRAPH_SUCCESS ? (a) : IGRAPH_ERROR_SELECT_4(b,c,d,e))
+
+/* Now comes the more convenient error handling macro arsenal.
+ * Ideas taken from exception.{h,c} by Laurent Deniau see
+ * http://cern.ch/Laurent.Deniau/html/oopc/oopc.html#Exceptions for more 
+ * information. We don't use the exception handling code though.  */
+
+struct igraph_i_protectedPtr {
+  int all;
+  void *ptr;
+  void (*func)(void*);
+};
+
+typedef void igraph_finally_func_t (void*);
+
+void IGRAPH_FINALLY_REAL(void (*func)(void*), void* ptr);
+
+/**
+ * \function IGRAPH_FINALLY_CLEAN
+ * \brief Signal clean deallocation of objects.
+ * 
+ * Removes the specified number of objects from the stack of
+ * temporarily allocated objects. Most often this is called just
+ * before returning from a function.
+ * \param num The number of objects to remove from the bookkeeping
+ *   stack. 
+ */
+
+void IGRAPH_FINALLY_CLEAN(int num); 
+
+/**
+ * \function IGRAPH_FINALLY_FREE
+ * \brief Deallocate all registered objects.
+ *
+ * Calls the destroy function for all objects in the stack of
+ * temporarily allocated objects. This is usually called only from an
+ * error handler. It is \em not appropriate to use it
+ * instead of destroying each unneeded object of a function, as it
+ * destroys the temporary objects of the caller function (and so on)
+ * as well.
+ */
+
+void IGRAPH_FINALLY_FREE(void);
+
+/**
+ * \function IGRAPH_FINALLY_STACK_SIZE
+ * \brief Returns the number of registered objects.
+ *
+ * Returns the number of objects in the stack of temporarily allocated
+ * objects. This function is handy if you write an own igraph routine and
+ * you want to make sure it handles errors properly. A properly written
+ * igraph routine should not leave pointers to temporarily allocated objects
+ * in the finally stack, because otherwise an \ref IGRAPH_FINALLY_FREE call
+ * in another igraph function would result in freeing these objects as well
+ * (and this is really hard to debug, since the error will be not in that
+ * function that shows erroneous behaviour). Therefore, it is advised to
+ * write your own test cases and examine \ref IGRAPH_FINALLY_STACK_SIZE
+ * before and after your test cases - the numbers should be equal.
+ */
+int IGRAPH_FINALLY_STACK_SIZE(void);
+
+/**
+ * \define IGRAPH_FINALLY_STACK_EMPTY
+ * \brief Returns true if there are no registered objects, false otherwise.
+ *
+ * This is just a shorthand notation for checking that
+ * \ref IGRAPH_FINALLY_STACK_SIZE is zero.
+ */
+#define IGRAPH_FINALLY_STACK_EMPTY (IGRAPH_FINALLY_STACK_SIZE() == 0)
+
+/**
+ * \define IGRAPH_FINALLY
+ * \brief Register an object for deallocation.
+ * \param func The address of the function which is normally called to
+ *   destroy the object.
+ * \param ptr Pointer to the object itself.
+ * 
+ * This macro places the address of an object, together with the
+ * address of its destructor in a stack. This stack is used if an
+ * error happens to deallocate temporarily allocated objects to
+ * prevent memory leaks.
+ */
+
+#define IGRAPH_FINALLY(func,ptr) \
+  IGRAPH_FINALLY_REAL((igraph_finally_func_t*)(func), (ptr))
+
+#if (defined(__GNUC__) && GCC_VERSION_MAJOR >= 3)
+#  define IGRAPH_UNLIKELY(a) __builtin_expect((a), 0)
+#  define IGRAPH_LIKELY(a)   __builtin_expect((a), 1)
+#else
+#  define IGRAPH_UNLIKELY(a) a
+#  define IGRAPH_LIKELY(a)   a
+#endif
+
+/**
+ * \define IGRAPH_CHECK
+ * \brief Check the return value of a function call.
+ *
+ * \param a An expression, usually a function call.
+ * 
+ * Executes the expression and checks its value. If this is not
+ * \c IGRAPH_SUCCESS, it calls \ref IGRAPH_ERROR with
+ * the value as the error code. Here is an example usage:
+ * \verbatim IGRAPH_CHECK(vector_push_back(&v, 100)); \endverbatim
+ * 
+ * </para><para>There is only one reason to use this macro when writing 
+ * \a igraph functions. If the user installs an error handler which
+ * returns to the auxiliary calling code (like \ref
+ * igraph_error_handler_ignore and \ref
+ * 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
+ * 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)
+
+
+/**
+ * \section about_igraph_warnings Warning messages
+ * 
+ * <para>
+ * Igraph also supports warning messages in addition to error 
+ * messages. Warning messages typically do not terminate the 
+ * program, but they are usually crucial to the user.
+ * </para>
+ * 
+ * <para>
+ * Igraph warning are handled similarly to errors. There is a 
+ * separate warning handler function that is called whenever
+ * an igraph function triggers a warning. This handler can be 
+ * set by the \ref igraph_set_warning_handler() function. There are 
+ * two predefined simple warning handlers, 
+ * \ref igraph_warning_handler_ignore() and 
+ * \ref igraph_warning_handler_print(), the latter being the default.
+ * </para>
+ * 
+ * <para>
+ * To trigger a warning, igraph functions typically use the 
+ * \ref IGRAPH_WARNING() macro, the \ref igraph_warning() function, 
+ * or if more flexibility is needed, \ref igraph_warningf().
+ * </para>
+ */
+
+/**
+ * \typedef igraph_warning_handler_t
+ * Type of igraph warning handler functions
+ * 
+ * Currently it is defined to have the same type as 
+ * \ref igraph_error_handler_t, although the last (error code)
+ * argument is not used.
+ */
+
+typedef igraph_error_handler_t igraph_warning_handler_t;
+
+/**
+ * \function igraph_set_warning_handler
+ * Install a warning handler
+ * 
+ * Install the supplied warning handler function.
+ * \param new_handler The new warning handler function to install.
+ *        Supply a null pointer here to uninstall the current 
+ *        warning handler, without installing a new one.
+ * \return The current warning handler function.
+ */
+
+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;
+
+/**
+ * \function igraph_warning
+ * Trigger a warning
+ * 
+ * Call this function if you want to trigger a warning from within 
+ * a function that uses igraph.
+ * \param reason Textual description of the warning.
+ * \param file The source file in which the warning was noticed.
+ * \param line The number of line in the source file which triggered the
+ *         warning.
+ * \param igraph_errno Warnings could have potentially error codes as well, 
+ *        but this is currently not used in igraph.
+ * \return The supplied error code.
+ */
+
+int igraph_warning(const char *reason, const char *file, int line,
+		   int igraph_errno);
+
+/**
+ * \function igraph_warningf
+ * Trigger a warning, more flexible printf-like syntax
+ * 
+ * This function is similar to \ref igraph_warning(), but
+ * uses a printf-like syntax. It substitutes the additional arguments 
+ * into the \p reason template string and calls \ref igraph_warning().
+ * \param reason Textual description of the warning, a template string
+ *        with the same syntax as the standard printf C library function.
+ * \param file The source file in which the warning was noticed.
+ * \param line The number of line in the source file which triggered the
+ *         warning.
+ * \param igraph_errno Warnings could have potentially error codes as well, 
+ *        but this is currently not used in igraph.
+ * \param ... The additional arguments to be substituted into the 
+ *        template string.
+ * \return The supplied error code.
+ */
+
+int igraph_warningf(const char *reason, const char *file, int line, 
+		    int igraph_errno, ...);
+
+/**
+ * \define IGRAPH_WARNING
+ * Trigger a warning.
+ * 
+ * This is the usual way of triggering a warning from an igraph
+ * function. It calls \ref igraph_warning().
+ * \param reason The warning message.
+ */
+
+#define IGRAPH_WARNING(reason) \
+       do { \
+         igraph_warning(reason, __FILE__, __LINE__, -1); \
+       } while (0)
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_flow.h b/src/include/igraph_flow.h
similarity index 100%
rename from src/igraph_flow.h
rename to src/include/igraph_flow.h
diff --git a/src/igraph_foreign.h b/src/include/igraph_foreign.h
similarity index 100%
rename from src/igraph_foreign.h
rename to src/include/igraph_foreign.h
diff --git a/src/include/igraph_games.h b/src/include/igraph_games.h
new file mode 100644
index 0000000..311573c
--- /dev/null
+++ b/src/include/igraph_games.h
@@ -0,0 +1,235 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_GAMES_H
+#define IGRAPH_GAMES_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
+
+#include "igraph_constants.h"
+#include "igraph_types.h"
+#include "igraph_matrix.h"
+#include "igraph_vector.h"
+#include "igraph_datatype.h"
+#include "igraph_vector_ptr.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Constructors, games (=stochastic)                  */
+/* -------------------------------------------------- */
+
+int igraph_barabasi_game(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,
+			 igraph_barabasi_algorithm_t algo,
+			 const igraph_t *start_from);
+int igraph_nonlinear_barabasi_game(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 zeroappeal,
+				   igraph_bool_t directed);
+int igraph_erdos_renyi_game(igraph_t *graph, igraph_erdos_renyi_t type,
+			    igraph_integer_t n, igraph_real_t p,
+			    igraph_bool_t directed, igraph_bool_t loops);
+int igraph_erdos_renyi_game_gnp(igraph_t *graph, igraph_integer_t n, igraph_real_t p,
+				igraph_bool_t directed, igraph_bool_t loops);
+int igraph_erdos_renyi_game_gnm(igraph_t *graph, igraph_integer_t n, igraph_real_t m,
+				igraph_bool_t directed, igraph_bool_t loops);
+int igraph_degree_sequence_game(igraph_t *graph, const igraph_vector_t *out_deg,
+				const igraph_vector_t *in_deg, 
+				igraph_degseq_t method);
+int igraph_growing_random_game(igraph_t *graph, igraph_integer_t n, 
+			       igraph_integer_t m, igraph_bool_t directed, igraph_bool_t citation);
+int igraph_barabasi_aging_game(igraph_t *graph, 
+			       igraph_integer_t nodes,
+			       igraph_integer_t m,
+			       const igraph_vector_t *outseq,
+			       igraph_bool_t outpref,
+			       igraph_real_t pa_exp,
+			       igraph_real_t aging_exp,
+			       igraph_integer_t aging_bin,
+			       igraph_real_t zero_deg_appeal,
+			       igraph_real_t zero_age_appeal,
+			       igraph_real_t deg_coef,
+			       igraph_real_t age_coef,
+			       igraph_bool_t directed);
+int igraph_recent_degree_game(igraph_t *graph, igraph_integer_t n,
+			      igraph_real_t power,
+			      igraph_integer_t window,
+			      igraph_integer_t m,  
+			      const igraph_vector_t *outseq,
+			      igraph_bool_t outpref,
+			      igraph_real_t zero_appeal,
+			      igraph_bool_t directed);
+int igraph_recent_degree_aging_game(igraph_t *graph,
+				    igraph_integer_t nodes,
+				    igraph_integer_t m, 
+				    const igraph_vector_t *outseq,
+				    igraph_bool_t outpref,
+				    igraph_real_t pa_exp,
+				    igraph_real_t aging_exp,
+				    igraph_integer_t aging_bin,
+				    igraph_integer_t window,
+				    igraph_real_t zero_appeal,
+				    igraph_bool_t directed);
+int igraph_callaway_traits_game (igraph_t *graph, igraph_integer_t nodes, 
+				 igraph_integer_t types, igraph_integer_t edges_per_step, 
+				 igraph_vector_t *type_dist,
+				 igraph_matrix_t *pref_matrix,
+				 igraph_bool_t directed);
+int igraph_establishment_game(igraph_t *graph, igraph_integer_t nodes,
+			      igraph_integer_t types, igraph_integer_t k,
+			      igraph_vector_t *type_dist,
+			      igraph_matrix_t *pref_matrix,
+			      igraph_bool_t directed);
+int igraph_grg_game(igraph_t *graph, igraph_integer_t nodes,
+		    igraph_real_t radius, igraph_bool_t torus,
+		    igraph_vector_t *x, igraph_vector_t *y);
+int igraph_preference_game(igraph_t *graph, igraph_integer_t nodes,
+			   igraph_integer_t types, 
+			   const igraph_vector_t *type_dist,
+			   igraph_bool_t fixed_sizes,
+			   const igraph_matrix_t *pref_matrix,
+			   igraph_vector_t *node_type_vec,
+			   igraph_bool_t directed, igraph_bool_t loops);
+int igraph_asymmetric_preference_game(igraph_t *graph, igraph_integer_t nodes,
+				      igraph_integer_t types,
+				      igraph_matrix_t *type_dist_matrix,
+				      igraph_matrix_t *pref_matrix,
+				      igraph_vector_t *node_type_in_vec,
+				      igraph_vector_t *node_type_out_vec,
+				      igraph_bool_t loops);
+
+int igraph_rewire_edges(igraph_t *graph, igraph_real_t prob, 
+			igraph_bool_t loops, igraph_bool_t multiple);
+int igraph_watts_strogatz_game(igraph_t *graph, igraph_integer_t dim,
+			       igraph_integer_t size, igraph_integer_t nei,
+			       igraph_real_t p, igraph_bool_t loops, 
+			       igraph_bool_t multiple);
+
+int igraph_lastcit_game(igraph_t *graph, 
+			igraph_integer_t nodes, igraph_integer_t edges_per_node, 
+			igraph_integer_t agebins,
+			const igraph_vector_t *preference, igraph_bool_t directed);
+
+int igraph_cited_type_game(igraph_t *graph, igraph_integer_t nodes,
+			   const igraph_vector_t *types,
+			   const igraph_vector_t *pref,
+			   igraph_integer_t edges_per_step,
+			   igraph_bool_t directed);
+
+int igraph_citing_cited_type_game(igraph_t *graph, igraph_integer_t nodes,
+				  const igraph_vector_t *types,
+				  const igraph_matrix_t *pref,
+				  igraph_integer_t edges_per_step,
+				  igraph_bool_t directed);
+
+int igraph_forest_fire_game(igraph_t *graph, igraph_integer_t nodes,
+			    igraph_real_t fw_prob, igraph_real_t bw_factor,
+			    igraph_integer_t ambs, igraph_bool_t directed);
+
+
+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);
+
+int igraph_static_fitness_game(igraph_t *graph, igraph_integer_t no_of_edges,
+                igraph_vector_t* fitness_out, igraph_vector_t* fitness_in,
+                igraph_bool_t loops, igraph_bool_t multiple);
+
+int igraph_static_power_law_game(igraph_t *graph,
+    igraph_integer_t no_of_nodes, igraph_integer_t no_of_edges,
+    igraph_real_t exponent_out, igraph_real_t exponent_in,
+    igraph_bool_t loops, igraph_bool_t multiple,
+    igraph_bool_t finite_size_correction);
+
+int igraph_k_regular_game(igraph_t *graph,
+    igraph_integer_t no_of_nodes, igraph_integer_t k,
+    igraph_bool_t directed, igraph_bool_t multiple);
+
+int igraph_sbm_game(igraph_t *graph, igraph_integer_t n, 
+		    const igraph_matrix_t *pref_matrix,
+		    const igraph_vector_int_t *block_sizes,
+		    igraph_bool_t directed, igraph_bool_t loops);
+
+int igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, 
+		     igraph_integer_t m, const igraph_vector_t *rho,
+		     const igraph_matrix_t *C, igraph_real_t p);
+
+int igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n,
+			  const igraph_vector_int_t *mlist,
+			  const igraph_vector_ptr_t *rholist,
+			  const igraph_vector_ptr_t *Clist,
+			  igraph_real_t p);
+
+int igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_graph,
+			   igraph_real_t corr, igraph_real_t p,
+			   const igraph_vector_t *permutation);
+
+int igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2,
+				int n, igraph_real_t corr, igraph_real_t p,
+				igraph_bool_t directed,
+				const igraph_vector_t *permutation);
+
+int igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,
+			    igraph_bool_t directed);
+
+int igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n,
+				 igraph_real_t radius, 
+				 igraph_bool_t positive, 
+				 igraph_matrix_t *res);
+
+int igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n,
+				igraph_real_t radius,
+				igraph_bool_t positive,
+				igraph_matrix_t *res);
+
+int igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n,
+				igraph_real_t radius,
+				igraph_bool_t positive,
+				igraph_matrix_t *res);
+
+int igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha,
+			    igraph_matrix_t *res);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_graphlets.h b/src/include/igraph_graphlets.h
similarity index 100%
rename from src/igraph_graphlets.h
rename to src/include/igraph_graphlets.h
diff --git a/src/igraph_heap.h b/src/include/igraph_heap.h
similarity index 100%
rename from src/igraph_heap.h
rename to src/include/igraph_heap.h
diff --git a/src/igraph_heap_pmt.h b/src/include/igraph_heap_pmt.h
similarity index 100%
rename from src/igraph_heap_pmt.h
rename to src/include/igraph_heap_pmt.h
diff --git a/src/igraph_hrg.h b/src/include/igraph_hrg.h
similarity index 100%
rename from src/igraph_hrg.h
rename to src/include/igraph_hrg.h
diff --git a/src/igraph_interface.h b/src/include/igraph_interface.h
similarity index 100%
rename from src/igraph_interface.h
rename to src/include/igraph_interface.h
diff --git a/src/igraph_interrupt.h b/src/include/igraph_interrupt.h
similarity index 100%
rename from src/igraph_interrupt.h
rename to src/include/igraph_interrupt.h
diff --git a/src/igraph_iterators.h b/src/include/igraph_iterators.h
similarity index 100%
rename from src/igraph_iterators.h
rename to src/include/igraph_iterators.h
diff --git a/src/include/igraph_lapack.h b/src/include/igraph_lapack.h
new file mode 100644
index 0000000..4c862f4
--- /dev/null
+++ b/src/include/igraph_lapack.h
@@ -0,0 +1,121 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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 LAPACK_H
+#define LAPACK_H
+
+#include "igraph_vector.h"
+#include "igraph_matrix.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
+
+/**
+ * \section about_lapack LAPACK interface in igraph
+ * 
+ * <para>
+ * LAPACK is written in Fortran90 and provides routines for solving
+ * systems of simultaneous linear equations, least-squares solutions
+ * of linear systems of equations, eigenvalue problems, and singular
+ * value problems. The associated matrix factorizations (LU, Cholesky,
+ * QR, SVD, Schur, generalized Schur) are also provided, as are
+ * related computations such as reordering of the Schur factorizations
+ * and estimating condition numbers. Dense and banded matrices are
+ * handled, but not general sparse matrices. In all areas, similar
+ * functionality is provided for real and complex matrices, in both
+ * single and double precision.
+ * </para>
+ * 
+ * <para>
+ * igraph provides an interface to a very limited set of LAPACK
+ * functions, using the regular igraph data structures.
+ * </para>
+ * 
+ * <para>
+ * See more about LAPACK at http://www.netlib.org/lapack/
+ * </para>
+ */
+
+int igraph_lapack_dgetrf(igraph_matrix_t *a, igraph_vector_int_t *ipiv,
+			 int *info);
+int igraph_lapack_dgetrs(igraph_bool_t transpose, const igraph_matrix_t *a,
+			 igraph_vector_int_t *ipiv, igraph_matrix_t *b);
+int igraph_lapack_dgesv(igraph_matrix_t *a, igraph_vector_int_t *ipiv,
+			igraph_matrix_t *b, int *info);
+
+typedef enum { IGRAPH_LAPACK_DSYEV_ALL,
+	       IGRAPH_LAPACK_DSYEV_INTERVAL,
+	       IGRAPH_LAPACK_DSYEV_SELECT } igraph_lapack_dsyev_which_t;
+
+int igraph_lapack_dsyevr(const igraph_matrix_t *A, 
+			 igraph_lapack_dsyev_which_t which,
+			 igraph_real_t vl, igraph_real_t vu, int vestimate, 
+			 int il, int iu, igraph_real_t abstol,
+			 igraph_vector_t *values, igraph_matrix_t *vectors,
+			 igraph_vector_int_t *support);
+
+/* TODO: should we use complex vectors/matrices? */
+
+int igraph_lapack_dgeev(const igraph_matrix_t *A, 
+			igraph_vector_t *valuesreal,
+			igraph_vector_t *valuesimag, 
+			igraph_matrix_t *vectorsleft,
+			igraph_matrix_t *vectorsright, int *info);
+
+typedef enum { IGRAPH_LAPACK_DGEEVX_BALANCE_NONE=0, 
+	       IGRAPH_LAPACK_DGEEVX_BALANCE_PERM,
+	       IGRAPH_LAPACK_DGEEVX_BALANCE_SCALE,
+	       IGRAPH_LAPACK_DGEEVX_BALANCE_BOTH } 
+  igraph_lapack_dgeevx_balance_t;
+
+int igraph_lapack_dgeevx(igraph_lapack_dgeevx_balance_t balance,
+			 const igraph_matrix_t *A,
+			 igraph_vector_t *valuesreal,
+			 igraph_vector_t *valuesimag,
+			 igraph_matrix_t *vectorsleft,
+			 igraph_matrix_t *vectorsright,
+			 int *ilo, int *ihi, igraph_vector_t *scale,
+			 igraph_real_t *abnrm,
+			 igraph_vector_t *rconde,
+			 igraph_vector_t *rcondv,
+			 int *info);
+
+int igraph_lapack_dgehrd(const igraph_matrix_t *A, 
+			 int ilo, int ihi,
+			 igraph_matrix_t *result);
+
+int igraph_lapack_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2,
+		       igraph_real_t *res);
+			
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_layout.h b/src/include/igraph_layout.h
new file mode 100644
index 0000000..17cd17b
--- /dev/null
+++ b/src/include/igraph_layout.h
@@ -0,0 +1,258 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_LAYOUT_H
+#define IGRAPH_LAYOUT_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
+
+#include "igraph_constants.h"
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_matrix.h"
+#include "igraph_datatype.h"
+#include "igraph_arpack.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Layouts                                            */
+/* -------------------------------------------------- */
+
+int igraph_layout_random(const igraph_t *graph, igraph_matrix_t *res);
+int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res,
+			 igraph_vs_t order);
+int igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res,
+		       igraph_integer_t center, const igraph_vector_t *order);
+int igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, long int width);
+int igraph_layout_fruchterman_reingold(const igraph_t *graph,
+				       igraph_matrix_t *res,
+				       igraph_bool_t use_seed,
+				       igraph_integer_t niter,
+				       igraph_real_t start_temp,
+				       igraph_layout_grid_t grid,
+				       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);
+
+int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res,
+	       igraph_bool_t use_seed, igraph_integer_t maxiter,
+	       igraph_real_t epsilon, igraph_real_t kkconst, 
+	       const igraph_vector_t *weights,
+	       const igraph_vector_t *minx, const igraph_vector_t *maxx,
+	       const igraph_vector_t *miny, const igraph_vector_t *maxy);
+
+int igraph_layout_springs(const igraph_t *graph, igraph_matrix_t *res,
+			  igraph_real_t mass, igraph_real_t equil, igraph_real_t k,
+			  igraph_real_t repeqdis, igraph_real_t kfr, igraph_bool_t repulse);
+int igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res,
+		      igraph_integer_t maxiter, igraph_real_t maxdelta, 
+		      igraph_real_t area, igraph_real_t coolexp,
+		      igraph_real_t repulserad, igraph_real_t cellsize, igraph_integer_t root);
+int igraph_layout_reingold_tilford(const igraph_t *graph, igraph_matrix_t *res,
+				   igraph_neimode_t mode,
+				   const igraph_vector_t *roots,
+				   const igraph_vector_t *rootlevel);
+int igraph_layout_reingold_tilford_circular(const igraph_t *graph,
+					    igraph_matrix_t *res, 
+					    igraph_neimode_t mode,
+					    const igraph_vector_t *roots,
+					    const igraph_vector_t *rootlevel);
+int igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *res,
+        igraph_t *extd_graph, igraph_vector_t *extd_to_orig_eids,
+        const igraph_vector_t* layers, igraph_real_t hgap,
+        igraph_real_t vgap, long int maxiter, const igraph_vector_t *weights);
+
+int igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res);
+int igraph_layout_sphere(const igraph_t *graph, igraph_matrix_t *res);
+int igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res,
+        long int width, long int height);
+int igraph_layout_fruchterman_reingold_3d(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,
+					  const igraph_vector_t *minz,
+					  const igraph_vector_t *maxz);
+
+int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res,
+	       igraph_bool_t use_seed, igraph_integer_t maxiter,
+	       igraph_real_t epsilon, igraph_real_t kkconst, 
+	       const igraph_vector_t *weights,
+	       const igraph_vector_t *minx, const igraph_vector_t *maxx,
+	       const igraph_vector_t *miny, const igraph_vector_t *maxy,
+	       const igraph_vector_t *minz, const igraph_vector_t *maxz);
+
+int igraph_layout_graphopt(const igraph_t *graph, 
+			   igraph_matrix_t *res, igraph_integer_t niter,
+			   igraph_real_t node_charge, igraph_real_t node_mass,
+			   igraph_real_t spring_length,
+			   igraph_real_t spring_constant, 
+			   igraph_real_t max_sa_movement,
+			   igraph_bool_t use_seed);
+
+int igraph_layout_mds(const igraph_t *graph, igraph_matrix_t *res, 
+                      const igraph_matrix_t *dist, long int dim,
+                      igraph_arpack_options_t *options);
+
+int igraph_layout_bipartite(const igraph_t *graph, 
+			    const igraph_vector_bool_t *types,
+			    igraph_matrix_t *res, igraph_real_t hgap, 
+			    igraph_real_t vgap, long int maxiter);
+
+/** 
+ * \struct igraph_layout_drl_options_t
+ * Parameters for the DrL layout generator
+ *
+ * \member edge_cut The edge cutting parameter.
+ *    Edge cutting is done in the late stages of the
+ *    algorithm in order to achieve less dense layouts.  Edges are cut
+ *    if there is a lot of stress on them (a large value in the
+ *    objective function sum).  The edge cutting parameter is a value
+ *    between 0 and 1 with 0 representing no edge cutting and 1
+ *    representing maximal edge cutting. The default value is 32/40.
+ * \member init_iterations Number of iterations, initial phase.
+ * \member init_temperature Start temperature, initial phase.
+ * \member init_attraction Attraction, initial phase.
+ * \member init_damping_mult Damping factor, initial phase.
+ * \member liquid_iterations Number of iterations in the liquid phase.
+ * \member liquid_temperature Start temperature in the liquid phase.
+ * \member liquid_attraction Attraction in the liquid phase.
+ * \member liquid_damping_mult Multiplicatie damping factor, liquid phase.
+ * \member expansion_iterations Number of iterations in the expansion phase.
+ * \member expansion_temperature Start temperature in the expansion phase.
+ * \member expansion_attraction Attraction, expansion phase.
+ * \member expansion_damping_mult Damping factor, expansion phase.
+ * \member cooldown_iterations Number of iterations in the cooldown phase.
+ * \member cooldown_temperature Start temperature in the cooldown phase.
+ * \member cooldown_attraction Attraction in the cooldown phase.
+ * \member cooldown_damping_mult Damping fact int the cooldown phase.
+ * \member crunch_iterations Number of iterations in the crunch phase.
+ * \member crunch_temperature Start temperature in the crunch phase.
+ * \member crunch_attraction Attraction in the crunch phase.
+ * \member crunch_damping_mult Damping factor in the crunch phase.
+ * \member simmer_iterations Number of iterations in the simmer phase.
+ * \member simmer_temperature Start temperature in te simmer phase.
+ * \member simmer_attraction Attraction in the simmer phase.
+ * \member simmer_damping_mult Multiplicative damping factor in the simmer phase.
+ */
+
+typedef struct igraph_layout_drl_options_t {
+  igraph_real_t    edge_cut;
+  igraph_integer_t init_iterations;
+  igraph_real_t    init_temperature;
+  igraph_real_t    init_attraction;
+  igraph_real_t    init_damping_mult;
+  igraph_integer_t liquid_iterations;
+  igraph_real_t    liquid_temperature;
+  igraph_real_t    liquid_attraction;
+  igraph_real_t    liquid_damping_mult;
+  igraph_integer_t expansion_iterations;
+  igraph_real_t    expansion_temperature;
+  igraph_real_t    expansion_attraction;
+  igraph_real_t    expansion_damping_mult;
+  igraph_integer_t cooldown_iterations;
+  igraph_real_t    cooldown_temperature;
+  igraph_real_t    cooldown_attraction;
+  igraph_real_t    cooldown_damping_mult;
+  igraph_integer_t crunch_iterations;
+  igraph_real_t    crunch_temperature;
+  igraph_real_t    crunch_attraction;
+  igraph_real_t    crunch_damping_mult;
+  igraph_integer_t simmer_iterations;
+  igraph_real_t    simmer_temperature;
+  igraph_real_t    simmer_attraction;
+  igraph_real_t    simmer_damping_mult;
+} igraph_layout_drl_options_t;
+
+/**
+ * \typedef igraph_layout_drl_default_t 
+ * Predefined parameter templates for the DrL layout generator
+ * 
+ * These constants can be used to initialize a set of DrL parameters. 
+ * These can then be modified according to the user's needs.
+ * \enumval IGRAPH_LAYOUT_DRL_DEFAULT The deafult parameters.
+ * \enumval IGRAPH_LAYOUT_DRL_COARSEN Slightly modified parameters to
+ *      get a coarser layout.  
+ * \enumval IGRAPH_LAYOUT_DRL_COARSEST An even coarser layout.
+ * \enumval IGRAPH_LAYOUT_DRL_REFINE Refine an already calculated layout.
+ * \enumval IGRAPH_LAYOUT_DRL_FINAL Finalize an already refined layout.
+ */
+
+typedef enum { IGRAPH_LAYOUT_DRL_DEFAULT=0, 
+	       IGRAPH_LAYOUT_DRL_COARSEN,
+	       IGRAPH_LAYOUT_DRL_COARSEST,
+	       IGRAPH_LAYOUT_DRL_REFINE,
+	       IGRAPH_LAYOUT_DRL_FINAL } igraph_layout_drl_default_t;
+
+int igraph_layout_drl_options_init(igraph_layout_drl_options_t *options,
+				   igraph_layout_drl_default_t templ);
+int igraph_layout_drl(const igraph_t *graph, igraph_matrix_t *res, 
+		      igraph_bool_t use_seed,
+		      igraph_layout_drl_options_t *options,
+		      const igraph_vector_t *weights, 
+		      const igraph_vector_bool_t *fixed);
+
+int igraph_layout_drl_3d(const igraph_t *graph, igraph_matrix_t *res, 
+			 igraph_bool_t use_seed,
+			 igraph_layout_drl_options_t *options,
+			 const igraph_vector_t *weights,
+			 const igraph_vector_bool_t *fixed);
+
+int igraph_layout_merge_dla(igraph_vector_ptr_t *graphs,
+			    igraph_vector_ptr_t *coords, 
+			    igraph_matrix_t *res);
+
+int igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res,
+		      igraph_bool_t use_seed, igraph_integer_t maxiter,
+		      igraph_real_t temp_max, igraph_real_t temp_min,
+		      igraph_real_t temp_init);
+
+int igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix_t *res,
+		 igraph_bool_t use_seed, igraph_integer_t maxiter,
+		 igraph_integer_t fineiter, igraph_real_t cool_fact,
+		 igraph_real_t weight_node_dist, igraph_real_t weight_border, 
+		 igraph_real_t weight_edge_lengths, 
+		 igraph_real_t weight_edge_crossings,
+		 igraph_real_t weight_node_edge_dist);
+
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_lsap.h b/src/include/igraph_lsap.h
new file mode 100644
index 0000000..977ad7a
--- /dev/null
+++ b/src/include/igraph_lsap.h
@@ -0,0 +1,12 @@
+
+#ifndef IGRAPH_LSAP
+#define IGRAPH_LSAP
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_matrix.h"
+
+int igraph_solve_lsap(igraph_matrix_t *c, igraph_integer_t n,
+		      igraph_vector_int_t *p);
+
+#endif
diff --git a/src/igraph_matching.h b/src/include/igraph_matching.h
similarity index 100%
rename from src/igraph_matching.h
rename to src/include/igraph_matching.h
diff --git a/src/include/igraph_matrix.h b/src/include/igraph_matrix.h
new file mode 100644
index 0000000..fc57d9a
--- /dev/null
+++ b/src/include/igraph_matrix.h
@@ -0,0 +1,109 @@
+/* -*- mode: C -*-  */
+/*
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_MATRIX_H
+#define IGRAPH_MATRIX_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
+
+#include "igraph_vector.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Matrix, very similar to vector                     */
+/* -------------------------------------------------- */
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "igraph_matrix_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "igraph_matrix_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "igraph_matrix_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "igraph_matrix_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "igraph_matrix_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_COMPLEX
+#include "igraph_pmt.h"
+#include "igraph_matrix_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_COMPLEX
+
+#define IGRAPH_MATRIX_NULL { IGRAPH_VECTOR_NULL, 0, 0 }
+#define IGRAPH_MATRIX_INIT_FINALLY(m, nr, nc) \
+  do { IGRAPH_CHECK(igraph_matrix_init(m, nr, nc)); \
+  IGRAPH_FINALLY(igraph_matrix_destroy, m); } while (0)
+
+/**
+ * \ingroup matrix
+ * \define MATRIX
+ * \brief Accessing an element of a matrix.
+ *
+ * Note that there are no range checks right now.
+ * This functionality might be redefined as a proper function later.
+ * \param m The matrix object.
+ * \param i The index of the row, starting with zero.
+ * \param j The index of the column, starting with zero.
+ *
+ * Time complexity: O(1).
+ */
+#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,
+				      const igraph_matrix_t *rhs,
+				      igraph_real_t tol);
+
+int igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol);
+
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_matrix_pmt.h b/src/include/igraph_matrix_pmt.h
new file mode 100644
index 0000000..c3dd7e2
--- /dev/null
+++ b/src/include/igraph_matrix_pmt.h
@@ -0,0 +1,243 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+typedef struct TYPE(igraph_matrix) {
+  TYPE(igraph_vector) data;
+  long int nrow, ncol;
+} TYPE(igraph_matrix);
+
+/*---------------*/
+/* Allocation    */
+/*---------------*/
+
+int FUNCTION(igraph_matrix,init)(TYPE(igraph_matrix) *m, 
+				 long int nrow, long int ncol);
+int FUNCTION(igraph_matrix,copy)(TYPE(igraph_matrix) *to, 
+				 const TYPE(igraph_matrix) *from);
+void FUNCTION(igraph_matrix,destroy)(TYPE(igraph_matrix) *m);
+long int FUNCTION(igraph_matrix,capacity)(const TYPE(igraph_matrix) *m);
+
+/*--------------------*/
+/* Accessing elements */
+/*--------------------*/
+
+/* MATRIX */
+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,
+				    long int row, long int col);
+void FUNCTION(igraph_matrix,set)(TYPE(igraph_matrix)* m, long int row, long int col,
+				 BASE value);
+
+/*------------------------------*/
+/* Initializing matrix elements */
+/*------------------------------*/
+
+void FUNCTION(igraph_matrix,null)(TYPE(igraph_matrix) *m);
+void FUNCTION(igraph_matrix,fill)(TYPE(igraph_matrix) *m, BASE e);
+
+/*-----------------------*/
+/* Matrix views          */
+/*-----------------------*/
+
+const TYPE(igraph_matrix) *FUNCTION(igraph_matrix,view)(const TYPE(igraph_matrix) *m,
+							const BASE *data,
+							long int nrow,
+							long int ncol);
+
+/*------------------*/
+/* Copying matrices */
+/*------------------*/
+
+void FUNCTION(igraph_matrix,copy_to)(const TYPE(igraph_matrix) *m, BASE *to);
+int FUNCTION(igraph_matrix,update)(TYPE(igraph_matrix) *to, 
+				   const TYPE(igraph_matrix) *from);
+int FUNCTION(igraph_matrix,rbind)(TYPE(igraph_matrix) *to,
+				  const TYPE(igraph_matrix) *from);
+int FUNCTION(igraph_matrix,cbind)(TYPE(igraph_matrix) *to,
+				  const TYPE(igraph_matrix) *from);
+int FUNCTION(igraph_matrix,swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2);
+
+/*--------------------------*/
+/* Copying rows and columns */
+/*--------------------------*/
+
+int FUNCTION(igraph_matrix,get_row)(const TYPE(igraph_matrix) *m, 
+				    TYPE(igraph_vector) *res, long int index);
+int FUNCTION(igraph_matrix,get_col)(const TYPE(igraph_matrix) *m, 
+				    TYPE(igraph_vector) *res, long int index);
+int FUNCTION(igraph_matrix,set_row)(TYPE(igraph_matrix) *m,
+				     const TYPE(igraph_vector) *v, long int index);
+int FUNCTION(igraph_matrix,set_col)(TYPE(igraph_matrix) *m,
+				    const TYPE(igraph_vector) *v, long int index);
+int FUNCTION(igraph_matrix,select_rows)(const TYPE(igraph_matrix) *m,
+					TYPE(igraph_matrix) *res, 
+					const igraph_vector_t *rows);
+int FUNCTION(igraph_matrix,select_cols)(const TYPE(igraph_matrix) *m,
+					TYPE(igraph_matrix) *res, 
+					const igraph_vector_t *cols);
+int FUNCTION(igraph_matrix,select_rows_cols)(const TYPE(igraph_matrix) *m,
+					TYPE(igraph_matrix) *res, 
+					const igraph_vector_t *rows,
+					const igraph_vector_t *cols);
+
+/*-----------------------------*/
+/* Exchanging rows and columns */
+/*-----------------------------*/
+
+int FUNCTION(igraph_matrix,swap_rows)(TYPE(igraph_matrix) *m, 
+				      long int i, long int j);
+int FUNCTION(igraph_matrix,swap_cols)(TYPE(igraph_matrix) *m, 
+				      long int i, long int j);
+int FUNCTION(igraph_matrix,swap_rowcol)(TYPE(igraph_matrix) *m,
+				       long int i, long int j);
+int FUNCTION(igraph_matrix,transpose)(TYPE(igraph_matrix) *m);
+
+/*-----------------------------*/
+/* Matrix operations           */
+/*-----------------------------*/
+
+int FUNCTION(igraph_matrix,add)(TYPE(igraph_matrix) *m1, 
+				const TYPE(igraph_matrix) *m2);
+int FUNCTION(igraph_matrix,sub)(TYPE(igraph_matrix) *m1, 
+				const TYPE(igraph_matrix) *m2);
+int FUNCTION(igraph_matrix,mul_elements)(TYPE(igraph_matrix) *m1, 
+					 const TYPE(igraph_matrix) *m2);
+int FUNCTION(igraph_matrix,div_elements)(TYPE(igraph_matrix) *m1, 
+					 const TYPE(igraph_matrix) *m2);
+void FUNCTION(igraph_matrix,scale)(TYPE(igraph_matrix) *m, BASE by);
+void FUNCTION(igraph_matrix,add_constant)(TYPE(igraph_matrix) *m, BASE plus);
+
+/*-----------------------------*/
+/* Finding minimum and maximum */
+/*-----------------------------*/
+
+igraph_real_t FUNCTION(igraph_matrix,min)(const TYPE(igraph_matrix) *m);
+igraph_real_t FUNCTION(igraph_matrix,max)(const TYPE(igraph_matrix) *m);
+int FUNCTION(igraph_matrix,which_min)(const TYPE(igraph_matrix) *m,
+				      long int *i, long int *j);
+int FUNCTION(igraph_matrix,which_max)(const TYPE(igraph_matrix) *m,
+				      long int *i, long int *j);
+int FUNCTION(igraph_matrix,minmax)(const TYPE(igraph_matrix) *m,
+				   BASE *min, BASE *max);
+int FUNCTION(igraph_matrix,which_minmax)(const TYPE(igraph_matrix) *m,
+					 long int *imin, long int *jmin,
+					 long int *imax, long int *jmax);
+
+/*------------------------------*/
+/* Comparison                   */
+/*------------------------------*/
+
+igraph_bool_t FUNCTION(igraph_matrix,all_e)(const TYPE(igraph_matrix) *lhs, 
+					    const TYPE(igraph_matrix) *rhs);
+igraph_bool_t FUNCTION(igraph_matrix,all_l)(const TYPE(igraph_matrix) *lhs, 
+					    const TYPE(igraph_matrix) *rhs);
+igraph_bool_t FUNCTION(igraph_matrix,all_g)(const TYPE(igraph_matrix) *lhs, 
+					    const TYPE(igraph_matrix) *rhs);
+igraph_bool_t FUNCTION(igraph_matrix,all_le)(const TYPE(igraph_matrix) *lhs, 
+					     const TYPE(igraph_matrix) *rhs);
+igraph_bool_t FUNCTION(igraph_matrix,all_ge)(const TYPE(igraph_matrix) *lhs, 
+					     const TYPE(igraph_matrix) *rhs);
+
+/*-------------------*/
+/* Matrix properties */
+/*-------------------*/
+
+igraph_bool_t FUNCTION(igraph_matrix,isnull)(const TYPE(igraph_matrix) *m);
+igraph_bool_t FUNCTION(igraph_matrix,empty)(const TYPE(igraph_matrix) *m);
+long int FUNCTION(igraph_matrix,size)(const TYPE(igraph_matrix) *m);
+long int FUNCTION(igraph_matrix,nrow)(const TYPE(igraph_matrix) *m);
+long int FUNCTION(igraph_matrix,ncol)(const TYPE(igraph_matrix) *m);
+igraph_bool_t FUNCTION(igraph_matrix,is_symmetric)(const TYPE(igraph_matrix) *m);
+BASE FUNCTION(igraph_matrix,sum)(const TYPE(igraph_matrix) *m);
+BASE FUNCTION(igraph_matrix,prod)(const TYPE(igraph_matrix) *m);
+int FUNCTION(igraph_matrix,rowsum)(const TYPE(igraph_matrix) *m,
+				   TYPE(igraph_vector) *res);
+int FUNCTION(igraph_matrix,colsum)(const TYPE(igraph_matrix) *m,
+				   TYPE(igraph_vector) *res);
+igraph_bool_t FUNCTION(igraph_matrix,is_equal)(const TYPE(igraph_matrix) *m1, 
+					       const TYPE(igraph_matrix) *m2);
+BASE FUNCTION(igraph_matrix,maxdifference)(const TYPE(igraph_matrix) *m1,
+						    const TYPE(igraph_matrix) *m2);
+
+/*------------------------*/
+/* Searching for elements */
+/*------------------------*/
+
+igraph_bool_t FUNCTION(igraph_matrix,contains)(const TYPE(igraph_matrix) *m,
+					       BASE e);
+igraph_bool_t FUNCTION(igraph_matrix,search)(const TYPE(igraph_matrix) *m,
+					     long int from, BASE what, 
+					     long int *pos, 
+					     long int *row, long int *col);
+
+/*------------------------*/
+/* Resizing operations    */
+/*------------------------*/
+
+int FUNCTION(igraph_matrix,resize)(TYPE(igraph_matrix) *m, 
+				   long int nrow, long int ncol);
+int FUNCTION(igraph_matrix,resize_min)(TYPE(igraph_matrix) *m);
+int FUNCTION(igraph_matrix,add_cols)(TYPE(igraph_matrix) *m, long int n);
+int FUNCTION(igraph_matrix,add_rows)(TYPE(igraph_matrix) *m, long int n);
+int FUNCTION(igraph_matrix,remove_col)(TYPE(igraph_matrix) *m, long int col);
+int FUNCTION(igraph_matrix,remove_row)(TYPE(igraph_matrix) *m, long int row);
+
+/*------------------------*/
+/* Print as text          */
+/*------------------------*/
+
+int FUNCTION(igraph_matrix,print)(const TYPE(igraph_matrix) *m);
+int FUNCTION(igraph_matrix,printf)(const TYPE(igraph_matrix) *m,
+																	 const char *format);
+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, 
+			       igraph_matrix_t *real);
+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, 
+				   igraph_matrix_t *real, 
+				   igraph_matrix_t *imag);
+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,
+				       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, 
+					    long int *index, long int nremove);
+int FUNCTION(igraph_matrix,delete_rows_neg)(TYPE(igraph_matrix) *m, 
+					    const igraph_vector_t *neg, 
+					    long int nremove);
+
diff --git a/src/igraph_memory.h b/src/include/igraph_memory.h
similarity index 100%
rename from src/igraph_memory.h
rename to src/include/igraph_memory.h
diff --git a/src/igraph_microscopic_update.h b/src/include/igraph_microscopic_update.h
similarity index 100%
rename from src/igraph_microscopic_update.h
rename to src/include/igraph_microscopic_update.h
diff --git a/src/igraph_mixing.h b/src/include/igraph_mixing.h
similarity index 100%
rename from src/igraph_mixing.h
rename to src/include/igraph_mixing.h
diff --git a/src/include/igraph_motifs.h b/src/include/igraph_motifs.h
new file mode 100644
index 0000000..61f01b8
--- /dev/null
+++ b/src/include/igraph_motifs.h
@@ -0,0 +1,106 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_MOTIFS_H
+#define IGRAPH_MOTIFS_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
+
+#include "igraph_types.h"
+#include "igraph_datatype.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Graph motifs                                       */
+/* -------------------------------------------------- */
+
+/**
+ * \typedef igraph_motifs_handler_t
+ * Callback type for \c igraph_motifs_randesu_callback
+ * 
+ * \ref igraph_motifs_randesu_callback() calls a specified callback
+ * function whenever a new motif is found during a motif search. This
+ * callback function must be of type \c igraph_motifs_handler_t. It has
+ * the following arguments:
+ * \param graph The graph that that algorithm is working on. Of course
+ *   this must not be modified.
+ * \param vids The IDs of the vertices in the motif that has just been
+ *   found. This vector is owned by the motif search algorithm, so do not
+ *   modify or destroy it; make a copy of it if you need it later.
+ * \param isoclass The isomorphism class of the motif that has just been
+ *   found. Use \ref igraph_isoclass or \ref igraph_isoclass_subgraph to find
+ *   out which isomorphism class belongs to a given motif.
+ * \param extra The extra argument that was passed to \ref
+ *   igraph_motifs_randesu_callback().
+ * \return A logical value, if TRUE (=non-zero), that is interpreted
+ *    as a request to stop the motif search and return to the caller.
+ * 
+ * \sa \ref igraph_motifs_randesu_callback()
+ */
+
+typedef igraph_bool_t igraph_motifs_handler_t(const igraph_t *graph,
+					      igraph_vector_t *vids,
+					      int isoclass,
+					      void* extra);
+
+int igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *hist, 
+			  int size, const igraph_vector_t *cut_prob);
+
+int igraph_motifs_randesu_callback(const igraph_t *graph, int size,
+				   const igraph_vector_t *cut_prob,
+				   igraph_motifs_handler_t *callback,
+				   void* extra);
+
+int igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_integer_t *est,
+				   int size, const igraph_vector_t *cut_prob, 
+				   igraph_integer_t sample_size, 
+				   const igraph_vector_t *sample);
+int igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no,
+			     int size, const igraph_vector_t *cut_prob);
+
+int igraph_dyad_census(const igraph_t *graph, igraph_integer_t *mut,
+		       igraph_integer_t *asym, igraph_integer_t *null);
+int igraph_triad_census(const igraph_t *igraph, igraph_vector_t *res);
+int igraph_triad_census_24(const igraph_t *graph, igraph_integer_t *res2,
+			   igraph_integer_t *res4);
+
+int igraph_adjacent_triangles(const igraph_t *graph,
+			      igraph_vector_t *res,
+			      const igraph_vs_t vids);
+
+int igraph_list_triangles(const igraph_t *graph,
+			  igraph_vector_int_t *res);
+
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_neighborhood.h b/src/include/igraph_neighborhood.h
new file mode 100644
index 0000000..c5b6f5d
--- /dev/null
+++ b/src/include/igraph_neighborhood.h
@@ -0,0 +1,52 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_NEIGHBORHOOD_H
+#define IGRAPH_NEIGHBORHOOD_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
+
+int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
+			     igraph_vs_t vids, igraph_integer_t order, 
+			     igraph_neimode_t mode, igraph_integer_t mindist);
+int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
+			igraph_vs_t vids, igraph_integer_t order,
+			igraph_neimode_t mode, igraph_integer_t mindist);
+int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
+			       igraph_vs_t vids, igraph_integer_t order,
+			       igraph_neimode_t mode,
+			       igraph_integer_t mindist);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_nongraph.h b/src/include/igraph_nongraph.h
similarity index 100%
rename from src/igraph_nongraph.h
rename to src/include/igraph_nongraph.h
diff --git a/src/igraph_operators.h b/src/include/igraph_operators.h
similarity index 100%
rename from src/igraph_operators.h
rename to src/include/igraph_operators.h
diff --git a/src/include/igraph_paths.h b/src/include/igraph_paths.h
new file mode 100644
index 0000000..ede598d
--- /dev/null
+++ b/src/include/igraph_paths.h
@@ -0,0 +1,147 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_PATHS_H
+#define IGRAPH_PATHS_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
+
+#include "igraph_constants.h"
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_matrix.h"
+#include "igraph_iterators.h"
+
+__BEGIN_DECLS
+
+int igraph_diameter(const igraph_t *graph, igraph_integer_t *res, 
+		    igraph_integer_t *from, igraph_integer_t *to,
+		    igraph_vector_t *path,
+		    igraph_bool_t directed, igraph_bool_t unconn);
+int igraph_diameter_dijkstra(const igraph_t *graph,
+			     const igraph_vector_t *weights,
+			     igraph_real_t *pres,
+			     igraph_integer_t *pfrom,
+			     igraph_integer_t *pto,
+			     igraph_vector_t *path,
+			     igraph_bool_t directed,
+			     igraph_bool_t unconn);
+
+int igraph_shortest_paths(const igraph_t *graph, igraph_matrix_t *res, 
+			  const igraph_vs_t from, const igraph_vs_t to, 
+			  igraph_neimode_t mode);
+int igraph_get_shortest_paths(const igraph_t *graph, 
+			      igraph_vector_ptr_t *vertices,
+			      igraph_vector_ptr_t *edges,
+			      igraph_integer_t from, const igraph_vs_t to, 
+			      igraph_neimode_t mode,
+			      igraph_vector_long_t *predecessors,
+			      igraph_vector_long_t *inbound_edges);
+int igraph_get_shortest_path(const igraph_t *graph, 
+			     igraph_vector_t *vertices,
+			     igraph_vector_t *edges, 
+			     igraph_integer_t from,
+			     igraph_integer_t to,
+			     igraph_neimode_t mode);
+
+int igraph_get_all_shortest_paths(const igraph_t *graph,
+				  igraph_vector_ptr_t *res, 
+				  igraph_vector_t *nrgeo,
+				  igraph_integer_t from, const igraph_vs_t to, 
+				  igraph_neimode_t mode);
+int igraph_shortest_paths_dijkstra(const igraph_t *graph,
+				   igraph_matrix_t *res,
+				   const igraph_vs_t from,
+				   const igraph_vs_t to,
+				   const igraph_vector_t *weights, 
+				   igraph_neimode_t mode);
+int igraph_shortest_paths_bellman_ford(const igraph_t *graph,
+				   igraph_matrix_t *res,
+				   const igraph_vs_t from,
+				   const igraph_vs_t to,
+				   const igraph_vector_t *weights, 
+				   igraph_neimode_t mode);
+int igraph_get_shortest_paths_dijkstra(const igraph_t *graph,
+                                       igraph_vector_ptr_t *vertices,
+				       igraph_vector_ptr_t *edges,
+				       igraph_integer_t from,
+				       igraph_vs_t to,
+				       const igraph_vector_t *weights,
+				       igraph_neimode_t mode,
+				       igraph_vector_long_t *predecessors,
+				       igraph_vector_long_t *inbound_edges);
+int igraph_get_shortest_path_dijkstra(const igraph_t *graph,
+				      igraph_vector_t *vertices,
+				      igraph_vector_t *edges,
+				      igraph_integer_t from,
+				      igraph_integer_t to,
+				      const igraph_vector_t *weights,
+				      igraph_neimode_t mode);
+int igraph_get_all_shortest_paths_dijkstra(const igraph_t *graph,
+               igraph_vector_ptr_t *res, 
+               igraph_vector_t *nrgeo,
+               igraph_integer_t from, igraph_vs_t to,
+               const igraph_vector_t *weights,
+               igraph_neimode_t mode);
+int igraph_shortest_paths_johnson(const igraph_t *graph,
+				  igraph_matrix_t *res,
+				  const igraph_vs_t from,
+				  const igraph_vs_t to,
+				  const igraph_vector_t *weights);
+
+int igraph_average_path_length(const igraph_t *graph, igraph_real_t *res,
+			       igraph_bool_t directed, igraph_bool_t unconn);
+int igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res,
+			    igraph_real_t *unconnected, igraph_bool_t directed);
+
+int igraph_eccentricity(const igraph_t *graph, 
+			igraph_vector_t *res,
+			igraph_vs_t vids,
+			igraph_neimode_t mode);
+
+int igraph_radius(const igraph_t *graph, igraph_real_t *radius, 
+		  igraph_neimode_t mode);
+
+int igraph_get_all_simple_paths(const igraph_t *graph,
+				igraph_vector_int_t *res,
+				igraph_integer_t from,
+				const igraph_vs_t to,
+				igraph_neimode_t mode);
+
+int igraph_random_walk(const igraph_t *graph, igraph_vector_t *walk,
+		       igraph_integer_t start, igraph_neimode_t mode,
+		       igraph_integer_t steps,
+		       igraph_random_walk_stuck_t stuck);
+
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_pmt.h b/src/include/igraph_pmt.h
new file mode 100644
index 0000000..1f0f312
--- /dev/null
+++ b/src/include/igraph_pmt.h
@@ -0,0 +1,150 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#define CONCAT2x(a,b) a ## _ ## b 
+#define CONCAT2(a,b) CONCAT2x(a,b)
+#define CONCAT3x(a,b,c) a ## _ ## b ## _ ## c
+#define CONCAT3(a,b,c) CONCAT3x(a,b,c)
+#define CONCAT4x(a,b,c,d) a ## _ ## b ## _ ## c ## _ ## d
+#define CONCAT4(a,b,c,d) CONCAT4x(a,b,c,d)
+
+#if defined(BASE_IGRAPH_REAL)
+#define BASE igraph_real_t
+#define SHORT
+#define OUT_FORMAT "%G"
+#define PRINTFUNC(val) igraph_real_printf(val)
+#define FPRINTFUNC(file, val) igraph_real_fprintf(file, val)
+#define ZERO 0.0
+#define ONE 1.0
+#define MULTIPLICITY 1
+
+#elif defined(BASE_FLOAT)
+#define BASE float
+#define SHORT float
+#define OUT_FORMAT "%f"
+#define ZERO 0.0F
+#define ONE 1.0F
+#define MULTIPLICITY 1
+
+#elif defined(BASE_LONG)
+#define BASE long
+#define SHORT long
+#define OUT_FORMAT "%ld"
+#define ZERO 0L
+#define ONE 1L
+#define MULTIPLICITY 1
+
+#elif defined(BASE_CHAR)
+#define BASE char
+#define SHORT char
+#define OUT_FORMAT "%d"
+#define ZERO 0
+#define ONE 1
+#define MULTIPLICITY 1
+
+#elif defined(BASE_BOOL)
+#define BASE igraph_bool_t
+#define SHORT bool
+#define OUT_FORMAT "%d"
+#define ZERO 0
+#define ONE 1
+#define MULTIPLICITY 1
+
+#elif defined(BASE_INT)
+#define BASE int
+#define SHORT int
+#define OUT_FORMAT "%d"
+#define ZERO 0
+#define ONE 1
+#define MULTIPLICITY 1
+
+#elif defined(BASE_LIMB)
+#define BASE limb_t
+#define SHORT limb
+#define ZERO 0
+#define ONE 1
+#define MULTIPLICITY 1
+#define UNSIGNED 1
+
+#elif defined(BASE_PTR)
+#define BASE void*
+#define SHORT ptr
+#define ZERO 0
+#define MULTIPLICITY 1
+
+#elif defined(BASE_COMPLEX)
+#undef complex
+#define BASE igraph_complex_t
+#define SHORT complex
+#define ZERO igraph_complex(0,0)
+#define ONE {{1.0,0.0}}
+#define MULTIPLICITY 2
+#define NOTORDERED 1
+#define NOABS 1
+#define SUM(a,b,c) ((a) = igraph_complex_add((b),(c)))
+#define DIFF(a,b,c) ((a) = igraph_complex_sub((b),(c)))
+#define PROD(a,b,c) ((a) = igraph_complex_mul((b),(c)))
+#define DIV(a,b,c) ((a) = igraph_complex_div((b),(c)))
+#define EQ(a,b) IGRAPH_COMPLEX_EQ((a),(b))
+#define SQ(a) IGRAPH_REAL(igraph_complex_mul((a),(a)))
+
+#else
+#error unknown BASE_ directive
+#endif
+
+#if defined(BASE_IGRAPH_REAL)
+#  define FUNCTION(dir,name) CONCAT2(dir,name)
+#  define TYPE(dir) CONCAT2(dir,t)
+#elif defined(BASE_BOOL)
+   /* Special case because stdbool.h defines bool as a macro to _Bool which would
+    * screw things up */
+#  define FUNCTION(a,c) CONCAT3x(a,bool,c)
+#  define TYPE(dir) CONCAT3x(dir,bool,t)
+#else
+#  define FUNCTION(a,c) CONCAT3(a,SHORT,c)
+#  define TYPE(dir) CONCAT3(dir,SHORT,t)
+#endif
+
+#if defined(HEAP_TYPE_MIN)
+#define HEAPMORE <
+#define HEAPMOREEQ <=
+#define HEAPLESS >
+#define HEAPLESSEQ >=
+#undef FUNCTION
+#undef TYPE
+#if defined(BASE_IGRAPH_REAL)
+#define FUNCTION(dir,name) CONCAT3(dir,min,name)
+#define TYPE(dir) CONCAT3(dir,min,t)
+#else
+#define FUNCTION(a,c) CONCAT4(a,min,SHORT,c)
+#define TYPE(dir) CONCAT4(dir,min,SHORT,t)
+#endif
+#endif
+
+#if defined(HEAP_TYPE_MAX)
+#define HEAPMORE >
+#define HEAPMOREEQ >=
+#define HEAPLESS <
+#define HEAPLESSEQ <=
+#endif
+
diff --git a/src/igraph_pmt_off.h b/src/include/igraph_pmt_off.h
similarity index 100%
rename from src/igraph_pmt_off.h
rename to src/include/igraph_pmt_off.h
diff --git a/src/igraph_progress.h b/src/include/igraph_progress.h
similarity index 100%
rename from src/igraph_progress.h
rename to src/include/igraph_progress.h
diff --git a/src/igraph_psumtree.h b/src/include/igraph_psumtree.h
similarity index 100%
rename from src/igraph_psumtree.h
rename to src/include/igraph_psumtree.h
diff --git a/src/igraph_qsort.h b/src/include/igraph_qsort.h
similarity index 100%
rename from src/igraph_qsort.h
rename to src/include/igraph_qsort.h
diff --git a/src/include/igraph_random.h b/src/include/igraph_random.h
new file mode 100644
index 0000000..37e35d4
--- /dev/null
+++ b/src/include/igraph_random.h
@@ -0,0 +1,142 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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 REST_RANDOM_H
+#define REST_RANDOM_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
+
+#include <stdlib.h>
+#include <time.h>
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+
+/* The new RNG interface is (somewhat) modelled based on the GSL */
+
+typedef struct igraph_rng_type_t {
+  const char *name;
+  unsigned long int min;
+  unsigned long int max;
+  int (*init)(void **state);
+  void (*destroy)(void *state);
+  int (*seed)(void *state, unsigned long int seed);  
+  unsigned long int (*get)(void *state);
+  igraph_real_t (*get_real)(void *state);
+  igraph_real_t (*get_norm)(void *state);
+  igraph_real_t (*get_geom)(void *state, igraph_real_t p);
+  igraph_real_t (*get_binom)(void *state, long int n, igraph_real_t p);
+  igraph_real_t (*get_exp)(void *state, igraph_real_t rate);
+  igraph_real_t (*get_gamma)(void *state, igraph_real_t shape,
+			     igraph_real_t scale);
+} igraph_rng_type_t;
+
+typedef struct igraph_rng_t {
+  const igraph_rng_type_t *type;
+  void *state;
+  int def;
+} igraph_rng_t;
+
+/* --------------------------------- */
+
+int igraph_rng_init(igraph_rng_t *rng, const igraph_rng_type_t *type);
+void igraph_rng_destroy(igraph_rng_t *rng);
+
+int igraph_rng_seed(igraph_rng_t *rng, unsigned long int seed);
+unsigned long int igraph_rng_max(igraph_rng_t *rng);
+unsigned long int igraph_rng_min(igraph_rng_t *rng);
+const char *igraph_rng_name(igraph_rng_t *rng);
+
+long int igraph_rng_get_integer(igraph_rng_t *rng,
+				long int l, long int h);
+igraph_real_t igraph_rng_get_normal(igraph_rng_t *rng, 
+				    igraph_real_t m, igraph_real_t s);
+igraph_real_t igraph_rng_get_unif(igraph_rng_t *rng, 
+				  igraph_real_t l, igraph_real_t h);
+igraph_real_t igraph_rng_get_unif01(igraph_rng_t *rng);
+igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p);
+igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, long int n, 
+				   igraph_real_t p);
+igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate);
+unsigned long int igraph_rng_get_int31(igraph_rng_t *rng);
+igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate);
+igraph_real_t igraph_rng_get_gamma(igraph_rng_t *rng, igraph_real_t shape,
+				   igraph_real_t scale);
+int igraph_rng_get_dirichlet(igraph_rng_t *rng,
+			     const igraph_vector_t *alpha,
+			     igraph_vector_t *result);
+
+/* --------------------------------- */
+
+extern const igraph_rng_type_t igraph_rngtype_glibc2;
+extern const igraph_rng_type_t igraph_rngtype_rand;
+extern const igraph_rng_type_t igraph_rngtype_mt19937;
+
+igraph_rng_t *igraph_rng_default(void);
+void igraph_rng_set_default(igraph_rng_t *rng);
+
+/* --------------------------------- */
+
+#ifdef USING_R
+
+void GetRNGstate(void);
+void PutRNGstate(void);
+#define RNG_BEGIN()    GetRNGstate()
+#define RNG_END()      PutRNGstate()
+
+double Rf_dnorm4(double x, double mu, double sigma, int give_log);
+#define igraph_dnorm Rf_dnorm4
+
+#else 
+
+#define RNG_BEGIN()      if (igraph_rng_default()->def==1) {	\
+  igraph_rng_seed(igraph_rng_default(), time(0));		\
+  igraph_rng_default()->def=2;					\
+  }
+#define RNG_END()		/* do nothing */
+
+double igraph_dnorm(double x, double mu, double sigma, int give_log);
+
+#endif
+
+#define RNG_INTEGER(l,h) (igraph_rng_get_integer(igraph_rng_default(),(l),(h)))
+#define RNG_NORMAL(m,s)  (igraph_rng_get_normal(igraph_rng_default(),(m),(s)))
+#define RNG_UNIF(l,h)    (igraph_rng_get_unif(igraph_rng_default(),(l),(h)))
+#define RNG_UNIF01()     (igraph_rng_get_unif01(igraph_rng_default()))
+#define RNG_GEOM(p)      (igraph_rng_get_geom(igraph_rng_default(),(p)))
+#define RNG_BINOM(n,p)   (igraph_rng_get_binom(igraph_rng_default(),(n),(p)))
+#define RNG_INT31()      (igraph_rng_get_int31(igraph_rng_default()))
+
+__END_DECLS
+
+#endif
diff --git a/src/include/igraph_scan.h b/src/include/igraph_scan.h
new file mode 100644
index 0000000..86d920d
--- /dev/null
+++ b/src/include/igraph_scan.h
@@ -0,0 +1,78 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   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_SCAN_H
+#define IGRAPH_SCAN_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
+
+#include "igraph_datatype.h"
+#include "igraph_arpack.h"
+#include "igraph_constants.h"
+#include "igraph_vector_ptr.h"
+
+__BEGIN_DECLS
+
+int igraph_local_scan_0(const igraph_t *graph, igraph_vector_t *res,
+			const igraph_vector_t *weights, igraph_neimode_t mode);
+
+int igraph_local_scan_0_them(const igraph_t *us, const igraph_t *them,
+			     igraph_vector_t *res,
+			     const igraph_vector_t *weigths_them,
+			     igraph_neimode_t mode);
+
+int igraph_local_scan_1_ecount(const igraph_t *graph, igraph_vector_t *res,
+			       const igraph_vector_t *weights,
+			       igraph_neimode_t mode);
+
+int igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_t *them,
+				    igraph_vector_t *res,
+				    const igraph_vector_t *weights,
+				    igraph_neimode_t mode);
+
+int igraph_local_scan_k_ecount(const igraph_t *graph,int k,
+			       igraph_vector_t *res,
+			       const igraph_vector_t *weights,
+			       igraph_neimode_t mode);
+
+int igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them,
+				    int k, igraph_vector_t *res,
+				    const igraph_vector_t *weights_them,
+				    igraph_neimode_t mode);
+
+int igraph_local_scan_neighborhood_ecount(const igraph_t *graph,
+			  igraph_vector_t *res,
+			  const igraph_vector_t *weights,
+			  const igraph_vector_ptr_t *neighborhoods);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_scg.h b/src/include/igraph_scg.h
similarity index 100%
rename from src/igraph_scg.h
rename to src/include/igraph_scg.h
diff --git a/src/igraph_separators.h b/src/include/igraph_separators.h
similarity index 100%
rename from src/igraph_separators.h
rename to src/include/igraph_separators.h
diff --git a/src/include/igraph_sparsemat.h b/src/include/igraph_sparsemat.h
new file mode 100644
index 0000000..cd0e254
--- /dev/null
+++ b/src/include/igraph_sparsemat.h
@@ -0,0 +1,281 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_SPARSEMAT_H
+#define IGRAPH_SPARSEMAT_H
+
+#include "igraph_types.h"
+#include "igraph_vector.h"
+#include "igraph_datatype.h"
+#include "igraph_arpack.h"
+
+#include <stdio.h>
+
+struct cs_di_sparse;
+struct cs_di_symbolic;
+struct cs_di_numeric;
+
+typedef struct {
+  struct cs_di_sparse *cs;
+} igraph_sparsemat_t;
+
+typedef struct {
+  struct cs_di_symbolic *symbolic;
+} igraph_sparsemat_symbolic_t;
+
+typedef struct {
+  struct cs_di_numeric *numeric;
+} igraph_sparsemat_numeric_t;
+
+typedef enum { IGRAPH_SPARSEMAT_TRIPLET, 
+	       IGRAPH_SPARSEMAT_CC        } igraph_sparsemat_type_t;
+
+typedef struct {
+  igraph_sparsemat_t *mat;
+  int pos;
+  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, 
+			  const igraph_sparsemat_t *from);
+void igraph_sparsemat_destroy(igraph_sparsemat_t *A);
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+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);
+
+int igraph_sparsemat_rowmins(igraph_sparsemat_t *A,
+			     igraph_vector_t *res);
+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);
+
+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);
+
+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);
+
+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);
+
+int igraph_sparsemat_nzmax(const igraph_sparsemat_t *A);
+
+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);
+
+#endif
diff --git a/src/igraph_spmatrix.h b/src/include/igraph_spmatrix.h
similarity index 100%
rename from src/igraph_spmatrix.h
rename to src/include/igraph_spmatrix.h
diff --git a/src/include/igraph_stack.h b/src/include/igraph_stack.h
new file mode 100644
index 0000000..70867e0
--- /dev/null
+++ b/src/include/igraph_stack.h
@@ -0,0 +1,88 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_STACK_H
+#define IGRAPH_STACK_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
+
+#include "igraph_types.h"
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Plain stack                                        */
+/* -------------------------------------------------- */
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "igraph_stack_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "igraph_stack_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "igraph_stack_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "igraph_stack_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "igraph_stack_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_PTR
+#include "igraph_pmt.h"
+#include "igraph_stack_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_PTR
+
+#define IGRAPH_STACK_NULL { 0,0,0 }
+
+void igraph_stack_ptr_free_all(igraph_stack_ptr_t* s);
+void igraph_stack_ptr_destroy_all(igraph_stack_ptr_t* s);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_stack_pmt.h b/src/include/igraph_stack_pmt.h
similarity index 100%
rename from src/igraph_stack_pmt.h
rename to src/include/igraph_stack_pmt.h
diff --git a/src/igraph_statusbar.h b/src/include/igraph_statusbar.h
similarity index 100%
rename from src/igraph_statusbar.h
rename to src/include/igraph_statusbar.h
diff --git a/src/igraph_structural.h b/src/include/igraph_structural.h
similarity index 100%
rename from src/igraph_structural.h
rename to src/include/igraph_structural.h
diff --git a/src/igraph_strvector.h b/src/include/igraph_strvector.h
similarity index 100%
rename from src/igraph_strvector.h
rename to src/include/igraph_strvector.h
diff --git a/src/include/igraph_threading.h.in b/src/include/igraph_threading.h.in
new file mode 100644
index 0000000..928269c
--- /dev/null
+++ b/src/include/igraph_threading.h.in
@@ -0,0 +1,51 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_THREADING_H
+#define IGRAPH_THREADING_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
+
+/** 
+ * \define IGRAPH_THREAD_SAFE
+ * 
+ * Macro that is defined to be 1 if the current build of the 
+ * igraph library is thread-safe, and 0 if it is not.
+ */
+
+#define IGRAPH_THREAD_SAFE @HAVE_TLS@
+
+__END_DECLS
+
+#endif
+
diff --git a/src/igraph_topology.h b/src/include/igraph_topology.h
similarity index 100%
rename from src/igraph_topology.h
rename to src/include/igraph_topology.h
diff --git a/src/igraph_transitivity.h b/src/include/igraph_transitivity.h
similarity index 100%
rename from src/igraph_transitivity.h
rename to src/include/igraph_transitivity.h
diff --git a/src/igraph_types.h b/src/include/igraph_types.h
similarity index 100%
rename from src/igraph_types.h
rename to src/include/igraph_types.h
diff --git a/src/include/igraph_vector.h b/src/include/igraph_vector.h
new file mode 100644
index 0000000..c70a3c9
--- /dev/null
+++ b/src/include/igraph_vector.h
@@ -0,0 +1,188 @@
+/* -*- mode: C -*-  */
+/*
+   IGraph library.
+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_VECTOR_H
+#define IGRAPH_VECTOR_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
+
+#include "igraph_types.h"
+#include "igraph_complex.h"
+
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#else
+#  if HAVE_SYS_INT_TYPES_H
+#    include <sys/int_types.h>    /* for Solaris */
+#  endif
+#endif
+
+__BEGIN_DECLS
+
+/* -------------------------------------------------- */
+/* Flexible vector                                    */
+/* -------------------------------------------------- */
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_FLOAT
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_FLOAT
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define BASE_COMPLEX
+#include "igraph_pmt.h"
+#include "igraph_vector_type.h"
+#include "igraph_pmt_off.h"
+#undef BASE_COMPLEX
+
+#define BASE_IGRAPH_REAL
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_IGRAPH_REAL
+
+#define BASE_FLOAT
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_FLOAT
+
+#define BASE_LONG
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_LONG
+
+#define BASE_CHAR
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_CHAR
+
+#define BASE_BOOL
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_BOOL
+
+#define BASE_INT
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_INT
+
+#define BASE_COMPLEX
+#include "igraph_pmt.h"
+#include "igraph_vector_pmt.h"
+#include "igraph_pmt_off.h"
+#undef BASE_COMPLEX
+
+/* -------------------------------------------------- */
+/* Helper macros                                      */
+/* -------------------------------------------------- */
+
+#ifndef IGRAPH_VECTOR_NULL
+#define IGRAPH_VECTOR_NULL { 0,0,0 }
+#endif
+
+#ifndef IGRAPH_VECTOR_INIT_FINALLY
+#define IGRAPH_VECTOR_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_vector_init(v, size)); \
+  IGRAPH_FINALLY(igraph_vector_destroy, v); } while (0)
+#endif
+#ifndef IGRAPH_VECTOR_BOOL_INIT_FINALLY
+#define IGRAPH_VECTOR_BOOL_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_vector_bool_init(v, size)); \
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, v); } while (0)
+#endif
+#ifndef IGRAPH_VECTOR_LONG_INIT_FINALLY
+#define IGRAPH_VECTOR_LONG_INIT_FINALLY(v, size) \
+  do { IGRAPH_CHECK(igraph_vector_long_init(v, size)); \
+  IGRAPH_FINALLY(igraph_vector_long_destroy, v); } while (0)
+#endif
+
+/* -------------------------------------------------- */
+/* Type-specific vector functions                     */
+/* -------------------------------------------------- */
+
+int igraph_vector_floor(const igraph_vector_t *from, igraph_vector_long_t *to);
+int igraph_vector_round(const igraph_vector_t *from, igraph_vector_long_t *to);
+
+igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs,
+				  const igraph_vector_t *rhs,
+				  igraph_real_t tol);
+
+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,
+			igraph_vector_t* res, igraph_real_t maxval);
+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,
+			 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,
+		       long int nodes);
+
+__END_DECLS
+
+#endif
diff --git a/src/igraph_vector_pmt.h b/src/include/igraph_vector_pmt.h
similarity index 100%
rename from src/igraph_vector_pmt.h
rename to src/include/igraph_vector_pmt.h
diff --git a/src/igraph_vector_ptr.h b/src/include/igraph_vector_ptr.h
similarity index 100%
rename from src/igraph_vector_ptr.h
rename to src/include/igraph_vector_ptr.h
diff --git a/src/igraph_vector_type.h b/src/include/igraph_vector_type.h
similarity index 100%
rename from src/igraph_vector_type.h
rename to src/include/igraph_vector_type.h
diff --git a/src/include/igraph_version.h.in b/src/include/igraph_version.h.in
new file mode 100644
index 0000000..cd6f3b5
--- /dev/null
+++ b/src/include/igraph_version.h.in
@@ -0,0 +1,40 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   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_VERSION_H
+#define IGRAPH_VERSION_H
+
+#define IGRAPH_VERSION "@PACKAGE_VERSION@"
+#define IGRAPH_VERSION_MAJOR @PACKAGE_VERSION_MAJOR@
+#define IGRAPH_VERSION_MINOR @PACKAGE_VERSION_MINOR@
+#define IGRAPH_VERSION_PATCH @PACKAGE_VERSION_PATCH@
+#define IGRAPH_VERSION_PRERELEASE "@PACKAGE_VERSION_PRERELEASE@"
+
+int igraph_version(const char **version_string,
+		   int *major,
+		   int *minor,
+		   int *subminor);
+
+#endif
+
+
diff --git a/src/igraph_visitor.h b/src/include/igraph_visitor.h
similarity index 100%
rename from src/igraph_visitor.h
rename to src/include/igraph_visitor.h
diff --git a/src/lad.c b/src/lad.c
index bc2b1e6..0e8aba7 100644
--- a/src/lad.c
+++ b/src/lad.c
@@ -66,7 +66,8 @@
 #define false 0
 #define bool char
 
-/* helper to allocate an array of given size */
+/* helper to allocate an array of given size and free it using IGRAPH_FINALLY
+ * when needed */
 #define ALLOC_ARRAY(VAR, SIZE, TYPE) { \
   VAR = igraph_Calloc(SIZE, TYPE);   \
   if (VAR == 0) {                    \
@@ -75,6 +76,18 @@
   IGRAPH_FINALLY(igraph_free, VAR);  \
 }
 
+/* helper to allocate an array of given size and store its address in a
+ * pointer array */
+#define ALLOC_ARRAY_IN_HISTORY(VAR, SIZE, TYPE, HISTORY) { \
+  VAR = igraph_Calloc(SIZE, TYPE);   \
+  if (VAR == 0) {                    \
+    IGRAPH_ERROR("cannot allocate '" #VAR "' array in LAD isomorphism search", IGRAPH_ENOMEM); \
+  }  \
+  IGRAPH_FINALLY(igraph_free, VAR);  \
+  IGRAPH_CHECK(igraph_vector_ptr_push_back(HISTORY, VAR));  \
+  IGRAPH_FINALLY_CLEAN(1);           \
+}
+
 /* ---------------------------------------------------------*/
 /* Coming from graph.c                                      */
 /* ---------------------------------------------------------*/
@@ -1303,7 +1316,7 @@ int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
 		       int *invalid, igraph_bool_t *iso, 
 		       igraph_vector_t *map, igraph_vector_ptr_t *maps, 
 		       int *nbNodes, int *nbFail, int *nbSol, 
-		       clock_t *begin) {
+		       clock_t *begin, igraph_vector_ptr_t *alloc_history) {
   /* if firstSol then search for the first solution; otherwise search
      for all solutions if induced then search for induced subgraphs;
      otherwise search for partial subgraphs 
@@ -1326,8 +1339,8 @@ int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
   }
 
   /* Allocate memory */
-  ALLOC_ARRAY(nbVal, Gp->nbVertices, int);
-  ALLOC_ARRAY(globalMatching, Gp->nbVertices, int);
+  ALLOC_ARRAY_IN_HISTORY(nbVal, Gp->nbVertices, int, alloc_history);
+  ALLOC_ARRAY_IN_HISTORY(globalMatching, Gp->nbVertices, int, alloc_history);
 
   IGRAPH_CHECK(igraph_i_lad_filter(induced, D, Gp, Gt, &result));
   if (!result) { 
@@ -1378,7 +1391,7 @@ int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
   }
 	
   /* save the domain of minDom to iterate on its values */
-  ALLOC_ARRAY(val, VECTOR(D->nbVal)[minDom], int);
+  ALLOC_ARRAY_IN_HISTORY(val, VECTOR(D->nbVal)[minDom], int, alloc_history);
   for (i=0; i < VECTOR(D->nbVal)[minDom]; i++) {
     val[i]=VECTOR(D->val)[ VECTOR(D->firstVal)[minDom]+i ]; 
   }
@@ -1395,7 +1408,8 @@ int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
     } else {
       IGRAPH_CHECK(igraph_i_lad_solve(timeLimit, firstSol, induced,
 				      D, Gp, Gt, invalid, iso, map, maps, 
-				      nbNodes, nbFail, nbSol, begin));
+				      nbNodes, nbFail, nbSol, begin,
+				      alloc_history));
     }
     /* restore domain sizes and global all different matching */
     igraph_vector_int_fill(&D->globalMatchingT, -1);
@@ -1408,12 +1422,13 @@ int igraph_i_lad_solve(int timeLimit, bool firstSol, bool induced,
   *invalid=0;
 
   igraph_free(val);
-  IGRAPH_FINALLY_CLEAN(1);
+  igraph_vector_ptr_pop_back(alloc_history);
 
 cleanup:
   igraph_free(globalMatching);
+  igraph_vector_ptr_pop_back(alloc_history);
   igraph_free(nbVal);
-  IGRAPH_FINALLY_CLEAN(2);
+  igraph_vector_ptr_pop_back(alloc_history);
 
   return 0;
 }
@@ -1484,6 +1499,8 @@ int igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t *target,
   int nbSol=0;
   /* reusable structure to get CPU time usage */
   clock_t begin=clock();
+  /* Stack to store memory blocks that are allocated during igraph_i_lad_solve */
+  igraph_vector_ptr_t alloc_history;
 
   if (!iso && !map && !maps) {
     IGRAPH_ERROR("Please give least one of `iso', `map' or `maps'", 
@@ -1492,8 +1509,8 @@ int igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t *target,
 
   if (time_limit<=0) { time_limit = INT_MAX; }
     
-  igraph_i_lad_createGraph(pattern, &Gp);
-  igraph_i_lad_createGraph(target, &Gt);
+  IGRAPH_CHECK(igraph_i_lad_createGraph(pattern, &Gp));
+  IGRAPH_CHECK(igraph_i_lad_createGraph(target, &Gt));
   
   if (iso)  { *iso = 0; }
   if (map)  { igraph_vector_clear(map); } 
@@ -1531,10 +1548,17 @@ int igraph_subisomorphic_lad(const igraph_t *pattern, const igraph_t *target,
   igraph_vector_int_destroy(&toMatch);
   IGRAPH_FINALLY_CLEAN(1);
   if (invalidDomain) { goto exit; }
-	
+
+  IGRAPH_CHECK(igraph_vector_ptr_init(&alloc_history, 0));
+  IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &alloc_history);
+
   IGRAPH_CHECK(igraph_i_lad_solve(time_limit, firstSol, (char) induced, &D, 
 				  &Gp, &Gt, &invalidDomain, iso, map, maps, 
-				  &nbNodes, &nbFail, &nbSol, &begin));
+				  &nbNodes, &nbFail, &nbSol, &begin,
+				  &alloc_history));
+
+  igraph_vector_ptr_destroy_all(&alloc_history);
+  IGRAPH_FINALLY_CLEAN(1);
 
  exit:
   
diff --git a/src/lapack.c b/src/lapack.c
index ea3a811..6ca31ec 100644
--- a/src/lapack.c
+++ b/src/lapack.c
@@ -922,3 +922,20 @@ int igraph_lapack_dgehrd(const igraph_matrix_t *A,
   
   return 0;
 }
+
+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;
+}
+  
diff --git a/src/layout.c b/src/layout.c
index d531d7d..48dbf1e 100644
--- a/src/layout.c
+++ b/src/layout.c
@@ -2,7 +2,7 @@
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* 
    IGraph R package.
-   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor at gmail.com>
+   Copyright (C) 2003-2014  Gabor Csardi <csardi.gabor at gmail.com>
    334 Harvard street, Cambridge, MA 02139 USA
    
    This program is free software; you can redistribute it and/or modify
@@ -135,24 +135,37 @@ int igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res) {
  * \param graph Pointer to an initialized graph object.
  * \param res Pointer to an initialized matrix object. This will
  *        contain the result and will be resized as needed.
+ * \param order The order of the vertices on the circle. The vertices
+ *        not included here, will be placed at (0,0). Supply
+ *        \ref igraph_vss_all() here for all vertices, in the order of
+ *        their vertex ids.
  * \return Error code.
  * 
  * Time complexity: O(|V|), the
  * number of vertices. 
  */
 
-int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res) {
+int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res,
+			 igraph_vs_t order) {
 
   long int no_of_nodes=igraph_vcount(graph);
+  igraph_integer_t vs_size;
   long int i;
+  igraph_vit_t vit;
 
-  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));  
+  IGRAPH_CHECK(igraph_vs_size(graph, &order, &vs_size));
 
-  for (i=0; i<no_of_nodes; i++) {
-    igraph_real_t phi=2*M_PI/no_of_nodes*i;
-    MATRIX(*res, i, 0)=cos(phi);
-    MATRIX(*res, i, 1)=sin(phi);
+  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
+  igraph_matrix_null(res);
+
+  igraph_vit_create(graph, order, &vit);
+  for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
+    igraph_real_t phi=2*M_PI/vs_size*i;
+    int idx = IGRAPH_VIT_GET(vit);
+    MATRIX(*res, idx, 0)=cos(phi);
+    MATRIX(*res, idx, 1)=sin(phi);
   }
+  igraph_vit_destroy(&vit);
   
   return 0;
 }
@@ -354,803 +367,6 @@ int igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res,
   return 0;
 }
 
-/**
- * \ingroup layout
- * \function igraph_layout_fruchterman_reingold
- * \brief Places the vertices on a plane according to the Fruchterman-Reingold algorithm.
- *
- * </para><para>
- * This is a force-directed layout, see Fruchterman, T.M.J. and
- * Reingold, E.M.: Graph Drawing by Force-directed Placement.
- * Software -- Practice and Experience, 21/11, 1129--1164,
- * 1991. 
- * This function was ported from the SNA R package.
- * \param graph Pointer to an initialized graph object.
- * \param res Pointer to an initialized matrix object. This will
- *        contain the result and will be resized as needed.
- * \param niter The number of iterations to do. A reasonable
- *        default value is 500.
- * \param maxdelta The maximum distance to move a vertex in an
- *        iteration. A reasonable default value is the number of
- *        vertices.
- * \param area The area parameter of the algorithm. A reasonable
- *        default is the square of the number of vertices.
- * \param coolexp The cooling exponent of the simulated annealing.
- *        A reasonable default is 1.5.
- * \param repulserad Determines the radius at which
- *        vertex-vertex repulsion cancels out attraction of
- *        adjacent vertices. A reasonable default is \p area
- *        times the number of vertices.
- * \param use_seed Logical, if true the supplied values in the
- *        \p res argument are used as an initial layout, if
- *        false a random initial layout is used.
- * \param weight Pointer to a vector containing edge weights, 
- *        the attraction along the edges will be multiplied by these. 
- *        It will be ignored if it is a null-pointer.
- * \param minx Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote x \endquote coordinate for every vertex.
- * \param maxx Same as \p minx, but the maximum \quote x \endquote 
- *        coordinates.
- * \param miny Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote y \endquote coordinate for every vertex.
- * \param maxy Same as \p miny, but the maximum \quote y \endquote 
- *        coordinates.
- * \return Error code.
- * 
- * Time complexity: O(|V|^2) in each
- * iteration, |V| is the number of
- * vertices in the graph. 
- */
-
-int igraph_layout_fruchterman_reingold(const igraph_t *graph, igraph_matrix_t *res,
-				       igraph_integer_t niter, igraph_real_t maxdelta,
-				       igraph_real_t area, igraph_real_t coolexp, 
-				       igraph_real_t repulserad, igraph_bool_t use_seed,
-				       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_real_t frk,t,ded,xd,yd;
-  igraph_real_t rf,af;
-  long int i,j,k;
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_matrix_t dxdy=IGRAPH_MATRIX_NULL;
-  igraph_eit_t edgeit;
-  igraph_integer_t from, to;
-  
-  if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {
-    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
-  }
-
-  if (minx && igraph_vector_size(minx) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
-  }
-  if (maxx && igraph_vector_size(maxx) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
-  }
-  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
-    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
-  }
-  if (miny && igraph_vector_size(miny) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
-  }
-  if (maxy && igraph_vector_size(maxy) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
-  }
-  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
-    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
-  if (!use_seed) {
-    IGRAPH_CHECK(igraph_layout_random(graph, res));
-  }
-  IGRAPH_MATRIX_INIT_FINALLY(&dxdy, no_of_nodes, 2);
-
-  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
-  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
-  
-  frk=sqrt(area/no_of_nodes);
-
-  for(i=niter;i>0;i--) {
-    /* Report progress in approx. every 100th step */
-    if (i%10 == 0)
-      IGRAPH_PROGRESS("Fruchterman-Reingold layout: ",
-		      100.0-100.0*i/niter, NULL);
-    
-    /* Set the temperature (maximum move/iteration) */
-    t=maxdelta*pow(i/(double)niter,coolexp);
-    /* Clear the deltas */
-    igraph_matrix_null(&dxdy);
-    /* Increment deltas for each undirected pair */
-    for(j=0;j<no_of_nodes;j++) {
-      IGRAPH_ALLOW_INTERRUPTION();
-      for(k=j+1;k<no_of_nodes;k++){
-        /* Obtain difference vector */
-        xd=MATRIX(*res, j, 0)-MATRIX(*res, k, 0);
-        yd=MATRIX(*res, j, 1)-MATRIX(*res, k, 1);
-        ded=sqrt(xd*xd+yd*yd);  /* Get dyadic euclidean distance */
-        if (ded != 0) {
-          xd/=ded;                      /*Rescale differences to length 1*/
-          yd/=ded;
-          /*Calculate repulsive "force"*/
-          rf=frk*frk*(1.0/ded-ded*ded/repulserad);
-	      } else {
-          /* ded is exactly zero. Use some small random displacement. */
-          xd=RNG_NORMAL(0,0.1);
-          yd=RNG_NORMAL(0,0.1);
-          rf=RNG_NORMAL(0,0.1);
-        }
-        MATRIX(dxdy, j, 0)+=xd*rf; /* Add to the position change vector */
-        MATRIX(dxdy, k, 0)-=xd*rf;
-        MATRIX(dxdy, j, 1)+=yd*rf;
-        MATRIX(dxdy, k, 1)-=yd*rf;
-      }
-    }
-    /* Calculate the attractive "force" */
-    IGRAPH_EIT_RESET(edgeit);
-    while (!IGRAPH_EIT_END(edgeit)) {
-      long int edge=IGRAPH_EIT_GET(edgeit);
-      igraph_real_t w= weight ? VECTOR(*weight)[ edge ] : 1.0;
-      igraph_edge(graph, (igraph_integer_t) edge, &from, &to);
-      j=from; 
-      k=to;
-      xd=MATRIX(*res, j, 0)-MATRIX(*res, k, 0);
-      yd=MATRIX(*res, j, 1)-MATRIX(*res, k, 1);
-      ded=sqrt(xd*xd+yd*yd);  /* Get dyadic euclidean distance */
-      if (ded != 0) {
-        xd/=ded;                /* Rescale differences to length 1 */
-        yd/=ded;
-        af=ded*ded/frk*w;
-      } else {
-        xd=RNG_NORMAL(0,0.1);
-        yd=RNG_NORMAL(0,0.1);
-        af=RNG_NORMAL(0,0.1);
-      }
-      MATRIX(dxdy, j, 0)-=xd*af; /* Add to the position change vector */
-      MATRIX(dxdy, k, 0)+=xd*af;
-      MATRIX(dxdy, j, 1)-=yd*af;
-      MATRIX(dxdy, k, 1)+=yd*af;
-      IGRAPH_EIT_NEXT(edgeit);
-    }
-    
-    /* Dampen motion, if needed, and move the points */   
-    for(j=0;j<no_of_nodes;j++){
-      ded=sqrt(MATRIX(dxdy, j, 0)*MATRIX(dxdy, j, 0)+
-	       MATRIX(dxdy, j, 1)*MATRIX(dxdy, j, 1));    
-      if(ded>t){		/* Dampen to t */
-        ded=t/ded;
-        MATRIX(dxdy, j, 0)*=ded;
-        MATRIX(dxdy, j, 1)*=ded;
-      }
-      MATRIX(*res, j, 0)+=MATRIX(dxdy, j, 0); /* Update positions */
-      MATRIX(*res, j, 1)+=MATRIX(dxdy, j, 1);
-      if (minx && MATRIX(*res, j, 0) < VECTOR(*minx)[j]) {
-        MATRIX(*res, j, 0) = VECTOR(*minx)[j];
-      } else if (maxx && MATRIX(*res, j, 0) > VECTOR(*maxx)[j]) {
-        MATRIX(*res, j, 0) = VECTOR(*maxx)[j];
-      }
-      if (miny && MATRIX(*res, j, 1) < VECTOR(*miny)[j]) {
-        MATRIX(*res, j, 1) = VECTOR(*miny)[j];
-      } else if (maxy && MATRIX(*res, j, 1) > VECTOR(*maxy)[j]) {
-        MATRIX(*res, j, 1) = VECTOR(*maxy)[j];
-      }
-    }
-  }
-
-  IGRAPH_PROGRESS("Fruchterman-Reingold layout: ", 100.0, NULL);
-  
-  igraph_eit_destroy(&edgeit);
-  igraph_matrix_destroy(&dxdy);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-/**
- * \function igraph_layout_fruchterman_reingold_3d
- * \brief 3D Fruchterman-Reingold algorithm.
- * 
- * This is the 3D version of the force based
- * Fruchterman-Reingold layout (see \ref
- * igraph_layout_fruchterman_reingold for the 2D version
- *
- * </para><para>
- * This function was ported from the SNA R package.
- * \param graph Pointer to an initialized graph object.
- * \param res Pointer to an initialized matrix object. This will
- *        contain the result and will be resized as needed.
- * \param niter The number of iterations to do. A reasonable
- *        default value is 500.
- * \param maxdelta The maximum distance to move a vertex in an
- *        iteration. A reasonable default value is the number of
- *        vertices.
- * \param volume The volume parameter of the algorithm. A reasonable
- *        default is the number of vertices^3.
- * \param coolexp The cooling exponent of the simulated annealing.
- *        A reasonable default is 1.5.
- * \param repulserad Determines the radius at which
- *        vertex-vertex repulsion cancels out attraction of
- *        adjacent vertices. A reasonable default is \p volume
- *        times the number of vertices.
- * \param use_seed Logical, if true the supplied values in the
- *        \p res argument are used as an initial layout, if
- *        false a random initial layout is used.
- * \param weight Pointer to a vector containing edge weights, 
- *        the attraction along the edges will be multiplied by these. 
- *        It will be ignored if it is a null-pointer.
- * \param minx Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote x \endquote coordinate for every vertex.
- * \param maxx Same as \p minx, but the maximum \quote x \endquote 
- *        coordinates.
- * \param miny Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote y \endquote coordinate for every vertex.
- * \param maxy Same as \p miny, but the maximum \quote y \endquote 
- *        coordinates.
- * \param minz Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote z \endquote coordinate for every vertex.
- * \param maxz Same as \p minz, but the maximum \quote z \endquote 
- *        coordinates.
- * \return Error code.
- *
- * Added in version 0.2.</para><para>
- *
- * Time complexity: O(|V|^2) in each
- * iteration, |V| is the number of
- * vertices in the graph. 
- * 
- */
-
-int igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, 
-					  igraph_matrix_t *res,
-					  igraph_integer_t niter, igraph_real_t maxdelta,
-					  igraph_real_t volume, igraph_real_t coolexp,
-					  igraph_real_t repulserad,
-					  igraph_bool_t use_seed,
-					  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,
-					  const igraph_vector_t *minz,
-					  const igraph_vector_t *maxz) {
-  
-  igraph_real_t frk, t, ded, xd, yd, zd;
-  igraph_matrix_t dxdydz;
-  igraph_real_t rf, af;
-  long int i, j, k;
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_eit_t edgeit;
-  igraph_integer_t from, to;
-
-  if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {
-    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
-  }
-
-  if (minx && igraph_vector_size(minx) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
-  }
-  if (maxx && igraph_vector_size(maxx) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
-  }
-  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
-    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
-  }
-  if (miny && igraph_vector_size(miny) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
-  }
-  if (maxy && igraph_vector_size(maxy) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
-  }
-  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
-    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
-  }
-  if (minz && igraph_vector_size(minz) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);
-  }
-  if (maxz && igraph_vector_size(maxz) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);
-  }
-  if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {
-    IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_init(&dxdydz, no_of_nodes, 3));
-  IGRAPH_FINALLY(igraph_matrix_destroy, &dxdydz);
-  
-  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3));
-  if (!use_seed) {
-    IGRAPH_CHECK(igraph_layout_random_3d(graph, res));
-  }
-
-  IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(0), &edgeit));
-  IGRAPH_FINALLY(igraph_eit_destroy, &edgeit);
-
-  frk=pow(volume/(double)no_of_nodes,1.0/3.0); /*Define the F-R constant*/
-
-  /*Run the annealing loop*/
-  for(i=niter;i>=0;i--){
-    if (i%10 == 0)
-      IGRAPH_PROGRESS("3D Fruchterman-Reingold layout: ",
-		      100.0-100.0*i/niter, NULL);
-
-    /*Set the temperature (maximum move/iteration)*/
-    t=maxdelta*pow(i/(double)niter,coolexp);
-    /*Clear the deltas*/
-    igraph_matrix_null(&dxdydz);
-    /*Increment deltas for each undirected pair*/
-    for(j=0;j<no_of_nodes;j++) {
-      IGRAPH_ALLOW_INTERRUPTION();
-      for(k=j+1;k<no_of_nodes;k++){
-        /*Obtain difference vector*/
-        xd=MATRIX(*res, j, 0)-MATRIX(*res, k, 0);
-        yd=MATRIX(*res, j, 1)-MATRIX(*res, k, 1);
-        zd=MATRIX(*res, j, 2)-MATRIX(*res, k, 2);
-        ded=sqrt(xd*xd+yd*yd+zd*zd);  /*Get dyadic euclidean distance*/
-        if (ded != 0) {
-          xd/=ded;                      /*Rescale differences to length 1*/
-          yd/=ded;
-          zd/=ded;
-          /*Calculate repulsive "force"*/
-          rf=frk*frk*(1.0/ded-ded*ded/repulserad);
-	      } else {
-          /* ded is exactly zero. Use some small random displacement. */
-          xd=RNG_NORMAL(0,0.1);
-          yd=RNG_NORMAL(0,0.1);
-          zd=RNG_NORMAL(0,0.1);
-          rf=RNG_NORMAL(0,0.1);
-        }
-        MATRIX(dxdydz, j, 0)+=xd*rf;     /*Add to the position change vector*/
-        MATRIX(dxdydz, k, 0)-=xd*rf;
-        MATRIX(dxdydz, j, 1)+=yd*rf;
-        MATRIX(dxdydz, k, 1)-=yd*rf;
-        MATRIX(dxdydz, j, 2)+=zd*rf;
-        MATRIX(dxdydz, k, 2)-=zd*rf;
-      }
-    }
-
-    /*Calculate the attractive "force"*/
-    IGRAPH_EIT_RESET(edgeit);
-    while (!IGRAPH_EIT_END(edgeit)) {
-      long int edge=IGRAPH_EIT_GET(edgeit);
-      igraph_real_t w= weight ? VECTOR(*weight)[edge] : 1.0;
-      igraph_edge(graph, (igraph_integer_t) edge, &from, &to);
-      j=from;
-      k=to;
-      xd=MATRIX(*res, j, 0)-MATRIX(*res, k, 0);
-      yd=MATRIX(*res, j, 1)-MATRIX(*res, k, 1);
-      zd=MATRIX(*res, j, 2)-MATRIX(*res, k, 2);
-      ded=sqrt(xd*xd+yd*yd+zd*zd);  /*Get dyadic euclidean distance*/
-      if (ded != 0) {
-	xd/=ded;                      /*Rescale differences to length 1*/
-	yd/=ded;
-	zd/=ded;
-      }
-      af=ded*ded/frk*w;
-      MATRIX(dxdydz, j, 0)-=xd*af;   /*Add to the position change vector*/
-      MATRIX(dxdydz, k, 0)+=xd*af;
-      MATRIX(dxdydz, j, 1)-=yd*af;
-      MATRIX(dxdydz, k, 1)+=yd*af;
-      MATRIX(dxdydz, j, 2)-=zd*af;
-      MATRIX(dxdydz, k, 2)+=zd*af;
-      IGRAPH_EIT_NEXT(edgeit);
-    }
-
-    /*Dampen motion, if needed, and move the points*/
-    for(j=0;j<no_of_nodes;j++){
-      ded=sqrt(MATRIX(dxdydz, j, 0)*MATRIX(dxdydz, j, 0)+
-	       MATRIX(dxdydz, j, 1)*MATRIX(dxdydz, j, 1)+
-	       MATRIX(dxdydz, j, 2)*MATRIX(dxdydz, j, 2));
-      if(ded>t){                 /*Dampen to t*/
-        ded=t/ded;
-        MATRIX(dxdydz, j, 0)*=ded;
-        MATRIX(dxdydz, j, 1)*=ded;
-        MATRIX(dxdydz, j, 2)*=ded;
-      }
-      MATRIX(*res, j, 0)+=MATRIX(dxdydz, j, 0);          /*Update positions*/
-      MATRIX(*res, j, 1)+=MATRIX(dxdydz, j, 1);
-      MATRIX(*res, j, 2)+=MATRIX(dxdydz, j, 2);
-      if (minx && MATRIX(*res, j, 0) < VECTOR(*minx)[j]) {
-        MATRIX(*res, j, 0) = VECTOR(*minx)[j];
-      } else if (maxx && MATRIX(*res, j, 0) > VECTOR(*maxx)[j]) {
-        MATRIX(*res, j, 0) = VECTOR(*maxx)[j];
-      }
-      if (miny && MATRIX(*res, j, 1) < VECTOR(*miny)[j]) {
-        MATRIX(*res, j, 1) = VECTOR(*miny)[j];
-      } else if (maxy && MATRIX(*res, j, 1) > VECTOR(*maxy)[j]) {
-        MATRIX(*res, j, 1) = VECTOR(*maxy)[j];
-      }
-      if (minz && MATRIX(*res, j, 2) < VECTOR(*minz)[j]) {
-        MATRIX(*res, j, 2) = VECTOR(*minz)[j];
-      } else if (maxz && MATRIX(*res, j, 2) > VECTOR(*maxz)[j]) {
-        MATRIX(*res, j, 2) = VECTOR(*maxz)[j];
-      }
-    }
-  }
-
-  IGRAPH_PROGRESS("3D Fruchterman-Reingold layout: ", 100.0, NULL);
-  
-  igraph_matrix_destroy(&dxdydz);
-  igraph_eit_destroy(&edgeit);
-  IGRAPH_FINALLY_CLEAN(2);
-  return 0;
-}
-
-/**
- * \ingroup layout
- * \function igraph_layout_kamada_kawai
- * \brief Places the vertices on a plane according the Kamada-Kawai algorithm. 
- *
- * </para><para>
- * This is a force directed layout, see  Kamada, T. and Kawai, S.: An
- * Algorithm for Drawing General Undirected Graphs. Information
- * Processing Letters, 31/1, 7--15, 1989.
- * This function was ported from the SNA R package.
- * \param graph A graph object.
- * \param res Pointer to an initialized matrix object. This will
- *        contain the result (x-positions in column zero and
- *        y-positions in column one) and will be resized if needed.
- * \param niter The number of iterations to perform. A reasonable
- *        default value is 1000.  
- * \param sigma Sets the base standard deviation of position
- *        change proposals. A reasonable default value is the
- *        number of vertices / 4.
- * \param initemp Sets the initial temperature for the annealing.
- *        A reasonable default value is 10.
- * \param coolexp The cooling exponent of the annealing.  
- *        A reasonable default value is 0.99.
- * \param kkconst The Kamada-Kawai vertex attraction constant.
- *        Typical value: (number of vertices)^2
- * \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.
- * \param minx Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote x \endquote coordinate for every vertex.
- * \param maxx Same as \p minx, but the maximum \quote x \endquote 
- *        coordinates.
- * \param miny Pointer to a vector, or a \c NULL pointer. If not a 
- *        \c NULL pointer then the vector gives the minimum
- *        \quote y \endquote coordinate for every vertex.
- * \param maxy Same as \p miny, but the maximum \quote y \endquote 
- *        coordinates.
- * \return Error code.
- * 
- * Time complexity: O(|V|^2) for each
- * iteration, |V| is the number of
- * vertices in the graph. 
- */
-
-int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res,
-			       igraph_integer_t niter, igraph_real_t sigma, 
-			       igraph_real_t initemp, igraph_real_t coolexp,
-			       igraph_real_t kkconst, igraph_bool_t use_seed,
-			       const igraph_vector_t *minx,
-			       const igraph_vector_t *maxx,
-			       const igraph_vector_t *miny,
-			       const igraph_vector_t *maxy) {
-
-  igraph_real_t temp, candx, candy, dx, dy;
-  igraph_real_t dpot, odis, ndis, osqd, nsqd;
-  long int n=igraph_vcount(graph);
-  int i,j,k;
-  igraph_matrix_t elen;
-
-  if (minx && igraph_vector_size(minx) != n) {
-    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
-  }
-  if (maxx && igraph_vector_size(maxx) != n) {
-    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
-  }
-  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
-    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
-  }
-  if (miny && igraph_vector_size(miny) != n) {
-    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
-  }
-  if (maxy && igraph_vector_size(maxy) != n) {
-    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
-  }
-  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
-    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
-  }
-
-#define CHECK_BOUNDS(x) do {						\
-    if (minx && MATRIX(*res, (x), 0) < VECTOR(*minx)[(x)]) {		\
-      MATRIX(*res, (x), 0) = VECTOR(*minx)[(x)];			\
-    } else if (maxx && MATRIX(*res, (x), 0) > VECTOR(*maxx)[(x)]) {	\
-      MATRIX(*res, (x), 0) = VECTOR(*maxx)[(x)];			\
-    }									\
-    if (miny && MATRIX(*res, (x), 1) < VECTOR(*miny)[(x)]) {		\
-      MATRIX(*res, (x), 1) = VECTOR(*miny)[(x)];			\
-    } else if (maxy && MATRIX(*res, (x), 1) > VECTOR(*maxy)[(x)]) {	\
-      MATRIX(*res, (x), 1) = VECTOR(*maxy)[(x)];			\
-    }									\
-  } while (0)    
-
-  /* Calculate elen, initial x & y */
-
-  RNG_BEGIN();
-
-  IGRAPH_CHECK(igraph_matrix_resize(res, n, 2));
-  IGRAPH_MATRIX_INIT_FINALLY(&elen, n, n);
-  IGRAPH_CHECK(igraph_shortest_paths(graph, &elen, igraph_vss_all(),
-				     igraph_vss_all(), IGRAPH_ALL));
-
-  /* Scan the distance matrix and introduce an upper limit.
-   * This helps with disconnected graphs. */
-  temp = 0.0;
-  for (i=0; i<n; i++) {
-    for (j=i+1; j<n; j++) {
-      if (!igraph_finite(MATRIX(elen, i, j)))
-        continue;
-      if (MATRIX(elen, i, j) > temp)
-        temp = MATRIX(elen, i, j);
-    }
-  }
-  for (i=0; i<n; i++) {
-    for (j=0; j<n; j++) {
-      if (MATRIX(elen, i, j) > temp)
-        MATRIX(elen, i, j) = temp;
-    }
-  }
-
-  /* Initialize the layout if needed */
-  if (!use_seed) {
-    for (i=0; i<n; i++) {
-      MATRIX(*res, i, 0) = RNG_NORMAL(0, n/4.0);
-      MATRIX(*res, i, 1) = RNG_NORMAL(0, n/4.0);
-      CHECK_BOUNDS(i);
-    }
-  }
-  
-  /*Perform the annealing loop*/
-  temp=initemp;
-  for(i=0;i<niter;i++){
-    /* Report progress in approx. every 10th step */
-    if (i%10 == 0)
-      IGRAPH_PROGRESS("Kamada-Kawai layout: ",
-		      100.0*i/niter, NULL);
-    /*Update each vertex*/
-    for(j=0;j<n;j++){
-      IGRAPH_ALLOW_INTERRUPTION();
-      /*Draw the candidate via a gaussian perturbation*/
-      candx=RNG_NORMAL(MATRIX(*res, j, 0),sigma*temp/initemp);
-      candy=RNG_NORMAL(MATRIX(*res, j, 1),sigma*temp/initemp);
-      /*Calculate the potential difference for the new position*/
-      dpot=0.0;
-      for(k=0;k<n;k++) {
-        /*Potential differences for pairwise effects*/
-        if(j!=k){
-          dx = MATRIX(*res, j, 0) - MATRIX(*res, k, 0);
-          dy = MATRIX(*res, j, 1) - MATRIX(*res, k, 1);
-          odis = sqrt(dx*dx + dy*dy);
-          dx = candx - MATRIX(*res, k, 0);
-          dy = candy - MATRIX(*res, k, 1);
-          ndis = sqrt(dx*dx + dy*dy);
-          osqd = (odis-MATRIX(elen, j, k))*(odis-MATRIX(elen, j, k));
-          nsqd = (ndis-MATRIX(elen, j, k))*(ndis-MATRIX(elen, j, k));
-          dpot += kkconst*(osqd-nsqd)/(MATRIX(elen, j, k)*MATRIX(elen, j, k));
-        }
-      }
-      /*Make a keep/reject decision*/
-      if(log(RNG_UNIF(0.0,1.0))<dpot/temp){
-        MATRIX(*res, j, 0)=candx;
-        MATRIX(*res, j, 1)=candy;
-	CHECK_BOUNDS(j);
-      }
-    }
-    /*Cool the system*/
-    temp*=coolexp;
-  }
-
-  IGRAPH_PROGRESS("Kamada-Kawai layout: ", 100.0, NULL);
-
-  RNG_END();
-  igraph_matrix_destroy(&elen);
-  IGRAPH_FINALLY_CLEAN(1);
-
-#undef CHECK_BOUNDS
-
-  return 0;
-}
-
-/**
- * \function igraph_layout_kamada_kawai_3d
- * \brief 3D version of the force based Kamada-Kawai layout.
- *
- * The pair of the \ref igraph_layout_kamada_kawai 2D layout generator
- * 
- * </para><para>
- * This function was ported from the SNA R package.
- * \param graph A graph object.
- * \param res Pointer to an initialized matrix object. This will
- *        contain the result and will be resized if needed.
- * \param niter The number of iterations to perform. A reasonable
- *        default value is 1000.  
- * \param sigma Sets the base standard deviation of position
- *        change proposals. A reasonable default value is the
- *        number of vertices / 4.
- * \param initemp Sets the initial temperature for the annealing.
- *        A reasonable default value is 10.
- * \param coolexp The cooling exponent of the annealing.  
- *        A reasonable default value is 0.99.
- * \param kkconst The Kamada-Kawai vertex attraction constant.
- *        Typical value: (number of vertices)^2
- * \param use_seed Boolean, whether to use the values cupplied in the \p res 
- *     argument as the initial configuration. If zero then a random initial 
- *     configuration is used.
- * \param fixz Logical, whether to fix the third coordinate of the input 
- *     matrix.
- * \return Error code.
- * 
- * Added in version 0.2.</para><para>
- * 
- * Time complexity: O(|V|^2) for each
- * iteration, |V| is the number of
- * vertices in the graph. 
- */
-
-int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res,
-				  igraph_integer_t niter, igraph_real_t sigma, 
-				  igraph_real_t initemp, igraph_real_t coolexp, 
-				  igraph_real_t kkconst, igraph_bool_t use_seed,
-				  igraph_bool_t fixz,
-				  const igraph_vector_t *minx,
-				  const igraph_vector_t *maxx,
-				  const igraph_vector_t *miny,
-				  const igraph_vector_t *maxy,
-				  const igraph_vector_t *minz,
-				  const igraph_vector_t *maxz) {
-
-  igraph_real_t temp, candx, candy, candz;
-  igraph_real_t dpot, odis, ndis, osqd, nsqd;
-  long int i,j,k;
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_matrix_t elen;
-
-  if (minx && igraph_vector_size(minx) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
-  }
-  if (maxx && igraph_vector_size(maxx) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
-  }
-  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
-    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
-  }
-  if (miny && igraph_vector_size(miny) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
-  }
-  if (maxy && igraph_vector_size(maxy) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
-  }
-  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
-    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
-  }
-  if (minz && igraph_vector_size(minz) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);
-  }
-  if (maxz && igraph_vector_size(maxz) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);
-  }
-  if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {
-    IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);
-  }
-
-#define CHECK_BOUNDS(x) do {						\
-    if (minx && MATRIX(*res, (x), 0) < VECTOR(*minx)[(x)]) {		\
-      MATRIX(*res, (x), 0) = VECTOR(*minx)[(x)];			\
-    } else if (maxx && MATRIX(*res, (x), 0) > VECTOR(*maxx)[(x)]) {	\
-      MATRIX(*res, (x), 0) = VECTOR(*maxx)[(x)];			\
-    }									\
-    if (miny && MATRIX(*res, (x), 1) < VECTOR(*miny)[(x)]) {		\
-      MATRIX(*res, (x), 1) = VECTOR(*miny)[(x)];			\
-    } else if (maxy && MATRIX(*res, (x), 1) > VECTOR(*maxy)[(x)]) {	\
-      MATRIX(*res, (x), 1) = VECTOR(*maxy)[(x)];			\
-    }									\
-    if (minz && MATRIX(*res, (x), 2) < VECTOR(*minz)[(x)]) {		\
-      MATRIX(*res, (x), 2) = VECTOR(*minz)[(x)];			\
-    } else if (maxz && MATRIX(*res, (x), 2) > VECTOR(*maxz)[(x)]) {	\
-      MATRIX(*res, (x), 2) = VECTOR(*maxz)[(x)];			\
-    }									\
-  } while (0)    
-  
-  RNG_BEGIN();
-  
-  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 3));
-  IGRAPH_MATRIX_INIT_FINALLY(&elen,  no_of_nodes, no_of_nodes);
-  IGRAPH_CHECK(igraph_shortest_paths(graph, &elen, igraph_vss_all(), 
-				     igraph_vss_all(),
-				     IGRAPH_ALL));
-  
-  /* Scan the distance matrix and introduce an upper limit.
-   * This helps with disconnected graphs. */
-  temp = 0.0;
-  for (i=0; i<no_of_nodes; i++) {
-    for (j=i+1; j<no_of_nodes; j++) {
-      if (!igraph_finite(MATRIX(elen, i, j)))
-        continue;
-      if (MATRIX(elen, i, j) > temp)
-        temp = MATRIX(elen, i, j);
-    }
-  }
-  for (i=0; i<no_of_nodes; i++) {
-    for (j=0; j<no_of_nodes; j++) {
-      if (MATRIX(elen, i, j) > temp)
-        MATRIX(elen, i, j) = temp;
-    }
-  }
-
-  if (!use_seed) {
-    for (i=0; i<no_of_nodes; i++) {
-      MATRIX(*res, i, 0) = RNG_NORMAL(0, no_of_nodes/4.0);
-      MATRIX(*res, i, 1) = RNG_NORMAL(0, no_of_nodes/4.0);
-      MATRIX(*res, i, 2) = RNG_NORMAL(0, no_of_nodes/4.0);
-      CHECK_BOUNDS(i);
-    }
-  }
-
-  temp=initemp;
-  for(i=0;i<niter;i++){
-    if (i%10 == 0)
-      IGRAPH_PROGRESS("3D Kamada-Kawai layout: ",
-		      100.0*i/niter, NULL);
-
-    /*Update each vertex*/
-    for(j=0;j<no_of_nodes;j++){
-      IGRAPH_ALLOW_INTERRUPTION();
-      /*Draw the candidate via a gaussian perturbation*/
-      candx=RNG_NORMAL(MATRIX(*res, j, 0) ,sigma*temp/initemp);
-      candy=RNG_NORMAL(MATRIX(*res, j, 1) ,sigma*temp/initemp);
-      candz=RNG_NORMAL(MATRIX(*res, j, 2) ,sigma*temp/initemp);
-      /*Calculate the potential difference for the new position*/
-      dpot=0.0;
-      for(k=0;k<no_of_nodes;k++) /*Potential differences for pairwise effects*/
-        if(j!=k){
-          odis=sqrt((MATRIX(*res, j, 0)-MATRIX(*res, k, 0))*
-		    (MATRIX(*res, j, 0)-MATRIX(*res, k, 0))+
-		    (MATRIX(*res, j, 1)-MATRIX(*res, k, 1))*
-		    (MATRIX(*res, j, 1)-MATRIX(*res, k, 1))+
-		    (MATRIX(*res, j, 2)-MATRIX(*res, k, 2))*
-		    (MATRIX(*res, j, 2)-MATRIX(*res, k, 2)));
-          ndis=sqrt((candx-MATRIX(*res, k, 0))*(candx-MATRIX(*res, k, 0))+
-		    (candy-MATRIX(*res, k, 1))*(candy-MATRIX(*res, k, 1))+
-		    (candz-MATRIX(*res, k, 2))*(candz-MATRIX(*res, k, 2)));
-          osqd=(odis-MATRIX(elen, j, k))*(odis-MATRIX(elen, j, k));
-          nsqd=(ndis-MATRIX(elen, j, k))*(ndis-MATRIX(elen, j, k));
-          dpot+=kkconst*(osqd-nsqd)/(MATRIX(elen, j, k)*MATRIX(elen, j, k));
-        }
-      /*Make a keep/reject decision*/
-      if(log(RNG_UNIF(0.0,1.0))<dpot/temp){
-        MATRIX(*res, j, 0)=candx;
-        MATRIX(*res, j, 1)=candy;
-        if (!fixz) { MATRIX(*res, j, 2)=candz; }
-	CHECK_BOUNDS(j);
-      }
-    }
-    /*Cool the system*/
-    temp*=coolexp;
-  }
-
-  IGRAPH_PROGRESS("3D Kamada-Kawai layout: ", 100.0, NULL);
-
-  RNG_END();
-  igraph_matrix_destroy(&elen);
-  IGRAPH_FINALLY_CLEAN(1);
-
-#undef CHECK_BOUNDS
-
-  return 0;
-}
-
 int igraph_layout_springs(const igraph_t *graph, igraph_matrix_t *res,
 			  igraph_real_t mass, igraph_real_t equil, igraph_real_t k,
 			  igraph_real_t repeqdis, igraph_real_t kfr, igraph_bool_t repulse) {
@@ -1470,173 +686,6 @@ int igraph_layout_lgl(const igraph_t *graph, igraph_matrix_t *res,
 
 }
 
-/**
- * \function igraph_layout_grid_fruchterman_reingold
- * \brief Force based layout generator for large graphs.
- * 
- * </para><para>
- * This algorithm is the same as the Fruchterman-Reingold layout
- * generator, but it partitions the 2d space to a grid and and vertex
- * repulsion is calculated only for vertices nearby.
- *
- * \param graph The graph object. 
- * \param res The result, the coordinates in a matrix. The parameter
- *   should point to an initialized matrix object and will be resized.
- * \param niter The number of iterations to do. A reasonable
- *        default value is 500.
- * \param maxdelta The maximum distance to move a vertex in an
- *        iteration. A reasonable default value is the number of
- *        vertices.
- * \param area The area parameter of the algorithm. A reasonable
- *        default is the square of the number of vertices.
- * \param coolexp The cooling exponent of the simulated annealing.
- *        A reasonable default is 1.5.
- * \param repulserad Determines the radius at which
- *        vertex-vertex repulsion cancels out attraction of
- *        adjacent vertices. A reasonable default is \p area
- *        times the number of vertices.
- * \param cellsize The size of the grid cells. A reasonable default is
- *        the fourth root of \p area (or the square root of the
- *        number of vertices if \p area is also left at its default
- *        value)
- * \param use_seed Logical, if true, the coordinates passed in \p res
- *   (should have the appropriate size) will be used for the first
- *   iteration.
- * \param weight Pointer to a vector containing edge weights, 
- *        the attraction along the edges will be multiplied by these. 
- *        It will be ignored if it is a null-pointer.
- * \return Error code.
- *
- * Added in version 0.2.</para><para>
- * 
- * Time complexity: ideally (constant number of vertices in each cell) 
- * O(niter*(|V|+|E|)), in the worst case O(niter*(|V|^2+|E|)).
- */
-
-int igraph_layout_grid_fruchterman_reingold(const igraph_t *graph, 
-               igraph_matrix_t *res,
-               igraph_integer_t niter, igraph_real_t maxdelta, 
-               igraph_real_t area, igraph_real_t coolexp,
-               igraph_real_t repulserad, 
-               igraph_real_t cellsize,
-               igraph_bool_t use_seed,
-               const igraph_vector_t *weight) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  igraph_2dgrid_t grid;  
-  igraph_vector_t forcex;
-  igraph_vector_t forcey;
-  long int i, it=0;
-  igraph_2dgrid_iterator_t vidit;  
-
-  igraph_real_t frk=sqrt(area/no_of_nodes);
-
-  if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {
-    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
-  }
-
-  IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));
-  IGRAPH_VECTOR_INIT_FINALLY(&forcex, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&forcey, no_of_nodes);
-  
-  /* initial layout */
-  if (!use_seed) {
-    IGRAPH_CHECK(igraph_layout_random(graph, res));
-    igraph_matrix_scale(res, sqrt(area/M_PI));
-  }
-  
-  /* make grid */
-  IGRAPH_CHECK(igraph_2dgrid_init(&grid, res, 
-				  -sqrt(area/M_PI),sqrt(area/M_PI), cellsize,
-				  -sqrt(area/M_PI),sqrt(area/M_PI), cellsize));
-  IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid);
-  
-  /* place vertices on grid */
-  for (i=0; i<no_of_nodes; i++) {
-    igraph_2dgrid_add2(&grid, i);
-  }
-
-  while (it<niter) {
-    long int j;
-    igraph_real_t t=maxdelta*pow((niter-it)/(double)niter, coolexp);
-    long int vid, nei;
-
-    /* Report progress */
-    if (it%10 == 0) {
-      IGRAPH_PROGRESS("Grid based Fruchterman-Reingold layout: ", 
-		      (100.0*it)/niter, NULL);
-    }
-
-    igraph_vector_null(&forcex);
-    igraph_vector_null(&forcey);
-    
-    /* attraction */
-    for (j=0; j<no_of_edges; j++) {
-      igraph_integer_t from, to;
-      igraph_real_t xd, yd, dist, force;
-      igraph_real_t w = weight ? VECTOR(*weight)[j] : 1.0;
-      igraph_edge(graph, (igraph_integer_t) j, &from, &to);
-      xd=MATRIX(*res, (long int)from, 0)-MATRIX(*res, (long int)to, 0);
-      yd=MATRIX(*res, (long int)from, 1)-MATRIX(*res, (long int)to, 1);
-      dist=sqrt(xd*xd+yd*yd);
-      if (dist != 0) { xd/=dist; yd/=dist; }
-      force=dist*dist/frk*w;
-      VECTOR(forcex)[(long int)from] -= xd*force;
-      VECTOR(forcex)[(long int)to]   += xd*force;
-      VECTOR(forcey)[(long int)from] -= yd*force;
-      VECTOR(forcey)[(long int)to]   += yd*force;
-    }
-
-    /* repulsion */
-    igraph_2dgrid_reset(&grid, &vidit);
-    while ( (vid=igraph_2dgrid_next(&grid, &vidit)-1) != -1) {
-      IGRAPH_ALLOW_INTERRUPTION();
-      while ( (nei=igraph_2dgrid_next_nei(&grid, &vidit)-1) != -1) {
-	igraph_real_t xd=MATRIX(*res, (long int)vid, 0)-
-	  MATRIX(*res, (long int)nei, 0);
-	igraph_real_t yd=MATRIX(*res, (long int)vid, 1)-
-	  MATRIX(*res, (long int)nei, 1);
-	igraph_real_t dist=sqrt(xd*xd+yd*yd);
-	igraph_real_t force;
-	if (dist < cellsize) {
-	  if (dist==0) { dist=1e-6; };
-	  xd/=dist; yd/=dist;
-	  force=frk*frk*(1.0/dist-dist*dist/repulserad);
-	  VECTOR(forcex)[(long int)vid] += xd*force;
-	  VECTOR(forcex)[(long int)nei] -= xd*force;
-	  VECTOR(forcey)[(long int)vid] += yd*force;
-	  VECTOR(forcey)[(long int)nei] -= yd*force;	    
-	}
-      }
-    }
-
-    /* update */
-    for (j=0; j<no_of_nodes; j++) {
-      long int vvid=j;
-      igraph_real_t fx=VECTOR(forcex)[vvid];
-      igraph_real_t fy=VECTOR(forcey)[vvid];
-      igraph_real_t ded=sqrt(fx*fx+fy*fy);
-      if (ded > t) {
-	ded=t/ded;
-	fx*=ded; fy *=ded;
-      }
-      igraph_2dgrid_move(&grid, vvid, fx, fy);
-    }
-    it++;
-    
-  } /* it<niter */
-  
-  IGRAPH_PROGRESS("Grid based Fruchterman-Reingold layout: ", 
-		  100.0, NULL);
-
-  igraph_vector_destroy(&forcex);
-  igraph_vector_destroy(&forcey);
-  igraph_2dgrid_destroy(&grid);
-  IGRAPH_FINALLY_CLEAN(3);
-  return 0;
-}
-
 /* Internal structure for Reingold-Tilford layout */
 struct igraph_i_reingold_tilford_vertex {
   long int parent;        /* Parent node index */
@@ -1971,7 +1020,7 @@ int igraph_layout_reingold_tilford(const igraph_t *graph,
     if (igraph_is_directed(graph) && mode != IGRAPH_ALL) {
       IGRAPH_CHECK(igraph_topological_sorting(graph, &order, mode2));
       IGRAPH_CHECK(igraph_clusters(graph, &membership, /*csize=*/ 0, 
-        &no_comps, IGRAPH_STRONG));
+        &no_comps, IGRAPH_WEAK));
     } else {
       IGRAPH_CHECK(igraph_sort_vertex_ids_by_degree(graph, &order,
             igraph_vss_all(), IGRAPH_ALL, 0, IGRAPH_ASCENDING, 0));
diff --git a/src/layout_dh.c b/src/layout_dh.c
new file mode 100644
index 0000000..96c418e
--- /dev/null
+++ b/src/layout_dh.c
@@ -0,0 +1,399 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph R package.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_layout.h"
+#include "igraph_interface.h"
+#include "igraph_random.h"
+
+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,
+					  float p3_x, float p3_y) {
+    float s1_x = p1_x - p0_x;
+    float s1_y = p1_y - p0_y;
+    float s2_x = p3_x - p2_x;
+    float s2_y = p3_y - p2_y;
+
+    float s1, s2, t1, t2, s, t;
+    s1 = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y));
+    s2 = (-s2_x * s1_y + s1_x * s2_y);
+    if (s2 == 0) { return 0; }
+    t1 = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x));
+    t2 = (-s2_x * s1_y + s1_x * s2_y);    
+    s = s1 / s2;
+    t = t1 / t2;
+
+    return s >= 0 && s <= 1 && t >= 0 && t <= 1 ? 1 : 0;
+}
+
+float igraph_i_point_segment_dist2(float v_x, float v_y, 
+				   float u1_x, float u1_y, 
+				   float u2_x, float u2_y) {
+
+  float dx = u2_x - u1_x;
+  float dy = u2_y - u1_y;
+  float l2 = dx * dx + dy * dy;
+  float t, p_x, p_y;
+  if (l2 == 0) { return (v_x-u1_x) * (v_x-u1_x) + (v_y-u1_y) * (v_y-u1_y); }
+  t = ((v_x - u1_x) * dx + (v_y - u1_y) * dy) / l2;
+  if (t < 0.0) { 
+    return (v_x-u1_x) * (v_x-u1_x) + (v_y-u1_y) * (v_y-u1_y); 
+  } else if (t > 1.0) {
+    return (v_x-u2_x) * (v_x-u2_x) + (v_y-u2_y) * (v_y-u2_y);
+  }
+  p_x = u1_x + t * dx;
+  p_y = u1_y + t * dy;
+  return (v_x-p_x) * (v_x-p_x) + (v_y-p_y) * (v_y-p_y);
+}
+
+/**
+ * \function igraph_layout_davidson_harel
+ * Davidson-Harel layout algorithm
+ * 
+ * This function implements the algorithm by Davidson and Harel,
+ * see Ron Davidson, David Harel: Drawing Graphs Nicely Using 
+ * Simulated Annealing. ACM Transactions on Graphics 15(4),
+ * pp. 301-331, 1996.
+ * 
+ * </para><para>
+ * The algorithm uses simulated annealing and a sophisticated 
+ * energy function, which is unfortunately hard to parameterize
+ * for different graphs. The original publication did not disclose any
+ * parameter values, and the ones below were determined by 
+ * experimentation.
+ * 
+ * </para><para>
+ * The algorithm consists of two phases, an annealing phase, and a 
+ * fine-tuning phase. There is no simulated annealing in the second
+ * phase.
+ * 
+ * </para><para>
+ * Our implementation tries to follow the original publication, as
+ * much as possible. The only major difference is that coordinates are
+ * explicitly kept within the bounds of the rectangle of the layout.
+ *
+ * \param graph The input graph, edge directions are ignored.
+ * \param res A matrix, the result is stored here. It can be used to
+ *     supply start coordinates, see \p use_seed.
+ * \param use_seed Boolean, whether to use the supplied \p res as
+ *     start coordinates.
+ * \param maxiter The maximum number of annealing iterations. A
+ *     reasonable value for smaller graphs is 10.
+ * \param fineiter The number of fine tuning iterations. A reasonable
+ *     value is max(10, log2(n)) where n is the number of vertices.
+ * \param cool_fact Cooling factor. A reasonable value is 0.75.
+ * \param weight_node_dist Weight for the node-node distances
+ *     component of the energy function. Reasonable value: 1.0.
+ * \param weight_border Weight for the distance from the border
+ *     component of the energy function. It can be set to zero, if
+ *     vertices are allowed to sit on the border.
+ * \param weight_edge_lengths Weight for the edge length component
+ *     of the energy function, a reasonable value is the density of
+ *     the graph divided by 10.
+ * \param weight_edge_crossings Weight for the edge crossing component
+ *     of the energy function, a reasonable default is 1 minus the
+ *     square root of the density of the graph.
+ * \param weight_node_edge_dist Weight for the node-edge distance
+ *     component of the energy function. A reasonable value is 
+ *     1 minus the density, divided by 5.
+ * \return Error code.
+ * 
+ * Time complexity: one first phase iteration has time complexity
+ * O(n^2+m^2), one fine tuning iteration has time complexity O(mn).
+ * Time complexity might be smaller if some of the weights of the 
+ * components of the energy function are set to zero.
+ * 
+ */
+
+int igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix_t *res,
+		 igraph_bool_t use_seed, igraph_integer_t maxiter,
+		 igraph_integer_t fineiter, igraph_real_t cool_fact,
+		 igraph_real_t weight_node_dist, igraph_real_t weight_border, 
+		 igraph_real_t weight_edge_lengths, 
+		 igraph_real_t weight_edge_crossings,
+		 igraph_real_t weight_node_edge_dist) {
+  
+  igraph_integer_t no_nodes = igraph_vcount(graph);
+  igraph_integer_t no_edges = igraph_ecount(graph);
+  float width = sqrt(no_nodes) * 10, height = width;
+  igraph_vector_int_t perm;
+  igraph_bool_t fine_tuning=0;
+  igraph_integer_t round, i;
+  igraph_vector_float_t try_x, try_y;
+  igraph_vector_int_t try_idx;
+  float move_radius=width / 2;
+  float fine_tuning_factor=0.01;
+  igraph_vector_t neis;
+  float min_x=width/2, max_x=-width/2, min_y=height/2, max_y=-height/2;
+  
+  igraph_integer_t no_tries = 30;
+  float w_node_dist = weight_node_dist ;          /* 1.0 */
+  float w_borderlines = weight_border;	          /* 0.0 */
+  float w_edge_lengths = weight_edge_lengths;     /* 0.0001; */
+  float w_edge_crossings = weight_edge_crossings; /* 1.0 */
+  float w_node_edge_dist = weight_node_edge_dist; /* 0.2 */
+  
+  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
+		   igraph_matrix_ncol(res) != 2)) {
+    IGRAPH_ERROR("Invalid start position matrix size in "
+		 "Davidson-Harel layout", IGRAPH_EINVAL);
+  }
+  if (maxiter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negative in "
+		 "Davidson-Harel layout", IGRAPH_EINVAL);
+  }
+  if (fineiter < 0) {
+    IGRAPH_ERROR("Number of fine tuning iterations must be non-negative in "
+		 "Davidson-Harel layout", IGRAPH_EINVAL);
+  }
+  if (cool_fact <= 0 || cool_fact >= 1) {
+    IGRAPH_ERROR("Cooling factor must be in (0,1) in "
+		 "Davidson-Harel layout", IGRAPH_EINVAL);
+  }
+  
+  if (no_nodes == 0) { return 0; }
+
+  IGRAPH_CHECK(igraph_vector_int_init_seq(&perm, 0, no_nodes-1));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &perm);
+  IGRAPH_CHECK(igraph_vector_float_init(&try_x, no_tries));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &try_x);
+  IGRAPH_CHECK(igraph_vector_float_init(&try_y, no_tries));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &try_y);
+  IGRAPH_CHECK(igraph_vector_int_init_seq(&try_idx, 0, no_tries-1));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &try_idx);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 100);
+
+  RNG_BEGIN();
+
+  if (!use_seed) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
+    for (i=0; i<no_nodes; i++) {
+      float x, y;
+      x = MATRIX(*res, i, 0) = RNG_UNIF(-width/2, width/2);
+      y = MATRIX(*res, i, 1) = RNG_UNIF(-height/2, height/2);
+      if (x < min_x) { min_x = x; } else if (x > max_x) { max_x = x; }
+      if (y < min_y) { min_y = y; } else if (y > max_y) { max_y = y; }
+    }
+  } else {
+    min_x = IGRAPH_INFINITY; max_x = IGRAPH_NEGINFINITY;
+    min_y = IGRAPH_INFINITY; max_y = IGRAPH_NEGINFINITY;
+    for (i=0; i<no_nodes; i++) {
+      float x = MATRIX(*res, i, 0);
+      float y = MATRIX(*res, i, 1);
+      if (x < min_x) { min_x = x; } else if (x > max_x) { max_x = x; }
+      if (y < min_y) { min_y = y; } else if (y > max_y) { max_y = y; }
+    }
+  }
+
+  for (i = 0; i < no_tries; i++) {
+    float phi=2 * M_PI / no_tries * i;
+    VECTOR(try_x)[i] = cos(phi);
+    VECTOR(try_y)[i] = sin(phi);
+  }
+  
+  for (round = 0; round < maxiter + fineiter; round++) {
+    igraph_integer_t p;
+    igraph_vector_int_shuffle(&perm);
+    
+    fine_tuning = round >= maxiter;
+    if (fine_tuning) { 
+      float fx = fine_tuning_factor * (max_x - min_x);
+      float fy = fine_tuning_factor * (max_y - min_y);
+      move_radius = fx < fy ? fx : fy;
+    }
+    
+    for (p = 0; p < no_nodes; p++) {
+      igraph_integer_t t;
+      igraph_integer_t v=VECTOR(perm)[p];
+      igraph_vector_int_shuffle(&try_idx);
+      
+      for (t = 0; t < no_tries; t++) {
+	float diff_energy=0.0;
+	int ti=VECTOR(try_idx)[t];
+	
+	/* Try moving it */
+	float old_x = MATRIX(*res, v, 0);
+	float old_y = MATRIX(*res, v, 1);
+	float new_x = old_x + move_radius * VECTOR(try_x)[ti];
+	float new_y = old_y + move_radius * VECTOR(try_y)[ti];
+
+	if (new_x < -width /2) { new_x = -width/2 - 1e-6; }
+	if (new_x >  width /2) { new_x =  width/2 - 1e-6; }
+	if (new_y < -height/2) { new_y = -height/2 - 1e-6; }
+	if (new_y >  height/2) { new_y =  height/2 - 1e-6; }
+
+	if (w_node_dist != 0) {
+	  igraph_integer_t u;
+	  for (u = 0; u < no_nodes; u++) {
+	    float odx, ody, odist2, dx, dy, dist2;
+	    if (u == v) { continue; }
+	    odx = old_x - MATRIX(*res, u, 0);
+	    ody = old_y - MATRIX(*res, u, 1);
+	    dx = new_x - MATRIX(*res, u, 0);
+	    dy = new_y - MATRIX(*res, u, 1);
+	    odist2 = odx * odx + ody * ody;
+	    dist2 = dx * dx + dy * dy;
+	    diff_energy += w_node_dist / dist2 - w_node_dist / odist2;
+	  }
+	}
+
+	if (w_borderlines != 0) {
+	  float odx1 = width/2 - old_x, odx2 = old_x + width/2;
+	  float ody1 = height/2 - old_y, ody2 = old_y + height/2;
+	  float dx1 = width/2 - new_x, dx2 = new_x + width/2;
+	  float dy1 = height/2 - new_y, dy2 = new_y + height/2;
+	  if (odx1 < 0) { odx1 = 2; } if (odx2 < 0) { odx2 = 2; }
+	  if (ody1 < 0) { ody1 = 2; } if (ody2 < 0) { ody2 = 2; }
+	  if (dx1 < 0) { dx1 = 2; } if (dx2 < 0) { dx2 = 2; }
+	  if (dy1 < 0) { dy1 = 2; } if (dy2 < 0) { dy2 = 2; }
+	  diff_energy -= w_borderlines * 
+	    (1.0 / (odx1 * odx1) + 1.0 / (odx2 * odx2) + 
+	     1.0 / (ody1 * ody1) + 1.0 / (ody2 * ody2));
+	  diff_energy += w_borderlines *
+	    (1.0 / (dx1 * dx1) + 1.0 / (dx2 * dx2) + 
+	     1.0 / (dy1 * dy1) + 1.0 / (dy2 * dy2));	    
+	}
+
+	if (w_edge_lengths != 0) {
+	  igraph_integer_t len, j;
+	  igraph_neighbors(graph, &neis, v, IGRAPH_ALL);
+	  len=igraph_vector_size(&neis);
+	  for (j = 0; j < len; j++) {
+	    igraph_integer_t u=VECTOR(neis)[j];
+	    float odx = old_x - MATRIX(*res, u, 0);
+	    float ody = old_y - MATRIX(*res, u, 1);
+	    float odist2 = odx * odx + ody * ody;
+	    float dx = new_x - MATRIX(*res, u, 0);
+	    float dy = new_y - MATRIX(*res, u, 1);
+	    float dist2 = dx * dx + dy * dy;
+	    diff_energy += w_edge_lengths * (dist2 - odist2);
+	  }
+	}
+
+	if (w_edge_crossings != 0) {
+	  igraph_integer_t len, j, no=0;
+	  igraph_neighbors(graph, &neis, v, IGRAPH_ALL);
+	  len=igraph_vector_size(&neis);
+	  for (j = 0; j < len; j++) {
+	    igraph_integer_t u = VECTOR(neis)[j];
+	    float u_x = MATRIX(*res, u, 0);
+	    float u_y = MATRIX(*res, u, 1);
+	    igraph_integer_t e;
+	    for (e = 0; e < no_edges; e++) {
+	      igraph_integer_t u1 = IGRAPH_FROM(graph, e);
+	      igraph_integer_t u2 = IGRAPH_TO(graph, e);
+	      float u1_x, u1_y, u2_x, u2_y;
+	      if (u1 == v || u2 == v || u1 == u || u2 == u) { continue; }
+	      u1_x = MATRIX(*res, u1, 0);
+	      u1_y = MATRIX(*res, u1, 1);
+	      u2_x = MATRIX(*res, u2, 0);
+	      u2_y = MATRIX(*res, u2, 1);
+	      no -= igraph_i_segments_intersect(old_x, old_y, u_x, u_y, 
+						u1_x, u1_y, u2_x, u2_y);
+	      no += igraph_i_segments_intersect(new_x, new_y, u_x, u_y,
+						u1_x, u1_y, u2_x, u2_y);
+	    }
+	  }
+	  diff_energy += w_edge_crossings * no;
+	}
+
+	if (w_node_edge_dist != 0 && fine_tuning) {
+	  igraph_integer_t e, no;
+
+	  /* All non-incident edges from the moved 'v' */
+	  for (e = 0; e < no_edges; e++) {
+	    igraph_integer_t u1 = IGRAPH_FROM(graph, e);
+	    igraph_integer_t u2 = IGRAPH_TO(graph, e);
+	    float u1_x, u1_y, u2_x, u2_y, d_ev;
+	    if (u1 == v || u2 == v) { continue; }
+	    u1_x = MATRIX(*res, u1, 0);
+	    u1_y = MATRIX(*res, u1, 1);
+	    u2_x = MATRIX(*res, u2, 0);
+	    u2_y = MATRIX(*res, u2, 1);
+	    d_ev = igraph_i_point_segment_dist2(old_x, old_y, u1_x, u1_y,
+						u2_x, u2_y);
+	    diff_energy -= w_node_edge_dist / d_ev;
+	    d_ev = igraph_i_point_segment_dist2(new_x, new_y, u1_x, u1_y,
+						u2_x, u2_y);
+	    diff_energy += w_node_edge_dist / d_ev;
+	  }
+
+	  /* All other nodes from all of v's incident edges */
+	  igraph_incident(graph, &neis, v, IGRAPH_ALL);
+	  no=igraph_vector_size(&neis);
+	  for (e = 0; e < no; e++) {
+	    igraph_integer_t mye=VECTOR(neis)[e];
+	    igraph_integer_t u=IGRAPH_OTHER(graph, mye, v);
+	    float u_x=MATRIX(*res, u, 0);
+	    float u_y=MATRIX(*res, u, 1);
+	    igraph_integer_t w;
+	    for (w = 0; w < no_nodes; w++) {
+	      if (w == v || w == u) { continue; }
+	      float w_x=MATRIX(*res, w, 0);
+	      float w_y=MATRIX(*res, w, 1);
+	      float d_ev = igraph_i_point_segment_dist2(w_x, w_y, old_x,
+							old_y, u_x, u_y);
+	      diff_energy -= w_node_edge_dist / d_ev;
+	      d_ev = igraph_i_point_segment_dist2(w_x, w_y, new_x, new_y,
+						  u_x, u_y);
+	      diff_energy += w_node_edge_dist / d_ev;
+	    }
+	  }
+	} /* w_node_edge_dist != 0 && fine_tuning */
+	
+	if (diff_energy < 0 ||
+	    (!fine_tuning && RNG_UNIF01() < exp(-diff_energy/move_radius))) {
+	  MATRIX(*res, v, 0) = new_x;
+	  MATRIX(*res, v, 1) = new_y;
+	  if (new_x < min_x) { 
+	    min_x = new_x;
+	  } else if (new_x > max_x) {
+	    max_x = new_x;
+	  }
+	  if (new_y < min_y) {
+	    min_y = new_y;
+	  } else if (new_y > max_y) {
+	    max_y = new_y;
+	  }
+	}
+
+      }	/* t < no_tries */
+
+    } /* p < no_nodes  */
+    
+    move_radius *= cool_fact;
+
+  } /* round < maxiter */
+
+  RNG_END();
+
+  igraph_vector_destroy(&neis);
+  igraph_vector_int_destroy(&try_idx);
+  igraph_vector_float_destroy(&try_x);
+  igraph_vector_float_destroy(&try_y);
+  igraph_vector_int_destroy(&perm);
+  IGRAPH_FINALLY_CLEAN(5);
+ 
+  return 0;
+}
diff --git a/src/layout_fr.c b/src/layout_fr.c
new file mode 100644
index 0000000..f6a17f7
--- /dev/null
+++ b/src/layout_fr.c
@@ -0,0 +1,677 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph R package.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_layout.h"
+#include "igraph_random.h"
+#include "igraph_interface.h"
+#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) {
+
+  igraph_integer_t no_nodes=igraph_vcount(graph);
+  igraph_integer_t no_edges=igraph_ecount(graph);
+  igraph_integer_t i;
+  igraph_vector_float_t dispx, dispy;
+  igraph_real_t temp=start_temp;
+  igraph_real_t difftemp=start_temp / niter;
+  float width=sqrtf(no_nodes), height=width;
+  igraph_bool_t conn=1;
+  float C;
+
+  igraph_is_connected(graph, &conn, IGRAPH_WEAK);
+  if (!conn) { C = no_nodes * sqrtf(no_nodes); }
+
+  RNG_BEGIN();
+
+  if (!use_seed) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
+    for (i=0; i<no_nodes; i++) {
+      igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
+      igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
+      igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
+      igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
+      if (!igraph_finite(x1)) { x1 = -sqrt(no_nodes)/2; }
+      if (!igraph_finite(x2)) { x2 =  sqrt(no_nodes)/2; }
+      if (!igraph_finite(y1)) { y1 = -sqrt(no_nodes)/2; }
+      if (!igraph_finite(y2)) { y2 =  sqrt(no_nodes)/2; }
+      MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
+      MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
+    }
+  }
+
+  IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);
+  IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);
+
+  for (i=0; i<niter; i++) {
+    igraph_integer_t v, u, e;
+
+    /* calculate repulsive forces, we have a special version
+       for unconnected graphs */
+    igraph_vector_float_null(&dispx);
+    igraph_vector_float_null(&dispy);
+    if (conn) {
+      for (v=0; v<no_nodes; v++) {
+	for (u=v+1; u<no_nodes; u++) {
+	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+	  float dlen=dx * dx + dy * dy;
+
+          if (dlen == 0) {
+            dx = RNG_UNIF01() * 1e-9;
+            dy = RNG_UNIF01() * 1e-9;
+            dlen = dx * dx + dy * dy;
+          }
+
+	  VECTOR(dispx)[v] += dx/dlen;
+	  VECTOR(dispy)[v] += dy/dlen;
+	  VECTOR(dispx)[u] -= dx/dlen;
+	  VECTOR(dispy)[u] -= dy/dlen;
+	}
+      }
+    } else {
+      for (v=0; v<no_nodes; v++) {
+	for (u=v+1; u<no_nodes; u++) {
+	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+	  float dlen, rdlen;
+
+	  dlen=dx * dx + dy * dy;
+          if (dlen == 0) {
+            dx = RNG_UNIF(0, 1e-6);
+            dy = RNG_UNIF(0, 1e-6);
+            dlen = dx * dx + dy * dy;
+          }
+
+	  rdlen=sqrt(dlen);
+
+	  VECTOR(dispx)[v] += dx * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispy)[v] += dy * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispx)[u] -= dx * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispy)[u] -= dy * (C-dlen * rdlen) / (dlen*C);
+	}
+      }
+    }
+
+    /* calculate attractive forces */
+    for (e=0; e<no_edges; e++) {
+      /* each edges is an ordered pair of vertices v and u */
+      igraph_integer_t v=IGRAPH_FROM(graph, e);
+      igraph_integer_t u=IGRAPH_TO(graph, e);
+      igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+      igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+      igraph_real_t dlen=sqrt(dx * dx + dy * dy);
+      VECTOR(dispx)[v] -= (dx * dlen);
+      VECTOR(dispy)[v] -= (dy * dlen);
+      VECTOR(dispx)[u] += (dx * dlen);
+      VECTOR(dispy)[u] += (dy * dlen);
+    }
+
+    /* limit max displacement to temperature t and prevent from
+       displacement outside frame */
+    for (v=0; v<no_nodes; v++) {
+      igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t displen=sqrt(dx * dx + dy * dy);
+      igraph_real_t mx=fabs(dx) < temp ? dx : temp;
+      igraph_real_t my=fabs(dy) < temp ? dy : temp;
+      if (displen > 0) {
+        MATRIX(*res, v, 0) += (dx / displen) * mx;
+        MATRIX(*res, v, 1) += (dy / displen) * my;
+      }
+      if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {
+	MATRIX(*res, v, 0) = VECTOR(*minx)[v];
+      }
+      if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {
+	MATRIX(*res, v, 0) = VECTOR(*maxx)[v];
+      }
+      if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {
+	MATRIX(*res, v, 1) = VECTOR(*miny)[v];
+      }
+      if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {
+	MATRIX(*res, v, 1) = VECTOR(*maxy)[v];
+      }
+    }
+
+    temp -= difftemp;
+  }
+
+  RNG_END();
+
+  igraph_vector_float_destroy(&dispx);
+  igraph_vector_float_destroy(&dispy);
+  IGRAPH_FINALLY_CLEAN(2);
+  
+  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) {
+
+  igraph_integer_t no_nodes=igraph_vcount(graph);
+  igraph_integer_t no_edges=igraph_ecount(graph);
+  float width=sqrtf(no_nodes), height=width;
+  igraph_2dgrid_t grid;
+  igraph_vector_float_t dispx, dispy;
+  igraph_real_t temp=start_temp;
+  igraph_real_t difftemp=start_temp / niter;
+  igraph_2dgrid_iterator_t vidit;
+  igraph_integer_t i;
+  const float cellsize=2.0;
+
+  RNG_BEGIN();
+
+  if (!use_seed) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
+    for (i=0; i<no_nodes; i++) {
+      igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
+      igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
+      igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
+      igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
+      if (!igraph_finite(x1)) { x1 = -sqrt(no_nodes)/2; }
+      if (!igraph_finite(x2)) { x2 =  sqrt(no_nodes)/2; }
+      if (!igraph_finite(y1)) { y1 = -sqrt(no_nodes)/2; }
+      if (!igraph_finite(y2)) { y2 =  sqrt(no_nodes)/2; }
+      MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
+      MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
+    }
+  }
+
+  /* make grid */
+  IGRAPH_CHECK(igraph_2dgrid_init(&grid, res, -width/2, width/2, cellsize,
+				  -height/2, height/2, cellsize));
+  IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid);
+
+  /* place vertices on grid */
+  for (i=0; i<no_nodes; i++) {
+    igraph_2dgrid_add2(&grid, i);
+  }
+
+  IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);
+  IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);
+
+  for (i=0; i<niter; i++) {
+    igraph_integer_t v, u, e;
+
+    igraph_vector_float_null(&dispx);
+    igraph_vector_float_null(&dispy);
+
+    /* repulsion */
+    igraph_2dgrid_reset(&grid, &vidit);
+    while ( (v=igraph_2dgrid_next(&grid, &vidit)-1) != -1) {
+      while ( (u=igraph_2dgrid_next_nei(&grid, &vidit)-1) != -1) {
+	float dx=MATRIX(*res, v, 0)-MATRIX(*res, u, 0);
+	float dy=MATRIX(*res, v, 1)-MATRIX(*res, u, 1);
+	float dlen=dx * dx + dy * dy;
+	if (dlen < cellsize * cellsize) {
+	  VECTOR(dispx)[v] += dx/dlen;
+	  VECTOR(dispy)[v] += dy/dlen;
+	  VECTOR(dispx)[u] -= dx/dlen;
+	  VECTOR(dispy)[u] -= dy/dlen;
+	}
+      }
+    }
+
+    /* attraction */
+    for (e=0; e<no_edges; e++) {
+      igraph_integer_t v=IGRAPH_FROM(graph, e);
+      igraph_integer_t u=IGRAPH_TO(graph, e);
+      igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+      igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+      igraph_real_t dlen=sqrt(dx * dx + dy * dy);
+      VECTOR(dispx)[v] -= (dx * dlen);
+      VECTOR(dispy)[v] -= (dy * dlen);
+      VECTOR(dispx)[u] += (dx * dlen);
+      VECTOR(dispy)[u] += (dy * dlen);
+    }
+
+    /* update */
+    for (v=0; v<no_nodes; v++) {
+      igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t displen=sqrt(dx * dx + dy * dy);
+      igraph_real_t mx=fabs(dx) < temp ? dx : temp;
+      igraph_real_t my=fabs(dy) < temp ? dy : temp;
+      if (displen > 0) {
+        MATRIX(*res, v, 0) += (dx / displen) * mx;
+        MATRIX(*res, v, 1) += (dy / displen) * my;
+      }
+      if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {
+	MATRIX(*res, v, 0) = VECTOR(*minx)[v];
+      }
+      if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {
+	MATRIX(*res, v, 0) = VECTOR(*maxx)[v];
+      }
+      if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {
+	MATRIX(*res, v, 1) = VECTOR(*miny)[v];
+      }
+      if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {
+	MATRIX(*res, v, 1) = VECTOR(*maxy)[v];
+      }
+    }
+
+    temp -= difftemp;
+  }
+
+  igraph_vector_float_destroy(&dispx);
+  igraph_vector_float_destroy(&dispy);
+  igraph_2dgrid_destroy(&grid);
+  IGRAPH_FINALLY_CLEAN(3);
+  return 0;
+}
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_fruchterman_reingold
+ * \brief Places the vertices on a plane according to the Fruchterman-Reingold algorithm.
+ *
+ * </para><para>
+ * This is a force-directed layout, see Fruchterman, T.M.J. and
+ * Reingold, E.M.: Graph Drawing by Force-directed Placement.
+ * Software -- Practice and Experience, 21/11, 1129--1164,
+ * 1991.
+ * \param graph Pointer to an initialized graph object.
+ * \param res Pointer to an initialized matrix object. This will
+ *        contain the result and will be resized as needed.
+ * \param use_seed Logical, if true the supplied values in the
+ *        \p res argument are used as an initial layout, if
+ *        false a random initial layout is used.
+ * \param niter The number of iterations to do. A reasonable
+ *        default value is 500.
+ * \param start_temp Start temperature. This is the maximum amount
+ *        of movement alloved along one axis, within one step, for a
+ *        vertex. Currently it is decreased linearly to zero during
+ *        the iteration.
+ * \param grid Whether to use the (fast but less accurate) grid based
+ *        version of the algorithm. Possible values: \c
+ *        IGRAPH_LAYOUT_GRID, \c IGRAPH_LAYOUT_NOGRID, \c
+ *        IGRAPH_LAYOUT_AUTOGRID. The last one uses the grid based
+ *        version only for large graphs, currently the ones with
+ *        more than 1000 vertices.
+ * \param weight Pointer to a vector containing edge weights,
+ *        the attraction along the edges will be multiplied by these.
+ *        It will be ignored if it is a null-pointer.
+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote x \endquote coordinate for every vertex.
+ * \param maxx Same as \p minx, but the maximum \quote x \endquote
+ *        coordinates.
+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote y \endquote coordinate for every vertex.
+ * \param maxy Same as \p miny, but the maximum \quote y \endquote
+ *        coordinates.
+ * \return Error code.
+ *
+ * Time complexity: O(|V|^2) in each
+ * iteration, |V| is the number of
+ * vertices in the graph.
+ */
+
+int igraph_layout_fruchterman_reingold(const igraph_t *graph,
+				       igraph_matrix_t *res,
+				       igraph_bool_t use_seed,
+				       igraph_integer_t niter,
+				       igraph_real_t start_temp,
+				       igraph_layout_grid_t grid,
+				       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);
+
+  if (niter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negative in "
+		 "Fruchterman-Reingold layout", IGRAPH_EINVAL);
+  }
+
+  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
+		   igraph_matrix_ncol(res) != 2)) {
+    IGRAPH_ERROR("Invalid start position matrix size in "
+		 "Fruchterman-Reingold layout", IGRAPH_EINVAL);
+  }
+
+  if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (minx && igraph_vector_size(minx) != no_nodes) {
+    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
+  }
+  if (maxx && igraph_vector_size(maxx) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
+  }
+  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
+    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
+  }
+  if (miny && igraph_vector_size(miny) != no_nodes) {
+    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
+  }
+  if (maxy && igraph_vector_size(maxy) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
+  }
+  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
+    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
+  }
+
+  if (grid == IGRAPH_LAYOUT_AUTOGRID) {
+    if (no_nodes > 1000) { 
+      grid = IGRAPH_LAYOUT_GRID;
+    } else {
+      grid = IGRAPH_LAYOUT_NOGRID;
+    }
+  }
+
+  if (grid == IGRAPH_LAYOUT_GRID) {
+    return igraph_layout_i_grid_fr(graph, res, use_seed, niter, start_temp,
+				   weight, minx, maxx, miny, maxy);
+  } else {
+    return igraph_layout_i_fr(graph, res, use_seed, niter, start_temp,
+			      weight, minx, maxx, miny, maxy);
+  }
+}
+
+/**
+ * \function igraph_layout_fruchterman_reingold_3d
+ * \brief 3D Fruchterman-Reingold algorithm.
+ * 
+ * This is the 3D version of the force based
+ * Fruchterman-Reingold layout (see \ref
+ * igraph_layout_fruchterman_reingold for the 2D version
+ *
+ * \param graph Pointer to an initialized graph object.
+ * \param res Pointer to an initialized matrix object. This will
+ *        contain the result and will be resized as needed.
+ * \param use_seed Logical, if true the supplied values in the
+ *        \p res argument are used as an initial layout, if
+ *        false a random initial layout is used.
+ * \param niter The number of iterations to do. A reasonable
+ *        default value is 500.
+ * \param start_temp Start temperature. This is the maximum amount
+ *        of movement alloved along one axis, within one step, for a
+ *        vertex. Currently it is decreased linearly to zero during
+ *        the iteration.
+ * \param weight Pointer to a vector containing edge weights, 
+ *        the attraction along the edges will be multiplied by these. 
+ *        It will be ignored if it is a null-pointer.
+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote x \endquote coordinate for every vertex.
+ * \param maxx Same as \p minx, but the maximum \quote x \endquote 
+ *        coordinates.
+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote y \endquote coordinate for every vertex.
+ * \param maxy Same as \p miny, but the maximum \quote y \endquote 
+ *        coordinates.
+ * \param minz Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote z \endquote coordinate for every vertex.
+ * \param maxz Same as \p minz, but the maximum \quote z \endquote 
+ *        coordinates.
+ * \return Error code.
+ *
+ * Added in version 0.2.</para><para>
+ *
+ * Time complexity: O(|V|^2) in each
+ * iteration, |V| is the number of
+ * vertices in the graph. 
+ * 
+ */
+
+int igraph_layout_fruchterman_reingold_3d(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,
+					  const igraph_vector_t *minz,
+					  const igraph_vector_t *maxz) {
+
+  igraph_integer_t no_nodes=igraph_vcount(graph);
+  igraph_integer_t no_edges=igraph_ecount(graph);
+  igraph_integer_t i;
+  igraph_vector_float_t dispx, dispy, dispz;
+  igraph_real_t temp=start_temp;
+  igraph_real_t difftemp=start_temp / niter;
+  float width=sqrtf(no_nodes), height=width, depth=width;
+  igraph_bool_t conn=1;
+  float C;
+
+  if (niter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negative in "
+		 "Fruchterman-Reingold layout", IGRAPH_EINVAL);
+  }
+
+  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
+		   igraph_matrix_ncol(res) != 3)) {
+    IGRAPH_ERROR("Invalid start position matrix size in "
+		 "Fruchterman-Reingold layout", IGRAPH_EINVAL);
+  }
+
+  if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (minx && igraph_vector_size(minx) != no_nodes) {
+    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
+  }
+  if (maxx && igraph_vector_size(maxx) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
+  }
+  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
+    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
+  }
+  if (miny && igraph_vector_size(miny) != no_nodes) {
+    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
+  }
+  if (maxy && igraph_vector_size(maxy) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
+  }
+  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
+    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
+  }
+  if (minz && igraph_vector_size(minz) != no_nodes) {
+    IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);
+  }
+  if (maxz && igraph_vector_size(maxz) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);
+  }
+  if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {
+    IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);
+  }
+
+  igraph_is_connected(graph, &conn, IGRAPH_WEAK);
+  if (!conn) { C = no_nodes * sqrtf(no_nodes); }
+
+  RNG_BEGIN();
+
+  if (!use_seed) {
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3));
+    for (i=0; i<no_nodes; i++) {
+      igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
+      igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
+      igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
+      igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
+      igraph_real_t z1=minz ? VECTOR(*minz)[i] : -depth/2;
+      igraph_real_t z2=maxz ? VECTOR(*maxz)[i] :  depth/2;
+      MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
+      MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
+      MATRIX(*res, i, 2) = RNG_UNIF(z1, z2);
+    }
+  }
+
+  IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);
+  IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);
+  IGRAPH_CHECK(igraph_vector_float_init(&dispz, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &dispz);
+
+  for (i=0; i<niter; i++) {
+    igraph_integer_t v, u, e;
+    
+    /* calculate repulsive forces, we have a special version
+       for unconnected graphs */
+    igraph_vector_float_null(&dispx);
+    igraph_vector_float_null(&dispy);
+    igraph_vector_float_null(&dispz);
+    if (conn) {
+      for (v=0; v<no_nodes; v++) {
+	for (u=v+1; u<no_nodes; u++) {
+	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+	  float dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2);
+	  float dlen=dx * dx + dy * dy + dz * dz;
+
+          if (dlen == 0) {
+            dx = RNG_UNIF01() * 1e-9;
+            dy = RNG_UNIF01() * 1e-9;
+            dz = RNG_UNIF01() * 1e-9;
+            dlen = dx * dx + dy * dy + dz * dz;
+          }
+
+	  VECTOR(dispx)[v] += dx/dlen;
+	  VECTOR(dispy)[v] += dy/dlen;
+	  VECTOR(dispz)[v] += dz/dlen;
+	  VECTOR(dispx)[u] -= dx/dlen;
+	  VECTOR(dispy)[u] -= dy/dlen;
+	  VECTOR(dispz)[u] -= dz/dlen;
+	}
+      }
+    } else {
+      for (v=0; v<no_nodes; v++) {
+	for (u=v+1; u<no_nodes; u++) {
+	  float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+	  float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+	  float dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2);
+	  float dlen, rdlen;
+
+	  dlen=dx * dx + dy * dy + dz * dz;
+          if (dlen == 0) {
+            dx = RNG_UNIF01() * 1e-9;
+            dy = RNG_UNIF01() * 1e-9;
+            dz = RNG_UNIF01() * 1e-9;
+            dlen = dx * dx + dy * dy + dz * dz;
+          }
+
+	  rdlen=sqrt(dlen);
+
+	  VECTOR(dispx)[v] += dx * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispy)[v] += dy * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispy)[v] += dz * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispx)[u] -= dx * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispy)[u] -= dy * (C-dlen * rdlen) / (dlen*C);
+	  VECTOR(dispz)[u] -= dz * (C-dlen * rdlen) / (dlen*C);
+	}
+      }
+    }
+
+    /* calculate attractive forces */
+    for (e=0; e<no_edges; e++) {
+      /* each edges is an ordered pair of vertices v and u */
+      igraph_integer_t v=IGRAPH_FROM(graph, e);
+      igraph_integer_t u=IGRAPH_TO(graph, e);
+      igraph_real_t dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+      igraph_real_t dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+      igraph_real_t dz=MATRIX(*res, v, 2) - MATRIX(*res, u, 2);
+      igraph_real_t dlen=sqrt(dx * dx + dy * dy + dz * dz);
+      VECTOR(dispx)[v] -= (dx * dlen);
+      VECTOR(dispy)[v] -= (dy * dlen);
+      VECTOR(dispz)[v] -= (dz * dlen);
+      VECTOR(dispx)[u] += (dx * dlen);
+      VECTOR(dispy)[u] += (dy * dlen);
+      VECTOR(dispz)[u] += (dz * dlen);
+    }
+    
+    /* limit max displacement to temperature t and prevent from
+       displacement outside frame */
+    for (v=0; v<no_nodes; v++) {
+      igraph_real_t dx=VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t dy=VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t dz=VECTOR(dispz)[v] + RNG_UNIF01() * 1e-9;
+      igraph_real_t displen=sqrt(dx * dx + dy * dy + dz * dz);
+      igraph_real_t mx=fabs(dx) < temp ? dx : temp;
+      igraph_real_t my=fabs(dy) < temp ? dy : temp;
+      igraph_real_t mz=fabs(dz) < temp ? dz : temp;
+      if (displen > 0) {
+        MATRIX(*res, v, 0) += (dx / displen) * mx;
+        MATRIX(*res, v, 1) += (dy / displen) * my;
+        MATRIX(*res, v, 2) += (dz / displen) * mz;
+      }
+      if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) { 
+	MATRIX(*res, v, 0) = VECTOR(*minx)[v]; 
+      }
+      if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {
+	MATRIX(*res, v, 0) = VECTOR(*maxx)[v];
+      }
+      if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {
+	MATRIX(*res, v, 1) = VECTOR(*miny)[v];
+      }
+      if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {
+	MATRIX(*res, v, 1) = VECTOR(*maxy)[v];
+      }
+      if (minz && MATRIX(*res, v, 2) < VECTOR(*minz)[v]) {
+	MATRIX(*res, v, 2) = VECTOR(*minz)[v];
+      }
+      if (maxz && MATRIX(*res, v, 2) > VECTOR(*maxz)[v]) {
+	MATRIX(*res, v, 2) = VECTOR(*maxz)[v];
+      }
+    }
+
+    temp -= difftemp;
+  }
+
+  RNG_END();
+
+  igraph_vector_float_destroy(&dispx);
+  igraph_vector_float_destroy(&dispy);
+  igraph_vector_float_destroy(&dispz);
+  IGRAPH_FINALLY_CLEAN(3);
+  
+  return 0;
+}
diff --git a/src/layout_gem.c b/src/layout_gem.c
new file mode 100644
index 0000000..aab6442
--- /dev/null
+++ b/src/layout_gem.c
@@ -0,0 +1,241 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph R package.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_layout.h"
+#include "igraph_interface.h"
+#include "igraph_random.h"
+
+#include <math.h>
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_gem
+ *
+ * The GEM layout algorithm, as described in Arne Frick, Andreas Ludwig,
+ * Heiko Mehldau: A Fast Adaptive Layout Algorithm for Undirected Graphs,
+ * Proc. Graph Drawing 1994, LNCS 894, pp. 388-403, 1995.
+ * \param graph The input graph. Edge directions are ignored in
+ *        directed graphs.
+ * \param res The result is stored here. If the \p use_seed argument
+ *        is true (non-zero), then this matrix is also used as the
+ *        starting point of the algorithm.
+ * \param use_seed Boolean, whether to use the supplied coordinates in
+ *        \p res as the starting point. If false (zero), then a
+ *        uniform random starting point is used.
+ * \param maxiter The maximum number of iterations to
+ *        perform. Updating a single vertex counts as an iteration.
+ *        A reasonable default is 40 * n * n, where n is the number of 
+ *        vertices. The original paper suggests 4 * n * n, but this 
+ *        usually only works if the other parameters are set up carefully.
+ * \param temp_max The maximum allowed local temperature. A reasonable
+ *        default is the number of vertices.
+ * \param temp_min The global temperature at which the algorithm
+ *        terminates (even before reaching \p maxiter iterations). A
+ *        reasonable default is 1/10.
+ * \param temp_init Initial local temperature of all vertices. A
+ *        reasonable default is the square root of the number of
+ *        vertices.
+ * \return Error code.
+ * 
+ * Time complexity: O(t * n * (n+e)), where n is the number of vertices,
+ * e is the number of edges and t is the number of time steps
+ * performed.
+ */
+
+int igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res,
+		      igraph_bool_t use_seed, igraph_integer_t maxiter,
+		      igraph_real_t temp_max, igraph_real_t temp_min,
+		      igraph_real_t temp_init) {
+
+  igraph_integer_t no_nodes = igraph_vcount(graph);
+  igraph_vector_int_t perm;
+  igraph_vector_float_t impulse_x, impulse_y, temp, skew_gauge;
+  igraph_integer_t i;
+  float temp_global;
+  igraph_integer_t perm_pointer = 0;
+  float barycenter_x = 0.0, barycenter_y = 0.0;
+  igraph_vector_t phi;
+  igraph_vector_t neis;
+  const float elen_des2 = 128 * 128;
+  const float gamma = 1/16.0;
+  const float alpha_o = M_PI;
+  const float alpha_r = M_PI / 3.0;
+  const float sigma_o = 1.0 / 3.0;
+  const float sigma_r = 1.0 / 2.0 / no_nodes;
+  
+  if (maxiter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negative in GEM layout",
+		 IGRAPH_EINVAL);
+  }
+  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
+		   igraph_matrix_ncol(res) != 2)) {
+    IGRAPH_ERROR("Invalid start position matrix size in GEM layout",
+		 IGRAPH_EINVAL);
+  }
+  if (temp_max <= 0) {
+    IGRAPH_ERROR("Maximum temperature should be positive in GEM layout",
+		 IGRAPH_EINVAL);
+  }
+  if (temp_min <= 0) {
+    IGRAPH_ERROR("Minimum temperature should be positive in GEM layout",
+		 IGRAPH_EINVAL);
+  }
+  if (temp_init <= 0) {
+    IGRAPH_ERROR("Initial temperature should be positive in GEM layout",
+		 IGRAPH_EINVAL);
+  }
+  if (temp_max < temp_init || temp_init < temp_min) {
+    IGRAPH_ERROR("Minimum <= Initial <= Maximum temperature is required "
+		 "in GEM layout", IGRAPH_EINVAL);
+  }
+
+  if (no_nodes == 0) { return 0; }
+
+  IGRAPH_CHECK(igraph_vector_float_init(&impulse_x, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &impulse_x);
+  IGRAPH_CHECK(igraph_vector_float_init(&impulse_y, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &impulse_y);
+  IGRAPH_CHECK(igraph_vector_float_init(&temp, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &temp);
+  IGRAPH_CHECK(igraph_vector_float_init(&skew_gauge, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_float_destroy, &skew_gauge);
+  IGRAPH_CHECK(igraph_vector_int_init_seq(&perm, 0, no_nodes-1));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &perm);
+  IGRAPH_VECTOR_INIT_FINALLY(&phi, no_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&neis, 10);
+
+  RNG_BEGIN();
+
+  /* Initialization */
+  igraph_degree(graph, &phi, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);
+  if (!use_seed) {
+    const igraph_real_t width_half=no_nodes*100, height_half=width_half;
+    IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
+    for (i=0; i<no_nodes; i++) {
+      MATRIX(*res, i, 0) = RNG_UNIF(-width_half, width_half);
+      MATRIX(*res, i, 1) = RNG_UNIF(-height_half, height_half);
+      barycenter_x += MATRIX(*res, i, 0);
+      barycenter_y += MATRIX(*res, i, 1);
+      VECTOR(phi)[i] *= (VECTOR(phi)[i] / 2.0 + 1.0);
+    }
+  } else {
+    for (i=0; i<no_nodes; i++) {
+      barycenter_x += MATRIX(*res, i, 0);
+      barycenter_y += MATRIX(*res, i, 1);
+      VECTOR(phi)[i] *= (VECTOR(phi)[i] / 2.0 + 1.0);
+    }
+  }
+  igraph_vector_float_fill(&temp, temp_init);
+  temp_global = temp_init * no_nodes;
+  
+  while (temp_global > temp_min * no_nodes && maxiter > 0) {
+    
+    /* choose a vertex v to update */
+    igraph_integer_t u, v, nlen, j;
+    float px, py, pvx, pvy;
+    if (!perm_pointer) { 
+      igraph_vector_int_shuffle(&perm); 
+      perm_pointer=no_nodes-1;
+    }
+    v=VECTOR(perm)[perm_pointer--];
+    
+    /* compute v's impulse */
+    px = (barycenter_x/no_nodes - MATRIX(*res, v, 0)) * gamma * VECTOR(phi)[v];
+    py = (barycenter_y/no_nodes - MATRIX(*res, v, 1)) * gamma * VECTOR(phi)[v];
+    px += RNG_UNIF(-32.0, 32.0);
+    py += RNG_UNIF(-32.0, 32.0);
+
+    for (u = 0; u < no_nodes; u++) {
+      float dx, dy, dist2;
+      if (u == v) { continue; }
+      dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+      dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+      dist2=dx * dx + dy * dy;
+      if (dist2 != 0) {
+	px += dx * elen_des2 / dist2;
+	py += dy * elen_des2 / dist2;
+      }
+    }
+
+    IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL));
+    nlen=igraph_vector_size(&neis);
+    for (j = 0; j < nlen; j++) {
+      igraph_integer_t u=VECTOR(neis)[j];
+      float dx=MATRIX(*res, v, 0) - MATRIX(*res, u, 0);
+      float dy=MATRIX(*res, v, 1) - MATRIX(*res, u, 1);
+      float dist2= dx * dx + dy * dy;
+      px -= dx * dist2 / (elen_des2 * VECTOR(phi)[v]);
+      py -= dy * dist2 / (elen_des2 * VECTOR(phi)[v]);
+    }
+
+    /* update v's position and temperature */
+    if (px != 0 || py != 0) {
+      float plen = sqrtf(px * px + py * py);
+      px *= VECTOR(temp)[v] / plen;
+      py *= VECTOR(temp)[v] / plen;
+      MATRIX(*res, v, 0) += px;
+      MATRIX(*res, v, 1) += py;
+      barycenter_x += px;
+      barycenter_y += py;
+    }
+    
+    pvx=VECTOR(impulse_x)[v]; pvy=VECTOR(impulse_y)[v];
+    if (pvx != 0 || pvy != 0) {
+      float beta = atan2f(pvy - py, pvx - px);
+      float sin_beta = sinf(beta);
+      float sign_sin_beta = (sin_beta > 0) ? 1 : ((sin_beta < 0) ? -1 : 0);
+      float cos_beta = cosf(beta);
+      float abs_cos_beta = fabsf(cos_beta);
+      float old_temp=VECTOR(temp)[v];
+      if (sin(beta) >= sin(M_PI_2 + alpha_r / 2.0)) {
+	VECTOR(skew_gauge)[v] += sigma_r * sign_sin_beta;
+      }
+      if (abs_cos_beta >= cosf(alpha_o / 2.0)) {
+	VECTOR(temp)[v] *= sigma_o * cos_beta;
+      }
+      VECTOR(temp)[v] *= (1 - fabsf(VECTOR(skew_gauge)[v]));
+      if (VECTOR(temp)[v] > temp_max) { VECTOR(temp)[v] = temp_max; }
+      VECTOR(impulse_x)[v] = px;
+      VECTOR(impulse_y)[v] = py;
+      temp_global += VECTOR(temp)[v] - old_temp;
+    }
+
+    maxiter--;
+
+  } /* while temp && iter */
+  
+
+  RNG_END();
+    
+  igraph_vector_destroy(&neis);
+  igraph_vector_destroy(&phi);
+  igraph_vector_int_destroy(&perm);
+  igraph_vector_float_destroy(&skew_gauge);
+  igraph_vector_float_destroy(&temp);
+  igraph_vector_float_destroy(&impulse_y);
+  igraph_vector_float_destroy(&impulse_x);
+  IGRAPH_FINALLY_CLEAN(7);
+  
+  return 0;
+}
diff --git a/src/layout_kk.c b/src/layout_kk.c
new file mode 100644
index 0000000..59ba9ee
--- /dev/null
+++ b/src/layout_kk.c
@@ -0,0 +1,597 @@
+/* -*- mode: C -*-  */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 
+   IGraph R package.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_layout.h"
+#include "igraph_interface.h"
+#include "igraph_paths.h"
+#include "igraph_random.h"
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_kamada_kawai
+ * \brief Places the vertices on a plane according the Kamada-Kawai algorithm. 
+ *
+ * </para><para>
+ * This is a force directed layout, see  Kamada, T. and Kawai, S.: An
+ * Algorithm for Drawing General Undirected Graphs. Information
+ * Processing Letters, 31/1, 7--15, 1989.
+ * \param graph A graph object.
+ * \param res Pointer to an initialized matrix object. This will
+ *        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.
+ * \param maxiter The maximum number of iterations to perform. A reasonable
+ *        default value is at least ten (or more) times the number of 
+ *        vertices.  
+ * \param epsilon Stop the iteration, if the maximum delta value of the 
+ *        algorithm is smaller than still. It is safe to leave it at zero, 
+ *        and then \p maxiter iterations are performed.
+ * \param kkconst The Kamada-Kawai vertex attraction constant.
+ *        Typical value: number of vertices.
+ * \param weights Edge weights, larger values will result longer edges.
+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote x \endquote coordinate for every vertex.
+ * \param maxx Same as \p minx, but the maximum \quote x \endquote 
+ *        coordinates.
+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote y \endquote coordinate for every vertex.
+ * \param maxy Same as \p miny, but the maximum \quote y \endquote 
+ *        coordinates.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|) for each iteration, after an O(|V|^2
+ * log|V|) initialization step. |V| is the number of vertices in the
+ * graph.
+ */
+
+int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res,
+	       igraph_bool_t use_seed, igraph_integer_t maxiter,
+	       igraph_real_t epsilon, igraph_real_t kkconst, 
+	       const igraph_vector_t *weights,
+	       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);
+  igraph_real_t L, L0=sqrt(no_nodes);  
+  igraph_matrix_t dij, lij, kij;
+  igraph_real_t max_dij;
+  igraph_vector_t D1, D2;
+  igraph_integer_t i, j, m;
+
+  if (maxiter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negatice in "
+		 "Kamada-Kawai layout", IGRAPH_EINVAL);
+  }
+  if (kkconst <= 0) {
+    IGRAPH_ERROR("`K' constant must be positive in Kamada-Kawai layout",
+		 IGRAPH_EINVAL);
+  }
+
+  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
+		   igraph_matrix_ncol(res) != 2)) {
+    IGRAPH_ERROR("Invalid start position matrix size in "
+		 "Kamada-Kawai layout", IGRAPH_EINVAL);
+  }
+  if (weights && igraph_vector_size(weights) != no_edges) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (minx && igraph_vector_size(minx) != no_nodes) {
+    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
+  }
+  if (maxx && igraph_vector_size(maxx) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
+  }
+  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
+    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
+  }
+  if (miny && igraph_vector_size(miny) != no_nodes) {
+    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
+  }
+  if (maxy && igraph_vector_size(maxy) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
+  }
+  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
+    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
+  }
+
+  if (!use_seed) {
+    if (minx || maxx || miny || maxy) {
+      const igraph_real_t width=sqrt(no_nodes), height=width;
+      IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));
+      RNG_BEGIN();
+      for (i=0; i<no_nodes; i++) {
+	igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
+	igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
+	igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
+	igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
+	if (!igraph_finite(x1)) { x1 = -width/2; }
+	if (!igraph_finite(x2)) { x2 =  width/2; }
+	if (!igraph_finite(y1)) { y1 = -height/2; }
+	if (!igraph_finite(y2)) { y2 =  height/2; }
+	MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
+	MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
+      }
+      RNG_END();
+    } else {
+      igraph_layout_circle(graph, res, /* order= */ igraph_vss_all());
+    }
+  }
+
+  if (no_nodes <= 1) { return 0; }
+
+  IGRAPH_MATRIX_INIT_FINALLY(&dij, no_nodes, no_nodes);
+  IGRAPH_MATRIX_INIT_FINALLY(&kij, no_nodes, no_nodes);
+  IGRAPH_MATRIX_INIT_FINALLY(&lij, no_nodes, no_nodes);
+
+  if (weights && igraph_vector_min(weights) < 0) {
+    IGRAPH_CHECK(igraph_shortest_paths_bellman_ford(graph, &dij, igraph_vss_all(),
+						    igraph_vss_all(), weights,
+						    IGRAPH_ALL));
+  } else {
+
+    IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, &dij, igraph_vss_all(),
+						igraph_vss_all(), weights,
+						IGRAPH_ALL));
+  }
+  
+  max_dij = 0.0;
+  for (i=0; i<no_nodes; i++) {
+    for (j=i+1; j<no_nodes; j++) {
+      if (!igraph_finite(MATRIX(dij, i, j))) { continue; }
+      if (MATRIX(dij, i, j) > max_dij) { max_dij = MATRIX(dij, i, j); }
+    }
+  }
+  for (i=0; i<no_nodes; i++) {
+    for (j=0; j<no_nodes; j++) {
+      if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; }
+    }
+  }
+
+  L = L0 / max_dij;
+  for (i=0; i<no_nodes; i++) {
+    for (j=0; j<no_nodes; j++) {      
+      igraph_real_t tmp=MATRIX(dij, i, j) * MATRIX(dij, i, j);
+      if (i==j) { continue; }
+      MATRIX(kij, i, j) = kkconst / tmp;
+      MATRIX(lij, i, j) = L * MATRIX(dij, i, j);
+    }
+  }
+
+  /* Initialize delta */
+  IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes);
+  for (m=0; m<no_nodes; m++) {
+    igraph_real_t myD1=0.0, myD2=0.0;
+    for (i=0; i<no_nodes; i++) { 
+      if (i==m) { continue; }
+      igraph_real_t dx=MATRIX(*res, m, 0) - MATRIX(*res, i, 0);
+      igraph_real_t dy=MATRIX(*res, m, 1) - MATRIX(*res, i, 1);
+      igraph_real_t mi_dist=sqrt(dx * dx + dy * dy);
+      myD1 += MATRIX(kij, m, i) * (dx - MATRIX(lij, m, i) * dx / mi_dist);
+      myD2 += MATRIX(kij, m, i) * (dy - MATRIX(lij, m, i) * dy / mi_dist);
+    }
+    VECTOR(D1)[m] = myD1;
+    VECTOR(D2)[m] = myD2;
+  }
+
+  for (j=0; j<maxiter; j++) {
+    
+    igraph_real_t myD1=0.0, myD2=0.0, A=0.0, B=0.0, C=0.0;
+    igraph_real_t max_delta, delta_x, delta_y;
+    igraph_real_t old_x, old_y, new_x, new_y;
+
+    /* Select maximal delta */
+    m=0; max_delta=-1;
+    for (i=0; i<no_nodes; i++) {
+      igraph_real_t delta=(VECTOR(D1)[i] * VECTOR(D1)[i] + 
+			   VECTOR(D2)[i] * VECTOR(D2)[i]);
+      if (delta > max_delta) { 
+	m=i; max_delta=delta;
+      }
+    }
+    if (max_delta < epsilon) { break; }
+    old_x=MATRIX(*res, m, 0);
+    old_y=MATRIX(*res, m, 1);
+    
+    /* Calculate D1 and D2, A, B, C */
+    for (i=0; i<no_nodes; i++) {
+      if (i==m) { continue; }
+      igraph_real_t dx=old_x - MATRIX(*res, i, 0);
+      igraph_real_t dy=old_y - MATRIX(*res, i, 1);
+      igraph_real_t dist=sqrt(dx * dx + dy * dy);
+      igraph_real_t den=dist * (dx * dx + dy * dy);
+      A += MATRIX(kij, m, i) * (1 - MATRIX(lij, m, i) * dy * dy / den);
+      B += MATRIX(kij, m, i) * MATRIX(lij, m, i) * dx * dy / den;
+      C += MATRIX(kij, m, i) * (1 - MATRIX(lij, m, i) * dx * dx / den);
+    }
+    myD1 = VECTOR(D1)[m];
+    myD2 = VECTOR(D2)[m];
+
+    /* Need to solve some linear equations */
+    delta_y = (B * myD1 - myD2 * A) / (C * A - B * B);
+    delta_x = - (myD1 + B * delta_y) / A;
+    
+    new_x = old_x + delta_x;
+    new_y = old_y + delta_y;
+
+    /* Limits, if given */
+    if (minx && new_x < VECTOR(*minx)[m]) { new_x = VECTOR(*minx)[m]; }
+    if (maxx && new_x > VECTOR(*maxx)[m]) { new_x = VECTOR(*maxx)[m]; }
+    if (miny && new_y < VECTOR(*miny)[m]) { new_y = VECTOR(*miny)[m]; }
+    if (maxy && new_y > VECTOR(*maxy)[m]) { new_y = VECTOR(*maxy)[m]; }
+
+    /* Update delta, only with/for the affected node */
+    VECTOR(D1)[m] = VECTOR(D2)[m] = 0.0;
+    for (i=0; i<no_nodes; i++) {
+      if (i==m) { continue; }
+      igraph_real_t old_dx=old_x - MATRIX(*res, i, 0);
+      igraph_real_t old_dy=old_y - MATRIX(*res, i, 1);
+      igraph_real_t old_mi_dist=sqrt(old_dx * old_dx + old_dy * old_dy);
+      igraph_real_t new_dx=new_x - MATRIX(*res, i, 0);
+      igraph_real_t new_dy=new_y - MATRIX(*res, i, 1);
+      igraph_real_t new_mi_dist=sqrt(new_dx * new_dx + new_dy * new_dy);
+
+      VECTOR(D1)[i] -= MATRIX(kij, m, i) * 
+	(-old_dx + MATRIX(lij, m, i) * old_dx / old_mi_dist);
+      VECTOR(D2)[i] -= MATRIX(kij, m, i) *
+	(-old_dy + MATRIX(lij, m, i) * old_dy / old_mi_dist);
+      VECTOR(D1)[i] += MATRIX(kij, m, i) *
+	(-new_dx + MATRIX(lij, m, i) * new_dx / new_mi_dist);
+      VECTOR(D2)[i] += MATRIX(kij, m, i) *
+	(-new_dy + MATRIX(lij, m, i) * new_dy / new_mi_dist);
+
+      VECTOR(D1)[m] += MATRIX(kij, m, i) *
+	(new_dx - MATRIX(lij, m, i) * new_dx / new_mi_dist);
+      VECTOR(D2)[m] += MATRIX(kij, m, i) *
+	(new_dy - MATRIX(lij, m, i) * new_dy / new_mi_dist);
+    }
+      
+    /* Update coordinates*/
+    MATRIX(*res, m, 0) = new_x;
+    MATRIX(*res, m, 1) = new_y;
+  }
+
+  igraph_vector_destroy(&D2);
+  igraph_vector_destroy(&D1);
+  igraph_matrix_destroy(&lij);
+  igraph_matrix_destroy(&kij);
+  igraph_matrix_destroy(&dij);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \ingroup layout
+ * \function igraph_layout_kamada_kawai_3d
+ * \brief 3D version of the Kamada-Kawai layout generator
+ *
+ * </para><para>
+ * This is a force directed layout, see  Kamada, T. and Kawai, S.: An
+ * Algorithm for Drawing General Undirected Graphs. Information
+ * Processing Letters, 31/1, 7--15, 1989.
+ * \param graph A graph object.
+ * \param res Pointer to an initialized matrix object. This will
+ *        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.
+ * \param maxiter The maximum number of iterations to perform. A reasonable
+ *        default value is at least ten (or more) times the number of 
+ *        vertices.  
+ * \param epsilon Stop the iteration, if the maximum delta value of the 
+ *        algorithm is smaller than still. It is safe to leave it at zero, 
+ *        and then \p maxiter iterations are performed.
+ * \param kkconst The Kamada-Kawai vertex attraction constant.
+ *        Typical value: number of vertices.
+ * \param weights Edge weights, larger values will result longer edges.
+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote x \endquote coordinate for every vertex.
+ * \param maxx Same as \p minx, but the maximum \quote x \endquote 
+ *        coordinates.
+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote y \endquote coordinate for every vertex.
+ * \param maxy Same as \p miny, but the maximum \quote y \endquote 
+ *        coordinates.
+ * \param minz Pointer to a vector, or a \c NULL pointer. If not a 
+ *        \c NULL pointer then the vector gives the minimum
+ *        \quote z \endquote coordinate for every vertex.
+ * \param maxz Same as \p minz, but the maximum \quote z \endquote 
+ *        coordinates.
+ * \return Error code.
+ * 
+ * Time complexity: O(|V|) for each iteration, after an O(|V|^2
+ * log|V|) initialization step. |V| is the number of vertices in the
+ * graph.
+ */
+
+int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res,
+	       igraph_bool_t use_seed, igraph_integer_t maxiter,
+	       igraph_real_t epsilon, igraph_real_t kkconst, 
+	       const igraph_vector_t *weights,
+	       const igraph_vector_t *minx, const igraph_vector_t *maxx,
+	       const igraph_vector_t *miny, const igraph_vector_t *maxy,
+	       const igraph_vector_t *minz, const igraph_vector_t *maxz) {
+  
+  igraph_integer_t no_nodes=igraph_vcount(graph);
+  igraph_integer_t no_edges=igraph_ecount(graph);
+  igraph_real_t L, L0=sqrt(no_nodes);  
+  igraph_matrix_t dij, lij, kij;
+  igraph_real_t max_dij;
+  igraph_vector_t D1, D2, D3;
+  igraph_integer_t i, j, m;
+
+  if (maxiter < 0) {
+    IGRAPH_ERROR("Number of iterations must be non-negatice in "
+		 "Kamada-Kawai layout", IGRAPH_EINVAL);
+  }
+  if (kkconst <= 0) {
+    IGRAPH_ERROR("`K' constant must be positive in Kamada-Kawai layout",
+		 IGRAPH_EINVAL);
+  }
+
+  if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||
+		   igraph_matrix_ncol(res) != 3)) {
+    IGRAPH_ERROR("Invalid start position matrix size in "
+		 "3d Kamada-Kawai layout", IGRAPH_EINVAL);
+  }
+  if (weights && igraph_vector_size(weights) != no_edges) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  if (minx && igraph_vector_size(minx) != no_nodes) {
+    IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);
+  }
+  if (maxx && igraph_vector_size(maxx) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);
+  }
+  if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {
+    IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);
+  }
+  if (miny && igraph_vector_size(miny) != no_nodes) {
+    IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);
+  }
+  if (maxy && igraph_vector_size(maxy) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);
+  }
+  if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {
+    IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);
+  }
+  if (minz && igraph_vector_size(minz) != no_nodes) {
+    IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);
+  }
+  if (maxz && igraph_vector_size(maxz) != no_nodes) {
+    IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);
+  }
+  if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {
+    IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);
+  }
+
+  if (!use_seed) {
+    if (minx || maxx || miny || maxy || minz || maxz) {
+      const igraph_real_t width=sqrt(no_nodes), height=width, depth=width;
+      IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3));
+      RNG_BEGIN();
+      for (i=0; i<no_nodes; i++) {
+	igraph_real_t x1=minx ? VECTOR(*minx)[i] : -width/2;
+	igraph_real_t x2=maxx ? VECTOR(*maxx)[i] :  width/2;
+	igraph_real_t y1=miny ? VECTOR(*miny)[i] : -height/2;
+	igraph_real_t y2=maxy ? VECTOR(*maxy)[i] :  height/2;
+	igraph_real_t z1=minz ? VECTOR(*minz)[i] : -depth/2;
+	igraph_real_t z2=maxz ? VECTOR(*maxz)[i] :  depth/2;
+	if (!igraph_finite(x1)) { x1 = -width/2; }
+	if (!igraph_finite(x2)) { x2 =  width/2; }
+	if (!igraph_finite(y1)) { y1 = -height/2; }
+	if (!igraph_finite(y2)) { y2 =  height/2; }
+	if (!igraph_finite(z1)) { z1 = -depth/2; }
+	if (!igraph_finite(z2)) { z2 =  depth/2; }
+	MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);
+	MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);
+	MATRIX(*res, i, 2) = RNG_UNIF(z1, z2);
+      }
+      RNG_END();
+    } else {
+      igraph_layout_sphere(graph, res);
+    }
+  }
+
+  if (no_nodes <= 1) { return 0; }
+
+  IGRAPH_MATRIX_INIT_FINALLY(&dij, no_nodes, no_nodes);
+  IGRAPH_MATRIX_INIT_FINALLY(&kij, no_nodes, no_nodes);
+  IGRAPH_MATRIX_INIT_FINALLY(&lij, no_nodes, no_nodes);
+  IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, &dij, igraph_vss_all(),
+					      igraph_vss_all(), weights,
+					      IGRAPH_ALL));
+  
+  max_dij = 0.0;
+  for (i=0; i<no_nodes; i++) {
+    for (j=i+1; j<no_nodes; j++) {
+      if (!igraph_finite(MATRIX(dij, i, j))) { continue; }
+      if (MATRIX(dij, i, j) > max_dij) { max_dij = MATRIX(dij, i, j); }
+    }
+  }
+  for (i=0; i<no_nodes; i++) {
+    for (j=0; j<no_nodes; j++) {
+      if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; }
+    }
+  }
+
+  L = L0 / max_dij;
+  for (i=0; i<no_nodes; i++) {
+    for (j=0; j<no_nodes; j++) {      
+      igraph_real_t tmp=MATRIX(dij, i, j) * MATRIX(dij, i, j);
+      if (i==j) { continue; }
+      MATRIX(kij, i, j) = kkconst / tmp;
+      MATRIX(lij, i, j) = L * MATRIX(dij, i, j);
+    }
+  }
+
+  /* Initialize delta */
+  IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes);
+  IGRAPH_VECTOR_INIT_FINALLY(&D3, no_nodes);
+  for (m=0; m<no_nodes; m++) {
+    igraph_real_t myD1=0.0, myD2=0.0, myD3=0.0;
+    for (i=0; i<no_nodes; i++) { 
+      if (i==m) { continue; }
+      igraph_real_t dx=MATRIX(*res, m, 0) - MATRIX(*res, i, 0);
+      igraph_real_t dy=MATRIX(*res, m, 1) - MATRIX(*res, i, 1);
+      igraph_real_t dz=MATRIX(*res, m, 2) - MATRIX(*res, i, 2);
+      igraph_real_t mi_dist=sqrt(dx * dx + dy * dy + dz * dz);
+      myD1 += MATRIX(kij, m, i) * (dx - MATRIX(lij, m, i) * dx / mi_dist);
+      myD2 += MATRIX(kij, m, i) * (dy - MATRIX(lij, m, i) * dy / mi_dist);
+      myD3 += MATRIX(kij, m, i) * (dz - MATRIX(lij, m, i) * dz / mi_dist);
+    }
+    VECTOR(D1)[m] = myD1;
+    VECTOR(D2)[m] = myD2;
+    VECTOR(D3)[m] = myD3;
+  }
+
+  for (j=0; j<maxiter; j++) {
+    
+    igraph_real_t Ax=0.0, Ay=0.0, Az=0.0;
+    igraph_real_t Axx=0.0, Axy=0.0, Axz=0.0, Ayy=0.0, Ayz=0.0, Azz=0.0;
+    igraph_real_t max_delta, delta_x, delta_y, delta_z;
+    igraph_real_t old_x, old_y, old_z, new_x, new_y, new_z;
+    igraph_real_t detnum;
+
+    /* Select maximal delta */
+    m=0; max_delta=-1;
+    for (i=0; i<no_nodes; i++) {
+      igraph_real_t delta=(VECTOR(D1)[i] * VECTOR(D1)[i] + 
+			   VECTOR(D2)[i] * VECTOR(D2)[i] +
+			   VECTOR(D3)[i] * VECTOR(D3)[i]);
+      if (delta > max_delta) { 
+	m=i; max_delta=delta;
+      }
+    }
+    if (max_delta < epsilon) { break; }
+    old_x=MATRIX(*res, m, 0);
+    old_y=MATRIX(*res, m, 1);
+    old_z=MATRIX(*res, m, 2);
+    
+    /* Calculate D1, D2 and D3, and other coefficients */
+    for (i=0; i<no_nodes; i++) {
+      if (i==m) { continue; }
+      igraph_real_t dx=old_x - MATRIX(*res, i, 0);
+      igraph_real_t dy=old_y - MATRIX(*res, i, 1);
+      igraph_real_t dz=old_z - MATRIX(*res, i, 2);
+      igraph_real_t dist=sqrt(dx * dx + dy * dy + dz *dz);
+      igraph_real_t den=dist * (dx * dx + dy * dy + dz * dz);
+      igraph_real_t k_mi=MATRIX(kij, m, i);
+      igraph_real_t l_mi=MATRIX(lij, m, i);
+      Axx += k_mi * (1 - l_mi * (dy*dy + dz*dz) / den);
+      Ayy += k_mi * (1 - l_mi * (dx*dx + dz*dz) / den);
+      Azz += k_mi * (1 - l_mi * (dx*dx + dy*dy) / den);
+      Axy += k_mi * l_mi * dx * dy / den;
+      Axz += k_mi * l_mi * dx * dz / den;
+      Ayz += k_mi * l_mi * dy * dz / den;
+    }
+    Ax = -VECTOR(D1)[m];
+    Ay = -VECTOR(D2)[m];
+    Az = -VECTOR(D3)[m];
+
+    /* Need to solve some linear equations, we just use Cramer's rule */
+#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;
+    
+    new_x = old_x + delta_x;
+    new_y = old_y + delta_y;
+    new_z = old_z + delta_z;
+
+    /* Limits, if given */
+    if (minx && new_x < VECTOR(*minx)[m]) { new_x = VECTOR(*minx)[m]; }
+    if (maxx && new_x > VECTOR(*maxx)[m]) { new_x = VECTOR(*maxx)[m]; }
+    if (miny && new_y < VECTOR(*miny)[m]) { new_y = VECTOR(*miny)[m]; }
+    if (maxy && new_y > VECTOR(*maxy)[m]) { new_y = VECTOR(*maxy)[m]; }
+    if (minz && new_z < VECTOR(*minz)[m]) { new_z = VECTOR(*minz)[m]; }
+    if (maxz && new_z > VECTOR(*maxz)[m]) { new_z = VECTOR(*maxz)[m]; }
+
+    /* Update delta, only with/for the affected node */
+    VECTOR(D1)[m] = VECTOR(D2)[m] = VECTOR(D3)[m] = 0.0;
+    for (i=0; i<no_nodes; i++) {
+      if (i==m) { continue; }
+      igraph_real_t old_dx=old_x - MATRIX(*res, i, 0);
+      igraph_real_t old_dy=old_y - MATRIX(*res, i, 1);
+      igraph_real_t old_dz=old_z - MATRIX(*res, i, 2);
+      igraph_real_t old_mi_dist=sqrt(old_dx * old_dx + old_dy * old_dy + 
+				     old_dz * old_dz);
+      igraph_real_t new_dx=new_x - MATRIX(*res, i, 0);
+      igraph_real_t new_dy=new_y - MATRIX(*res, i, 1);
+      igraph_real_t new_dz=new_z - MATRIX(*res, i, 2);
+      igraph_real_t new_mi_dist=sqrt(new_dx * new_dx + new_dy * new_dy +
+				     new_dz * new_dz);
+
+      VECTOR(D1)[i] -= MATRIX(kij, m, i) * 
+	(-old_dx + MATRIX(lij, m, i) * old_dx / old_mi_dist);
+      VECTOR(D2)[i] -= MATRIX(kij, m, i) *
+	(-old_dy + MATRIX(lij, m, i) * old_dy / old_mi_dist);
+      VECTOR(D3)[i] -= MATRIX(kij, m, i) *
+	(-old_dz + MATRIX(lij, m, i) * old_dz / old_mi_dist);
+
+      VECTOR(D1)[i] += MATRIX(kij, m, i) *
+	(-new_dx + MATRIX(lij, m, i) * new_dx / new_mi_dist);
+      VECTOR(D2)[i] += MATRIX(kij, m, i) *
+	(-new_dy + MATRIX(lij, m, i) * new_dy / new_mi_dist);
+      VECTOR(D3)[i] += MATRIX(kij, m, i) *
+	(-new_dz + MATRIX(lij, m, i) * new_dz / new_mi_dist);
+
+      VECTOR(D1)[m] += MATRIX(kij, m, i) *
+	(new_dx - MATRIX(lij, m, i) * new_dx / new_mi_dist);
+      VECTOR(D2)[m] += MATRIX(kij, m, i) *
+	(new_dy - MATRIX(lij, m, i) * new_dy / new_mi_dist);
+      VECTOR(D3)[m] += MATRIX(kij, m, i) *
+	(new_dz - MATRIX(lij, m, i) * new_dz / new_mi_dist);
+    }
+      
+    /* Update coordinates*/
+    MATRIX(*res, m, 0) = new_x;
+    MATRIX(*res, m, 1) = new_y;
+    MATRIX(*res, m, 2) = new_z;
+  }
+
+  igraph_vector_destroy(&D3);
+  igraph_vector_destroy(&D2);
+  igraph_vector_destroy(&D1);
+  igraph_matrix_destroy(&lij);
+  igraph_matrix_destroy(&kij);
+  igraph_matrix_destroy(&dij);
+  IGRAPH_FINALLY_CLEAN(6);
+
+  return 0;
+}
diff --git a/src/lazyeval.c b/src/lazyeval.c
new file mode 100644
index 0000000..f5961c1
--- /dev/null
+++ b/src/lazyeval.c
@@ -0,0 +1,173 @@
+#include <R.h>
+#include <Rdefines.h>
+
+SEXP promise_as_lazy(SEXP promise, SEXP env, int follow_symbols) {
+  // recurse until we find the real promise, not a promise of a promise
+  // never go past the global environment
+  while(TYPEOF(promise) == PROMSXP && env != R_GlobalEnv) {
+
+    env = PRENV(promise);
+    promise = PREXPR(promise);
+
+    // If the promise is threaded through multiple functions, we'll
+    // get some symbols along the way. If the symbol is bound to a promise
+    // keep going on up
+    if (follow_symbols && TYPEOF(promise) == SYMSXP) {
+      SEXP obj = findVar(promise, env);
+      if (TYPEOF(obj) == PROMSXP) {
+        promise = obj;
+      }
+    }
+  }
+
+  // Make named list for output
+  SEXP lazy = PROTECT(allocVector(VECSXP, 2));
+  SET_VECTOR_ELT(lazy, 0, promise);
+  SET_VECTOR_ELT(lazy, 1, env);
+
+  SEXP names = PROTECT(allocVector(STRSXP, 2));
+  SET_STRING_ELT(names, 0, mkChar("expr"));
+  SET_STRING_ELT(names, 1, mkChar("env"));
+
+  setAttrib(lazy, install("names"), names);
+  setAttrib(lazy, install("class"), PROTECT(mkString("lazy")));
+
+  UNPROTECT(3);
+
+  return lazy;
+}
+
+SEXP make_lazy(SEXP name, SEXP env, SEXP follow_symbols_) {
+  SEXP promise = findVar(name, env);
+  int follow_symbols = asLogical(follow_symbols_);
+
+  return promise_as_lazy(promise, env, follow_symbols);
+}
+
+SEXP make_lazy_dots(SEXP env, SEXP follow_symbols_) {
+  SEXP dots = findVar(install("..."), env);
+  int follow_symbols = asLogical(follow_symbols_);
+
+  // Figure out how many elements in dots
+  int n = 0;
+  for(SEXP nxt = dots; nxt != R_NilValue; nxt = CDR(nxt)) {
+    n++;
+  }
+
+  // Allocate list to store results
+  SEXP lazy_dots = PROTECT(allocVector(VECSXP, n));
+  SEXP names = PROTECT(allocVector(STRSXP, n));
+
+  // Iterate through all elements of dots, converting promises into lazy exprs
+  int i = 0;
+  SEXP nxt = dots;
+  while(nxt != R_NilValue) {
+    SEXP promise = CAR(nxt);
+
+    SEXP lazy = promise_as_lazy(promise, env, follow_symbols);
+    SET_VECTOR_ELT(lazy_dots, i, lazy);
+    if (TAG(nxt) != R_NilValue)
+      SET_STRING_ELT(names, i, PRINTNAME(TAG(nxt)));
+
+    nxt = CDR(nxt);
+    i++;
+  }
+  setAttrib(lazy_dots, install("names"), names);
+  setAttrib(lazy_dots, install("class"), PROTECT(mkString("lazy_dots")));
+
+  UNPROTECT(3);
+
+  return lazy_dots;
+}
+#define USE_RINTERNALS
+#include <R.h>
+#include <Rdefines.h>
+
+/* For now, replace with pure R alternative ------------------------------------
+
+// This is a bit naughty, but there's no other way to create a promise
+SEXP Rf_mkPROMISE(SEXP, SEXP);
+SEXP Rf_installTrChar(SEXP);
+
+SEXP lazy_to_promise(SEXP x) {
+  // arg is a list of length 2 - LANGSXP/SYMSXP, followed by ENVSXP
+  return Rf_mkPROMISE(VECTOR_ELT(x, 0), VECTOR_ELT(x, 1));
+}
+
+SEXP eval_call_(SEXP fun, SEXP dots, SEXP env) {
+  if (TYPEOF(fun) != SYMSXP && TYPEOF(fun) != LANGSXP) {
+    error("fun must be a call or a symbol");
+  }
+  if (TYPEOF(dots) != VECSXP) {
+    error("dots must be a list");
+  }
+  if (!inherits(dots, "lazy_dots")) {
+    error("dots must be of class lazy_dots");
+  }
+  if (TYPEOF(env) != ENVSXP) {
+    error("env must be an environment");
+  }
+
+  int n = length(dots);
+  if (n == 0) {
+    return LCONS(fun, R_NilValue);
+  }
+
+  SEXP names = GET_NAMES(dots);
+
+  SEXP args = R_NilValue;
+  for (int i = n - 1; i >= 0; --i) {
+    SEXP dot = VECTOR_ELT(dots, i);
+    SEXP prom = lazy_to_promise(dot);
+    args = PROTECT(CONS(prom, args));
+    if (names != R_NilValue) {
+      SEXP name = STRING_ELT(names, i);
+      if (strlen(CHAR(name)) > 0)
+        SET_TAG(args, Rf_installTrChar(name));
+    }
+  }
+  UNPROTECT(n);
+
+  SEXP call = LCONS(fun, args);
+
+  return eval(call, env);
+}
+
+*/
+#define USE_RINTERNALS
+#include <R.h>
+#include <Rdefines.h>
+
+/* Fails on Linux --------------------------------------------------------------
+
+SEXP Rf_mkPROMISE(SEXP, SEXP);
+
+SEXP promise_(SEXP expr, SEXP env) {
+  if (TYPEOF(expr) != SYMSXP && TYPEOF(expr) != LANGSXP) {
+    error("expr must be a call or a symbol");
+  }
+  if (TYPEOF(env) != ENVSXP) {
+    error("env must be an environment");
+  }
+
+  return Rf_mkPROMISE(expr, env);
+}
+
+*/
+
+SEXP promise_expr_(SEXP prom) {
+  if (TYPEOF(prom) != PROMSXP) {
+    error("prom must be a promise");
+  }
+
+  return PREXPR(prom);
+}
+
+SEXP promise_env_(SEXP prom) {
+  if (TYPEOF(prom) != PROMSXP) {
+    error("prom must be a promise");
+  }
+
+  return PRENV(prom);
+}
+
diff --git a/src/lsap.c b/src/lsap.c
new file mode 100644
index 0000000..74296b9
--- /dev/null
+++ b/src/lsap.c
@@ -0,0 +1,614 @@
+
+#include "igraph_lsap.h"
+#include "igraph_error.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 */
+
+#define COVERED       1
+#define UNCOVERED     0
+#define ASSIGNED      1
+#define UNASSIGNED    0
+#define TRUE          1
+#define FALSE         0
+
+#define MARKED        1
+#define UNMARKED      0
+
+#define REDUCE        1
+#define NOREDUCE      0
+
+typedef struct{
+  int        n;            /* order of problem             */
+  double   **C;            /* cost matrix		   */
+  double   **c;            /* reduced cost matrix	   */
+  int       *s;            /* assignment                   */
+  int       *f;            /* column i is assigned to f[i] */
+  int       na;            /* number of assigned items;	   */
+  int     runs;            /* number of iterations	   */
+  double  cost;            /* minimum cost		   */
+  time_t rtime;            /* time                         */
+} AP;
+
+/* 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);
+
+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);
+
+/* error reporting */
+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);
+
+int ap_hungarian(AP *p)
+{
+    int      n;            /* size of problem */
+    int    *ri;            /* covered rows    */
+    int    *ci;            /* covered columns */
+    time_t start, end;     /* timer           */ 
+    int i, j, ok;
+
+    start = time(0);
+
+    n = p->n;
+    p->runs = 0;
+
+    /* allocate memory */
+    p->s = calloc(1 + n, sizeof(int));
+    p->f = calloc(1 + n, sizeof(int));
+    
+    ri = calloc(1 + n, sizeof(int));
+    ci = calloc(1 + n, sizeof(int));
+    
+    if(ri == NULL || ci == NULL || p->s == NULL || p->f == NULL)
+      IGRAPH_ERROR("ap_hungarian: could not allocate memory", IGRAPH_ENOMEM);   
+
+    preprocess(p);
+    preassign(p);
+
+    while(p->na < n){
+	if(REDUCE == cover(p, ri, ci))
+	    reduce(p, ri, ci);
+	++p->runs;
+    }
+
+    end = time(0);  
+  
+    p->rtime = end - start;
+  
+    /* check if assignment is a permutation of (1..n) */
+    for(i = 1; i <= n; i++){
+	ok = 0;
+	for(j = 1; j <= n; j++)
+	    if(p->s[j] == i)
+		++ok;
+	if(ok != 1)
+	  IGRAPH_ERROR("ap_hungarian: error in assigment, is not a permutation",
+		       IGRAPH_EINVAL);
+    }
+
+    /* calculate cost of assignment */
+    p->cost = 0;
+    for(i = 1; i <= n; i++)
+	p->cost+= p->C[i][p->s[i]];
+    
+    /* reset result back to base-0 indexing */
+    for(i = 1; i <= n; i++)
+	p->s[i - 1] = p->s[i] - 1;
+    
+    /* free memory */
+    
+    free(ri);
+    free(ci);
+
+    return 0;
+}
+
+/* abbreviated interface */
+int ap_assignment(AP *p, int *res)
+{
+    int i;
+
+    if(p->s == NULL)
+	ap_hungarian(p);
+
+    for(i = 0; i < p->n; i++)
+	res[i] = p->s[i];
+    
+    return p->n;
+}
+
+
+/*******************************************************************/
+/* constructors                                                    */
+/* read data from file                                             */
+/*******************************************************************/
+
+AP *ap_read_problem(char *file)
+{
+    FILE *f;
+    int i,j,c;
+    int m,n;
+    double x;
+    double **t;
+    int nrow,ncol;
+    AP *p;
+    
+    f = fopen(file,"r");
+    if(f==NULL)
+	return NULL;
+    
+    t = (double **)malloc(sizeof(double*));
+
+    m = 0; 
+    n = 0;  
+
+    nrow = 0;
+    ncol = 0;
+
+    while(EOF != (i = fscanf(f, "%lf", &x))){
+	if(i == 1){
+	    if(n == 0){
+		t = (double **) realloc(t,(m + 1) * sizeof(double *));
+		t[m] = (double *) malloc(sizeof(double));
+	    }else
+		t[m] = (double *) realloc(t[m], (n + 1) * sizeof(double));
+	    
+	    t[m][n++] = x;
+	    
+	    ncol = (ncol < n) ? n : ncol;
+	    c=fgetc(f);
+	    if(c == '\n'){
+		n = 0;
+		++m;
+		nrow = (nrow < m) ? m : nrow;
+	    }
+	}
+    }
+    fclose(f);
+
+    /* prepare data */
+    
+    if(nrow != ncol){
+	/*
+	  fprintf(stderr,"ap_read_problem: problem not quadratic\nrows =%d, cols = %d\n",nrow,ncol);
+	*/
+	igraph_warningf("ap_read_problem: problem not quadratic\nrows = %d, cols = %d\n",
+			__FILE__, __LINE__, -1, nrow, ncol);
+	return NULL;
+    }
+
+    p = (AP*) malloc(sizeof(AP)); 
+    p->n = ncol;
+    
+    p->C  = (double **) malloc((1 + nrow)*sizeof(double *));
+    p->c  = (double **) malloc((1 + nrow)*sizeof(double *));
+    if(p->C == NULL || p->c == NULL)
+	return NULL;
+    
+    for(i = 1; i <= nrow; i++){
+	p->C[i] = (double *) calloc(ncol + 1, sizeof(double));
+	p->c[i] = (double *) calloc(ncol + 1, sizeof(double));
+	if(p->C[i] == NULL || p->c[i] == NULL)
+	    return NULL;
+    }
+
+    for(i = 1; i <= nrow; i++)
+	for( j = 1; j <= ncol; j++){
+	    p->C[i][j] = t[i-1][j-1];
+	    p->c[i][j] = t[i-1][j-1];
+	}
+    
+    for(i = 0; i < nrow; i++)
+	free(t[i]);
+    free(t);
+    
+    p->cost = 0;
+    p->s = NULL;
+    p->f = NULL;
+    return p;
+}
+
+AP     *ap_create_problem_from_matrix(double **t, int n)
+{
+    int i,j;
+    AP *p;
+
+    p = (AP*) malloc(sizeof(AP)); 
+    if(p == NULL)
+	return NULL;
+    
+    p->n = n;
+    
+    p->C  = (double **) malloc((n + 1) * sizeof(double *));
+    p->c  = (double **) malloc((n + 1) * sizeof(double *));
+    if(p->C == NULL || p->c == NULL)
+	return NULL;
+
+    for(i = 1; i <= n; i++){
+	p->C[i] = (double *) calloc(n + 1, sizeof(double));
+	p->c[i] = (double *) calloc(n + 1, sizeof(double));
+	if(p->C[i] == NULL || p->c[i] == NULL)
+	    return NULL;
+    }
+
+
+    for(i = 1; i <= n; i++)
+	for( j = 1; j <= n; j++){
+	    p->C[i][j] = t[i-1][j-1];
+	    p->c[i][j] = t[i-1][j-1];
+	}
+    p->cost = 0;
+    p->s = NULL;
+    p->f = NULL;
+    return p;
+}
+
+/* read data from vector */
+AP *ap_create_problem(double *t, int n)
+{
+    int i,j;
+    AP *p;
+    
+    p = (AP*) malloc(sizeof(AP)); 
+    if(p == NULL)
+	return NULL;
+    
+    p->n = n;
+
+    p->C  = (double **) malloc((n + 1) * sizeof(double *));
+    p->c  = (double **) malloc((n + 1) * sizeof(double *));
+    if(p->C == NULL || p->c == NULL)
+	return NULL;
+    
+    for(i = 1; i <= n; i++){
+	p->C[i] = (double *) calloc(n + 1, sizeof(double));
+	p->c[i] = (double *) calloc(n + 1, sizeof(double));
+	if(p->C[i] == NULL || p->c[i] == NULL)
+	    return NULL;
+    }
+    
+    
+    for(i = 1; i <= n; i++)
+	for( j = 1; j <= n; j++){
+	    p->C[i][j] = t[n*(j - 1) + i - 1];
+	    p->c[i][j] = t[n*(j - 1) + i - 1];
+	}
+    p->cost = 0;
+    p->s = NULL;
+    p->f = NULL;
+    return p;
+}
+
+/* destructor */
+void ap_free(AP *p)
+{
+    int i;
+
+    free(p->s);
+    free(p->f);
+
+    for(i = 1; i <= p->n; i++){
+	free(p->C[i]);
+	free(p->c[i]);
+    }
+    
+    free(p->C);
+    free(p->c);
+    free(p);
+}
+
+/* set + get functions */
+
+/*
+void ap_show_data(AP *p)
+{
+    int i, j;
+  
+    for(i = 1; i <= p->n; i++){
+	for(j = 1; j <= p->n; j++)
+	    printf("%6.2f ", p->c[i][j]);
+	printf("\n");
+    }
+}
+*/
+
+double ap_mincost(AP *p)
+{
+    if(p->s == NULL)
+	ap_hungarian(p);
+    
+    return p->cost;
+}
+
+int ap_size(AP *p)
+{
+    return p->n;
+}
+
+int ap_time(AP *p)
+{
+    return (int) p->rtime; 
+}
+
+int ap_iterations(AP *p)
+{
+    return p->runs; 
+}
+
+/*
+void ap_print_solution(AP *p)
+{
+    int i;
+    
+    printf("%d itertations, %d secs.\n",p->runs, (int)p->rtime);
+    printf("Min Cost: %10.4f\n",p->cost);
+    
+    for(i = 0; i < p->n; i++)
+	printf("%4d",p->s[i]);
+    printf("\n");
+}
+*/
+
+int ap_costmatrix(AP *p, double **m)
+{
+    int i,j;
+  
+    for(i = 0; i < p->n; i++)
+	for(j = 0; j < p->n; j++)
+	    m[i][j] = p->C[i + 1][j + 1];
+    
+    return p->n;
+}
+
+int ap_datamatrix(AP *p, double **m)
+{
+    int i,j;
+  
+    for(i = 0; i < p->n; i++)
+	for(j = 0; j < p->n; j++)
+	    m[i][j] = p->c[i + 1][j + 1];
+    
+    return p->n;
+}
+
+/* error reporting */
+
+/*
+void ap_error(char *message)
+{
+    fprintf(stderr,"%s\n",message);
+    exit(1);
+}
+*/
+
+/*************************************************************/
+/* these functions are used internally                       */
+/* by ap_hungarian                                           */
+/*************************************************************/
+
+int cover(AP *p, int *ri, int *ci)
+{
+    int *mr, i, r;
+    int n;
+    
+    n = p->n;
+    mr = calloc(1 + p->n, sizeof(int));
+    
+    /* reset cover indices */
+    for(i = 1; i <= n; i++){
+	if(p->s[i] == UNASSIGNED){
+	    ri[i] = UNCOVERED;
+	    mr[i] = MARKED;
+	}
+	else
+	    ri[i] = COVERED;
+	ci[i] = UNCOVERED;
+    }
+
+    while(TRUE){
+	/* find marked row */
+	r = 0;
+	for(i = 1; i <= n; i++)
+	    if(mr[i] == MARKED){
+		r = i;
+		break;
+	    }
+
+	if(r == 0)
+	    break;
+	for(i = 1; i <= n; i++)
+	    if(p->c[r][i] == 0 && ci[i] == UNCOVERED){
+		if(p->f[i]){
+		    ri[p->f[i]] = UNCOVERED;
+		    mr[p->f[i]] = MARKED;
+		    ci[i] = COVERED;
+		}else{
+		    if(p->s[r] == UNASSIGNED)
+			++p->na;
+		    
+		    p->f[p->s[r]] = 0;
+		    p->f[i] = r;
+		    p->s[r] = i;
+		    
+		    free(mr);
+		    return NOREDUCE;
+		}
+	    }
+	mr[r] = UNMARKED;
+    }
+    free(mr);
+    return REDUCE;
+}
+
+void reduce(AP *p, int *ri, int *ci)
+{
+    int i, j, n;
+    double min;
+    
+    n = p->n;
+    
+    /* find minimum in uncovered c-matrix */
+    min = DBL_MAX;
+    for(i = 1; i <= n; i++)
+	for(j = 1; j <= n; j++)
+	    if(ri[i] == UNCOVERED && ci[j] == UNCOVERED){
+		if(p->c[i][j] < min)
+		    min = p->c[i][j];
+	    }
+    
+    /* subtract min from each uncovered element and add it to each element */
+    /* which is covered twice                                              */
+    for(i = 1; i <= n; i++)
+	for(j = 1; j <= n; j++){
+	    if(ri[i] == UNCOVERED && ci[j] == UNCOVERED)
+		p->c[i][j]-= min;
+	    if(ri[i] == COVERED && ci[j] == COVERED)
+		p->c[i][j]+= min;
+	}
+}
+
+void preassign(AP *p)
+{
+    int i, j, min, r, c, n, count;
+    int *ri, *ci, *rz, *cz;
+    
+    n = p->n;
+    p->na = 0;
+    
+    /* row and column markers */
+    ri = calloc(1 + n, sizeof(int));
+    ci = calloc(1 + n, sizeof(int));
+    
+    /* row and column counts of zeroes */
+    rz = calloc(1 + n, sizeof(int));
+    cz = calloc(1 + n, sizeof(int));
+    
+    for(i = 1; i <= n; i++){
+	count = 0;
+	for(j = 1; j <= n; j++)
+	    if(p->c[i][j] == 0)
+		++count;
+	rz[i] = count;
+    }
+    
+    for(i = 1; i <= n; i++){
+	count = 0;
+	for(j = 1; j <= n; j++)
+	    if(p->c[j][i] == 0)
+		++count;
+	cz[i] = count;
+    }
+    
+    while(TRUE){
+	/* find unassigned row with least number of zeroes > 0 */
+	min = INT_MAX;
+	r = 0;
+	for(i = 1; i <= n; i++)
+	    if(rz[i] > 0 && rz[i] < min && ri[i] == UNASSIGNED){
+		min = rz[i];
+		r = i;
+	    }
+	/* check if we are done */
+	if(r == 0)
+	    break;
+	
+	/* find unassigned column in row r with least number of zeroes */
+	c = 0;
+	min = INT_MAX;
+	for(i = 1; i <= n; i++)
+	    if(p->c[r][i] == 0 && cz[i] < min && ci[i] == UNASSIGNED){
+		min = cz[i];
+		c = i;
+	    }
+	
+	if(c){
+	    ++p->na;
+	    p->s[r] = c;
+	    p->f[c] = r;
+	    
+	    ri[r] = ASSIGNED;
+	    ci[c] = ASSIGNED;
+	    
+	    /* adjust zero counts */
+	    cz[c] = 0;
+	    for(i = 1; i <= n; i++)
+		if(p->c[i][c] == 0)
+		    --rz[i];
+	}
+    }
+    
+    /* free memory */
+    free(ri);
+    free(ci);
+    free(rz);
+    free(cz);
+}
+  
+void preprocess(AP *p)
+{
+    int i, j, n;
+    double min;
+    
+    n = p->n;
+    
+    /* subtract column minima in each row */
+    for(i = 1; i <= n; i++){
+	min = p->c[i][1];
+	for(j = 2; j <= n; j++)
+	    if(p->c[i][j] < min)
+		min = p->c[i][j];
+	for(j = 1; j <= n; j++)
+	    p->c[i][j]-= min;
+    }
+    
+    /* subtract row minima in each column */
+    for(i = 1; i <= n; i++){
+	min = p->c[1][i];
+	for(j = 2; j <= n; j++)
+	    if(p->c[j][i] < min)
+		min = p->c[j][i];
+	for(j = 1; j <= n; j++)
+	    p->c[j][i]-= min;
+    }
+}
+
+int igraph_solve_lsap(igraph_matrix_t *c, igraph_integer_t n,
+		      igraph_vector_int_t *p) {
+  AP *ap;
+
+  IGRAPH_CHECK(igraph_vector_int_resize(p, n));
+  igraph_vector_int_null(p);
+  
+  ap = ap_create_problem(&MATRIX(*c, 0, 0), n);
+  ap_hungarian(ap);
+  ap_assignment(ap, VECTOR(*p));
+  ap_free(ap);
+
+  return 0;
+}
diff --git a/src/matching.c b/src/matching.c
index 840340d..ace6aa2 100644
--- a/src/matching.c
+++ b/src/matching.c
@@ -537,7 +537,7 @@ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
   igraph_real_t dual;               /* solution of the dual problem */
   igraph_adjlist_t tight_phantom_edges; /* adjacency list to manage tight phantom edges */
   igraph_integer_t alternating_path_endpoint;
-  igraph_vector_t* neis;
+  igraph_vector_int_t* neis;
   igraph_vector_int_t *neis2;
   igraph_inclist_t inclist;         /* incidence list of the original graph */ 
 
@@ -593,7 +593,7 @@ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
     }
 
     neis = igraph_inclist_get(&inclist, i);
-    n = igraph_vector_size(neis);
+    n = igraph_vector_int_size(neis);
     for (j = 0, k = 0; j < n; j++) {
       if (VECTOR(*weights)[(long int)VECTOR(*neis)[j]] > max_weight) {
         k = (long int) VECTOR(*neis)[j];
@@ -674,7 +674,7 @@ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
        * (ab)use an adjacency list data structure that lists the
        * vertices connected to v by phantom edges only. */
       neis = igraph_inclist_get(&inclist, v);
-      n = igraph_vector_size(neis);
+      n = igraph_vector_int_size(neis);
       for (i = 0; i < n; i++) {
         j = (long int) VECTOR(*neis)[i];
         /* We only care about tight edges */
@@ -828,7 +828,7 @@ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
        * when we determined the initial value for min_slack. */
       debug("Trying to expand along vertex %ld\n", (long int)u);
       neis = igraph_inclist_get(&inclist, u);
-      k = igraph_vector_size(neis);
+      k = igraph_vector_int_size(neis);
       for (j = 0; j < k; j++) {
         /* v is the vertex sitting at the other end of an edge incident
          * on u; check whether it was reached */
@@ -860,7 +860,7 @@ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
         u = (igraph_integer_t) VECTOR(vec1)[i];
         VECTOR(labels)[u] -= min_slack;
         neis = igraph_inclist_get(&inclist, u);
-        k = igraph_vector_size(neis);
+        k = igraph_vector_int_size(neis);
         for (j = 0; j < k; j++) {
           debug("  Decreasing slack of edge %ld (%ld--%ld) by %.4f\n",
               (long)VECTOR(*neis)[j], (long)u,
@@ -877,7 +877,7 @@ int igraph_i_maximum_bipartite_matching_weighted(const igraph_t* graph,
         u = (igraph_integer_t) VECTOR(vec2)[i];
         VECTOR(labels)[u] += min_slack;
         neis = igraph_inclist_get(&inclist, u);
-        k = igraph_vector_size(neis);
+        k = igraph_vector_int_size(neis);
         for (j = 0; j < k; j++) {
           debug("  Increasing slack of edge %ld (%ld--%ld) by %.4f\n",
               (long)VECTOR(*neis)[j], (long)u,
diff --git a/src/matrix.c b/src/matrix.c
index d8f93cf..9156af4 100644
--- a/src/matrix.c
+++ b/src/matrix.c
@@ -1,22 +1,22 @@
 /* -*- mode: C -*-  */
-/* 
+/*
    IGraph library.
    Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
    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 
+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301 USA
 
 */
@@ -74,12 +74,12 @@ int igraph_matrix_complex_print(const igraph_matrix_complex_t *m) {
     }
     printf("\n");
   }
-  
+
   return 0;
 }
 #endif
 
-int igraph_matrix_complex_fprint(const igraph_matrix_complex_t *m, 
+int igraph_matrix_complex_fprint(const igraph_matrix_complex_t *m,
 				 FILE *file) {
 
   long int nr=igraph_matrix_complex_nrow(m);
@@ -93,11 +93,11 @@ int igraph_matrix_complex_fprint(const igraph_matrix_complex_t *m,
     }
     fprintf(file, "\n");
   }
-  
+
   return 0;
 }
 
-int igraph_matrix_complex_real(const igraph_matrix_complex_t *v, 
+int igraph_matrix_complex_real(const igraph_matrix_complex_t *v,
 			       igraph_matrix_t *real) {
   long int nrow=igraph_matrix_complex_nrow(v);
   long int ncol=igraph_matrix_complex_ncol(v);
@@ -106,7 +106,7 @@ int igraph_matrix_complex_real(const igraph_matrix_complex_t *v,
   return 0;
 }
 
-int igraph_matrix_complex_imag(const igraph_matrix_complex_t *v, 
+int igraph_matrix_complex_imag(const igraph_matrix_complex_t *v,
 			       igraph_matrix_t *imag) {
   long int nrow=igraph_matrix_complex_nrow(v);
   long int ncol=igraph_matrix_complex_ncol(v);
@@ -115,14 +115,14 @@ int igraph_matrix_complex_imag(const igraph_matrix_complex_t *v,
   return 0;
 }
 
-int igraph_matrix_complex_realimag(const igraph_matrix_complex_t *v, 
-				   igraph_matrix_t *real, 
+int igraph_matrix_complex_realimag(const igraph_matrix_complex_t *v,
+				   igraph_matrix_t *real,
 				   igraph_matrix_t *imag) {
   long int nrow=igraph_matrix_complex_nrow(v);
   long int ncol=igraph_matrix_complex_ncol(v);
   IGRAPH_CHECK(igraph_matrix_resize(real, nrow, ncol));
   IGRAPH_CHECK(igraph_matrix_resize(imag, nrow, ncol));
-  IGRAPH_CHECK(igraph_vector_complex_realimag(&v->data, &real->data, 
+  IGRAPH_CHECK(igraph_vector_complex_realimag(&v->data, &real->data,
 					      &imag->data));
   return 0;
 }
@@ -148,3 +148,7 @@ igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs,
 				      igraph_real_t tol) {
   return igraph_vector_e_tol(&lhs->data, &rhs->data, tol);
 }
+
+int igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol) {
+  return igraph_vector_zapsmall(&m->data, tol);
+}
diff --git a/src/matrix.pmt b/src/matrix.pmt
index b9a37d5..b9c7d76 100644
--- a/src/matrix.pmt
+++ b/src/matrix.pmt
@@ -72,6 +72,17 @@ int FUNCTION(igraph_matrix,init)(TYPE(igraph_matrix) *m, long int nrow, long int
   return ret1;
 }
 
+const TYPE(igraph_matrix) *FUNCTION(igraph_matrix,view)(const TYPE(igraph_matrix) *m,
+							const BASE *data,
+							long int nrow,
+							long int ncol) {
+  TYPE(igraph_matrix) *m2=(TYPE(igraph_matrix)*)m;
+  FUNCTION(igraph_vector,view)(&m2->data, data, nrow * ncol);
+  m2->nrow=nrow;
+  m2->ncol=ncol;
+  return m;
+}
+
 /** 
  * \ingroup matrix
  * \function igraph_matrix_destroy
diff --git a/src/operators.c b/src/operators.c
index 122edaa..4f3ef78 100644
--- a/src/operators.c
+++ b/src/operators.c
@@ -933,7 +933,7 @@ int igraph_difference(igraph_t *res,
   igraph_bool_t directed=igraph_is_directed(orig);
   igraph_vector_t edges;
   igraph_vector_t edge_ids;
-  igraph_vector_t *nei1, *nei2;
+  igraph_vector_int_t *nei1, *nei2;
   igraph_inclist_t inc_orig, inc_sub;
   long int i;
   igraph_integer_t v1, v2;
@@ -958,8 +958,8 @@ int igraph_difference(igraph_t *res,
     IGRAPH_ALLOW_INTERRUPTION();
     nei1=igraph_inclist_get(&inc_orig, i);
     nei2=igraph_inclist_get(&inc_sub, i);
-    n1=igraph_vector_size(nei1)-1;
-    n2=igraph_vector_size(nei2)-1;
+    n1=igraph_vector_int_size(nei1)-1;
+    n2=igraph_vector_int_size(nei2)-1;
     while (n1>=0 && n2>=0) {
       e1=(long int) VECTOR(*nei1)[n1];
       e2=(long int) VECTOR(*nei2)[n2];
@@ -1000,7 +1000,7 @@ int igraph_difference(igraph_t *res,
   for (; i<no_of_nodes_orig; i++) {
     long int n1, e1;
     nei1=igraph_inclist_get(&inc_orig, i);
-    n1=igraph_vector_size(nei1)-1;
+    n1=igraph_vector_int_size(nei1)-1;
     while (n1>=0) {
       e1=(long int) VECTOR(*nei1)[n1];
       v1=IGRAPH_OTHER(orig, e1, i);
diff --git a/src/other.c b/src/other.c
index 8b13abe..8fec9a9 100644
--- a/src/other.c
+++ b/src/other.c
@@ -179,55 +179,40 @@ int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts,
   igraph_Free(angles);
   IGRAPH_FINALLY_CLEAN(1);
 
-  if (no_of_nodes == 1) {
-    IGRAPH_CHECK(igraph_vector_push_back(&stack, 0));
-    igraph_indheap_delete_max(&order);
-  } else {
-    /* Do the trick */
-    IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1));
-    igraph_indheap_delete_max(&order);
-    IGRAPH_CHECK(igraph_vector_push_back(&stack, igraph_indheap_max_index(&order)-1));
-    igraph_indheap_delete_max(&order);
-    
-    j=2;
-    while (!igraph_indheap_empty(&order)) {
-      /* Determine whether we are at a left or right turn */
-      last_idx=(long int) VECTOR(stack)[j-1];
-      before_last_idx=(long int) VECTOR(stack)[j-2];
-      next_idx=(long)igraph_indheap_max_index(&order)-1;
-      igraph_indheap_delete_max(&order);
+  j=0;
+  last_idx=-1;
+  before_last_idx=-1;
+  while (!igraph_indheap_empty(&order)) {
+    next_idx=(long)igraph_indheap_max_index(&order)-1;
+    /* Determine whether we are at a left or right turn */
+    if (j < 2) {
+      /* Pretend that we are turning into the right direction if we have less
+       * than two items in the stack */
+      cp=-1;
+    } else {
       cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))*
-	(MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))-
-	(MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))*
-	(MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1));
-      /*
-       printf("B L N cp: %d, %d, %d, %f [", before_last_idx, last_idx, next_idx, (float)cp);
-       for (k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]);
-       printf("]\n");
-       */
-      if (cp == 0) {
-	/* The last three points are collinear. Replace the last one in
-	 * the stack to the newest one */
-	VECTOR(stack)[j-1]=next_idx;
-      } else if (cp < 0) {
-	/* We are turning into the right direction */
-	IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));
-	j++;
-      } else {
-	/* No, skip back until we're okay */
-	while (cp >= 0 && j > 2) {
-	  igraph_vector_pop_back(&stack);
-	  j--;
-	  last_idx=(long int) VECTOR(stack)[j-1];
-	  before_last_idx=(long int) VECTOR(stack)[j-2];
-	  cp=(MATRIX(*data, last_idx, 0)-MATRIX(*data, before_last_idx, 0))*
-	    (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))-
-	    (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))*
-	    (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1));
-	}
-	IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));
-	j++;
-      }
+         (MATRIX(*data, next_idx, 1)-MATRIX(*data, before_last_idx, 1))-
+         (MATRIX(*data, next_idx, 0)-MATRIX(*data, before_last_idx, 0))*
+         (MATRIX(*data, last_idx, 1)-MATRIX(*data, before_last_idx, 1));
+    }
+    /*
+    printf("B L N cp: %ld, %ld, %ld, %f [", before_last_idx, last_idx, next_idx, (float)cp);
+    for (int k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]);
+    printf("]\n");
+    */
+    if (cp < 0) {
+      /* We are turning into the right direction */
+      igraph_indheap_delete_max(&order);
+      IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));
+      before_last_idx = last_idx;
+      last_idx = next_idx;
+      j++;
+    } else {
+      /* No, skip back and try again in the next iteration */
+      igraph_vector_pop_back(&stack);
+      j--;
+      last_idx = before_last_idx;
+      before_last_idx = (j >= 2) ? (long int) VECTOR(stack)[j-2] : -1;
     }
   }
   
diff --git a/src/paths.c b/src/paths.c
new file mode 100644
index 0000000..049163a
--- /dev/null
+++ b/src/paths.c
@@ -0,0 +1,159 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_interface.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_vector_ptr.h"
+#include "igraph_iterators.h"
+#include "igraph_adjlist.h"
+#include "igraph_stack.h"
+
+/**
+ * \function igraph_get_all_simple_paths
+ * List all simple paths from one source
+ *
+ * A path is simple, if its vertices are unique, no vertex
+ * is visited more than once.
+ *
+ * </para><para>
+ * Note that potentially there are exponentially many
+ * paths between two vertices of a graph, and you may
+ * run out of memory when using this function, if your
+ * graph is lattice-like.
+ *
+ * </para><para>
+ * This function currently ignored multiple and loop edges.
+ * \param graph The input graph.
+ * \param res Initialized integer vector, all paths are
+ *        returned here, separated by -1 markers. The paths
+ *        are included in arbitrary order, as they are found.
+ * \param from The start vertex.
+ * \param to The target vertices.
+ * \param mode The type of the paths to consider, it is ignored
+ *        for undirectred graphs.
+ * \return Error code.
+ *
+ * Time complexity: O(n!) in the worst case, n is the number of
+ * vertices.
+ */
+
+int igraph_get_all_simple_paths(const igraph_t *graph,
+				igraph_vector_int_t *res,
+				igraph_integer_t from,
+				const igraph_vs_t to,
+				igraph_neimode_t mode) {
+
+  igraph_integer_t no_nodes=igraph_vcount(graph);
+  igraph_vit_t vit;
+  igraph_bool_t toall=igraph_vs_is_all(&to);
+  igraph_vector_char_t markto;
+  igraph_lazy_adjlist_t adjlist;
+  igraph_vector_int_t stack;
+  igraph_vector_char_t added;
+  igraph_vector_int_t nptr;
+  int iteration;
+
+  if (from < 0 || from >= no_nodes) {
+    IGRAPH_ERROR("Invalid starting vertex", IGRAPH_EINVAL);
+  }
+  
+  if (!toall) {
+    igraph_vector_char_init(&markto, no_nodes);
+    IGRAPH_FINALLY(igraph_vector_char_destroy, &markto);
+    IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+    for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+      VECTOR(markto)[ IGRAPH_VIT_GET(vit) ] = 1;
+    }
+    igraph_vit_destroy(&vit);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  IGRAPH_CHECK(igraph_vector_char_init(&added, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
+  IGRAPH_CHECK(igraph_vector_int_init(&stack, 100));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &stack);
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode, 
+					/*simplify=*/ 1));  
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+  IGRAPH_CHECK(igraph_vector_int_init(&nptr, no_nodes));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &nptr);
+
+  igraph_vector_int_clear(res);
+
+  igraph_vector_int_clear(&stack);
+  igraph_vector_int_push_back(&stack, from);
+  VECTOR(added)[from] = 1;
+  while (!igraph_vector_int_empty(&stack)) {
+    int act=igraph_vector_int_tail(&stack);
+    igraph_vector_t *neis=igraph_lazy_adjlist_get(&adjlist, act);
+    int n=igraph_vector_size(neis);
+    int *ptr=igraph_vector_int_e_ptr(&nptr, act);
+
+    if (iteration == 0) {
+      IGRAPH_ALLOW_INTERRUPTION();
+    }
+
+    /* Search for a neighbor that was not yet visited */
+    igraph_bool_t any=0;
+    int nei;
+    while (!any && (*ptr) <n) {
+      nei = (int) VECTOR(*neis)[(*ptr)];
+      any = !VECTOR(added)[nei];
+      (*ptr) ++;
+    }
+    if (any) {
+      /* There is such a neighbor, add it */
+      IGRAPH_CHECK(igraph_vector_int_push_back(&stack, nei));
+      VECTOR(added)[nei] = 1;
+      /* Add to results */
+      if (toall || VECTOR(markto)[nei]) {
+	IGRAPH_CHECK(igraph_vector_int_append(res, &stack));
+	IGRAPH_CHECK(igraph_vector_int_push_back(res, -1));
+      }
+    } else {
+      /* There is no such neighbor, finished with the subtree */
+      int up=igraph_vector_int_pop_back(&stack);
+      VECTOR(added)[up] = 0;
+      VECTOR(nptr)[up] = 0;
+    }
+
+    iteration++;
+    if (iteration >= 10000) {
+      iteration = 0;
+    }
+  }
+
+  igraph_vector_int_destroy(&nptr);
+  igraph_lazy_adjlist_destroy(&adjlist);
+  igraph_vector_int_destroy(&stack);
+  igraph_vector_char_destroy(&added);
+  IGRAPH_FINALLY_CLEAN(4);
+
+  if (!toall) {
+    igraph_vector_char_destroy(&markto);
+    IGRAPH_FINALLY_CLEAN(1);
+  }
+
+  return 0;
+}
diff --git a/src/error.c b/src/plfit/error.c
similarity index 100%
rename from src/error.c
rename to src/plfit/error.c
diff --git a/src/gss.c b/src/plfit/gss.c
similarity index 100%
rename from src/gss.c
rename to src/plfit/gss.c
diff --git a/src/kolmogorov.c b/src/plfit/kolmogorov.c
similarity index 100%
rename from src/kolmogorov.c
rename to src/plfit/kolmogorov.c
diff --git a/src/lbfgs.c b/src/plfit/lbfgs.c
similarity index 100%
rename from src/lbfgs.c
rename to src/plfit/lbfgs.c
diff --git a/src/options.c b/src/plfit/options.c
similarity index 100%
rename from src/options.c
rename to src/plfit/options.c
diff --git a/src/plfit.c b/src/plfit/plfit.c
similarity index 100%
rename from src/plfit.c
rename to src/plfit/plfit.c
diff --git a/src/plfit/plfit.inc b/src/plfit/plfit.inc
new file mode 100644
index 0000000..48c933a
--- /dev/null
+++ b/src/plfit/plfit.inc
@@ -0,0 +1,9 @@
+PLFIT = plfit/error.c     plfit/gss.c       plfit/kolmogorov.c \
+        plfit/lbfgs.c     plfit/options.c   plfit/plfit.c      \
+		plfit/zeta.c      \
+		plfit/arithmetic_ansi.h plfit/arithmetic_sse_double.h plfit/arithmetic_sse_float.h \
+		plfit/error.h     plfit/gss.h       plfit/kolmogorov.h \
+		plfit/lbfgs.h     plfit/platform.h  plfit/plfit.h      \
+		plfit/zeta.h
+
+
diff --git a/src/zeta.c b/src/plfit/zeta.c
similarity index 100%
rename from src/zeta.c
rename to src/plfit/zeta.c
diff --git a/src/prpack.cpp b/src/prpack.cpp
index 1b145c7..9a9f863 100644
--- a/src/prpack.cpp
+++ b/src/prpack.cpp
@@ -82,7 +82,7 @@ int igraph_personalized_pagerank_prpack(const igraph_t *graph, igraph_vector_t *
     IGRAPH_CHECK(igraph_vector_resize(vector, nodes_to_calc));
     for (IGRAPH_VIT_RESET(vit), i = 0; !IGRAPH_VIT_END(vit);
             IGRAPH_VIT_NEXT(vit), i++) {
-        VECTOR(*vector)[i] = res->x[i];
+        VECTOR(*vector)[i] = res->x[(long int)IGRAPH_VIT_GET(vit)];
     }
     igraph_vit_destroy(&vit);
     IGRAPH_FINALLY_CLEAN(1);
diff --git a/src/prpack/prpack.inc b/src/prpack/prpack.inc
new file mode 100644
index 0000000..ce1e7fa
--- /dev/null
+++ b/src/prpack/prpack.inc
@@ -0,0 +1,23 @@
+PRPACK = prpack/prpack_base_graph.cpp \
+         prpack/prpack_igraph_graph.cpp \
+         prpack/prpack_preprocessed_ge_graph.cpp \
+         prpack/prpack_preprocessed_gs_graph.cpp \
+         prpack/prpack_preprocessed_scc_graph.cpp \
+         prpack/prpack_preprocessed_schur_graph.cpp \
+         prpack/prpack_result.cpp \
+         prpack/prpack_solver.cpp \
+         prpack/prpack_utils.cpp \
+         prpack/prpack.h \
+         prpack/prpack_base_graph.h \
+         prpack/prpack_csc.h \
+         prpack/prpack_csr.h \
+         prpack/prpack_edge_list.h \
+         prpack/prpack_igraph_graph.h \
+         prpack/prpack_preprocessed_ge_graph.h \
+         prpack/prpack_preprocessed_graph.h \
+         prpack/prpack_preprocessed_gs_graph.h \
+         prpack/prpack_preprocessed_scc_graph.h \
+         prpack/prpack_preprocessed_schur_graph.h \
+         prpack/prpack_result.h \
+         prpack/prpack_solver.h \
+         prpack/prpack_utils.h
diff --git a/src/prpack_base_graph.cpp b/src/prpack/prpack_base_graph.cpp
similarity index 100%
rename from src/prpack_base_graph.cpp
rename to src/prpack/prpack_base_graph.cpp
diff --git a/src/prpack_igraph_graph.cpp b/src/prpack/prpack_igraph_graph.cpp
similarity index 100%
rename from src/prpack_igraph_graph.cpp
rename to src/prpack/prpack_igraph_graph.cpp
diff --git a/src/prpack_preprocessed_ge_graph.cpp b/src/prpack/prpack_preprocessed_ge_graph.cpp
similarity index 100%
rename from src/prpack_preprocessed_ge_graph.cpp
rename to src/prpack/prpack_preprocessed_ge_graph.cpp
diff --git a/src/prpack_preprocessed_gs_graph.cpp b/src/prpack/prpack_preprocessed_gs_graph.cpp
similarity index 100%
rename from src/prpack_preprocessed_gs_graph.cpp
rename to src/prpack/prpack_preprocessed_gs_graph.cpp
diff --git a/src/prpack_preprocessed_scc_graph.cpp b/src/prpack/prpack_preprocessed_scc_graph.cpp
similarity index 100%
rename from src/prpack_preprocessed_scc_graph.cpp
rename to src/prpack/prpack_preprocessed_scc_graph.cpp
diff --git a/src/prpack_preprocessed_schur_graph.cpp b/src/prpack/prpack_preprocessed_schur_graph.cpp
similarity index 100%
rename from src/prpack_preprocessed_schur_graph.cpp
rename to src/prpack/prpack_preprocessed_schur_graph.cpp
diff --git a/src/prpack_result.cpp b/src/prpack/prpack_result.cpp
similarity index 100%
rename from src/prpack_result.cpp
rename to src/prpack/prpack_result.cpp
diff --git a/src/prpack/prpack_solver.cpp b/src/prpack/prpack_solver.cpp
new file mode 100644
index 0000000..d67e132
--- /dev/null
+++ b/src/prpack/prpack_solver.cpp
@@ -0,0 +1,879 @@
+#include "prpack_solver.h"
+#include "prpack_utils.h"
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+#include <stdint.h>
+using namespace prpack;
+using namespace std;
+
+void prpack_solver::initialize() {
+    geg = NULL;
+    gsg = NULL;
+    sg = NULL;
+    sccg = NULL;
+	owns_bg = true;
+}
+
+prpack_solver::prpack_solver(const prpack_csc* g) {
+    initialize();
+    TIME(read_time, bg = new prpack_base_graph(g));
+}
+
+prpack_solver::prpack_solver(const prpack_int64_csc* g) {
+    initialize();
+    TIME(read_time, bg = new prpack_base_graph(g));
+}
+
+prpack_solver::prpack_solver(const prpack_csr* g) {
+    initialize();
+    TIME(read_time, bg = new prpack_base_graph(g));
+}
+
+prpack_solver::prpack_solver(const prpack_edge_list* g) {
+    initialize();
+    TIME(read_time, bg = new prpack_base_graph(g));
+}
+
+prpack_solver::prpack_solver(prpack_base_graph* g, bool owns_bg) {
+    initialize();
+	this->owns_bg = owns_bg;
+    TIME(read_time, bg = g);
+}
+
+prpack_solver::prpack_solver(const char* filename, const char* format, const bool weighted) {
+    initialize();
+    TIME(read_time, bg = new prpack_base_graph(filename, format, weighted));
+}
+
+prpack_solver::~prpack_solver() {
+	if (owns_bg) {
+		delete bg;
+	}
+    delete geg;
+    delete gsg;
+    delete sg;
+    delete sccg;
+}
+
+int prpack_solver::get_num_vs() {
+    return bg->num_vs;
+}
+
+prpack_result* prpack_solver::solve(const double alpha, const double tol, const char* method) {
+    return solve(alpha, tol, NULL, NULL, method);
+}
+
+prpack_result* prpack_solver::solve(
+        const double alpha,
+        const double tol,
+        const double* u,
+        const double* v,
+        const char* method) {
+    double preprocess_time = 0;
+    double compute_time = 0;
+    prpack_result* ret = NULL;
+    // decide which method to run
+    string m;
+    if (strcmp(method, "") != 0)
+        m = string(method);
+    else {
+        if (bg->num_vs < 128)
+            m = "ge";
+        else if (sccg != NULL)
+            m = "sccgs";
+        else if (sg != NULL)
+            m = "sg";
+        else
+            m = "sccgs";
+        if (u != v)
+            m += "_uv";
+    }
+    // run the appropriate method
+    if (m == "ge") {
+        if (geg == NULL) {
+            TIME(preprocess_time, geg = new prpack_preprocessed_ge_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_ge(
+                alpha,
+                tol,
+                geg->num_vs,
+                geg->matrix,
+                u));
+    } else if (m == "ge_uv") {
+        if (geg == NULL) {
+            TIME(preprocess_time, geg = new prpack_preprocessed_ge_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_ge_uv(
+                alpha,
+                tol,
+                geg->num_vs,
+                geg->matrix,
+                geg->d,
+                u,
+                v));
+    } else if (m == "gs") {
+        if (gsg == NULL) {
+            TIME(preprocess_time, gsg = new prpack_preprocessed_gs_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_gs(
+                alpha,
+                tol,
+                gsg->num_vs,
+                gsg->num_es,
+                gsg->heads,
+                gsg->tails,
+                gsg->vals,
+                gsg->ii,
+                gsg->d,
+                gsg->num_outlinks,
+                u,
+                v));
+    } else if (m == "gserr") {
+        if (gsg == NULL) {
+            TIME(preprocess_time, gsg = new prpack_preprocessed_gs_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_gs_err(
+                alpha,
+                tol,
+                gsg->num_vs,
+                gsg->num_es,
+                gsg->heads,
+                gsg->tails,
+                gsg->ii,
+                gsg->num_outlinks,
+                u,
+                v));
+    } else if (m == "sgs") {
+        if (sg == NULL) {
+            TIME(preprocess_time, sg = new prpack_preprocessed_schur_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_schur_gs(
+                alpha,
+                tol,
+                sg->num_vs,
+                sg->num_no_in_vs,
+                sg->num_no_out_vs,
+                sg->num_es,
+                sg->heads,
+                sg->tails,
+                sg->vals,
+                sg->ii,
+                sg->d,
+                sg->num_outlinks,
+                u,
+                sg->encoding,
+                sg->decoding));
+    } else if (m == "sgs_uv") {
+        if (sg == NULL) {
+            TIME(preprocess_time, sg = new prpack_preprocessed_schur_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_schur_gs_uv(
+                alpha,
+                tol,
+                sg->num_vs,
+                sg->num_no_in_vs,
+                sg->num_no_out_vs,
+                sg->num_es,
+                sg->heads,
+                sg->tails,
+                sg->vals,
+                sg->ii,
+                sg->d,
+                sg->num_outlinks,
+                u,
+                v,
+                sg->encoding,
+                sg->decoding));
+    } else if (m == "sccgs") {
+        if (sccg == NULL) {
+            TIME(preprocess_time, sccg = new prpack_preprocessed_scc_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_scc_gs(
+                alpha,
+                tol,
+                sccg->num_vs,
+                sccg->num_es_inside,
+                sccg->heads_inside,
+                sccg->tails_inside,
+                sccg->vals_inside,
+                sccg->num_es_outside,
+                sccg->heads_outside,
+                sccg->tails_outside,
+                sccg->vals_outside,
+                sccg->ii,
+                sccg->d,
+                sccg->num_outlinks,
+                u,
+                sccg->num_comps,
+                sccg->divisions,
+                sccg->encoding,
+                sccg->decoding));
+    } else if (m == "sccgs_uv") {
+        if (sccg == NULL) {
+            TIME(preprocess_time, sccg = new prpack_preprocessed_scc_graph(bg));
+        }
+        TIME(compute_time, ret = solve_via_scc_gs_uv(
+                alpha,
+                tol,
+                sccg->num_vs,
+                sccg->num_es_inside,
+                sccg->heads_inside,
+                sccg->tails_inside,
+                sccg->vals_inside,
+                sccg->num_es_outside,
+                sccg->heads_outside,
+                sccg->tails_outside,
+                sccg->vals_outside,
+                sccg->ii,
+                sccg->d,
+                sccg->num_outlinks,
+                u,
+                v,
+                sccg->num_comps,
+                sccg->divisions,
+                sccg->encoding,
+                sccg->decoding));
+    } else {
+        // TODO: throw exception
+    }
+    ret->method = m.c_str();
+    ret->read_time = read_time;
+    ret->preprocess_time = preprocess_time;
+    ret->compute_time = compute_time;
+    ret->num_vs = bg->num_vs;
+    ret->num_es = bg->num_es;
+    return ret;
+}
+
+// VARIOUS SOLVING METHODS ////////////////////////////////////////////////////////////////////////
+
+prpack_result* prpack_solver::solve_via_ge(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const double* matrix,
+        const double* uv) {
+    prpack_result* ret = new prpack_result();
+    // initialize uv values
+    const double uv_const = 1.0/num_vs;
+    const int uv_exists = (uv) ? 1 : 0;
+    uv = (uv) ? uv : &uv_const;
+    // create matrix A
+    double* A = new double[num_vs*num_vs];
+    for (int i = 0; i < num_vs*num_vs; ++i)
+        A[i] = -alpha*matrix[i];
+    for (int i = 0; i < num_vs*num_vs; i += num_vs + 1)
+        ++A[i];
+    // create vector b
+    double* b = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        b[i] = uv[uv_exists*i];
+    // solve and normalize
+    ge(num_vs, A, b);
+    normalize(num_vs, b);
+    // clean up and return
+    delete[] A;
+    ret->num_es_touched = -1;
+    ret->x = b;
+    return ret;
+}
+
+prpack_result* prpack_solver::solve_via_ge_uv(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const double* matrix,
+        const double* d,
+        const double* u,
+        const double* v) {
+    prpack_result* ret = new prpack_result();
+    // initialize u and v values
+    const double u_const = 1.0/num_vs;
+    const double v_const = 1.0/num_vs;
+    const int u_exists = (u) ? 1 : 0;
+    const int v_exists = (v) ? 1 : 0;
+    u = (u) ? u : &u_const;
+    v = (v) ? v : &v_const;
+    // create matrix A
+    double* A = new double[num_vs*num_vs];
+    for (int i = 0; i < num_vs*num_vs; ++i)
+        A[i] = -alpha*matrix[i];
+    for (int i = 0, inum_vs = 0; i < num_vs; ++i, inum_vs += num_vs)
+        for (int j = 0; j < num_vs; ++j)
+            A[inum_vs + j] -= alpha*u[u_exists*i]*d[j];
+    for (int i = 0; i < num_vs*num_vs; i += num_vs + 1)
+        ++A[i];
+    // create vector b
+    double* b = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        b[i] = (1 - alpha)*v[v_exists*i];
+    // solve
+    ge(num_vs, A, b);
+    // clean up and return
+    delete[] A;
+    ret->num_es_touched = -1;
+    ret->x = b;
+    return ret;
+}
+
+// Vanilla Gauss-Seidel.
+prpack_result* prpack_solver::solve_via_gs(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const int num_es,
+        const int* heads,
+        const int* tails,
+        const double* vals,
+        const double* ii,
+        const double* d,
+        const double* num_outlinks,
+        const double* u,
+        const double* v) {
+    prpack_result* ret = new prpack_result();
+    const bool weighted = vals != NULL;
+    // initialize u and v values
+    const double u_const = 1.0/num_vs;
+    const double v_const = 1.0/num_vs;
+    const int u_exists = (u) ? 1 : 0;
+    const int v_exists = (v) ? 1 : 0;
+    u = (u) ? u : &u_const;
+    v = (v) ? v : &v_const;
+    // initialize the eigenvector (and use personalization vector)
+    double* x = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        x[i] = 0;
+    // initialize delta
+    double delta = 0;
+    // run Gauss-Seidel
+    ret->num_es_touched = 0;
+    double err = 1, c = 0;
+    do {
+        if (weighted) {
+            for (int i = 0; i < num_vs; ++i) {
+                double new_val = 0;
+                const int start_j = tails[i];
+                const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+                for (int j = start_j; j < end_j; ++j)
+                    // TODO: might want to use compensation summation for large: end_j - start_j
+                    new_val += x[heads[j]]*vals[j];
+                new_val = alpha*new_val + (1 - alpha)*v[v_exists*i];
+                delta -= alpha*x[i]*d[i];
+                new_val += delta*u[u_exists*i];
+                new_val /= 1 - alpha*(d[i]*u[u_exists*i] + (1 - d[i])*ii[i]);
+                delta += alpha*new_val*d[i];
+                COMPENSATED_SUM(err, x[i] - new_val, c);
+                x[i] = new_val;
+            }
+        } else {
+            for (int i = 0; i < num_vs; ++i) {
+                const double old_val = x[i]*num_outlinks[i];
+                double new_val = 0;
+                const int start_j = tails[i];
+                const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+                for (int j = start_j; j < end_j; ++j)
+                    // TODO: might want to use compensation summation for large: end_j - start_j
+                    new_val += x[heads[j]];
+                new_val = alpha*new_val + (1 - alpha)*v[v_exists*i];
+                if (num_outlinks[i] < 0) {
+                    delta -= alpha*old_val;
+                    new_val += delta*u[u_exists*i];
+                    new_val /= 1 - alpha*u[u_exists*i];
+                    delta += alpha*new_val;
+                } else {
+                    new_val += delta*u[u_exists*i];
+                    new_val /= 1 - alpha*ii[i];
+                }
+                COMPENSATED_SUM(err, old_val - new_val, c);
+                x[i] = new_val/num_outlinks[i];
+            }
+        }
+        // update iteration index
+        ret->num_es_touched += num_es;
+    } while (err >= tol);
+    // undo num_outlinks transformation
+    if (!weighted)
+        for (int i = 0; i < num_vs; ++i)
+            x[i] *= num_outlinks[i];
+    // return results
+    ret->x = x;
+    return ret;
+}
+
+// Implement a gauss-seidel-like process with a strict error bound
+// we return a solution with 1-norm error less than tol.
+prpack_result* prpack_solver::solve_via_gs_err(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const int num_es,
+        const int* heads,
+        const int* tails,
+        const double* ii,
+        const double* num_outlinks,
+        const double* u,
+        const double* v) {
+    prpack_result* ret = new prpack_result();
+    // initialize u and v values
+    const double u_const = 1.0/num_vs;
+    const double v_const = 1.0/num_vs;
+    const int u_exists = (u) ? 1 : 0;
+    const int v_exists = (v) ? 1 : 0;
+    u = (u) ? u : &u_const;
+    v = (v) ? v : &v_const;
+    // Note to Dave, we can't rescale v because we could be running this
+    // same routine from multiple threads.
+    // initialize the eigenvector (and use personalization vector)
+    double* x = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i) {
+        x[i] = 0.;
+    }
+    // initialize delta
+    double delta = 0.;
+    // run Gauss-Seidel, note that we store x/deg[i] throughout this 
+    // iteration.
+    int64_t maxedges = (int64_t)((double)num_es*std::min(
+                            log(tol)/log(alpha),
+                            (double)PRPACK_SOLVER_MAX_ITERS));
+    ret->num_es_touched = 0;
+    double err=1., c = 0.;
+    do {
+        // iterate through vertices
+        for (int i = 0; i < num_vs; ++i) {
+            double old_val = x[i]*num_outlinks[i]; // adjust back to the "true" value.
+            double new_val = 0.;
+            int start_j = tails[i], end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+            for (int j = start_j; j < end_j; ++j) {
+                // TODO: might want to use compensation summation for large: end_j - start_j
+                new_val += x[heads[j]];
+            }
+            new_val = alpha*new_val + alpha*ii[i]*old_val + (1.0-alpha)*v[v_exists*i];
+            new_val += delta*u[u_exists*i]; // add the dangling node adjustment
+            if (num_outlinks[i] < 0) {
+                delta += alpha*(new_val - old_val);
+            } 
+            // note that new_val > old_val, but the fabs is just for 
+            COMPENSATED_SUM(err, -(new_val - old_val), c);
+            x[i] = new_val/num_outlinks[i];
+        }
+        // update iteration index
+        ret->num_es_touched += num_es;
+    } while (err >= tol && ret->num_es_touched < maxedges);
+    if (err >= tol) {
+        ret->converged = 0;
+    } else {
+        ret->converged = 1;
+    }
+    // undo num_outlinks transformation
+    for (int i = 0; i < num_vs; ++i)
+        x[i] *= num_outlinks[i];
+    // return results
+    ret->x = x;
+    return ret;
+}
+
+// Gauss-Seidel using the Schur complement to separate dangling nodes.
+prpack_result* prpack_solver::solve_via_schur_gs(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const int num_no_in_vs,
+        const int num_no_out_vs,
+        const int num_es,
+        const int* heads,
+        const int* tails,
+        const double* vals,
+        const double* ii,
+        const double* d,
+        const double* num_outlinks,
+        const double* uv,
+        const int* encoding,
+        const int* decoding,
+        const bool should_normalize) {
+    prpack_result* ret = new prpack_result();
+    const bool weighted = vals != NULL;
+    // initialize uv values
+    const double uv_const = 1.0/num_vs;
+    const int uv_exists = (uv) ? 1 : 0;
+    uv = (uv) ? prpack_utils::permute(num_vs, uv, encoding) : &uv_const;
+    // initialize the eigenvector (and use personalization vector)
+    double* x = new double[num_vs];
+    for (int i = 0; i < num_vs - num_no_out_vs; ++i)
+        x[i] = uv[uv_exists*i]/(1 - alpha*ii[i])/((weighted) ? 1 : num_outlinks[i]);
+    // run Gauss-Seidel for the top left part of (I - alpha*P)*x = uv
+    ret->num_es_touched = 0;
+    double err, c;
+    do {
+        // iterate through vertices
+        int num_es_touched = 0;
+        err = c = 0;
+        #pragma omp parallel for firstprivate(c) reduction(+:err, num_es_touched) schedule(dynamic, 64)
+        for (int i = num_no_in_vs; i < num_vs - num_no_out_vs; ++i) {
+            double new_val = 0;
+            const int start_j = tails[i];
+            const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+            if (weighted) {
+                for (int j = start_j; j < end_j; ++j)
+                    // TODO: might want to use compensation summation for large: end_j - start_j
+                    new_val += x[heads[j]]*vals[j];
+                COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);
+                new_val = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
+                x[i] = new_val;
+            } else {
+                for (int j = start_j; j < end_j; ++j)
+                    // TODO: might want to use compensation summation for large: end_j - start_j
+                    new_val += x[heads[j]];
+                COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);
+                new_val = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
+                x[i] = new_val/num_outlinks[i];
+            }
+            num_es_touched += end_j - start_j;
+        }
+        // update iteration index
+        ret->num_es_touched += num_es_touched;
+    } while (err/(1 - alpha) >= tol);
+    // solve for the dangling nodes
+    int num_es_touched = 0;
+    #pragma omp parallel for reduction(+:num_es_touched) schedule(dynamic, 64)
+    for (int i = num_vs - num_no_out_vs; i < num_vs; ++i) {
+        x[i] = 0;
+        const int start_j = tails[i];
+        const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
+        for (int j = start_j; j < end_j; ++j)
+            x[i] += x[heads[j]]*((weighted) ? vals[j] : 1);
+        x[i] = (alpha*x[i] + uv[uv_exists*i])/(1 - alpha*ii[i]);
+        num_es_touched += end_j - start_j;
+    }
+    ret->num_es_touched += num_es_touched;
+    // undo num_outlinks transformation
+    if (!weighted)
+        for (int i = 0; i < num_vs - num_no_out_vs; ++i)
+            x[i] *= num_outlinks[i];
+    // normalize x to get the solution for: (I - alpha*P - alpha*u*d')*x = (1 - alpha)*v
+    if (should_normalize)
+        normalize(num_vs, x);
+    // return results
+    ret->x = prpack_utils::permute(num_vs, x, decoding);
+    delete[] x;
+    if (uv_exists)
+        delete[] uv;
+    return ret;
+}
+
+prpack_result* prpack_solver::solve_via_schur_gs_uv(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const int num_no_in_vs,
+        const int num_no_out_vs,
+        const int num_es,
+        const int* heads,
+        const int* tails,
+        const double* vals,
+        const double* ii,
+        const double* d,
+        const double* num_outlinks,
+        const double* u,
+        const double* v,
+        const int* encoding,
+        const int* decoding) {
+    // solve uv = u
+    prpack_result* ret_u = solve_via_schur_gs(
+            alpha,
+            tol,
+            num_vs,
+            num_no_in_vs,
+            num_no_out_vs,
+            num_es,
+            heads,
+            tails,
+            vals,
+            ii,
+            d,
+            num_outlinks,
+            u,
+            encoding,
+            decoding,
+            false);
+    // solve uv = v
+    prpack_result* ret_v = solve_via_schur_gs(
+            alpha,
+            tol,
+            num_vs,
+            num_no_in_vs,
+            num_no_out_vs,
+            num_es,
+            heads,
+            tails,
+            vals,
+            ii,
+            d,
+            num_outlinks,
+            v,
+            encoding,
+            decoding,
+            false);
+    // combine the u and v cases
+    return combine_uv(num_vs, d, num_outlinks, encoding, alpha, ret_u, ret_v);
+}
+
+/** Gauss-Seidel using strongly connected components.
+ * Notes:
+ *   If not weighted, then we store x[i] = "x[i]/outdegree" to 
+ *   avoid additional arithmetic.  We don't do this for the weighted
+ *   case because the adjustment may not be constant.
+ */
+prpack_result* prpack_solver::solve_via_scc_gs(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const int num_es_inside,
+        const int* heads_inside,
+        const int* tails_inside,
+        const double* vals_inside,
+        const int num_es_outside,
+        const int* heads_outside,
+        const int* tails_outside,
+        const double* vals_outside,
+        const double* ii,
+        const double* d,
+        const double* num_outlinks,
+        const double* uv,
+        const int num_comps,
+        const int* divisions,
+        const int* encoding,
+        const int* decoding,
+        const bool should_normalize) {
+    prpack_result* ret = new prpack_result();
+    const bool weighted = vals_inside != NULL;
+    // initialize uv values
+    const double uv_const = 1.0/num_vs;
+    const int uv_exists = (uv) ? 1 : 0;
+    uv = (uv) ? prpack_utils::permute(num_vs, uv, encoding) : &uv_const;
+    // CHECK initialize the solution with one iteration of GS from x=0.
+    double* x = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        x[i] = uv[uv_exists*i]/(1 - alpha*ii[i])/((weighted) ? 1 : num_outlinks[i]);
+    // create x_outside
+    double* x_outside = new double[num_vs];
+    // run Gauss-Seidel for (I - alpha*P)*x = uv
+    ret->num_es_touched = 0;
+    for (int comp_i = 0; comp_i < num_comps; ++comp_i) {
+        const int start_comp = divisions[comp_i];
+        const int end_comp = (comp_i + 1 != num_comps) ? divisions[comp_i + 1] : num_vs;
+        const bool parallelize = end_comp - start_comp > 512;
+        // initialize relevant x_outside values
+        for (int i = start_comp; i < end_comp; ++i) {
+            x_outside[i] = 0;
+            const int start_j = tails_outside[i];
+            const int end_j = (i + 1 != num_vs) ? tails_outside[i + 1] : num_es_outside;
+            for (int j = start_j; j < end_j; ++j)
+                x_outside[i] += x[heads_outside[j]]*((weighted) ? vals_outside[j] : 1.);
+            ret->num_es_touched += end_j - start_j;
+        }
+        double err, c;
+        do {
+            int num_es_touched = 0;
+            err = c = 0;
+            if (parallelize) {
+                // iterate through vertices
+                #pragma omp parallel for firstprivate(c) reduction(+:err, num_es_touched) schedule(dynamic, 64)
+                for (int i = start_comp; i < end_comp; ++i) {
+                    double new_val = x_outside[i];
+                    const int start_j = tails_inside[i];
+                    const int end_j = (i + 1 != num_vs) ? tails_inside[i + 1] : num_es_inside;
+                    if (weighted) {
+                        for (int j = start_j; j < end_j; ++j) {
+                            // TODO: might want to use compensation summation for large: end_j - start_j
+                            new_val += x[heads_inside[j]]*vals_inside[j];
+                        }
+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);
+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
+                    } else {
+                        for (int j = start_j; j < end_j; ++j) {
+                            // TODO: might want to use compensation summation for large: end_j - start_j
+                            new_val += x[heads_inside[j]];
+                        }
+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);
+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i])/num_outlinks[i];
+                    }
+                    num_es_touched += end_j - start_j;
+                }
+            } else {
+                for (int i = start_comp; i < end_comp; ++i) {
+                    double new_val = x_outside[i];
+                    const int start_j = tails_inside[i];
+                    const int end_j = (i + 1 != num_vs) ? tails_inside[i + 1] : num_es_inside;
+                    if (weighted) {
+                        for (int j = start_j; j < end_j; ++j) {
+                            // TODO: might want to use compensation summation for large: end_j - start_j
+                            new_val += x[heads_inside[j]]*vals_inside[j];
+                        }
+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);
+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
+                    } else {
+                        for (int j = start_j; j < end_j; ++j) {
+                            // TODO: might want to use compensation summation for large: end_j - start_j
+                            new_val += x[heads_inside[j]];
+                        }
+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);
+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i])/num_outlinks[i];
+                    }
+                    num_es_touched += end_j - start_j;
+                }
+            }
+            // update iteration index
+            ret->num_es_touched += num_es_touched;
+        } while (err/(1 - alpha) >= tol*(end_comp - start_comp)/num_vs);
+    }
+    // undo num_outlinks transformation
+    if (!weighted)
+        for (int i = 0; i < num_vs; ++i)
+            x[i] *= num_outlinks[i];
+    // normalize x to get the solution for: (I - alpha*P - alpha*u*d')*x = (1 - alpha)*v
+    if (should_normalize)
+        normalize(num_vs, x);
+    // return results
+    ret->x = prpack_utils::permute(num_vs, x, decoding);
+    delete[] x;
+    delete[] x_outside;
+    if (uv_exists)
+        delete[] uv;
+    return ret;
+}
+
+prpack_result* prpack_solver::solve_via_scc_gs_uv(
+        const double alpha,
+        const double tol,
+        const int num_vs,
+        const int num_es_inside,
+        const int* heads_inside,
+        const int* tails_inside,
+        const double* vals_inside,
+        const int num_es_outside,
+        const int* heads_outside,
+        const int* tails_outside,
+        const double* vals_outside,
+        const double* ii,
+        const double* d,
+        const double* num_outlinks,
+        const double* u,
+        const double* v,
+        const int num_comps,
+        const int* divisions,
+        const int* encoding,
+        const int* decoding) {
+    // solve uv = u
+    prpack_result* ret_u = solve_via_scc_gs(
+            alpha,
+            tol,
+            num_vs,
+            num_es_inside,
+            heads_inside,
+            tails_inside,
+            vals_inside,
+            num_es_outside,
+            heads_outside,
+            tails_outside,
+            vals_outside,
+            ii,
+            d,
+            num_outlinks,
+            u,
+            num_comps,
+            divisions,
+            encoding,
+            decoding,
+            false);
+    // solve uv = v
+    prpack_result* ret_v = solve_via_scc_gs(
+            alpha,
+            tol,
+            num_vs,
+            num_es_inside,
+            heads_inside,
+            tails_inside,
+            vals_inside,
+            num_es_outside,
+            heads_outside,
+            tails_outside,
+            vals_outside,
+            ii,
+            d,
+            num_outlinks,
+            v,
+            num_comps,
+            divisions,
+            encoding,
+            decoding,
+            false);
+    // combine u and v
+    return combine_uv(num_vs, d, num_outlinks, encoding, alpha, ret_u, ret_v);
+}
+
+// VARIOUS HELPER METHODS /////////////////////////////////////////////////////////////////////////
+
+// Run Gaussian-Elimination (note: this changes A and returns the solution in b)
+void prpack_solver::ge(const int sz, double* A, double* b) {
+    // put into triangular form
+    for (int i = 0, isz = 0; i < sz; ++i, isz += sz)
+        for (int k = 0, ksz = 0; k < i; ++k, ksz += sz)
+            if (A[isz + k] != 0) {
+                const double coeff = A[isz + k]/A[ksz + k];
+                A[isz + k] = 0;
+                for (int j = k + 1; j < sz; ++j)
+                    A[isz + j] -= coeff*A[ksz + j];
+                b[i] -= coeff*b[k];
+            }
+    // backwards substitution
+    for (int i = sz - 1, isz = (sz - 1)*sz; i >= 0; --i, isz -= sz) {
+        for (int j = i + 1; j < sz; ++j)
+            b[i] -= A[isz + j]*b[j];
+        b[i] /= A[isz + i];
+    }
+}
+
+// Normalize a vector to sum to 1.
+void prpack_solver::normalize(const int length, double* x) {
+    double norm = 0, c = 0;
+    for (int i = 0; i < length; ++i) {
+        COMPENSATED_SUM(norm, x[i], c);
+    }
+    norm = 1/norm;
+    for (int i = 0; i < length; ++i)
+        x[i] *= norm;
+}
+
+// Combine u and v results.
+prpack_result* prpack_solver::combine_uv(
+        const int num_vs,
+        const double* d,
+        const double* num_outlinks,
+        const int* encoding,
+        const double alpha,
+        const prpack_result* ret_u,
+        const prpack_result* ret_v) {
+    prpack_result* ret = new prpack_result();
+    const bool weighted = d != NULL;
+    double delta_u = 0;
+    double delta_v = 0;
+    for (int i = 0; i < num_vs; ++i) {
+        if ((weighted) ? (d[encoding[i]] == 1) : (num_outlinks[encoding[i]] < 0)) {
+            delta_u += ret_u->x[i];
+            delta_v += ret_v->x[i];
+        }
+    }
+    const double s = ((1 - alpha)*alpha*delta_v)/(1 - alpha*delta_u);
+    const double t = 1 - alpha;
+    ret->x = new double[num_vs];
+    for (int i = 0; i < num_vs; ++i)
+        ret->x[i] = s*ret_u->x[i] + t*ret_v->x[i];
+    ret->num_es_touched = ret_u->num_es_touched + ret_v->num_es_touched;
+    // clean up and return
+    delete ret_u;
+    delete ret_v;
+    return ret;
+}
+
diff --git a/src/prpack/prpack_utils.cpp b/src/prpack/prpack_utils.cpp
new file mode 100644
index 0000000..a306d3f
--- /dev/null
+++ b/src/prpack/prpack_utils.cpp
@@ -0,0 +1,60 @@
+/**
+ * @file prpack_utils.cpp
+ * An assortment of utility functions for reporting errors, checking time,
+ * and working with vectors.
+ */
+
+#include <stdlib.h>
+#include "prpack_utils.h"
+#include <cassert>
+#include <iostream>
+#include <string>
+using namespace prpack;
+using namespace std;
+
+#ifdef PRPACK_IGRAPH_SUPPORT
+#include "igraph_error.h"
+#endif
+
+#if defined(_WIN32) || defined(_WIN64)
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+double prpack_utils::get_time() {
+    LARGE_INTEGER t, freq;
+    QueryPerformanceCounter(&t);
+    QueryPerformanceFrequency(&freq);
+    return double(t.QuadPart)/double(freq.QuadPart);
+}
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+double prpack_utils::get_time() {
+    struct timeval t;
+    gettimeofday(&t, 0);
+    return (t.tv_sec*1.0 + t.tv_usec/1000000.0);
+}
+#endif
+
+// Fails and outputs 'msg' if 'condition' is false.
+void prpack_utils::validate(const bool condition, const string& msg) {
+    if (!condition) {
+#ifdef PRPACK_IGRAPH_SUPPORT
+        igraph_error("Internal error in PRPACK", __FILE__, __LINE__, 
+	             IGRAPH_EINTERNAL);
+#else
+        cerr << msg << endl;
+        exit(-1);
+#endif
+    }
+}
+
+// Permute a vector.
+double* prpack_utils::permute(const int length, const double* a, const int* coding) {
+    double* ret = new double[length];
+    for (int i = 0; i < length; ++i)
+        ret[coding[i]] = a[i];
+    return ret;
+}
+
diff --git a/src/prpack_solver.cpp b/src/prpack_solver.cpp
deleted file mode 100644
index 8649d89..0000000
--- a/src/prpack_solver.cpp
+++ /dev/null
@@ -1,877 +0,0 @@
-#include "prpack_solver.h"
-#include "prpack_utils.h"
-#include <cmath>
-#include <cstdlib>
-#include <cstring>
-using namespace prpack;
-using namespace std;
-
-void prpack_solver::initialize() {
-    geg = NULL;
-    gsg = NULL;
-    sg = NULL;
-    sccg = NULL;
-	owns_bg = true;
-}
-
-prpack_solver::prpack_solver(const prpack_csc* g) {
-    initialize();
-    TIME(read_time, bg = new prpack_base_graph(g));
-}
-
-prpack_solver::prpack_solver(const prpack_int64_csc* g) {
-    initialize();
-    TIME(read_time, bg = new prpack_base_graph(g));
-}
-
-prpack_solver::prpack_solver(const prpack_csr* g) {
-    initialize();
-    TIME(read_time, bg = new prpack_base_graph(g));
-}
-
-prpack_solver::prpack_solver(const prpack_edge_list* g) {
-    initialize();
-    TIME(read_time, bg = new prpack_base_graph(g));
-}
-
-prpack_solver::prpack_solver(prpack_base_graph* g, bool owns_bg) {
-    initialize();
-	this->owns_bg = owns_bg;
-    TIME(read_time, bg = g);
-}
-
-prpack_solver::prpack_solver(const char* filename, const char* format, const bool weighted) {
-    initialize();
-    TIME(read_time, bg = new prpack_base_graph(filename, format, weighted));
-}
-
-prpack_solver::~prpack_solver() {
-	if (owns_bg) {
-		delete bg;
-	}
-    delete geg;
-    delete gsg;
-    delete sg;
-    delete sccg;
-}
-
-int prpack_solver::get_num_vs() {
-    return bg->num_vs;
-}
-
-prpack_result* prpack_solver::solve(const double alpha, const double tol, const char* method) {
-    return solve(alpha, tol, NULL, NULL, method);
-}
-
-prpack_result* prpack_solver::solve(
-        const double alpha,
-        const double tol,
-        const double* u,
-        const double* v,
-        const char* method) {
-    double preprocess_time = 0;
-    double compute_time = 0;
-    prpack_result* ret = NULL;
-    // decide which method to run
-    string m;
-    if (strcmp(method, "") != 0)
-        m = string(method);
-    else {
-        if (bg->num_vs < 128)
-            m = "ge";
-        else if (sccg != NULL)
-            m = "sccgs";
-        else if (sg != NULL)
-            m = "sg";
-        else
-            m = "sccgs";
-        if (u != v)
-            m += "_uv";
-    }
-    // run the appropriate method
-    if (m == "ge") {
-        if (geg == NULL) {
-            TIME(preprocess_time, geg = new prpack_preprocessed_ge_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_ge(
-                alpha,
-                tol,
-                geg->num_vs,
-                geg->matrix,
-                u));
-    } else if (m == "ge_uv") {
-        if (geg == NULL) {
-            TIME(preprocess_time, geg = new prpack_preprocessed_ge_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_ge_uv(
-                alpha,
-                tol,
-                geg->num_vs,
-                geg->matrix,
-                geg->d,
-                u,
-                v));
-    } else if (m == "gs") {
-        if (gsg == NULL) {
-            TIME(preprocess_time, gsg = new prpack_preprocessed_gs_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_gs(
-                alpha,
-                tol,
-                gsg->num_vs,
-                gsg->num_es,
-                gsg->heads,
-                gsg->tails,
-                gsg->vals,
-                gsg->ii,
-                gsg->d,
-                gsg->num_outlinks,
-                u,
-                v));
-    } else if (m == "gserr") {
-        if (gsg == NULL) {
-            TIME(preprocess_time, gsg = new prpack_preprocessed_gs_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_gs_err(
-                alpha,
-                tol,
-                gsg->num_vs,
-                gsg->num_es,
-                gsg->heads,
-                gsg->tails,
-                gsg->ii,
-                gsg->num_outlinks,
-                u,
-                v));
-    } else if (m == "sgs") {
-        if (sg == NULL) {
-            TIME(preprocess_time, sg = new prpack_preprocessed_schur_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_schur_gs(
-                alpha,
-                tol,
-                sg->num_vs,
-                sg->num_no_in_vs,
-                sg->num_no_out_vs,
-                sg->num_es,
-                sg->heads,
-                sg->tails,
-                sg->vals,
-                sg->ii,
-                sg->d,
-                sg->num_outlinks,
-                u,
-                sg->encoding,
-                sg->decoding));
-    } else if (m == "sgs_uv") {
-        if (sg == NULL) {
-            TIME(preprocess_time, sg = new prpack_preprocessed_schur_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_schur_gs_uv(
-                alpha,
-                tol,
-                sg->num_vs,
-                sg->num_no_in_vs,
-                sg->num_no_out_vs,
-                sg->num_es,
-                sg->heads,
-                sg->tails,
-                sg->vals,
-                sg->ii,
-                sg->d,
-                sg->num_outlinks,
-                u,
-                v,
-                sg->encoding,
-                sg->decoding));
-    } else if (m == "sccgs") {
-        if (sccg == NULL) {
-            TIME(preprocess_time, sccg = new prpack_preprocessed_scc_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_scc_gs(
-                alpha,
-                tol,
-                sccg->num_vs,
-                sccg->num_es_inside,
-                sccg->heads_inside,
-                sccg->tails_inside,
-                sccg->vals_inside,
-                sccg->num_es_outside,
-                sccg->heads_outside,
-                sccg->tails_outside,
-                sccg->vals_outside,
-                sccg->ii,
-                sccg->d,
-                sccg->num_outlinks,
-                u,
-                sccg->num_comps,
-                sccg->divisions,
-                sccg->encoding,
-                sccg->decoding));
-    } else if (m == "sccgs_uv") {
-        if (sccg == NULL) {
-            TIME(preprocess_time, sccg = new prpack_preprocessed_scc_graph(bg));
-        }
-        TIME(compute_time, ret = solve_via_scc_gs_uv(
-                alpha,
-                tol,
-                sccg->num_vs,
-                sccg->num_es_inside,
-                sccg->heads_inside,
-                sccg->tails_inside,
-                sccg->vals_inside,
-                sccg->num_es_outside,
-                sccg->heads_outside,
-                sccg->tails_outside,
-                sccg->vals_outside,
-                sccg->ii,
-                sccg->d,
-                sccg->num_outlinks,
-                u,
-                v,
-                sccg->num_comps,
-                sccg->divisions,
-                sccg->encoding,
-                sccg->decoding));
-    } else {
-        // TODO: throw exception
-    }
-    ret->method = m.c_str();
-    ret->read_time = read_time;
-    ret->preprocess_time = preprocess_time;
-    ret->compute_time = compute_time;
-    ret->num_vs = bg->num_vs;
-    ret->num_es = bg->num_es;
-    return ret;
-}
-
-// VARIOUS SOLVING METHODS ////////////////////////////////////////////////////////////////////////
-
-prpack_result* prpack_solver::solve_via_ge(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const double* matrix,
-        const double* uv) {
-    prpack_result* ret = new prpack_result();
-    // initialize uv values
-    const double uv_const = 1.0/num_vs;
-    const int uv_exists = (uv) ? 1 : 0;
-    uv = (uv) ? uv : &uv_const;
-    // create matrix A
-    double* A = new double[num_vs*num_vs];
-    for (int i = 0; i < num_vs*num_vs; ++i)
-        A[i] = -alpha*matrix[i];
-    for (int i = 0; i < num_vs*num_vs; i += num_vs + 1)
-        ++A[i];
-    // create vector b
-    double* b = new double[num_vs];
-    for (int i = 0; i < num_vs; ++i)
-        b[i] = uv[uv_exists*i];
-    // solve and normalize
-    ge(num_vs, A, b);
-    normalize(num_vs, b);
-    // clean up and return
-    delete[] A;
-    ret->num_es_touched = -1;
-    ret->x = b;
-    return ret;
-}
-
-prpack_result* prpack_solver::solve_via_ge_uv(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const double* matrix,
-        const double* d,
-        const double* u,
-        const double* v) {
-    prpack_result* ret = new prpack_result();
-    // initialize u and v values
-    const double u_const = 1.0/num_vs;
-    const double v_const = 1.0/num_vs;
-    const int u_exists = (u) ? 1 : 0;
-    const int v_exists = (v) ? 1 : 0;
-    u = (u) ? u : &u_const;
-    v = (v) ? v : &v_const;
-    // create matrix A
-    double* A = new double[num_vs*num_vs];
-    for (int i = 0; i < num_vs*num_vs; ++i)
-        A[i] = -alpha*matrix[i];
-    for (int i = 0, inum_vs = 0; i < num_vs; ++i, inum_vs += num_vs)
-        for (int j = 0; j < num_vs; ++j)
-            A[inum_vs + j] -= alpha*u[u_exists*i]*d[j];
-    for (int i = 0; i < num_vs*num_vs; i += num_vs + 1)
-        ++A[i];
-    // create vector b
-    double* b = new double[num_vs];
-    for (int i = 0; i < num_vs; ++i)
-        b[i] = (1 - alpha)*v[v_exists*i];
-    // solve
-    ge(num_vs, A, b);
-    // clean up and return
-    delete[] A;
-    ret->num_es_touched = -1;
-    ret->x = b;
-    return ret;
-}
-
-// Vanilla Gauss-Seidel.
-prpack_result* prpack_solver::solve_via_gs(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const int num_es,
-        const int* heads,
-        const int* tails,
-        const double* vals,
-        const double* ii,
-        const double* d,
-        const double* num_outlinks,
-        const double* u,
-        const double* v) {
-    prpack_result* ret = new prpack_result();
-    const bool weighted = vals != NULL;
-    // initialize u and v values
-    const double u_const = 1.0/num_vs;
-    const double v_const = 1.0/num_vs;
-    const int u_exists = (u) ? 1 : 0;
-    const int v_exists = (v) ? 1 : 0;
-    u = (u) ? u : &u_const;
-    v = (v) ? v : &v_const;
-    // initialize the eigenvector (and use personalization vector)
-    double* x = new double[num_vs];
-    for (int i = 0; i < num_vs; ++i)
-        x[i] = 0;
-    // initialize delta
-    double delta = 0;
-    // run Gauss-Seidel
-    ret->num_es_touched = 0;
-    double err = 1, c = 0;
-    do {
-        if (weighted) {
-            for (int i = 0; i < num_vs; ++i) {
-                double new_val = 0;
-                const int start_j = tails[i];
-                const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
-                for (int j = start_j; j < end_j; ++j)
-                    // TODO: might want to use compensation summation for large: end_j - start_j
-                    new_val += x[heads[j]]*vals[j];
-                new_val = alpha*new_val + (1 - alpha)*v[v_exists*i];
-                delta -= alpha*x[i]*d[i];
-                new_val += delta*u[u_exists*i];
-                new_val /= 1 - alpha*(d[i]*u[u_exists*i] + (1 - d[i])*ii[i]);
-                delta += alpha*new_val*d[i];
-                COMPENSATED_SUM(err, x[i] - new_val, c);
-                x[i] = new_val;
-            }
-        } else {
-            for (int i = 0; i < num_vs; ++i) {
-                const double old_val = x[i]*num_outlinks[i];
-                double new_val = 0;
-                const int start_j = tails[i];
-                const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
-                for (int j = start_j; j < end_j; ++j)
-                    // TODO: might want to use compensation summation for large: end_j - start_j
-                    new_val += x[heads[j]];
-                new_val = alpha*new_val + (1 - alpha)*v[v_exists*i];
-                if (num_outlinks[i] < 0) {
-                    delta -= alpha*old_val;
-                    new_val += delta*u[u_exists*i];
-                    new_val /= 1 - alpha*u[u_exists*i];
-                    delta += alpha*new_val;
-                } else {
-                    new_val += delta*u[u_exists*i];
-                    new_val /= 1 - alpha*ii[i];
-                }
-                COMPENSATED_SUM(err, old_val - new_val, c);
-                x[i] = new_val/num_outlinks[i];
-            }
-        }
-        // update iteration index
-        ret->num_es_touched += num_es;
-    } while (err >= tol);
-    // undo num_outlinks transformation
-    if (!weighted)
-        for (int i = 0; i < num_vs; ++i)
-            x[i] *= num_outlinks[i];
-    // return results
-    ret->x = x;
-    return ret;
-}
-
-// Implement a gauss-seidel-like process with a strict error bound
-// we return a solution with 1-norm error less than tol.
-prpack_result* prpack_solver::solve_via_gs_err(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const int num_es,
-        const int* heads,
-        const int* tails,
-        const double* ii,
-        const double* num_outlinks,
-        const double* u,
-        const double* v) {
-    prpack_result* ret = new prpack_result();
-    // initialize u and v values
-    const double u_const = 1.0/num_vs;
-    const double v_const = 1.0/num_vs;
-    const int u_exists = (u) ? 1 : 0;
-    const int v_exists = (v) ? 1 : 0;
-    u = (u) ? u : &u_const;
-    v = (v) ? v : &v_const;
-    // Note to Dave, we can't rescale v because we could be running this
-    // same routine from multiple threads.
-    // initialize the eigenvector (and use personalization vector)
-    double* x = new double[num_vs];
-    for (int i = 0; i < num_vs; ++i) {
-        x[i] = 0.;
-    }
-    // initialize delta
-    double delta = 0.;
-    // run Gauss-Seidel, note that we store x/deg[i] throughout this 
-    // iteration.
-    long long maxedges = (long long)((double)num_es*std::min(
-                            log(tol)/log(alpha),
-                            (double)PRPACK_SOLVER_MAX_ITERS));
-    ret->num_es_touched = 0;
-    double err=1., c = 0.;
-    do {
-        // iterate through vertices
-        for (int i = 0; i < num_vs; ++i) {
-            double old_val = x[i]*num_outlinks[i]; // adjust back to the "true" value.
-            double new_val = 0.;
-            int start_j = tails[i], end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
-            for (int j = start_j; j < end_j; ++j) {
-                // TODO: might want to use compensation summation for large: end_j - start_j
-                new_val += x[heads[j]];
-            }
-            new_val = alpha*new_val + alpha*ii[i]*old_val + (1.0-alpha)*v[v_exists*i];
-            new_val += delta*u[u_exists*i]; // add the dangling node adjustment
-            if (num_outlinks[i] < 0) {
-                delta += alpha*(new_val - old_val);
-            } 
-            // note that new_val > old_val, but the fabs is just for 
-            COMPENSATED_SUM(err, -(new_val - old_val), c);
-            x[i] = new_val/num_outlinks[i];
-        }
-        // update iteration index
-        ret->num_es_touched += num_es;
-    } while (err >= tol && ret->num_es_touched < maxedges);
-    if (err >= tol) {
-        ret->converged = 0;
-    } else {
-        ret->converged = 1;
-    }
-    // undo num_outlinks transformation
-    for (int i = 0; i < num_vs; ++i)
-        x[i] *= num_outlinks[i];
-    // return results
-    ret->x = x;
-    return ret;
-}
-
-// Gauss-Seidel using the Schur complement to separate dangling nodes.
-prpack_result* prpack_solver::solve_via_schur_gs(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const int num_no_in_vs,
-        const int num_no_out_vs,
-        const int num_es,
-        const int* heads,
-        const int* tails,
-        const double* vals,
-        const double* ii,
-        const double* d,
-        const double* num_outlinks,
-        const double* uv,
-        const int* encoding,
-        const int* decoding,
-        const bool should_normalize) {
-    prpack_result* ret = new prpack_result();
-    const bool weighted = vals != NULL;
-    // initialize uv values
-    const double uv_const = 1.0/num_vs;
-    const int uv_exists = (uv) ? 1 : 0;
-    uv = (uv) ? prpack_utils::permute(num_vs, uv, encoding) : &uv_const;
-    // initialize the eigenvector (and use personalization vector)
-    double* x = new double[num_vs];
-    for (int i = 0; i < num_vs - num_no_out_vs; ++i)
-        x[i] = uv[uv_exists*i]/(1 - alpha*ii[i])/((weighted) ? 1 : num_outlinks[i]);
-    // run Gauss-Seidel for the top left part of (I - alpha*P)*x = uv
-    ret->num_es_touched = 0;
-    double err, c;
-    do {
-        // iterate through vertices
-        int num_es_touched = 0;
-        err = c = 0;
-        #pragma omp parallel for firstprivate(c) reduction(+:err, num_es_touched) schedule(dynamic, 64)
-        for (int i = num_no_in_vs; i < num_vs - num_no_out_vs; ++i) {
-            double new_val = 0;
-            const int start_j = tails[i];
-            const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
-            if (weighted) {
-                for (int j = start_j; j < end_j; ++j)
-                    // TODO: might want to use compensation summation for large: end_j - start_j
-                    new_val += x[heads[j]]*vals[j];
-                COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);
-                new_val = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
-                x[i] = new_val;
-            } else {
-                for (int j = start_j; j < end_j; ++j)
-                    // TODO: might want to use compensation summation for large: end_j - start_j
-                    new_val += x[heads[j]];
-                COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);
-                new_val = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
-                x[i] = new_val/num_outlinks[i];
-            }
-            num_es_touched += end_j - start_j;
-        }
-        // update iteration index
-        ret->num_es_touched += num_es_touched;
-    } while (err/(1 - alpha) >= tol);
-    // solve for the dangling nodes
-    int num_es_touched = 0;
-    #pragma omp parallel for reduction(+:num_es_touched) schedule(dynamic, 64)
-    for (int i = num_vs - num_no_out_vs; i < num_vs; ++i) {
-        x[i] = 0;
-        const int start_j = tails[i];
-        const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;
-        for (int j = start_j; j < end_j; ++j)
-            x[i] += x[heads[j]]*((weighted) ? vals[j] : 1);
-        x[i] = (alpha*x[i] + uv[uv_exists*i])/(1 - alpha*ii[i]);
-        num_es_touched += end_j - start_j;
-    }
-    ret->num_es_touched += num_es_touched;
-    // undo num_outlinks transformation
-    if (!weighted)
-        for (int i = 0; i < num_vs - num_no_out_vs; ++i)
-            x[i] *= num_outlinks[i];
-    // normalize x to get the solution for: (I - alpha*P - alpha*u*d')*x = (1 - alpha)*v
-    if (should_normalize)
-        normalize(num_vs, x);
-    // return results
-    ret->x = prpack_utils::permute(num_vs, x, decoding);
-    delete[] x;
-    if (uv_exists)
-        delete[] uv;
-    return ret;
-}
-
-prpack_result* prpack_solver::solve_via_schur_gs_uv(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const int num_no_in_vs,
-        const int num_no_out_vs,
-        const int num_es,
-        const int* heads,
-        const int* tails,
-        const double* vals,
-        const double* ii,
-        const double* d,
-        const double* num_outlinks,
-        const double* u,
-        const double* v,
-        const int* encoding,
-        const int* decoding) {
-    // solve uv = u
-    prpack_result* ret_u = solve_via_schur_gs(
-            alpha,
-            tol,
-            num_vs,
-            num_no_in_vs,
-            num_no_out_vs,
-            num_es,
-            heads,
-            tails,
-            vals,
-            ii,
-            d,
-            num_outlinks,
-            u,
-            encoding,
-            decoding,
-            false);
-    // solve uv = v
-    prpack_result* ret_v = solve_via_schur_gs(
-            alpha,
-            tol,
-            num_vs,
-            num_no_in_vs,
-            num_no_out_vs,
-            num_es,
-            heads,
-            tails,
-            vals,
-            ii,
-            d,
-            num_outlinks,
-            v,
-            encoding,
-            decoding,
-            false);
-    // combine the u and v cases
-    return combine_uv(num_vs, d, num_outlinks, encoding, alpha, ret_u, ret_v);
-}
-
-/** Gauss-Seidel using strongly connected components.
- * Notes:
- *   If not weighted, then we store x[i] = "x[i]/outdegree" to 
- *   avoid additional arithmetic.  We don't do this for the weighted
- *   case because the adjustment may not be constant.
- */
-prpack_result* prpack_solver::solve_via_scc_gs(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const int num_es_inside,
-        const int* heads_inside,
-        const int* tails_inside,
-        const double* vals_inside,
-        const int num_es_outside,
-        const int* heads_outside,
-        const int* tails_outside,
-        const double* vals_outside,
-        const double* ii,
-        const double* d,
-        const double* num_outlinks,
-        const double* uv,
-        const int num_comps,
-        const int* divisions,
-        const int* encoding,
-        const int* decoding,
-        const bool should_normalize) {
-    prpack_result* ret = new prpack_result();
-    const bool weighted = vals_inside != NULL;
-    // initialize uv values
-    const double uv_const = 1.0/num_vs;
-    const int uv_exists = (uv) ? 1 : 0;
-    uv = (uv) ? prpack_utils::permute(num_vs, uv, encoding) : &uv_const;
-    // CHECK initialize the solution with one iteration of GS from x=0.
-    double* x = new double[num_vs];
-    for (int i = 0; i < num_vs; ++i)
-        x[i] = uv[uv_exists*i]/(1 - alpha*ii[i])/((weighted) ? 1 : num_outlinks[i]);
-    // create x_outside
-    double* x_outside = new double[num_vs];
-    // run Gauss-Seidel for (I - alpha*P)*x = uv
-    ret->num_es_touched = 0;
-    for (int comp_i = 0; comp_i < num_comps; ++comp_i) {
-        const int start_comp = divisions[comp_i];
-        const int end_comp = (comp_i + 1 != num_comps) ? divisions[comp_i + 1] : num_vs;
-        const bool parallelize = end_comp - start_comp > 512;
-        // initialize relevant x_outside values
-        for (int i = start_comp; i < end_comp; ++i) {
-            x_outside[i] = 0;
-            const int start_j = tails_outside[i];
-            const int end_j = (i + 1 != num_vs) ? tails_outside[i + 1] : num_es_outside;
-            for (int j = start_j; j < end_j; ++j)
-                x_outside[i] += x[heads_outside[j]]*((weighted) ? vals_outside[j] : 1.);
-            ret->num_es_touched += end_j - start_j;
-        }
-        double err, c;
-        do {
-            int num_es_touched = 0;
-            err = c = 0;
-            if (parallelize) {
-                // iterate through vertices
-                #pragma omp parallel for firstprivate(c) reduction(+:err, num_es_touched) schedule(dynamic, 64)
-                for (int i = start_comp; i < end_comp; ++i) {
-                    double new_val = x_outside[i];
-                    const int start_j = tails_inside[i];
-                    const int end_j = (i + 1 != num_vs) ? tails_inside[i + 1] : num_es_inside;
-                    if (weighted) {
-                        for (int j = start_j; j < end_j; ++j) {
-                            // TODO: might want to use compensation summation for large: end_j - start_j
-                            new_val += x[heads_inside[j]]*vals_inside[j];
-                        }
-                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);
-                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
-                    } else {
-                        for (int j = start_j; j < end_j; ++j) {
-                            // TODO: might want to use compensation summation for large: end_j - start_j
-                            new_val += x[heads_inside[j]];
-                        }
-                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);
-                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i])/num_outlinks[i];
-                    }
-                    num_es_touched += end_j - start_j;
-                }
-            } else {
-                for (int i = start_comp; i < end_comp; ++i) {
-                    double new_val = x_outside[i];
-                    const int start_j = tails_inside[i];
-                    const int end_j = (i + 1 != num_vs) ? tails_inside[i + 1] : num_es_inside;
-                    if (weighted) {
-                        for (int j = start_j; j < end_j; ++j) {
-                            // TODO: might want to use compensation summation for large: end_j - start_j
-                            new_val += x[heads_inside[j]]*vals_inside[j];
-                        }
-                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);
-                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);
-                    } else {
-                        for (int j = start_j; j < end_j; ++j) {
-                            // TODO: might want to use compensation summation for large: end_j - start_j
-                            new_val += x[heads_inside[j]];
-                        }
-                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);
-                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i])/num_outlinks[i];
-                    }
-                    num_es_touched += end_j - start_j;
-                }
-            }
-            // update iteration index
-            ret->num_es_touched += num_es_touched;
-        } while (err/(1 - alpha) >= tol*(end_comp - start_comp)/num_vs);
-    }
-    // undo num_outlinks transformation
-    if (!weighted)
-        for (int i = 0; i < num_vs; ++i)
-            x[i] *= num_outlinks[i];
-    // normalize x to get the solution for: (I - alpha*P - alpha*u*d')*x = (1 - alpha)*v
-    if (should_normalize)
-        normalize(num_vs, x);
-    // return results
-    ret->x = prpack_utils::permute(num_vs, x, decoding);
-    delete[] x;
-    delete[] x_outside;
-    if (uv_exists)
-        delete[] uv;
-    return ret;
-}
-
-prpack_result* prpack_solver::solve_via_scc_gs_uv(
-        const double alpha,
-        const double tol,
-        const int num_vs,
-        const int num_es_inside,
-        const int* heads_inside,
-        const int* tails_inside,
-        const double* vals_inside,
-        const int num_es_outside,
-        const int* heads_outside,
-        const int* tails_outside,
-        const double* vals_outside,
-        const double* ii,
-        const double* d,
-        const double* num_outlinks,
-        const double* u,
-        const double* v,
-        const int num_comps,
-        const int* divisions,
-        const int* encoding,
-        const int* decoding) {
-    // solve uv = u
-    prpack_result* ret_u = solve_via_scc_gs(
-            alpha,
-            tol,
-            num_vs,
-            num_es_inside,
-            heads_inside,
-            tails_inside,
-            vals_inside,
-            num_es_outside,
-            heads_outside,
-            tails_outside,
-            vals_outside,
-            ii,
-            d,
-            num_outlinks,
-            u,
-            num_comps,
-            divisions,
-            encoding,
-            decoding,
-            false);
-    // solve uv = v
-    prpack_result* ret_v = solve_via_scc_gs(
-            alpha,
-            tol,
-            num_vs,
-            num_es_inside,
-            heads_inside,
-            tails_inside,
-            vals_inside,
-            num_es_outside,
-            heads_outside,
-            tails_outside,
-            vals_outside,
-            ii,
-            d,
-            num_outlinks,
-            v,
-            num_comps,
-            divisions,
-            encoding,
-            decoding,
-            false);
-    // combine u and v
-    return combine_uv(num_vs, d, num_outlinks, encoding, alpha, ret_u, ret_v);
-}
-
-// VARIOUS HELPER METHODS /////////////////////////////////////////////////////////////////////////
-
-// Run Gaussian-Elimination (note: this changes A and returns the solution in b)
-void prpack_solver::ge(const int sz, double* A, double* b) {
-    // put into triangular form
-    for (int i = 0, isz = 0; i < sz; ++i, isz += sz)
-        for (int k = 0, ksz = 0; k < i; ++k, ksz += sz)
-            if (A[isz + k] != 0) {
-                const double coeff = A[isz + k]/A[ksz + k];
-                A[isz + k] = 0;
-                for (int j = k + 1; j < sz; ++j)
-                    A[isz + j] -= coeff*A[ksz + j];
-                b[i] -= coeff*b[k];
-            }
-    // backwards substitution
-    for (int i = sz - 1, isz = (sz - 1)*sz; i >= 0; --i, isz -= sz) {
-        for (int j = i + 1; j < sz; ++j)
-            b[i] -= A[isz + j]*b[j];
-        b[i] /= A[isz + i];
-    }
-}
-
-// Normalize a vector to sum to 1.
-void prpack_solver::normalize(const int length, double* x) {
-    double norm = 0, c = 0;
-    for (int i = 0; i < length; ++i) {
-        COMPENSATED_SUM(norm, x[i], c);
-    }
-    norm = 1/norm;
-    for (int i = 0; i < length; ++i)
-        x[i] *= norm;
-}
-
-// Combine u and v results.
-prpack_result* prpack_solver::combine_uv(
-        const int num_vs,
-        const double* d,
-        const double* num_outlinks,
-        const int* encoding,
-        const double alpha,
-        const prpack_result* ret_u,
-        const prpack_result* ret_v) {
-    prpack_result* ret = new prpack_result();
-    const bool weighted = d != NULL;
-    double delta_u = 0;
-    double delta_v = 0;
-    for (int i = 0; i < num_vs; ++i) {
-        if ((weighted) ? (d[encoding[i]] == 1) : (num_outlinks[encoding[i]] < 0)) {
-            delta_u += ret_u->x[i];
-            delta_v += ret_v->x[i];
-        }
-    }
-    const double s = ((1 - alpha)*alpha*delta_v)/(1 - alpha*delta_u);
-    const double t = 1 - alpha;
-    ret->x = new double[num_vs];
-    for (int i = 0; i < num_vs; ++i)
-        ret->x[i] = s*ret_u->x[i] + t*ret_v->x[i];
-    ret->num_es_touched = ret_u->num_es_touched + ret_v->num_es_touched;
-    // clean up and return
-    delete ret_u;
-    delete ret_v;
-    return ret;
-}
-
diff --git a/src/prpack_utils.cpp b/src/prpack_utils.cpp
deleted file mode 100644
index f5aee84..0000000
--- a/src/prpack_utils.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * @file prpack_utils.cpp
- * An assortment of utility functions for reporting errors, checking time,
- * and working with vectors.
- */
-
-#include <stdlib.h>
-#include "prpack_utils.h"
-#include <cassert>
-#include <iostream>
-#include <string>
-using namespace prpack;
-using namespace std;
-
-#ifdef PRPACK_IGRAPH_SUPPORT
-#include "igraph_error.h"
-#endif
-
-#if defined(_WIN32) || defined(_WIN64)
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#endif
-double prpack_utils::get_time() {
-    LARGE_INTEGER t, freq;
-    QueryPerformanceCounter(&t);
-    QueryPerformanceFrequency(&freq);
-    return double(t.QuadPart)/double(freq.QuadPart);
-}
-#else
-#include <sys/types.h>
-#include <sys/timeb.h>
-#include <sys/time.h>
-double prpack_utils::get_time() {
-    struct timeval t;
-    gettimeofday(&t, 0);
-    return (t.tv_sec*1.0 + t.tv_usec/1000000.0);
-}
-#endif
-
-// Fails and outputs 'msg' if 'condition' is false.
-void prpack_utils::validate(const bool condition, const string& msg) {
-    if (!condition) {
-#ifdef PRPACK_IGRAPH_SUPPORT
-        igraph_error("Internal error in PRPACK", __FILE__, __LINE__, 
-	             IGRAPH_EINTERNAL);
-#else
-        cerr << msg << endl;
-        exit(-1);
-#endif
-    }
-}
-
-// Permute a vector.
-double* prpack_utils::permute(const int length, const double* a, const int* coding) {
-    double* ret = new double[length];
-    for (int i = 0; i < length; ++i)
-        ret[coding[i]] = a[i];
-    return ret;
-}
-
diff --git a/src/random.c b/src/random.c
index a9de73f..0cc19b0 100644
--- a/src/random.c
+++ b/src/random.c
@@ -32,6 +32,7 @@
 #include "igraph_types.h"
 #include "igraph_vector.h"
 #include "igraph_memory.h"
+#include "igraph_matrix.h"
 
 /** 
  * \section about_rngs 
@@ -530,6 +531,7 @@ double  norm_rand(void);
 double  exp_rand(void);
 double  Rf_rgeom(double);
 double  Rf_rbinom(double, double);
+double  Rf_rgamma(double, double);
 
 int igraph_rng_R_init(void **state) {
   IGRAPH_ERROR("R RNG error, unsupported function called",
@@ -569,6 +571,11 @@ igraph_real_t igraph_rng_R_get_binom(void *state, long int n,
   return Rf_rbinom(n, p);
 }
 
+igraph_real_t igraph_rng_R_get_gamma(void *state, igraph_real_t shape,
+				     igraph_real_t scale) {
+  return Rf_rgamma(shape, scale);
+}
+
 igraph_real_t igraph_rng_R_get_exp(void *state, igraph_real_t rate) {
   igraph_real_t scale = 1.0 / rate;
   if (!IGRAPH_FINITE(scale) || scale <= 0.0) {
@@ -622,6 +629,7 @@ double igraph_norm_rand(igraph_rng_t *rng);
 double igraph_rgeom(igraph_rng_t *rng, double p);
 double igraph_rbinom(igraph_rng_t *rng, double nin, double pp);
 double igraph_rexp(igraph_rng_t *rng, double rate);
+double igraph_rgamma(igraph_rng_t *rng, double shape, double scale);
 
 /** 
  * \function igraph_rng_init
@@ -871,6 +879,29 @@ igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, long int n,
   }
 }
 
+/**
+ * \function igraph_rng_get_gamma
+ * Generate sample from a Gamma distribution
+ *
+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()
+ *        here to use the default igraph RNG.
+ * \param a
+ * \param scale
+ * \return The generated sample
+ * 
+ * Time complexity: depends on RNG.
+ */
+
+igraph_real_t igraph_rng_get_gamma(igraph_rng_t *rng, igraph_real_t shape,
+				   igraph_real_t scale) {
+  const igraph_rng_type_t *type=rng->type;
+  if (type->get_gamma) {
+    return type->get_gamma(rng->state, shape, scale);
+  } else {
+    return igraph_rgamma(rng, shape, scale);
+  }
+}
+
 unsigned long int igraph_rng_get_int31(igraph_rng_t *rng) {
   const igraph_rng_type_t *type=rng->type;
   unsigned long int max=type->max;
@@ -1163,6 +1194,10 @@ double igraph_rexp(igraph_rng_t *rng, double rate) {
   return scale * exp_rand();
 }
 
+double igraph_rgamma(igraph_rng_t *rng, double shape, double scale) {
+  return Rf_rgamma(shape, scale);
+}
+
 #else
 
 /*
@@ -1885,6 +1920,14 @@ double igraph_rpois(igraph_rng_t *rng, double mu)
     return pois;
 }
 
+#undef a1
+#undef a2
+#undef a3
+#undef a4
+#undef a5
+#undef a6
+#undef a7
+
 double igraph_rgeom(igraph_rng_t *rng, double p) {
     if (ISNAN(p) || p <= 0 || p > 1) ML_ERR_return_NAN;
 
@@ -2061,8 +2104,304 @@ igraph_real_t igraph_rexp(igraph_rng_t *rng, double rate) {
   return scale * igraph_exp_rand(rng);
 }
 
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000      The R Core Team
+ *  Copyright (C) 2003      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
+ *
+ *      double dnorm4(double x, double mu, double sigma, int give_log)
+ *            {dnorm (..) is synonymous and preferred inside R}
+ *
+ *  DESCRIPTION
+ *
+ *      Compute the density of the normal distribution.
+ */
+
+double igraph_dnorm(double x, double mu, double sigma, int give_log)
+{
+#ifdef IEEE_754
+    if (ISNAN(x) || ISNAN(mu) || ISNAN(sigma))
+        return x + mu + sigma;
+#endif
+    if(!R_FINITE(sigma)) return R_D__0;
+    if(!R_FINITE(x) && mu == x) return ML_NAN;/* x-mu is NaN */
+    if (sigma <= 0) {
+        if (sigma < 0) ML_ERR_return_NAN;
+        /* sigma == 0 */
+        return (x == mu) ? ML_POSINF : R_D__0;
+    }
+    x = (x - mu) / sigma;
+
+    if(!R_FINITE(x)) return R_D__0;
+    return (give_log ?
+            -(M_LN_SQRT_2PI  +  0.5 * x * x + log(sigma)) :
+            M_1_SQRT_2PI * exp(-0.5 * x * x)  /   sigma);
+    /* M_1_SQRT_2PI = 1 / sqrt(2 * pi) */
+}
+
+/* This is from nmath/rgamma.c */
+
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000--2008 The R Core Team
+ *
+ *  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 rgamma(double a, double scale);
+ *
+ *  DESCRIPTION
+ *
+ *    Random variates from the gamma distribution.
+ *
+ *  REFERENCES
+ *
+ *    [1] Shape parameter a >= 1.  Algorithm GD in:
+ *
+ *	  Ahrens, J.H. and Dieter, U. (1982).
+ *	  Generating gamma variates by a modified
+ *	  rejection technique.
+ *	  Comm. ACM, 25, 47-54.
+ *
+ *
+ *    [2] Shape parameter 0 < a < 1. Algorithm GS in:
+ *
+ *	  Ahrens, J.H. and Dieter, U. (1974).
+ *	  Computer methods for sampling from gamma, beta,
+ *	  poisson and binomial distributions.
+ *	  Computing, 12, 223-246.
+ *
+ *    Input: a = parameter (mean) of the standard gamma distribution.
+ *    Output: a variate from the gamma(a)-distribution
+ */
+
+double igraph_rgamma(igraph_rng_t *rng, double a, double scale)
+{
+/* Constants : */
+    const static double sqrt32 = 5.656854;
+    const static double exp_m1 = 0.36787944117144232159;/* exp(-1) = 1/e */
+
+    /* Coefficients q[k] - for q0 = sum(q[k]*a^(-k))
+     * Coefficients a[k] - for q = q0+(t*t/2)*sum(a[k]*v^k)
+     * Coefficients e[k] - for exp(q)-1 = sum(e[k]*q^k)
+     */
+    const static double q1 = 0.04166669;
+    const static double q2 = 0.02083148;
+    const static double q3 = 0.00801191;
+    const static double q4 = 0.00144121;
+    const static double q5 = -7.388e-5;
+    const static double q6 = 2.4511e-4;
+    const static double q7 = 2.424e-4;
+
+    const static double a1 = 0.3333333;
+    const static double a2 = -0.250003;
+    const static double a3 = 0.2000062;
+    const static double a4 = -0.1662921;
+    const static double a5 = 0.1423657;
+    const static double a6 = -0.1367177;
+    const static double a7 = 0.1233795;
+
+    /* State variables [FIXME for threading!] :*/
+    static double aa = 0.;
+    static double aaa = 0.;
+    static double s, s2, d;    /* no. 1 (step 1) */
+    static double q0, b, si, c;/* no. 2 (step 4) */
+
+    double e, p, q, r, t, u, v, w, x, ret_val;
+
+    if (!R_FINITE(a) || !R_FINITE(scale) || a < 0.0 || scale <= 0.0) {
+	if(scale == 0.) return 0.;
+	ML_ERR_return_NAN;
+    }
+
+    if (a < 1.) { /* GS algorithm for parameters a < 1 */
+	if(a == 0)
+	    return 0.;
+	e = 1.0 + exp_m1 * a;
+	repeat {
+	    p = e * igraph_rng_get_unif01(rng);
+	    if (p >= 1.0) {
+		x = -log((e - p) / a);
+		if (igraph_exp_rand(rng) >= (1.0 - a) * log(x))
+		    break;
+	    } else {
+		x = exp(log(p) / a);
+		if (igraph_exp_rand(rng) >= x)
+		    break;
+	    }
+	}
+	return scale * x;
+    }
+
+    /* --- a >= 1 : GD algorithm --- */
+
+    /* Step 1: Recalculations of s2, s, d if a has changed */
+    if (a != aa) {
+	aa = a;
+	s2 = a - 0.5;
+	s = sqrt(s2);
+	d = sqrt32 - s * 12.0;
+    }
+    /* Step 2: t = standard normal deviate,
+               x = (s,1/2) -normal deviate. */
+
+    /* immediate acceptance (i) */
+    t = igraph_norm_rand(rng);
+    x = s + 0.5 * t;
+    ret_val = x * x;
+    if (t >= 0.0)
+	return scale * ret_val;
+
+    /* Step 3: u = 0,1 - uniform sample. squeeze acceptance (s) */
+    u = igraph_rng_get_unif01(rng);
+    if (d * u <= t * t * t)
+	return scale * ret_val;
+
+    /* Step 4: recalculations of q0, b, si, c if necessary */
+
+    if (a != aaa) {
+	aaa = a;
+	r = 1.0 / a;
+	q0 = ((((((q7 * r + q6) * r + q5) * r + q4) * r + q3) * r
+	       + q2) * r + q1) * r;
+
+	/* Approximation depending on size of parameter a */
+	/* The constants in the expressions for b, si and c */
+	/* were established by numerical experiments */
+
+	if (a <= 3.686) {
+	    b = 0.463 + s + 0.178 * s2;
+	    si = 1.235;
+	    c = 0.195 / s - 0.079 + 0.16 * s;
+	} else if (a <= 13.022) {
+	    b = 1.654 + 0.0076 * s2;
+	    si = 1.68 / s + 0.275;
+	    c = 0.062 / s + 0.024;
+	} else {
+	    b = 1.77;
+	    si = 0.75;
+	    c = 0.1515 / s;
+	}
+    }
+    /* Step 5: no quotient test if x not positive */
+
+    if (x > 0.0) {
+	/* Step 6: calculation of v and quotient q */
+	v = t / (s + s);
+	if (fabs(v) <= 0.25)
+	    q = q0 + 0.5 * t * t * ((((((a7 * v + a6) * v + a5) * v + a4) * v
+				      + a3) * v + a2) * v + a1) * v;
+	else
+	    q = q0 - s * t + 0.25 * t * t + (s2 + s2) * log(1.0 + v);
+
+
+	/* Step 7: quotient acceptance (q) */
+	if (log(1.0 - u) <= q)
+	    return scale * ret_val;
+    }
+
+    repeat {
+	/* Step 8: e = standard exponential deviate
+	 *	u =  0,1 -uniform deviate
+	 *	t = (b,si)-double exponential (laplace) sample */
+	e = igraph_exp_rand(rng);
+	u = igraph_rng_get_unif01(rng);
+	u = u + u - 1.0;
+	if (u < 0.0)
+	    t = b - si * e;
+	else
+	    t = b + si * e;
+	/* Step	 9:  rejection if t < tau(1) = -0.71874483771719 */
+	if (t >= -0.71874483771719) {
+	    /* Step 10:	 calculation of v and quotient q */
+	    v = t / (s + s);
+	    if (fabs(v) <= 0.25)
+		q = q0 + 0.5 * t * t *
+		    ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v
+		      + a2) * v + a1) * v;
+	    else
+		q = q0 - s * t + 0.25 * t * t + (s2 + s2) * log(1.0 + v);
+	    /* Step 11:	 hat acceptance (h) */
+	    /* (if q not positive go to step 8) */
+	    if (q > 0.0) {
+		w = expm1(q);
+		/*  ^^^^^ original code had approximation with rel.err < 2e-7 */
+		/* if t is rejected sample again at step 8 */
+		if (c * fabs(u) <= w * exp(e - 0.5 * t * t))
+		    break;
+	    }
+	}
+    } /* repeat .. until  `t' is accepted */
+    x = s + 0.5 * t;
+    return scale * x * x;
+}
+
 #endif
 
+int igraph_rng_get_dirichlet(igraph_rng_t *rng,
+			     const igraph_vector_t *alpha,
+			     igraph_vector_t *result) {
+
+  igraph_integer_t len=igraph_vector_size(alpha);
+  igraph_integer_t j;
+  igraph_real_t sum=0.0;
+
+  if (len < 2) {
+    IGRAPH_ERROR("Dirichlet parameter vector too short, must "
+		 "have at least two entries", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_min(alpha) <= 0) {
+    IGRAPH_ERROR("Dirichlet concentration parameters must be positive",
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vector_resize(result, len));
+
+  RNG_BEGIN();
+
+  for (j = 0; j < len; j++) {
+    VECTOR(*result)[j] = igraph_rng_get_gamma(rng, VECTOR(*alpha)[j], 1.0);
+    sum += VECTOR(*result)[j];
+  }
+  for (j = 0; j < len; j++) { VECTOR(*result)[j] /= sum; }
+
+  RNG_END();
+
+  return 0;
+}
+
 /**********************************************************
  * Testing purposes                                       *
  *********************************************************/
diff --git a/src/random_walk.c b/src/random_walk.c
new file mode 100644
index 0000000..b7815c8
--- /dev/null
+++ b/src/random_walk.c
@@ -0,0 +1,113 @@
+/* -*- mode: C -*-  */
+/*
+   IGraph library.
+   Copyright (C) 2014  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_paths.h"
+#include "igraph_adjlist.h"
+#include "igraph_interface.h"
+#include "igraph_random.h"
+
+/**
+ * \function igraph_random_walk
+ * Perform a random walk on a graph
+ *
+ * Performs a random walk with a given length on a graph, from the given
+ * start vertex. Edge directions are (potentially) considered, depending on
+ * the \p mode argument.
+ *
+ * \param graph The input graph, it can be directed or undirected.
+ *   Multiple edges are respected, so are loop edges.
+ * \param walk An allocated vector, the result is stored here.
+ *   It will be resized as needed.
+ * \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.
+ *   \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.
+ * \param stuck What to do if the random walk gets stuck.
+ *   \c IGRAPH_RANDOM_WALK_STUCK_RETURN means that the function returns
+ *   with a shorter walk; \c IGRAPH_RANDOM_WALK_STUCK_ERROR means
+ *   that an error is reported. In both cases \p walk is truncated
+ *   to contain the actual interrupted walk.
+ * \return Error code.
+ *
+ * Time complexity: O(l + d), where \c l is the length of the
+ * walk, and \c d is the total degree of the visited nodes.
+ */
+
+
+int igraph_random_walk(const igraph_t *graph, igraph_vector_t *walk,
+		       igraph_integer_t start, igraph_neimode_t mode,
+		       igraph_integer_t steps,
+		       igraph_random_walk_stuck_t stuck) {
+
+  /* TODO:
+     - multiple walks potentially from multiple start vertices
+     - weights
+  */
+
+  igraph_lazy_adjlist_t adj;
+  igraph_integer_t vc = igraph_vcount(graph);
+  igraph_integer_t i;
+
+  if (start < 0 || start >= vc) {
+    IGRAPH_ERROR("Invalid start vertex", IGRAPH_EINVAL);
+  }
+  if (steps < 0) {
+    IGRAPH_ERROR("Invalid number of steps", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adj, mode,
+					IGRAPH_DONT_SIMPLIFY));
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adj);
+
+  IGRAPH_CHECK(igraph_vector_resize(walk, steps));
+
+  RNG_BEGIN();
+
+  VECTOR(*walk)[0] = start;
+  for (i = 1; i < steps; i++) {
+    igraph_vector_t *neis;
+    igraph_integer_t nn;
+    neis = igraph_lazy_adjlist_get(&adj, start);
+    nn = igraph_vector_size(neis);
+
+    if (IGRAPH_UNLIKELY(nn == 0)) {
+      igraph_vector_resize(walk, i);
+      if (stuck == IGRAPH_RANDOM_WALK_STUCK_RETURN) {
+	break;
+      } else {
+	IGRAPH_ERROR("Random walk got stuck", IGRAPH_ERWSTUCK);
+      }
+    }
+    start = VECTOR(*walk)[i] = VECTOR(*neis)[ RNG_INTEGER(0, nn - 1) ];
+  }
+
+  RNG_END();
+
+  igraph_lazy_adjlist_destroy(&adj);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
diff --git a/src/revolver_cit.c b/src/revolver_cit.c
deleted file mode 100644
index 897caf1..0000000
--- a/src/revolver_cit.c
+++ /dev/null
@@ -1,6479 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph R package.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-#include "igraph_revolver.h"
-#include "igraph_progress.h"
-#include "igraph_interrupt_internal.h"
-#include "igraph_interface.h"
-#include "igraph_iterators.h"
-#include "igraph_structural.h"
-#include "config.h"
-
-#include <math.h>
-
-/***********************************************/
-/* in-degree                                   */
-/***********************************************/
-
-int igraph_revolver_d(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));  
-  
-  IGRAPH_PROGRESS("Revolver d", 0, NULL);
-  for (i=0; i<niter; i++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1!=niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_d(graph, kernel, 0 /*sd*/, 0 /*norm*/, 
-					 0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					 0 /*logmax*/,
-					 &st, maxdegree));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_d(graph, &st, kernel));
-    } else {			/* last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_d(graph, kernel, sd, norm, cites, debug,
-					debugres, logmax, &st, maxdegree));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_d(graph, &st, kernel));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_d(graph, expected, kernel,
-					  &st, maxdegree));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_d(graph, kernel, &st, maxdegree,
-					    logprob, lognull));
-      }
-    }
-    
-    IGRAPH_PROGRESS("Revolver d", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}
-
-int igraph_revolver_mes_d(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 igraph_integer_t maxind) {
-  
-  long int classes=maxind+1;
-  long int no_of_nodes=igraph_vcount(graph);
-  
-  igraph_vector_t indegree;
-  igraph_vector_t v_normfact, *normfact;
-  igraph_vector_t ntk, ch;
-  igraph_vector_t v_notnull, *notnull;
-
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-  long int edges=0;
-
-  IGRAPH_UNUSED(debug);
-  IGRAPH_UNUSED(debugres);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ntk, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ch, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_vector_resize(normfact, classes));
-    igraph_vector_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_VECTOR_INIT_FINALLY(normfact, classes);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_vector_resize(notnull, classes));
-    igraph_vector_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_VECTOR_INIT_FINALLY(notnull, classes);
-  }
-  
-  IGRAPH_CHECK(igraph_vector_resize(kernel, classes));
-  igraph_vector_null(kernel);
-  if (sd) { 
-    IGRAPH_CHECK(igraph_vector_resize(sd, classes)); 
-    igraph_vector_null(sd);
-  }
-
-  VECTOR(ntk)[0]=1;
-
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntk)[xidx];
-      double oldm=VECTOR(*kernel)[xidx];
-      VECTOR(*notnull)[xidx]+=1;
-      VECTOR(*kernel)[xidx] += (xk-oldm)/VECTOR(*notnull)[xidx];
-      if (sd) {
-	VECTOR(*sd)[xidx] += (xk-oldm)*(xk-VECTOR(*kernel)[xidx]);
-      }
-      /* TODO: debug */
-      if (logmax) {
-	*logmax += log(1.0/VECTOR(ntk)[xidx]);
-      }
-    }
-    
-    /* Update ntk & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      VECTOR(indegree)[to] += 1;
-      VECTOR(ntk)[xidx] -= 1;
-      if (VECTOR(ntk)[xidx]==0) {
-	VECTOR(*normfact)[xidx] += (edges-VECTOR(ch)[xidx]);
-      }
-      VECTOR(ntk)[xidx+1] += 1;
-      if (VECTOR(ntk)[xidx+1]==1) {
-	VECTOR(ch)[xidx+1]=edges;
-      }
-    }
-    VECTOR(ntk)[0] += 1;
-    if (VECTOR(ntk)[0]==1) {
-      VECTOR(ch)[0]=edges;
-    }
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<classes; i++) {
-    igraph_real_t oldmean;
-    if (VECTOR(ntk)[i] != 0) {
-      VECTOR(*normfact)[i] += (edges-VECTOR(ch)[i]);
-    }
-    if (VECTOR(*normfact)[i]==0) {
-      VECTOR(*kernel)[i]=0;
-      VECTOR(*normfact)[i]=1;
-    }
-    oldmean=VECTOR(*kernel)[i];
-    VECTOR(*kernel)[i] *= VECTOR(*notnull)[i] / VECTOR(*normfact)[i];
-    if (sd) {
-      VECTOR(*sd)[i] += oldmean * oldmean * VECTOR(*notnull)[i] *
-	(1-VECTOR(*notnull)[i]/VECTOR(*normfact)[i]);
-      VECTOR(*sd)[i] = sqrt(VECTOR(*sd)[i]/(VECTOR(*normfact)[i]-1));
-    }
-  }
-  
-  if (!cites) {
-    igraph_vector_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_vector_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&ch);
-  igraph_vector_destroy(&ntk);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(4);
-	
-  return 0;
-}
-
-int igraph_revolver_st_d(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  VECTOR(*st)[0]=VECTOR(*kernel)[0];
-  
-  for (node=1; node<no_of_nodes; node++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1]+VECTOR(*kernel)[0];
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      VECTOR(*st)[node] += -VECTOR(*kernel)[xidx]+VECTOR(*kernel)[xidx+1];
-    }
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to]+=1;
-    }
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_d(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pmaxind) {
-
-  long int classes=pmaxind+1;
-  
-  igraph_vector_t ntk;
-  igraph_vector_t cumst;
-  igraph_vector_t ch;
-  igraph_vector_t indegree;
-  igraph_vector_t outdegree;
-  igraph_vector_t neis;
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int node, i;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&ntk, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ch, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&cumst, no_of_nodes+1);
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&outdegree, no_of_nodes);
-  
-  IGRAPH_CHECK(igraph_degree(graph, &outdegree, igraph_vss_all(),
-			     IGRAPH_OUT, IGRAPH_LOOPS));
-  
-  /* create the cumulative sum of dt/S(t) */
-  VECTOR(cumst)[0]=0;
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(cumst)[i+1]=VECTOR(cumst)[i] +
-      VECTOR(outdegree)[i]/VECTOR(*st)[i];
-  }
-  
-  igraph_vector_destroy(&outdegree);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  IGRAPH_CHECK(igraph_vector_resize(expected, classes));
-  igraph_vector_null(expected);
-  
-  for (node=0; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    
-    /* update degree and ntk, and result when needed */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      VECTOR(indegree)[to]++;
-      
-      VECTOR(ntk)[xidx]--;
-      VECTOR(*expected)[xidx] += (VECTOR(ntk)[xidx]+1)*
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)VECTOR(ch)[xidx]]);
-      VECTOR(ch)[xidx]=node;
-
-      VECTOR(ntk)[xidx+1]++;
-      VECTOR(*expected)[xidx+1] += (VECTOR(ntk)[xidx+1]-1)*
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)VECTOR(ch)[xidx+1]]);
-      VECTOR(ch)[xidx+1]=node;
-    }
-    
-    VECTOR(ntk)[0]++;
-    VECTOR(*expected)[0] += (VECTOR(ntk)[0]-1)*
-      (VECTOR(cumst)[node]-VECTOR(cumst)[(long int)VECTOR(ch)[0]]);
-    VECTOR(ch)[0]=node;
-  }
-  
-  /* complete res */
-  for (i=0; i<classes; i++) {
-    VECTOR(*expected)[i] += VECTOR(ntk)[i]*
-      (VECTOR(cumst)[node]-VECTOR(cumst)[(long int)VECTOR(ch)[i]]);
-    VECTOR(*expected)[i] *= VECTOR(*kernel)[i];
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  igraph_vector_destroy(&cumst);
-  igraph_vector_destroy(&ch);
-  igraph_vector_destroy(&ntk);
-  IGRAPH_FINALLY_CLEAN(5);
-    
-  return 0;
-}
-
-int igraph_revolver_error_d(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t maxind,
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_UNUSED(maxind);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!mylogprob) { mylogprob=&rlogprob; }
-  if (!mylognull) { mylognull=&rlognull; }
-
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      igraph_real_t prob=VECTOR(*kernel)[xidx]/VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1.0);
-
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-} 
-
-int igraph_revolver_error2_d(const igraph_t *graph,
-			     const igraph_vector_t *kernel,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_vector_size(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_d(graph, &st, kernel));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_d(graph, kernel, &st, maxdegree,
-					 logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}		
-
-  
-/***********************************************/
-/* in-degree, age                              */
-/***********************************************/
-
-int igraph_revolver_ad(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  IGRAPH_PROGRESS("Revolver ad", 0, NULL);
-  for (i=0; i<niter; i++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ad(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					 0 /*logmax*/, &st, maxdegree, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ad(graph, &st, kernel));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ad(graph, kernel, sd, norm, cites, debug,
-					  debugres, logmax, &st, 
-					  maxdegree, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ad(graph, &st, kernel));
-
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_ad(graph, expected, kernel, &st,
-					   maxdegree, agebins));
-      }
-
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_ad(graph, kernel, &st, maxdegree,
-					     agebins, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver ad", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_ad(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t pagebins) {
-  
-  long int maxind=pmaxind, agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_matrix_t ntkl, ch, v_normfact, *normfact, v_notnull, *notnull;
-
-  igraph_vector_t neis;
-
-  long int node, i, j, k;
-  long int edges=0;
-
-  IGRAPH_UNUSED(debug);
-  IGRAPH_UNUSED(debugres);
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, maxind+1, agebins+1);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, maxind+1, agebins+1);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, maxind+1, agebins));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, maxind+1, agebins);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, maxind+1, agebins));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, maxind+1, agebins);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, maxind+1, agebins));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, maxind+1, agebins));
-    igraph_matrix_null(sd);
-  }  
-
-  if (binwidth>1) {
-    MATRIX(ntkl, 0, 0)=1;
-  } else {
-    MATRIX(ntkl, 0, 1)=1;
-  }
-
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntkl, xidx, yidx);
-      double oldm=MATRIX(*kernel, xidx, yidx);      
-      MATRIX(*notnull, xidx, yidx) += 1;
-      MATRIX(*kernel, xidx, yidx) += (xk-oldm)/MATRIX(*notnull, xidx, yidx);
-      if (sd) {
-	MATRIX(*sd, xidx, yidx) += (xk-oldm)*(xk-MATRIX(*kernel, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) {
-	*logmax += log(1.0/MATRIX(ntkl, xidx, yidx));
-      }
-    }
-    
-    /* Update ntkl & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      VECTOR(indegree)[to] += 1;
-      MATRIX(ntkl, xidx, yidx) -= 1;
-      if (MATRIX(ntkl, xidx, yidx)==0) {
-	MATRIX(*normfact, xidx, yidx) += (edges-MATRIX(ch, xidx, yidx));
-      }
-      MATRIX(ntkl, xidx+1, yidx) += 1;
-      if (MATRIX(ntkl, xidx+1, yidx)==1) {
-	MATRIX(ch, xidx+1, yidx)=edges;
-      }
-    }
-    /* new node */
-    MATRIX(ntkl, 0, 0) += 1;
-    if (MATRIX(ntkl, 0, 0)==1) {
-      MATRIX(ch, 0, 0)=edges;
-    }
-    /* aging */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      MATRIX(ntkl, deg, k-1)--;
-      if (MATRIX(ntkl, deg, k-1)==0) {
-	MATRIX(*normfact, deg, k-1) += (edges-MATRIX(ch, deg, k-1));
-      }
-      MATRIX(ntkl, deg, k) += 1;
-      if (MATRIX(ntkl, deg, k)==1) {
-	MATRIX(ch, deg, k)=edges;
-      }
-    }
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<maxind+1; i++) {
-    for (j=0; j<agebins; j++) {
-      igraph_real_t oldmean;
-      if (MATRIX(ntkl, i, j) != 0) {
-	MATRIX(*normfact, i, j) += (edges-MATRIX(ch, i, j));
-      }
-      if (MATRIX(*normfact, i, j)==0) {
-	MATRIX(*kernel, i, j)=0;
-	MATRIX(*normfact, i, j)=1;
-      }
-      oldmean=MATRIX(*kernel, i, j);
-      MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
-      if (sd) {
-	MATRIX(*sd, i, j) +=
-	  oldmean * oldmean * MATRIX(*notnull, i, j) * 
-	  (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
-	MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(4);
-
-  return 0;
-}
-
-int igraph_revolver_st_ad(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel) {
-  long int agebins=igraph_matrix_ncol(kernel);
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node, i, k;  
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  if (binwidth>1) {
-    VECTOR(*st)[0]=MATRIX(*kernel, 0, 0);
-  } else {
-    VECTOR(*st)[0]=MATRIX(*kernel, 0, 1);
-  }
-  
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1] + MATRIX(*kernel, 0, 0);
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node-to)/binwidth;
-      VECTOR(indegree)[to] += 1;
-      VECTOR(*st)[node] +=
-	-MATRIX(*kernel, xidx, yidx)+MATRIX(*kernel, xidx+1, yidx);
-    }
-
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      VECTOR(*st)[node] += -MATRIX(*kernel, deg, k-1)+MATRIX(*kernel, deg, k);
-    }    
-    
-  }  
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_exp_ad(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t pagebins) {
-  
-  long int maxind=pmaxind, agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_vector_t outdegree;
-  igraph_vector_t cumst;
-  igraph_matrix_t ntkl;
-  igraph_matrix_t ch;
-  igraph_vector_t neis;
-
-  long int node, i, j, k;
-  
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, maxind+1, agebins);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, maxind+1, agebins);
-  IGRAPH_VECTOR_INIT_FINALLY(&cumst, no_of_nodes+1);
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&outdegree, no_of_nodes);
-  
-  IGRAPH_CHECK(igraph_degree(graph, &outdegree, igraph_vss_all(), 
-			     IGRAPH_OUT, IGRAPH_LOOPS));
-  
-  /* create cumulative sum of dt/S(t) */
-  VECTOR(cumst)[0]=0;
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(cumst)[i+1]=VECTOR(cumst)[i] +
-      VECTOR(outdegree)[i]/VECTOR(*st)[i];
-  }
-
-  igraph_vector_destroy(&outdegree);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  IGRAPH_CHECK(igraph_matrix_resize(expected, maxind+1, agebins));
-  igraph_matrix_null(expected);
-  
-  for (node=0; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* update degree and ntk, and result when needed */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node-to)/binwidth;
-      
-      VECTOR(indegree)[to] += 1;
-      
-      MATRIX(ntkl, xidx, yidx) -= 1;
-      MATRIX(*expected, xidx, yidx) += (MATRIX(ntkl, xidx, yidx)+1) *
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)MATRIX(ch, xidx, yidx)]);
-      MATRIX(ch, xidx, yidx)=node;
-      
-      MATRIX(ntkl, xidx+1, yidx) += 1;
-      MATRIX(*expected, xidx+1, yidx) += (MATRIX(ntkl, xidx+1, yidx)-1) *
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)MATRIX(ch, xidx+1, yidx)]);
-      MATRIX(ch, xidx+1, yidx)=node;
-    }
-    /* new node */
-    MATRIX(ntkl, 0, 0) += 1;
-    MATRIX(*expected, 0, 0) += (MATRIX(ntkl, 0, 0)-1)*
-      (VECTOR(cumst)[node]-VECTOR(cumst)[(long int)MATRIX(ch, 0, 0)]);
-    MATRIX(ch, 0, 0)=node;
-    /* aging */
-    for (k=1; node-binwidth*k+1>=0; k++) {
-      long int shnode=node-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      MATRIX(ntkl, deg, k-1) -= 1;
-      MATRIX(*expected, deg, k-1) += (MATRIX(ntkl, deg, k-1)+1) *
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)MATRIX(ch, deg, k-1)]);
-      MATRIX(ch, deg, k-1)=node;
-      MATRIX(ntkl, deg, k) += 1;
-      MATRIX(*expected, deg, k) += (MATRIX(ntkl, deg, k)-1) *
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)MATRIX(ch, deg, k)]);
-      MATRIX(ch, deg, k)=node;
-    }
-    
-  }
-
-  /* complete res */
-  for (i=0; i<maxind+1; i++) {
-    for (j=0; j<agebins; j++) {
-      MATRIX(*expected, i, j) += MATRIX(ntkl, i, j) *
-	(VECTOR(cumst)[node]-VECTOR(cumst)[(long int)MATRIX(ch, i, j)]);
-      MATRIX(*expected, i, j) *= MATRIX(*kernel, i, j);
-    }
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  igraph_vector_destroy(&cumst);
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  IGRAPH_FINALLY_CLEAN(5);
-
-  return 0;
-}
-
-int igraph_revolver_error_ad(const igraph_t *graph, 
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pmaxind,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) {
-  
-  long int agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  
-  igraph_vector_t neis;
-  
-  long int node, i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_UNUSED(pmaxind);
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-						    
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      igraph_real_t prob=MATRIX(*kernel, xidx, yidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_error2_ad(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_matrix_nrow(kernel)-1;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_matrix_ncol(kernel);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_ad(graph, &st, kernel));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_ad(graph, kernel, &st, maxdegree, agebins,
-					  logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-  
-/***********************************************/
-/* in-degree, age, cited category              */
-/***********************************************/
-
-
-int igraph_revolver_ade(const igraph_t *graph,
-		       igraph_integer_t niter,
-		       igraph_integer_t agebins,
-		       const igraph_vector_t *cats,
-		       igraph_array3_t *kernel,
-		       igraph_array3_t *sd,
-		       igraph_array3_t *norm,
-		       igraph_array3_t *cites,
-		       igraph_array3_t *expected,
-		       igraph_real_t *logprob,
-		       igraph_real_t *lognull,
-		       igraph_real_t *logmax,
-		       const igraph_matrix_t *debug,
-		       igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  IGRAPH_PROGRESS("Revolver ade", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ade(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					   0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					   0/*logmax*/,
-					   &st, cats, nocats, maxdegree, agebins));
-      
-      /* normalize */
-      igraph_array3_scale(kernel, 1/igraph_array3_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ade(graph, &st, kernel, cats));
-    } else { 
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ade(graph, kernel, sd, norm, cites, debug,
-					  debugres, logmax, &st, cats, nocats, 
-					  maxdegree, agebins));
-      
-      /* normalize */
-      igraph_array3_scale(kernel, 1/igraph_array3_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ade(graph, &st, kernel, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_ade(graph, expected, kernel,
-					    &st, cats, nocats, 
-					    maxdegree, agebins));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_ade(graph, kernel, &st,
-					      cats, nocats, maxdegree, 
-					      agebins, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver ade", 100*(i+1)/niter, NULL);
-  }
-
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}
-
-int igraph_revolver_mes_ade(const igraph_t *graph, 
-			   igraph_array3_t *kernel, 
-			   igraph_array3_t *sd,
-			   igraph_array3_t *norm,
-			   igraph_array3_t *cites,
-			   const igraph_matrix_t *debug,
-			   igraph_vector_ptr_t *debugres,
-			   igraph_real_t *logmax,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins) {
-  long int nocats=pnocats, maxind=pmaxind, agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_array3_t ntkl, ch, v_normfact, *normfact, v_notnull, *notnull;
-  
-  igraph_vector_t neis;
-  
-  long int node, j, i, k;
-  long int edges=0;
-
-  IGRAPH_UNUSED(debug);
-  IGRAPH_UNUSED(debugres);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_ARRAY3_INIT_FINALLY(&ntkl, nocats, maxind+1, agebins+1);
-  IGRAPH_ARRAY3_INIT_FINALLY(&ch, nocats, maxind+1, agebins+1);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_array3_resize(normfact, nocats, maxind+1, agebins));
-    igraph_array3_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_ARRAY3_INIT_FINALLY(normfact, nocats, maxind+1, agebins);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_array3_resize(normfact, nocats, maxind+1, agebins));
-    igraph_array3_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_ARRAY3_INIT_FINALLY(notnull, nocats, maxind+1, agebins);
-  }
-
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  IGRAPH_CHECK(igraph_array3_resize(kernel, nocats, maxind+1, agebins));
-  igraph_array3_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_array3_resize(sd, nocats, maxind+1, agebins));
-    igraph_array3_null(sd);
-  }
-  
-  if (binwidth>1) {
-    ARRAY3(ntkl, (long int)VECTOR(*cats)[0], 0, 0)=1;
-  } else {
-    ARRAY3(ntkl, (long int)VECTOR(*cats)[0], 0, 1)=1;
-  }
-
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx;
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      double xk=VECTOR(*st)[node]/ARRAY3(ntkl, cidx, xidx, yidx);
-      double oldm=ARRAY3(*kernel, cidx, xidx, yidx);
-      ARRAY3(*notnull, cidx, xidx, yidx) += 1;
-      ARRAY3(*kernel, cidx, xidx, yidx) += 
-	(xk-oldm)/ARRAY3(*notnull, cidx, xidx, yidx);
-      if (sd) {
-	ARRAY3(*sd, cidx, xidx, yidx) += 
-	  (xk-oldm)*(xk-ARRAY3(*kernel, cidx, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) { 
-	*logmax += log(1.0/ARRAY3(ntkl, cidx, xidx, yidx));
-      }
-    }
-    
-    /* Update ntkl & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      VECTOR(indegree)[to] += 1;
-      ARRAY3(ntkl, cidx, xidx, yidx) -= 1;
-      if (ARRAY3(ntkl, cidx, xidx, yidx)==0) {
-	ARRAY3(*normfact, cidx, xidx, yidx) += (edges-ARRAY3(ch, cidx, xidx, yidx));
-      }
-      ARRAY3(ntkl, cidx, xidx+1, yidx) += 1;
-      if (ARRAY3(ntkl, cidx, xidx+1, yidx)==1) {
-	ARRAY3(ch, cidx, xidx+1, yidx)=edges;
-      }
-    }
-    /* new node */
-    cidx=(long int) VECTOR(*cats)[node+1];
-    ARRAY3(ntkl, cidx, 0, 0) += 1;
-    if (ARRAY3(ntkl, cidx, 0, 0)==1) {
-      ARRAY3(ch, cidx, 0, 0)=edges;
-    }
-    /* aging */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      long int cidx=(long int) VECTOR(*cats)[shnode];
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      ARRAY3(ntkl, cidx, deg, k-1) -= 1;
-      if (ARRAY3(ntkl, cidx, deg, k-1)==0) {
-	ARRAY3(*normfact, cidx, deg, k-1) += (edges-ARRAY3(ch, cidx, deg, k-1));
-      }
-      ARRAY3(ntkl, cidx, deg, k) += 1;
-      if (ARRAY3(ntkl, cidx, deg, k)==1) {
-	ARRAY3(ch, cidx, deg, k)=edges;
-      }
-    }
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (k=0; k<nocats; k++) {
-    for (i=0; i<maxind+1; i++) {
-      for (j=0; j<agebins; j++) {
-	igraph_real_t oldmean;
-	if (ARRAY3(ntkl, k, i, j) != 0) {
-	  ARRAY3(*normfact, k, i, j) += (edges-ARRAY3(ch, k, i, j));
-	}
-	if (ARRAY3(*normfact, k, i, j)==0) {
-	  ARRAY3(*kernel, k, i, j)=0;
-	  ARRAY3(*normfact, k, i, j)=1;
-	}
-	oldmean=ARRAY3(*kernel, k, i, j);
-	ARRAY3(*kernel, k, i, j) *= 
-	  ARRAY3(*notnull, k, i, j)/ARRAY3(*normfact, k, i, j);	  
-	if (sd) {
-	  ARRAY3(*sd, k, i, j) +=
-	    oldmean*oldmean*ARRAY3(*notnull, k, i, j)*
-	    (1-ARRAY3(*notnull, k, i, j)/ARRAY3(*normfact, k, i, j));
-	  ARRAY3(*sd, k, i, j)=
-	    sqrt(ARRAY3(*sd, k, i, j)/(ARRAY3(*normfact, k, i, j)-1));
-	}
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_array3_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_array3_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_array3_destroy(&ch);
-  igraph_array3_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(4);
-
-  return 0;
-}
- 
-int igraph_revolver_st_ade(const igraph_t *graph,
-			  igraph_vector_t *st,
-			  const igraph_array3_t *kernel,
-			  const igraph_vector_t *cats) {
-
-  long int agebins=igraph_array3_n(kernel, 3);
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node, i, k;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-
-  VECTOR(*st)[0]=ARRAY3(*kernel, (long int) VECTOR(*cats)[0], 0, 
-			binwidth > 1 ? 0 : 1);
-  
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=
-      VECTOR(*st)[node-1]+ARRAY3(*kernel, (long int)VECTOR(*cats)[node], 0, 0);
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node-to)/binwidth;
-      VECTOR(indegree)[to] += 1;
-      VECTOR(*st)[node] += 
-	-ARRAY3(*kernel, cidx, xidx, yidx) + ARRAY3(*kernel, cidx, xidx+1, yidx);
-    }
-    
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      long int cidx=(long int) VECTOR(*cats)[shnode];
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      VECTOR(*st)[node] += 
-	-ARRAY3(*kernel, cidx, deg, k-1) + ARRAY3(*kernel, cidx, deg, k);
-    }
-
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_ade(const igraph_t *graph, 
-			   igraph_array3_t *expected,
-			   const igraph_array3_t *kernel,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins) {
-  
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_ade(const igraph_t *graph,
-			     const igraph_array3_t *kernel,
-			     const igraph_vector_t *st,
-			     const igraph_vector_t *cats,
-			     igraph_integer_t pnocats,
-			     igraph_integer_t pmaxdegree,
-			     igraph_integer_t pagebins,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) {
-  
-  long int agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-
-  long int node, i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      igraph_real_t prob=ARRAY3(*kernel, cidx, xidx, yidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_error2_ade(const igraph_t *graph,
-			       const igraph_array3_t *kernel,
-			       const igraph_vector_t *cats,
-			       igraph_real_t *logprob,
-			       igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_array3_n(kernel, 1);
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_array3_n(kernel, 2)-1;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_array3_n(kernel, 3);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_ade(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_ade(graph, kernel, &st, cats, 
-					   nocats, maxdegree, agebins, 
-					   logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-			       
-
-/***********************************************/
-/* cited category                              */
-/***********************************************/
-
-int igraph_revolver_e(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     const igraph_vector_t *cats,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *st,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t vst, *myst=st;
-  long int i;
-  igraph_integer_t nocats;
-  
-  if (!myst) {     
-    IGRAPH_VECTOR_INIT_FINALLY(&vst, no_of_nodes);
-    myst=&vst;
-  } else {
-    IGRAPH_CHECK(igraph_vector_resize(myst, no_of_nodes));
-  }
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(*myst)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-
-  IGRAPH_PROGRESS("Revolver e", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_e(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-				        0 /*logmax*/, myst, cats, nocats));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_e(graph, myst, kernel, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_e(graph, kernel, sd, norm, cites, debug,
-					debugres, logmax, myst, cats, nocats));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_e(graph, myst, kernel, cats));
-
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_e(graph, expected, kernel,
-					  myst, cats, nocats));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_e(graph, kernel, myst, cats, nocats,
-					    logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver e", 100*(i+1)/niter, NULL);
-
-  }
-
-  if (!st) {
-    igraph_vector_destroy(myst);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  return 0;
-}
-
-int igraph_revolver_mes_e(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 const igraph_vector_t *cats,
-			 igraph_integer_t pnocats) {
-  
-  long int classes=pnocats;
-  long int no_of_nodes=igraph_vcount(graph);
-  
-  igraph_vector_t v_normfact, *normfact;
-  igraph_vector_t v_notnull, *notnull;
-  igraph_vector_t ntk, ch;
-  
-  igraph_vector_t neis;
-  
-  long int node, i, edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&ntk, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ch, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  if (norm) { 
-    normfact=norm;
-    IGRAPH_CHECK(igraph_vector_resize(normfact, classes));
-    igraph_vector_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_VECTOR_INIT_FINALLY(normfact, classes);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_vector_resize(notnull, classes));
-    igraph_vector_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_VECTOR_INIT_FINALLY(notnull, classes);
-  }
-  
-  IGRAPH_CHECK(igraph_vector_resize(kernel, classes));
-  igraph_vector_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_vector_resize(sd, classes));
-    igraph_vector_null(sd);
-  }
-  
-  VECTOR(ntk)[ (long int) VECTOR(*cats)[0] ]=1;
-
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx;
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int idx=(long int) VECTOR(*cats)[to];
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntk)[idx];
-      double oldm=VECTOR(*kernel)[idx];
-      VECTOR(*notnull)[idx] += 1;
-      VECTOR(*kernel)[idx] += (xk-oldm)/VECTOR(*notnull)[idx];
-      if (sd) {
-	VECTOR(*sd)[idx] += (xk-oldm)*(xk-VECTOR(*kernel)[idx]);
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/VECTOR(ntk)[idx]); }
-    }
-    
-    /* Update ntk & co */
-    edges += igraph_vector_size(&neis);
-    cidx=(long int) VECTOR(*cats)[node+1];
-    VECTOR(ntk)[cidx] += 1;
-    if (VECTOR(ntk)[cidx]==1) {
-      VECTOR(ch)[cidx]=edges;
-    }
-    
-  }
-
-  /* Make normfact up to data, calculate mean, sd */
-  for (i=0; i<classes; i++) {
-    igraph_real_t oldmean;
-    if (VECTOR(ntk)[i] != 0) {
-      VECTOR(*normfact)[i] += (edges-VECTOR(ch)[i]);
-    }
-    if (VECTOR(*normfact)[i]==0) {
-      VECTOR(*kernel)[i]=0;
-      VECTOR(*normfact)[i]=1;
-    }
-    oldmean=VECTOR(*kernel)[i];
-    VECTOR(*kernel)[i] *= VECTOR(*notnull)[i]/VECTOR(*normfact)[i];
-    if (sd) {
-      VECTOR(*sd)[i] += oldmean*oldmean*VECTOR(*notnull)[i] *
-	(1-VECTOR(*notnull)[i]/VECTOR(*normfact)[i]);
-      VECTOR(*sd)[i] = sqrt(VECTOR(*sd)[i]/(VECTOR(*normfact)[i]-1));
-    }
-  }
-  
-  if (!cites) {
-    igraph_vector_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_vector_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&ch);
-  igraph_vector_destroy(&ntk);
-  IGRAPH_FINALLY_CLEAN(3);
-
-  return 0;
-}
-
-int igraph_revolver_st_e(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel,
-			const igraph_vector_t *cats) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  
-  long int node;
-  
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  
-  VECTOR(*st)[0]=VECTOR(*kernel)[ (long int) VECTOR(*cats)[0] ];
-  
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=
-      VECTOR(*st)[node-1]+VECTOR(*kernel)[ (long int) VECTOR(*cats)[node] ];
-    
-  }
-  
-  return 0;
-}
-
-int igraph_revolver_exp_e(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 const igraph_vector_t *cats,
-			 igraph_integer_t pnocats) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_e(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t neis;
-  long int node, i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      
-      igraph_real_t prob=VECTOR(*kernel)[cidx]/VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}
-
-int igraph_revolver_error2_e(const igraph_t *graph,
-			     const igraph_vector_t *kernel,
-			     const igraph_vector_t *cats,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_vector_size(kernel);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_e(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_e(graph, kernel, &st, cats, nocats,
-					 logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-/***********************************************/
-/* in-degree, cited category                   */
-/***********************************************/
-
-int igraph_revolver_de(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  IGRAPH_PROGRESS("Revolver de", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION(); 
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_de(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					 0/*logmax*/, &st, cats, nocats, maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_de(graph, &st, kernel, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_de(graph, kernel, sd, norm, cites, debug,
-					 debugres, logmax, &st, cats, nocats, 
-					 maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_de(graph, &st, kernel, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_de(graph, expected, kernel,
-					   &st, cats, nocats, maxdegree)); 
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_de(graph, kernel, &st,
-					     cats, nocats, maxdegree, 
-					     logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver de", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_de(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind) {
-  long int nocats=pnocats, maxind=pmaxind;
-  long int no_of_nodes=igraph_vcount(graph);
-  
-  igraph_vector_t indegree;
-  igraph_matrix_t ntkl, ch, v_normfact, *normfact, v_notnull, *notnull;
-  
-  igraph_vector_t neis;
-  
-  long int node, i, j;
-  long int edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, nocats, maxind+1);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, nocats, maxind+1);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, maxind+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, nocats, maxind+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, maxind+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, nocats, maxind+1);
-  }
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, nocats, maxind+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, nocats, maxind+1));
-    igraph_matrix_null(sd);
-  }
-  
-  MATRIX(ntkl, (long int)VECTOR(*cats)[0], 0)=1;
-  
-  if (logmax) { *logmax=0.0; }
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx;
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntkl, cidx, xidx);
-      double oldm=MATRIX(*kernel, cidx, xidx);
-      MATRIX(*notnull, cidx, xidx) += 1;
-      MATRIX(*kernel, cidx, xidx) += 
-	(xk-oldm)/MATRIX(*notnull, cidx, xidx);
-      if (sd) {
-	MATRIX(*sd, cidx, xidx) += 
-	  (xk-oldm)*(xk-MATRIX(*kernel, cidx, xidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/MATRIX(ntkl, cidx, xidx)); }
-    }
-        
-    /* Update ntkl & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      VECTOR(indegree)[to] += 1;
-      MATRIX(ntkl, cidx, xidx) -= 1;
-      if (MATRIX(ntkl, cidx, xidx)==0) {
-	MATRIX(*normfact, cidx, xidx) += (edges-MATRIX(ch, cidx, xidx));
-      }
-      MATRIX(ntkl, cidx, xidx+1) += 1;
-      if (MATRIX(ntkl, cidx, xidx+1)==1) {
-	MATRIX(ch, cidx, xidx+1)=edges;
-      }
-    }
-    /* new node */
-    cidx=(long int) VECTOR(*cats)[node+1];
-    MATRIX(ntkl, cidx, 0) += 1;
-    if (MATRIX(ntkl, cidx, 0)==1) {
-      MATRIX(ch, cidx, 0)=edges;
-    }
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (j=0; j<nocats; j++) {
-    for (i=0; i<maxind+1; i++) {
-      igraph_real_t oldmean;
-      if (MATRIX(ntkl, j, i) != 0) {
-	MATRIX(*normfact, j, i) += (edges-MATRIX(ch, j, i));
-      }
-      if (MATRIX(*normfact, j, i)==0) {
-	MATRIX(*kernel, j, i)=0;
-	MATRIX(*normfact, j, i)=1;
-      }
-      oldmean=MATRIX(*kernel, j, i);
-      MATRIX(*kernel, j, i) *= 
-	MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i);	  
-      if (sd) {
-	MATRIX(*sd, j, i) +=
-	  oldmean*oldmean*MATRIX(*notnull, j, i)*
-	  (1-MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i));
-	MATRIX(*sd, j, i)=
-	  sqrt(MATRIX(*sd, j, i)/(MATRIX(*normfact, j, i)-1));
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(4);    
-  
-  return 0;
-}
-
-int igraph_revolver_st_de(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node, i;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-
-  VECTOR(*st)[0]=MATRIX(*kernel, (long int) VECTOR(*cats)[0], 0);
-  
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=
-      VECTOR(*st)[node-1]+MATRIX(*kernel, (long int)VECTOR(*cats)[node], 0);
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      VECTOR(indegree)[to] += 1;
-      VECTOR(*st)[node] += 
-	-MATRIX(*kernel, cidx, xidx) + MATRIX(*kernel, cidx, xidx+1);           
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_de(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_de(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) { 
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t indegree, neis;
-  long int node, i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int cidx=(long int) VECTOR(*cats)[to];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      igraph_real_t prob=MATRIX(*kernel, cidx, xidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_error2_de(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_matrix_nrow(kernel);
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_de(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_de(graph, kernel, &st, cats, nocats,
-					  maxdegree, logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}
-
-/***********************************************/
-/* time since last citation                    */
-/***********************************************/
-
-int igraph_revolver_l(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     igraph_integer_t agebins,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  IGRAPH_PROGRESS("Revolver l", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) { 	/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_l(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					0 /*logmax*/, &st, agebins));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_l(graph, &st, kernel));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_l(graph, kernel, sd, norm, cites, debug,
-					debugres, logmax, &st, agebins));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_l(graph, &st, kernel));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_l(graph, expected, kernel, &st,
-					  agebins));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_l(graph, kernel, &st,
-					    agebins, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver l", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_l(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pagebins) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t ntl, ch, v_normfact, v_notnull, *normfact, *notnull;
-  
-  igraph_vector_t lastcit;
-  igraph_vector_t neis;
-  
-  long int node, i, k, edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ntl, agebins+2); 	/* +1 for the never cited */
-  IGRAPH_VECTOR_INIT_FINALLY(&ch, agebins+2);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_vector_resize(normfact, agebins+1));
-    igraph_vector_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_VECTOR_INIT_FINALLY(normfact, agebins+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_vector_resize(notnull, agebins+1));
-    igraph_vector_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_VECTOR_INIT_FINALLY(notnull, agebins+1);
-  }
-  
-  IGRAPH_CHECK(igraph_vector_resize(kernel, agebins+1));
-  igraph_vector_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_vector_resize(sd, agebins+1));
-    igraph_vector_null(sd);
-  }  
-
-  VECTOR(ntl)[agebins]=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ? 
-	(node+2-(long int)VECTOR(lastcit)[to])/binwidth :	agebins;      
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntl)[xidx];
-      double oldm=VECTOR(*kernel)[xidx];
-      VECTOR(*notnull)[xidx] += 1;
-      VECTOR(*kernel)[xidx] += (xk-oldm)/VECTOR(*notnull)[xidx];
-      if (sd) {
-	VECTOR(*sd)[xidx] += (xk-oldm)*(xk-VECTOR(*kernel)[xidx]);
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/VECTOR(ntl)[xidx]); }
-    }
-    
-    /* Update ntkl & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ? 
-	(long int) ((node+2.0-VECTOR(lastcit)[to])/binwidth) : agebins;
-      
-      VECTOR(lastcit)[to]=node+2;
-      VECTOR(ntl)[xidx] -= 1; 
-      if (VECTOR(ntl)[xidx]==0) {
-	VECTOR(*normfact)[xidx] += (edges-VECTOR(ch)[xidx]);
-      }
-      VECTOR(ntl)[0] += 1;
-      if (VECTOR(ntl)[0]==1) {
-	VECTOR(ch)[0]=edges;
-      }
-    }
-    /* new node */
-    VECTOR(ntl)[agebins] += 1;
-    if (VECTOR(ntl)[agebins]==1) {
-      VECTOR(ch)[agebins]=edges;
-    }
-    /* should we move some citations to an older bin? */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  VECTOR(ntl)[k-1] -= 1;
-	  if (VECTOR(ntl)[k-1]==0) {
-	    VECTOR(*normfact)[k-1] += (edges-VECTOR(ch)[k-1]);
-	  }
-	  VECTOR(ntl)[k] += 1;
-	  if (VECTOR(ntl)[k]==1) {
-	    VECTOR(ch)[k]=edges;
-	  }
-	}
-      }
-    }
-
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<agebins+1; i++) {
-    igraph_real_t oldmean;
-    if (VECTOR(ntl)[i] != 0) {
-      VECTOR(*normfact)[i] += (edges-VECTOR(ch)[i]);
-    }
-    if (VECTOR(*normfact)[i]==0) {
-      VECTOR(*kernel)[i]=0;
-      VECTOR(*normfact)[i]=1;
-    }
-    oldmean=VECTOR(*kernel)[i];
-    VECTOR(*kernel)[i] *= VECTOR(*notnull)[i]/VECTOR(*normfact)[i];
-    if (sd) {
-      VECTOR(*sd)[i] += oldmean * oldmean * VECTOR(*notnull)[i] *
-	(1-VECTOR(*notnull)[i]/VECTOR(*normfact)[i]);
-      VECTOR(*sd)[i] = sqrt(VECTOR(*sd)[i]/(VECTOR(*normfact)[i]-1));
-    }
-  }
-  
-  if (!cites) {
-    igraph_vector_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_vector_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&ch);
-  igraph_vector_destroy(&ntl);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(4);  
-
-  return 0;
-}
-
-int igraph_revolver_st_l(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel) {
-  long int agebins=igraph_vector_size(kernel)-1;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit;
-
-  igraph_vector_t neis;
-  long int node, i, k;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  
-  VECTOR(*st)[0]=VECTOR(*kernel)[agebins];
-  
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1]+VECTOR(*kernel)[agebins];
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ?
-	(node+1-(long int)VECTOR(lastcit)[to])/binwidth : agebins;
-      VECTOR(lastcit)[to]=node+1;
-      VECTOR(*st)[node] += -VECTOR(*kernel)[xidx]+VECTOR(*kernel)[0];
-    }
-    
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  VECTOR(*st)[node] += -VECTOR(*kernel)[k-1]+VECTOR(*kernel)[k];
-	}
-      }
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_l(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pagebins) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_l(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pagebins,
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull) {
-  
-  long int agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit;
-  igraph_vector_t neis;
-  
-  long int node, i;
-  
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ?
-	(node+2-(long int)VECTOR(lastcit)[to])/binwidth : agebins;
-      
-      igraph_real_t prob=VECTOR(*kernel)[xidx] / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(lastcit)[to]=node+2;
-    }
-
-  }
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_l(const igraph_t *graph,
-			     const igraph_vector_t *kernel,			     
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_vector_size(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_l(graph, &st, kernel));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_l(graph, kernel, &st, agebins, 
-					 logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-      
-/***********************************************/
-/* degree, time since last citation            */
-/***********************************************/
-
-int igraph_revolver_dl(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));  
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-
-  IGRAPH_PROGRESS("Revolver dl", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) { 	/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_dl(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					 0 /*logmax */, &st, maxdegree, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_dl(graph, &st, kernel));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_dl(graph, kernel, sd, norm, cites, debug,
-					debugres, logmax, &st, maxdegree, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_dl(graph, &st, kernel));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_dl(graph, expected, kernel, &st,
-					   maxdegree, agebins));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_dl(graph, kernel, &st, maxdegree,
-					     agebins, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver dl", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-  
-int igraph_revolver_mes_dl(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t pagebins) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int maxind=pmaxind;
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_matrix_t ntkl, ch, v_normfact, v_notnull, *normfact, *notnull;
-  
-  igraph_vector_t indegree, lastcit, neis;
-  
-  long int node, i, j, k, edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, maxind+2, agebins+2);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, maxind+2, agebins+2);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, maxind+1, agebins+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, maxind+1, agebins+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, maxind+1, agebins+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, maxind+1, agebins+1);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, maxind+1, agebins+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, maxind+1, agebins+1));
-    igraph_matrix_null(sd);
-  }  
-  
-  MATRIX(ntkl, 0, agebins)=1;
-  
-  if (logmax) { *logmax=0.0; }
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ? 
-	(long int) ((node+2.0-VECTOR(lastcit)[to])/binwidth) : agebins;      
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntkl, xidx, yidx);
-      double oldm=MATRIX(*kernel, xidx, yidx);
-      MATRIX(*notnull, xidx, yidx) += 1;
-      MATRIX(*kernel, xidx, yidx) += (xk-oldm)/MATRIX(*notnull, xidx, yidx);
-      if (sd) {
-	MATRIX(*sd, xidx, yidx) += (xk-oldm)*(xk-MATRIX(*kernel, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/MATRIX(ntkl, xidx, yidx)); }
-    }
-    
-    /* Update ntkl & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ? 
-	(node+2-(long int)VECTOR(lastcit)[to])/binwidth :	agebins;
-
-      VECTOR(indegree)[to]+=1;
-      VECTOR(lastcit)[to]=node+2;
-      MATRIX(ntkl, xidx, yidx) -= 1; 
-      if (MATRIX(ntkl, xidx, yidx)==0) {
-	MATRIX(*normfact, xidx, yidx)+= (edges-MATRIX(ch, xidx, yidx));
-      }
-      MATRIX(ntkl, xidx+1, 0) += 1;
-      if (MATRIX(ntkl, xidx+1, 0)==1) {
-	MATRIX(ch, xidx+1, 0)=edges;
-      }
-    }
-    /* new node */
-    MATRIX(ntkl, 0, agebins) += 1;
-    if (MATRIX(ntkl, 0, agebins)==1) {
-      MATRIX(ch, 0, agebins)=edges;
-    }
-    
-    /* should we move some citations to an older bin? */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	long int deg=(long int) VECTOR(indegree)[cnode];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  MATRIX(ntkl, deg, k-1) -= 1;
-	  if (MATRIX(ntkl, deg, k-1)==0) {
-	    MATRIX(*normfact, deg, k-1) += (edges-MATRIX(ch, deg, k-1));
-	  }
-	  MATRIX(ntkl, deg, k) += 1;
-	  if (MATRIX(ntkl, deg, k)==1) {
-	    MATRIX(ch, deg, k)=edges;
-	  }
-	}
-      }
-    }
-    
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<maxind+1; i++) {
-    for (j=0; j<agebins+1; j++) {
-      igraph_real_t oldmean;
-      if (MATRIX(ntkl, i, j) != 0) {
-	MATRIX(*normfact, i, j) += (edges-MATRIX(ch, i, j));
-      }
-      if (MATRIX(*normfact, i, j)==0) {
-	MATRIX(*kernel, i, j)=0;
-	MATRIX(*normfact, i, j)=1;
-      }
-      oldmean=MATRIX(*kernel, i, j);
-      MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
-      if (sd) {
-	MATRIX(*sd, i, j) += oldmean * oldmean * MATRIX(*notnull, i, j) *
-	  (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
-	MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
-      }
-    }
-  }
-
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  igraph_vector_destroy(&lastcit);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(5);
-  
-  return 0;
-}
-
-int igraph_revolver_st_dl(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel) {
-  long int agebins=igraph_matrix_ncol(kernel)-1;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit, indegree;
-  
-  igraph_vector_t neis;
-  long int node, i, k;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);  
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  
-  VECTOR(*st)[0]=MATRIX(*kernel, 0, agebins);
-
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1]+MATRIX(*kernel, 0, agebins);
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ?
-	(node+1-(long int)VECTOR(lastcit)[to])/binwidth : agebins;
-      VECTOR(indegree)[to] += 1;
-      VECTOR(lastcit)[to]=node+1;
-      VECTOR(*st)[node] += 
-	-MATRIX(*kernel, xidx, yidx)+MATRIX(*kernel, xidx+1, 0);
-    }
-    
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	long int deg=(long int) VECTOR(indegree)[cnode];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  VECTOR(*st)[node] += 
-	    -MATRIX(*kernel, deg, k-1)+MATRIX(*kernel, deg, k);
-	}
-      }
-    }
-  }
-
-  igraph_vector_destroy(&lastcit);
-  igraph_vector_destroy(&indegree);
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(3);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_dl(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pmaxind,
-			  igraph_integer_t pagebins) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_dl(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pmaxind,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) {
-  
-  long int agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit, indegree;
-  igraph_vector_t neis;
-  
-  long int node, i;
-  
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ?
-	(node+2-(long int)VECTOR(lastcit)[to])/binwidth : agebins;
-      
-      igraph_real_t prob=MATRIX(*kernel, xidx, yidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-      VECTOR(lastcit)[to]=node+2;
-    }
-
-  }
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&lastcit);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(3);
-
-  return 0;
-}
-
-int igraph_revolver_error2_dl(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_matrix_nrow(kernel)-1;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_dl(graph, &st, kernel));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_dl(graph, kernel, &st, maxdegree, agebins,
-					  logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}
-
-/***********************************************/
-/* cited category, time since last citation    */
-/***********************************************/
-
-int igraph_revolver_el(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      const igraph_vector_t *cats,
-		      igraph_integer_t agebins,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));  
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-
-  IGRAPH_PROGRESS("Revolver el", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) { 	/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_el(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					 0 /*logmax */, &st, cats, nocats, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_el(graph, &st, kernel, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_el(graph, kernel, sd, norm, cites, debug,
-					  debugres, logmax, 
-					  &st, cats, nocats, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_el(graph, &st, kernel, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_el(graph, expected, kernel, &st,
-					   cats, nocats, agebins));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_el(graph, kernel, &st, cats, nocats,
-					     agebins, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver el", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);  
-  
-  return 0;
-}
-
-int igraph_revolver_mes_el(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pagebins) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int nocats=pnocats;
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_matrix_t ntkl, ch, v_normfact, v_notnull, *normfact, *notnull;
-  
-  igraph_vector_t lastcit, neis;
-  
-  long int node, i, j, k, edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, nocats, agebins+2);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, nocats, agebins+2);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, agebins+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, nocats, agebins+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, nocats, agebins+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, nocats, agebins+1);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, nocats, agebins+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, nocats, agebins+1));
-    igraph_matrix_null(sd);
-  }  
-  
-  MATRIX(ntkl, (long int)VECTOR(*cats)[0], agebins)=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx;
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(*cats)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ? 
-	(long int) ((node+2.0-VECTOR(lastcit)[to])/binwidth) : agebins;      
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntkl, xidx, yidx);
-      double oldm=MATRIX(*kernel, xidx, yidx);
-      MATRIX(*notnull, xidx, yidx) += 1;
-      MATRIX(*kernel, xidx, yidx) += (xk-oldm)/MATRIX(*notnull, xidx, yidx);
-      if (sd) {
-	MATRIX(*sd, xidx, yidx) += (xk-oldm)*(xk-MATRIX(*kernel, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/MATRIX(ntkl, xidx, yidx)); }
-    }
-    
-    /* Update ntkl & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(*cats)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ? 
-	(long int) ((node+2.0-VECTOR(lastcit)[to])/binwidth) : agebins;
-
-      VECTOR(lastcit)[to]=node+2;
-      MATRIX(ntkl, xidx, yidx) -= 1; 
-      if (MATRIX(ntkl, xidx, yidx)==0) {
-	MATRIX(*normfact, xidx, yidx)+= (edges-MATRIX(ch, xidx, yidx));
-      }
-      MATRIX(ntkl, xidx, 0) += 1;
-      if (MATRIX(ntkl, xidx, 0)==1) {
-	MATRIX(ch, xidx, 0)=edges;
-      }
-    }
-    /* new node */
-    cidx=(long int) VECTOR(*cats)[node+1];
-    MATRIX(ntkl, cidx, agebins) += 1;
-    if (MATRIX(ntkl, cidx, agebins)==1) {
-      MATRIX(ch, cidx, agebins)=edges;
-    }
-    
-    /* should we move some citations to an older bin? */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	long int cat=(long int) VECTOR(*cats)[cnode];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  MATRIX(ntkl, cat, k-1) -= 1;
-	  if (MATRIX(ntkl, cat, k-1)==0) {
-	    MATRIX(*normfact, cat, k-1) += (edges-MATRIX(ch, cat, k-1));
-	  }
-	  MATRIX(ntkl, cat, k) += 1;
-	  if (MATRIX(ntkl, cat, k)==1) {
-	    MATRIX(ch, cat, k)=edges;
-	  }
-	}
-      }
-    }
-    
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<nocats; i++) {
-    for (j=0; j<agebins+1; j++) {
-      igraph_real_t oldmean;
-      if (MATRIX(ntkl, i, j) != 0) {
-	MATRIX(*normfact, i, j) += (edges-MATRIX(ch, i, j));
-      }
-      if (MATRIX(*normfact, i, j)==0) {
-	MATRIX(*kernel, i, j)=0;
-	MATRIX(*normfact, i, j)=1;
-      }
-      oldmean=MATRIX(*kernel, i, j);
-      MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
-      if (sd) {
-	MATRIX(*sd, i, j) += oldmean * oldmean * MATRIX(*notnull, i, j) *
-	  (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
-	MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
-      }
-    }
-  }
-
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(4);
-
-  return 0;
-}
-
-int igraph_revolver_st_el(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats) {
-
-  long int agebins=igraph_matrix_ncol(kernel)-1;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit;
-  
-  igraph_vector_t neis;
-  long int node, i, k;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);  
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  
-  VECTOR(*st)[0]=MATRIX(*kernel, (long int)VECTOR(*cats)[0], agebins);
-
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1]+MATRIX(*kernel, 0, agebins);
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(*cats)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ?
-	(long int) ((node+1.0-VECTOR(lastcit)[to])/binwidth) : agebins;
-      VECTOR(lastcit)[to]=node+1;
-      VECTOR(*st)[node] += 
-	-MATRIX(*kernel, xidx, yidx)+MATRIX(*kernel, xidx, 0);
-    }
-    
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	long int cat=(long int) VECTOR(*cats)[cnode];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  VECTOR(*st)[node] += 
-	    -MATRIX(*kernel, cat, k-1)+MATRIX(*kernel, cat, k);
-	}
-      }
-    }
-  }
-
-  igraph_vector_destroy(&lastcit);
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_exp_el(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pagebins) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_el(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) {
-
-  long int agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit;
-  igraph_vector_t neis;
-  
-  long int node, i;
-  
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(*cats)[to];
-      long int yidx=VECTOR(lastcit)[to]!=0 ?
-	(long int) ((node+2.0-VECTOR(lastcit)[to])/binwidth) : agebins;
-      
-      igraph_real_t prob=MATRIX(*kernel, xidx, yidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(lastcit)[to]=node+2;
-    }
-
-  }
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_el(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_matrix_nrow(kernel);
-  igraph_integer_t agebins=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_el(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_el(graph, kernel, &st, cats, nocats, agebins,
-					  logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-
-/***********************************************/
-/* recent in-degree                            */
-/***********************************************/
-
-int igraph_revolver_r(const igraph_t *graph,
-		     igraph_integer_t niter,
-		     igraph_integer_t window,
-		     igraph_vector_t *kernel,
-		     igraph_vector_t *sd,
-		     igraph_vector_t *norm,
-		     igraph_vector_t *cites,
-		     igraph_vector_t *expected,
-		     igraph_real_t *logprob,
-		     igraph_real_t *lognull,
-		     igraph_real_t *logmax,
-		     const igraph_vector_t *debug,
-		     igraph_vector_ptr_t *debugres) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i, j;
-  igraph_integer_t maxdegree=0;
-  igraph_vector_t neis;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  /* determine maximum recent degree, we use st temporarily */
-  for (i=0; i<no_of_nodes; i++) {
-    if (i-window>=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t)(i-window),
-				    IGRAPH_OUT));
-      for (j=0; j<igraph_vector_size(&neis); j++) {
-	long int to=(long int) VECTOR(neis)[j];
-	VECTOR(st)[to] -= 1;
-      }
-    }
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, 
-				  IGRAPH_OUT));
-    for (j=0; j<igraph_vector_size(&neis); j++) {
-      long int to=(long int) VECTOR(neis)[j];
-      VECTOR(st)[to] += 1;
-      if (VECTOR(st)[to] > maxdegree) {
-	maxdegree=(igraph_integer_t) VECTOR(st)[to];
-      }
-    }
-  }
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  IGRAPH_PROGRESS("Revolver r", 0, NULL);
-  for (i=0; i<niter; i++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1!=niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_r(graph, kernel, 0 /*sd*/, 0 /*norm*/, 
-					0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					0 /*logmax*/, &st, window, maxdegree));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_r(graph, &st, kernel, window));
-    } else {			/* last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_r(graph, kernel, sd, norm, cites, debug,
-					debugres, logmax, &st, window, maxdegree));
-      
-      /* normalize */
-      igraph_vector_scale(kernel, 1/igraph_vector_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_r(graph, &st, kernel, window));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_r(graph, expected, kernel,
-					  &st, window, maxdegree));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_r(graph, kernel, &st, window, maxdegree,
-					    logprob, lognull));
-      }
-    }
-    
-    IGRAPH_PROGRESS("Revolver r", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  return 0;
-}
-
-int igraph_revolver_mes_r(const igraph_t *graph,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *sd,
-			 igraph_vector_t *norm,
-			 igraph_vector_t *cites,
-			 const igraph_vector_t *debug,
-			 igraph_vector_ptr_t *debugres,
-			 igraph_real_t *logmax,
-			 const igraph_vector_t *st,
-			 igraph_integer_t pwindow,
-			 igraph_integer_t maxind) {
-  long int classes=maxind+1;
-  long int window=pwindow;
-  long int no_of_nodes=igraph_vcount(graph);
-  
-  igraph_vector_t indegree;
-  igraph_vector_t v_normfact, *normfact;
-  igraph_vector_t ntk, ch;
-  igraph_vector_t v_notnull, *notnull;
-
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-  long int edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ntk, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ch, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_vector_resize(normfact, classes));
-    igraph_vector_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_VECTOR_INIT_FINALLY(normfact, classes);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_vector_resize(notnull, classes));
-    igraph_vector_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_VECTOR_INIT_FINALLY(notnull, classes);
-  }
-  
-  IGRAPH_CHECK(igraph_vector_resize(kernel, classes));
-  igraph_vector_null(kernel);
-  if (sd) { 
-    IGRAPH_CHECK(igraph_vector_resize(sd, classes)); 
-    igraph_vector_null(sd);
-  }
-
-  VECTOR(ntk)[0]=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntk)[xidx];
-      double oldm=VECTOR(*kernel)[xidx];
-      VECTOR(*notnull)[xidx]+=1;
-      VECTOR(*kernel)[xidx] += (xk-oldm)/VECTOR(*notnull)[xidx];
-      if (sd) {
-	VECTOR(*sd)[xidx] += (xk-oldm)*(xk-VECTOR(*kernel)[xidx]);
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/VECTOR(ntk)[xidx]); }
-    }
-    
-    /* Update ntk & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      VECTOR(indegree)[to] += 1;
-      VECTOR(ntk)[xidx] -= 1;
-      if (VECTOR(ntk)[xidx]==0) {
-	VECTOR(*normfact)[xidx] += (edges-VECTOR(ch)[xidx]);
-      }
-      VECTOR(ntk)[xidx+1] += 1;
-      if (VECTOR(ntk)[xidx+1]==1) {
-	VECTOR(ch)[xidx+1]=edges;
-      }
-    }
-    VECTOR(ntk)[0] += 1;
-    if (VECTOR(ntk)[0]==1) {
-      VECTOR(ch)[0]=edges;
-    }
-
-    /* Time window updates */
-    if (node+1-window >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node+1-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(long int) VECTOR(indegree)[to];
-	VECTOR(indegree)[to] -= 1;
-	VECTOR(ntk)[xidx] -= 1;
-	if (VECTOR(ntk)[xidx]==0) {
-	  VECTOR(*normfact)[xidx] += (edges-VECTOR(ch)[xidx]);
-	}
-	VECTOR(ntk)[xidx-1] += 1;
-	if (VECTOR(ntk)[xidx-1]==1) {
-	  VECTOR(ch)[xidx-1]=edges;
-	}
-      }
-    }
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<classes; i++) {
-    igraph_real_t oldmean;
-    if (VECTOR(ntk)[i] != 0) {
-      VECTOR(*normfact)[i] += (edges-VECTOR(ch)[i]);
-    }
-    if (VECTOR(*normfact)[i]==0) {
-      VECTOR(*kernel)[i]=0;
-      VECTOR(*normfact)[i]=1;
-    }
-    oldmean=VECTOR(*kernel)[i];
-    VECTOR(*kernel)[i] *= VECTOR(*notnull)[i] / VECTOR(*normfact)[i];
-    if (sd) {
-      VECTOR(*sd)[i] += oldmean * oldmean * VECTOR(*notnull)[i] *
-	(1-VECTOR(*notnull)[i]/VECTOR(*normfact)[i]);
-      VECTOR(*sd)[i] = sqrt(VECTOR(*sd)[i]/(VECTOR(*normfact)[i]-1));
-    }
-  }
-  
-  if (!cites) {
-    igraph_vector_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_vector_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&ch);
-  igraph_vector_destroy(&ntk);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(4);
-
-  return 0;
-}
-
-int igraph_revolver_st_r(const igraph_t *graph,
-			igraph_vector_t *st,
-			const igraph_vector_t *kernel,
-			igraph_integer_t pwindow) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int window=pwindow;
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  VECTOR(*st)[0]=VECTOR(*kernel)[0];
-  
-  for (node=1; node<no_of_nodes; node++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1]+VECTOR(*kernel)[0];
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      VECTOR(indegree)[to]+=1;
-      VECTOR(*st)[node] += -VECTOR(*kernel)[xidx]+VECTOR(*kernel)[xidx+1];
-    }
-    
-    /* time window update */
-    if (node-window >=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(long int) VECTOR(indegree)[to];
-	VECTOR(indegree)[to] -= 1;
-	VECTOR(*st)[node] += -VECTOR(*kernel)[xidx]+VECTOR(*kernel)[xidx-1];
-      }
-    }
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_exp_r(const igraph_t *graph,
-			 igraph_vector_t *expected,
-			 const igraph_vector_t *kernel,
-			 const igraph_vector_t *st,
-			 igraph_integer_t window,
-			 igraph_integer_t pmaxind) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_r(const igraph_t *graph,
-			   const igraph_vector_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pwindow,
-			   igraph_integer_t maxind,			   
-			   igraph_real_t *logprob,
-			   igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int window=pwindow;
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!mylogprob) { mylogprob=&rlogprob; }
-  if (!mylognull) { mylognull=&rlognull; }
-
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      igraph_real_t prob=VECTOR(*kernel)[xidx]/VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-
-    /* time window updates */
-    if (node-window+1 >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window+1), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	VECTOR(indegree)[to] -= 1;
-      }
-    }
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_r(const igraph_t *graph,
-			     const igraph_vector_t *kernel,
-			     igraph_integer_t window,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_vector_size(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_r(graph, &st, kernel, window));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_r(graph, kernel, &st, window, maxdegree,
-					 logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-  
-  
-
-/***********************************************/
-/* age, recent in-degree                       */
-/***********************************************/
-
-int igraph_revolver_ar(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      igraph_integer_t window,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i, j;
-  igraph_integer_t maxdegree=0;
-  igraph_vector_t neis;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  /* determine maximum recent degree, we use st temporarily */
-  for (i=0; i<no_of_nodes; i++) {
-    if (i-window>=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) (i-window),
-				    IGRAPH_OUT));
-      for (j=0; j<igraph_vector_size(&neis); j++) {
-	long int to=(long int) VECTOR(neis)[j];
-	VECTOR(st)[to] -= 1;
-      }
-    }
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, 
-				  IGRAPH_OUT));
-    for (j=0; j<igraph_vector_size(&neis); j++) {
-      long int to=(long int) VECTOR(neis)[j];
-      VECTOR(st)[to] += 1;
-      if (VECTOR(st)[to] > maxdegree) {
-	maxdegree=(igraph_integer_t) VECTOR(st)[to];
-      }
-    }
-  }
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  IGRAPH_PROGRESS("Revolver ar", 0, NULL);
-  for (i=0; i<niter; i++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1!=niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ar(graph, kernel, 0 /*sd*/, 0 /*norm*/, 
-					 0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					 0 /*logmax*/, &st, agebins,
-					 window, maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ar(graph, &st, kernel, window));
-    } else {			/* last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ar(graph, kernel, sd, norm, cites, debug,
-					  debugres, logmax, 
-					  &st, agebins, window, maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ar(graph, &st, kernel, window));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_ar(graph, expected, kernel,
-					  &st, agebins, window, maxdegree));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_ar(graph, kernel, &st, 
-					     agebins, window, maxdegree,
-					     logprob, lognull));
-      }
-    }
-    
-    IGRAPH_PROGRESS("Revolver ar", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  return 0;
-}
-
-int igraph_revolver_mes_ar(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pagebins,
-			  igraph_integer_t pwindow,
-			  igraph_integer_t maxind) {
-
-  long int classes=maxind+1;
-  long int agebins=pagebins;
-  long int window=pwindow;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_matrix_t v_normfact, *normfact;
-  igraph_matrix_t ntk, ch;
-  igraph_matrix_t v_notnull, *notnull;
-
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i, j, k;
-  long int edges=0;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntk, agebins+1, classes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, agebins+1, classes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, agebins, classes));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, agebins, classes);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, agebins, classes));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, agebins, classes);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, agebins, classes));
-  igraph_matrix_null(kernel);
-  if (sd) { 
-    IGRAPH_CHECK(igraph_matrix_resize(sd, agebins, classes)); 
-    igraph_matrix_null(sd);
-  }
-
-  MATRIX(ntk, binwidth>1 ? 0 : 1, 0)=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) (node+1),
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(node+1-to)/binwidth;
-      long int yidx=(long int) VECTOR(indegree)[to];
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntk, xidx, yidx);
-      double oldm=MATRIX(*kernel, xidx, yidx);
-      MATRIX(*notnull, xidx, yidx)+=1;
-      MATRIX(*kernel, xidx, yidx) += (xk-oldm)/MATRIX(*notnull, xidx, yidx);
-      if (sd) {
-	MATRIX(*sd, xidx, yidx) += (xk-oldm)*(xk-MATRIX(*kernel, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/MATRIX(ntk, xidx, yidx)); }
-    }
-    
-    /* Update ntk & co */
-    edges += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(node+1-to)/binwidth;
-      long int yidx=(long int) VECTOR(indegree)[to];
-      
-      VECTOR(indegree)[to] += 1;
-      MATRIX(ntk, xidx, yidx) -= 1;
-      if (MATRIX(ntk, xidx, yidx)==0) {
-	MATRIX(*normfact, xidx, yidx) += (edges-MATRIX(ch, xidx, yidx));
-      }
-      MATRIX(ntk, xidx, yidx+1) += 1;
-      if (MATRIX(ntk, xidx, yidx+1)==1) {
-	MATRIX(ch, xidx, yidx+1)=edges;
-      }
-    }
-    MATRIX(ntk, 0, 0) += 1;
-    if (MATRIX(ntk, 0, 0)==1) {
-      MATRIX(ch, 0, 0)=edges;
-    }
-    
-    /* Time window updates */
-    if (node+1-window >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node+1-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(node+1-to)/binwidth;
-	long int yidx=(long int) VECTOR(indegree)[to];
-	VECTOR(indegree)[to] -= 1;
-	MATRIX(ntk, xidx, yidx) -= 1;
-	if (MATRIX(ntk, xidx, yidx)==0) {
-	  MATRIX(*normfact, xidx, yidx) += (edges-MATRIX(ch, xidx, yidx));
-	}
-	MATRIX(ntk, xidx, yidx-1) += 1;
-	if (MATRIX(ntk, xidx, yidx-1)==1) {
-	  MATRIX(ch, xidx, yidx-1)=edges;
-	}
-      }
-    }
-    
-    /* Aging */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      MATRIX(ntk, k-1, deg)--;
-      if (MATRIX(ntk, k-1, deg)==0) {
-	MATRIX(*normfact, k-1, deg) += (edges-MATRIX(ch, k-1, deg));
-      }
-      MATRIX(ntk, k, deg) += 1;
-      if (MATRIX(ntk, k, deg)==1) {
-	MATRIX(ch, k, deg)=edges;
-      }
-    }
-    
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (i=0; i<agebins; i++) {
-    for (j=0; j<classes; j++) {
-      igraph_real_t oldmean;
-      if (MATRIX(ntk, i, j) != 0) {
-	MATRIX(*normfact, i, j) += (edges-MATRIX(ch, i, j));
-      }
-      if (MATRIX(*normfact, i, j)==0) {
-	MATRIX(*kernel, i, j)=0;
-	MATRIX(*normfact, i, j)=1;
-      }
-      oldmean=MATRIX(*kernel, i, j);
-      MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j) / MATRIX(*normfact, i, j);
-      if (sd) {
-	MATRIX(*sd, i, j) += oldmean * oldmean * MATRIX(*notnull, i, j) *
-	  (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
-	MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntk);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(4);
-
-  return 0;
-}
-
-int igraph_revolver_st_ar(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 igraph_integer_t pwindow) {
-  
-  long int agebins=igraph_matrix_nrow(kernel);
-  long int no_of_nodes=igraph_vcount(graph);
-  long int window=pwindow;
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i, k;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  VECTOR(*st)[0]=MATRIX(*kernel, binwidth>1 ? 0 : 1, 0);
-  
-  for (node=1; node<no_of_nodes; node++) {
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    VECTOR(*st)[node]=VECTOR(*st)[node-1]+MATRIX(*kernel, 0, 0);
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(node-to)/binwidth;
-      long int yidx=(long int) VECTOR(indegree)[to];
-      VECTOR(indegree)[to]+=1;
-      VECTOR(*st)[node] += 
-	-MATRIX(*kernel, xidx, yidx)+MATRIX(*kernel, xidx, yidx+1);
-    }
-    
-    /* time window update */
-    if (node-window >=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(node-to)/binwidth;
-	long int yidx=(long int) VECTOR(indegree)[to];
-	VECTOR(indegree)[to] -= 1;
-	VECTOR(*st)[node] += 
-	  -MATRIX(*kernel, xidx, yidx)+MATRIX(*kernel, xidx, yidx-1);
-      }
-    }
-
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      VECTOR(*st)[node] += -MATRIX(*kernel, k-1, deg)+MATRIX(*kernel, k, deg);
-    }    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_exp_ar(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t agebins,
-			  igraph_integer_t window,
-			  igraph_integer_t pmaxind) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_ar(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pagebins,
-			    igraph_integer_t pwindow,
-			    igraph_integer_t maxind,			   
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int window=pwindow;
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  
-  long int node;
-  long int i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!mylogprob) { mylogprob=&rlogprob; }
-  if (!mylognull) { mylognull=&rlognull; }
-
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(node+1-to)/binwidth;
-      long int yidx=(long int) VECTOR(indegree)[to];
-      
-      igraph_real_t prob=MATRIX(*kernel, xidx, yidx)/VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-
-    /* time window updates */
-    if (node-window+1 >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window+1), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	VECTOR(indegree)[to] -= 1;
-      }
-    }
-    
-    /* Aging update not needed */
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_ar(const igraph_t *graph, 
-			      const igraph_matrix_t *kernel,
-			      igraph_integer_t window, 
-			      igraph_real_t *logprob, 
-			      igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_matrix_nrow(kernel)-1;
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_ar(graph, &st, kernel, window));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_ar(graph, kernel, &st, agebins, window,
-					  maxdegree,
-					  logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-  
-
-/***********************************************/
-/* in-degree, citing category                  */
-/***********************************************/
-
-int igraph_revolver_di(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  IGRAPH_PROGRESS("Revolver di", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION(); 
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_di(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					 0/*logmax*/, &st, cats, nocats, maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_di(graph, &st, kernel, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_di(graph, kernel, sd, norm, cites, debug,
-					 debugres, logmax, &st, cats, nocats, 
-					 maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_di(graph, &st, kernel, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_di(graph, expected, kernel,
-					   &st, cats, nocats, maxdegree)); 
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_di(graph, kernel, &st,
-					     cats, nocats, maxdegree, 
-					     logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver di", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_di(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind) {
-  long int nocats=pnocats, maxind=pmaxind;
-  long int no_of_nodes=igraph_vcount(graph);
-  
-  igraph_vector_t indegree;
-  igraph_vector_t ntkl;
-  igraph_matrix_t ch, v_normfact, *normfact, v_notnull, *notnull;
-  
-  igraph_vector_t neis;
-  
-  long int node, i, j;
-  igraph_vector_t edges;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ntkl, maxind+1);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, nocats, maxind+1);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&edges, nocats);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, maxind+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, nocats, maxind+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, maxind+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, nocats, maxind+1);
-  }  
-
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, nocats, maxind+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, nocats, maxind+1));
-    igraph_matrix_null(sd);
-  }
-  
-  VECTOR(ntkl)[0]=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntkl)[xidx];
-      double oldm=MATRIX(*kernel, cidx, xidx);
-      MATRIX(*notnull, cidx, xidx) += 1;
-      MATRIX(*kernel, cidx, xidx) += 
-	(xk-oldm)/MATRIX(*notnull, cidx, xidx);
-      if (sd) {
-	MATRIX(*sd, cidx, xidx) += 
-	  (xk-oldm)*(xk-MATRIX(*kernel, cidx, xidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/VECTOR(ntkl)[xidx]); }
-    }
-        
-    /* Update ntkl & co */
-    VECTOR(edges)[cidx] += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      VECTOR(indegree)[to] += 1;
-      VECTOR(ntkl)[xidx] -= 1;
-      if (VECTOR(ntkl)[xidx]==0) {
-	for (j=0; j<nocats; j++) {
-	  MATRIX(*normfact, j, xidx) += (VECTOR(edges)[j]-MATRIX(ch, j, xidx));
-	}
-      }
-      VECTOR(ntkl)[xidx+1] += 1;
-      if (VECTOR(ntkl)[xidx+1]==1) {
-	for (j=0; j<nocats; j++) {
-	  MATRIX(ch, j, xidx+1)=VECTOR(edges)[j];
-	}
-      }
-    }
-    /* new node */
-    VECTOR(ntkl)[0] += 1;
-    if (VECTOR(ntkl)[0]==1) {
-      for (j=0; j<nocats; j++) {
-	MATRIX(ch, j, 0)=VECTOR(edges)[j];
-      }
-    }
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (j=0; j<nocats; j++) {
-    for (i=0; i<maxind+1; i++) {
-      igraph_real_t oldmean;
-      if (VECTOR(ntkl)[i] != 0) {
-	MATRIX(*normfact, j, i) += (VECTOR(edges)[j]-MATRIX(ch, j, i));
-      }
-      if (MATRIX(*normfact, j, i)==0) {
-	MATRIX(*kernel, j, i)=0;
-	MATRIX(*normfact, j, i)=1;
-      }
-      oldmean=MATRIX(*kernel, j, i);
-      MATRIX(*kernel, j, i) *= 
-	MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i);	  
-      if (sd) {
-	MATRIX(*sd, j, i) +=
-	  oldmean*oldmean*MATRIX(*notnull, j, i)*
-	  (1-MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i));
-	MATRIX(*sd, j, i)=
-	  sqrt(MATRIX(*sd, j, i)/(MATRIX(*normfact, j, i)-1));
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&edges);
-  igraph_matrix_destroy(&ch);
-  igraph_vector_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(5);    
-  
-  return 0;
-}
-
-int igraph_revolver_st_di(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int nocats=igraph_matrix_nrow(kernel);
-
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  igraph_matrix_t allst;
-  
-  long int node, i, j;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_MATRIX_INIT_FINALLY(&allst, nocats, no_of_nodes);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-
-  for (j=0; j<nocats; j++) {
-    MATRIX(allst, j, 0)=MATRIX(*kernel, j, 0);
-  }
-  VECTOR(*st)[0]=MATRIX(allst, (long int) VECTOR(*cats)[0], 0);
-  
-  for (node=1; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    for (j=0; j<nocats; j++) {
-      MATRIX(allst, j, node)=MATRIX(allst, j, node-1)+MATRIX(*kernel, j, 0);
-    }
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      VECTOR(indegree)[to] += 1;
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -MATRIX(*kernel, j, xidx)+MATRIX(*kernel, j, xidx+1);
-      }
-    }
-    
-    /* which one do we need in the next time step? */
-    VECTOR(*st)[node]=MATRIX(allst, (long int)VECTOR(*cats)[node+1], node);
-  }
-  
-  igraph_matrix_destroy(&allst);
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(3);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_di(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_di(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) { 
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t indegree, neis;
-  long int node, i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      igraph_real_t prob=MATRIX(*kernel, cidx, xidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_error2_di(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_matrix_nrow(kernel);
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_di(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_di(graph, kernel, &st, cats, nocats,
-					  maxdegree,
-					  logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-/***********************************************/
-/* age, in-degree, citing category             */
-/***********************************************/
-
-int igraph_revolver_adi(const igraph_t *graph,
-		       igraph_integer_t niter,
-		       igraph_integer_t agebins,
-		       const igraph_vector_t *cats,
-		       igraph_array3_t *kernel,
-		       igraph_array3_t *sd,
-		       igraph_array3_t *norm,
-		       igraph_array3_t *cites,
-		       igraph_array3_t *expected,
-		       igraph_real_t *logprob,
-		       igraph_real_t *lognull,
-		       igraph_real_t *logmax,
-		       const igraph_matrix_t *debug,
-		       igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  IGRAPH_PROGRESS("Revolver adi", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION(); 
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_adi(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					  0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					  0/*logmax*/, &st, cats,
-					  nocats, maxdegree, agebins));
-      
-      /* normalize */
-      igraph_array3_scale(kernel, 1/igraph_array3_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_adi(graph, &st, kernel, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_adi(graph, kernel, sd, norm, cites, debug,
-					  debugres, logmax, &st, cats, nocats, 
-					  maxdegree, agebins));
-      
-      /* normalize */
-      igraph_array3_scale(kernel, 1/igraph_array3_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_adi(graph, &st, kernel, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_adi(graph, expected, kernel,
-					    &st, cats, nocats, maxdegree, agebins)); 
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_adi(graph, kernel, &st,
-					      cats, nocats, maxdegree, agebins,
-					      logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver adi", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_adi(const igraph_t *graph,
-			   igraph_array3_t *kernel,
-			   igraph_array3_t *sd,
-			   igraph_array3_t *norm,
-			   igraph_array3_t *cites,
-			   const igraph_matrix_t *debug,
-			   igraph_vector_ptr_t *debugres,
-			   igraph_real_t *logmax,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins) {
-  long int nocats=pnocats, maxind=pmaxind;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_vector_t indegree;
-  igraph_matrix_t ntkl;
-  igraph_array3_t ch, v_normfact, *normfact, v_notnull, *notnull;
-  
-  igraph_vector_t neis;
-  
-  long int node, i, j, k;
-  igraph_vector_t edges;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, maxind+2, agebins+1);
-  IGRAPH_ARRAY3_INIT_FINALLY(&ch, nocats, maxind+1, agebins);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&edges, nocats);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_array3_resize(normfact, nocats, maxind+1, agebins));
-    igraph_array3_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_ARRAY3_INIT_FINALLY(normfact, nocats, maxind+1, agebins);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_array3_resize(normfact, nocats, maxind+1, agebins));
-    igraph_array3_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_ARRAY3_INIT_FINALLY(notnull, nocats, maxind+1, agebins);
-  }  
-
-  IGRAPH_CHECK(igraph_array3_resize(kernel, nocats, maxind+1, agebins));
-  igraph_array3_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_array3_resize(sd, nocats, maxind+1, agebins));
-    igraph_array3_null(sd);
-  }
-  
-  MATRIX(ntkl, 0, binwidth>1 ? 0 : 1)=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntkl, xidx, yidx);
-      double oldm=ARRAY3(*kernel, cidx, xidx, yidx);
-      ARRAY3(*notnull, cidx, xidx, yidx) += 1;
-      ARRAY3(*kernel, cidx, xidx, yidx) += 
-	(xk-oldm)/ARRAY3(*notnull, cidx, xidx, yidx);
-      if (sd) {
-	ARRAY3(*sd, cidx, xidx, yidx) += 
-	  (xk-oldm)*(xk-ARRAY3(*kernel, cidx, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/MATRIX(ntkl, xidx, yidx)); }
-    }
-        
-    /* Update ntkl & co */
-    VECTOR(edges)[cidx] += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      VECTOR(indegree)[to] += 1;
-      MATRIX(ntkl, xidx, yidx) -= 1;
-      if (MATRIX(ntkl, xidx, yidx)==0) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(*normfact, j, xidx, yidx) += 
-	    (VECTOR(edges)[j]-ARRAY3(ch, j, xidx, yidx));
-	}
-      }
-      MATRIX(ntkl, xidx+1, yidx) += 1;
-      if (MATRIX(ntkl, xidx+1, yidx)==1) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(ch, j, xidx+1, yidx)=VECTOR(edges)[j];
-	}
-      }
-    }
-    /* new node */
-    MATRIX(ntkl, 0, 0) += 1;
-    if (MATRIX(ntkl, 0, 0)==1) {
-      for (j=0; j<nocats; j++) {
-	ARRAY3(ch, j, 0, 0)=VECTOR(edges)[j];
-      }
-    }
-    /* aging */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      MATRIX(ntkl, deg, k-1) -= 1;
-      if (MATRIX(ntkl, deg, k-1)==0) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(*normfact, j, deg, k-1) += 
-	    (VECTOR(edges)[j]-ARRAY3(ch, j, deg, k-1));
-	}
-      }
-      MATRIX(ntkl, deg, k) += 1;
-      if (MATRIX(ntkl, deg, k)==1) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(ch, j, deg, k)=VECTOR(edges)[j];
-	}
-      }
-    }    
-    
-  } /* node */
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (j=0; j<nocats; j++) {
-    for (i=0; i<maxind+1; i++) {
-      for (k=0; k<agebins; k++) {
-	igraph_real_t oldmean;
-	if (MATRIX(ntkl, i, k) != 0) {
-	  ARRAY3(*normfact, j, i, k) += (VECTOR(edges)[j]-ARRAY3(ch, j, i, k));
-	}
-	if (ARRAY3(*normfact, j, i, k)==0) {
-	  ARRAY3(*kernel, j, i, k)=0;
-	  ARRAY3(*normfact, j, i, k)=1;
-	}
-	oldmean=ARRAY3(*kernel, j, i, k);
-	ARRAY3(*kernel, j, i, k) *= 
-	  ARRAY3(*notnull, j, i, k)/ARRAY3(*normfact, j, i, k);	  
-	if (sd) {
-	  ARRAY3(*sd, j, i, k) +=
-	    oldmean*oldmean*ARRAY3(*notnull, j, i, k)*
-	    (1-ARRAY3(*notnull, j, i, k)/ARRAY3(*normfact, j, i, k));
-	  ARRAY3(*sd, j, i, k)=
-	    sqrt(ARRAY3(*sd, j, i, k)/(ARRAY3(*normfact, j, i, k)-1));
-	}
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_array3_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_array3_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&edges);
-  igraph_array3_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(5);    
-  
-  return 0;
-}
-
-int igraph_revolver_st_adi(const igraph_t *graph,
-			  igraph_vector_t *st,
-			  const igraph_array3_t *kernel,
-			  const igraph_vector_t *cats) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int nocats=igraph_array3_n(kernel, 1);
-  long int agebins=igraph_array3_n(kernel, 3);
-  long int binwidth=no_of_nodes/agebins+1;
-
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  igraph_matrix_t allst;
-  
-  long int node, i, j, k;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_MATRIX_INIT_FINALLY(&allst, nocats, no_of_nodes);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-
-  for (j=0; j<nocats; j++) {
-    MATRIX(allst, j, 0)=ARRAY3(*kernel, j, 0, binwidth>1 ? 0 : 1);
-  }
-  VECTOR(*st)[0]=MATRIX(allst, (long int) VECTOR(*cats)[0], 0);
-  
-  for (node=1; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    for (j=0; j<nocats; j++) {
-      MATRIX(allst, j, node)=MATRIX(allst, j, node-1)+ARRAY3(*kernel, j, 0, 0);
-    }
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      VECTOR(indegree)[to] += 1;
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -ARRAY3(*kernel, j, xidx, yidx)+ARRAY3(*kernel, j, xidx+1, yidx);
-      }
-    }
-
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -ARRAY3(*kernel, j, deg, k-1) + ARRAY3(*kernel, j, deg, k);
-      }
-    }
-    
-    /* which one do we need in the next time step? */
-    VECTOR(*st)[node]=MATRIX(allst, (long int)VECTOR(*cats)[node+1], node);
-  }
-  
-  igraph_matrix_destroy(&allst);
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(3);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_adi(const igraph_t *graph,
-			   igraph_array3_t *expected,
-			   const igraph_array3_t *kernel,
-			   const igraph_vector_t *st,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_adi(const igraph_t *graph,
-			     const igraph_array3_t *kernel,
-			     const igraph_vector_t *st,
-			     const igraph_vector_t *cats,
-			     igraph_integer_t pnocats,
-			     igraph_integer_t pmaxind,
-			     igraph_integer_t pagebins,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) { 
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t indegree, neis;
-  long int node, i;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      igraph_real_t prob=ARRAY3(*kernel, cidx, xidx, yidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-  
-  return 0;
-}
-
-int igraph_revolver_error2_adi(const igraph_t *graph,
-			       const igraph_array3_t *kernel,
-			       const igraph_vector_t *cats,
-			       igraph_real_t *logprob,
-			       igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_array3_n(kernel, 1);
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_array3_n(kernel, 2)-1;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_array3_n(kernel, 3);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_adi(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_adi(graph, kernel, &st, cats, nocats, 
-					   maxdegree, agebins,
-					   logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}  
-
-/***********************************************/
-/* time since last citation, citing category   */
-/***********************************************/
-
-int igraph_revolver_il(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t agebins,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t nocats;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-
-  IGRAPH_PROGRESS("Revolver il", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) { 	/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_il(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0 /*cites*/, 0 /*debug*/, 0 /*debugres*/,
-					 0 /*logmax*/, &st, cats, nocats, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_il(graph, &st, kernel, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_il(graph, kernel, sd, norm, cites, debug,
-					 debugres, logmax, &st, 
-					 cats, nocats, agebins));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_il(graph, &st, kernel, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_il(graph, expected, kernel, &st,
-					   cats, nocats, agebins));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_il(graph, kernel, &st, cats, nocats,
-					     agebins, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver il", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_il(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pagebins) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  long int nocats=pnocats;
-  
-  igraph_vector_t ntl;
-  igraph_matrix_t ch, v_normfact, v_notnull, *normfact, *notnull;
-  
-  igraph_vector_t lastcit;
-  igraph_vector_t neis;
-  
-  long int node, i, k, j;
-  igraph_vector_t edges;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ntl, agebins+2); 	/* +1 for the never cited */
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, nocats, agebins+2);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&edges, nocats);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, agebins+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, nocats, agebins+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, nocats, agebins+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, nocats, agebins+1);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, nocats, agebins+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, nocats, agebins+1));
-    igraph_matrix_null(sd);
-  }  
-
-  VECTOR(ntl)[agebins]=1;
-  
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ? 
-	(node+2-(long int)VECTOR(lastcit)[to])/binwidth :	agebins;      
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntl)[xidx];
-      double oldm=MATRIX(*kernel, cidx, xidx);
-      MATRIX(*notnull, cidx, xidx) += 1;
-      MATRIX(*kernel, cidx, xidx) += (xk-oldm)/MATRIX(*notnull, cidx, xidx);
-      if (sd) {
-	MATRIX(*sd, cidx, xidx) += (xk-oldm)*(xk-MATRIX(*kernel, cidx, xidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/VECTOR(ntl)[xidx]); }
-    }
-  
-    /* Update ntkl & co */
-    VECTOR(edges)[cidx] += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ? 
-	(long int) ((node+2.0-VECTOR(lastcit)[to])/binwidth) : agebins;
-      
-      VECTOR(lastcit)[to]=node+2;
-      VECTOR(ntl)[xidx] -= 1; 
-      if (VECTOR(ntl)[xidx]==0) {
-	for (j=0; j<nocats; j++) {
-	  MATRIX(*normfact, j, xidx) += 
-	    (VECTOR(edges)[j]-MATRIX(ch, j, xidx));
-	}
-      }
-      VECTOR(ntl)[0] += 1;
-      if (VECTOR(ntl)[0]==1) {
-	for (j=0; j<nocats; j++) {
-	  MATRIX(ch, j, 0)=VECTOR(edges)[j];
-	}
-      }
-    }
-    /* new node */
-    VECTOR(ntl)[agebins] += 1;
-    if (VECTOR(ntl)[agebins]==1) {
-      for (j=0; j<nocats; j++) {
-	MATRIX(ch, j, agebins)=VECTOR(edges)[j];
-      }
-    }
-    /* should we move some citations to an older bin? */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode, 
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  VECTOR(ntl)[k-1] -= 1;
-	  if (VECTOR(ntl)[k-1]==0) {
-	    for (j=0; j<nocats; j++) {	      
-	      MATRIX(*normfact, j, k-1) += 
-		(VECTOR(edges)[j]-MATRIX(ch, j, k-1));
-	    }
-	  }
-	  VECTOR(ntl)[k] += 1;
-	  if (VECTOR(ntl)[k]==1) {
-	    for (j=0; j<nocats; j++) {
-	      MATRIX(ch, j, k)=VECTOR(edges)[j];
-	    }
-	  }
-	}
-      }
-    }
-
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (j=0; j<nocats; j++) {
-    for (i=0; i<agebins+1; i++) {
-      igraph_real_t oldmean;
-      if (VECTOR(ntl)[i] != 0) {
-	MATRIX(*normfact, j, i) += 
-	  (VECTOR(edges)[j]-MATRIX(ch, j, i));
-      }
-      if (MATRIX(*normfact, j, i)==0) {
-	MATRIX(*kernel, j, i)=0;
-	MATRIX(*normfact, j, i)=1;
-      }
-      oldmean=MATRIX(*kernel, j, i);
-      MATRIX(*kernel, j, i) *= MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i);
-      if (sd) {
-	MATRIX(*sd, j, i) += oldmean * oldmean * MATRIX(*notnull, j, i) *
-	  (1-MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i));
-	MATRIX(*sd, j, i) = sqrt(MATRIX(*sd, j, i)/(MATRIX(*normfact, j, i)-1));
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&edges);
-  igraph_vector_destroy(&neis);
-  igraph_matrix_destroy(&ch);
-  igraph_vector_destroy(&ntl);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(5);  
-
-  return 0;
-}
-
-int igraph_revolver_st_il(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 const igraph_vector_t *cats) {
-
-  long int nocats=igraph_matrix_nrow(kernel);
-  long int agebins=igraph_matrix_ncol(kernel)-1;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit;
-
-  igraph_vector_t neis;
-  igraph_matrix_t allst;
-  long int node, i, k, j;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&allst, nocats, no_of_nodes);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-  
-  for (j=0; j<nocats; j++) {
-    MATRIX(allst, j, 0)=MATRIX(*kernel, j, agebins);
-  }
-  VECTOR(*st)[0]=MATRIX(allst, (long int) VECTOR(*cats)[0], 0);
-  
-  for (node=1; node<no_of_nodes; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    for (j=0; j<nocats; j++) {
-      MATRIX(allst, j, node)=MATRIX(allst, j, node-1)+MATRIX(*kernel, j, agebins);
-    }
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ?
-	(node+1-(long int)VECTOR(lastcit)[to])/binwidth : agebins;
-      VECTOR(lastcit)[to]=node+1;
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -MATRIX(*kernel, j, xidx) + MATRIX(*kernel, j, 0);
-      }
-    }
-    
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode,
-				    IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int cnode=(long int) VECTOR(neis)[i];
-	if (VECTOR(lastcit)[cnode]==shnode+1) {
-	  for (j=0; j<nocats; j++) {
-	    MATRIX(allst, j, node) +=
-	      -MATRIX(*kernel, j, k-1) + MATRIX(*kernel, j, k);
-	  }
-	}
-      }
-    }
-    
-    VECTOR(*st)[node]=MATRIX(allst, (long int)VECTOR(*cats)[node+1], node);
-  }
-  
-  igraph_matrix_destroy(&allst);
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(3);
-
-  return 0;
-}
-
-int igraph_revolver_exp_il(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t nocats,
-			  igraph_integer_t pagebins) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_il(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pagebins,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) {
-
-  long int agebins=pagebins;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t lastcit;
-  igraph_vector_t neis;
-  
-  long int node, i;
-  
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&lastcit, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=VECTOR(lastcit)[to]!=0 ?
-	(node+2-(long int)VECTOR(lastcit)[to])/binwidth : agebins;
-      
-      igraph_real_t prob=MATRIX(*kernel, cidx, xidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(lastcit)[to]=node+2;
-    }
-
-  }
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&lastcit);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_il(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_matrix_nrow(kernel);
-  igraph_integer_t agebins=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_il(graph, &st, kernel, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_il(graph, kernel, &st, cats, nocats,
-					  agebins, logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-/***********************************************/
-/* in-degree, citing category                  */
-/***********************************************/
-
-int igraph_revolver_ir(const igraph_t *graph,
-		      igraph_integer_t niter,
-		      igraph_integer_t window,
-		      const igraph_vector_t *cats,
-		      igraph_matrix_t *kernel,
-		      igraph_matrix_t *sd,
-		      igraph_matrix_t *norm,
-		      igraph_matrix_t *cites,
-		      igraph_matrix_t *expected,
-		      igraph_real_t *logprob,
-		      igraph_real_t *lognull,
-		      igraph_real_t *logmax,
-		      const igraph_matrix_t *debug,
-		      igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i, j;
-  igraph_integer_t maxdegree=0;
-  igraph_integer_t nocats;
-  igraph_vector_t neis;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-
-  /* determine maximum recent degree, we use st temporarily */
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  for (i=0; i<no_of_nodes; i++) {
-    if (i-window>=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) (i-window),
-				    IGRAPH_OUT));
-      for (j=0; j<igraph_vector_size(&neis); j++) {
-	long int to=(long int) VECTOR(neis)[j];
-	VECTOR(st)[to] -= 1;
-      }
-    }
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i, 
-				  IGRAPH_OUT));
-    for (j=0; j<igraph_vector_size(&neis); j++) {
-      long int to=(long int)VECTOR(neis)[j];
-      VECTOR(st)[to] += 1;
-      if (VECTOR(st)[to] > maxdegree) {
-	maxdegree=(igraph_integer_t) VECTOR(st)[to];
-      }
-    }
-  }
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  IGRAPH_PROGRESS("Revolver di", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION(); 
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ir(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					 0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					 0/*logmax*/, &st, window, 
-					 cats, nocats, maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ir(graph, &st, kernel, window, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_ir(graph, kernel, sd, norm, cites, debug,
-					 debugres, logmax, &st, window, cats, nocats,
-					 maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_ir(graph, &st, kernel, window, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_ir(graph, expected, kernel,
-					   &st, window, cats, nocats, maxdegree)); 
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_ir(graph, kernel, &st, window,
-					     cats, nocats, maxdegree, 
-					     logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver di", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_ir(const igraph_t *graph,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *sd,
-			  igraph_matrix_t *norm,
-			  igraph_matrix_t *cites,
-			  const igraph_matrix_t *debug,
-			  igraph_vector_ptr_t *debugres,
-			  igraph_real_t *logmax,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pwindow,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind) {
-
-  long int nocats=pnocats, maxind=pmaxind;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int window=pwindow;
-  
-  igraph_vector_t indegree;
-  igraph_vector_t ntkl;
-  igraph_matrix_t ch, v_normfact, *normfact, v_notnull, *notnull;
-  
-  igraph_vector_t neis;
-  
-  long int node, i, j;
-  igraph_vector_t edges;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&ntkl, maxind+1);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, nocats, maxind+1);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&edges, nocats);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, maxind+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, nocats, maxind+1);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, nocats, maxind+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, nocats, maxind+1);
-  }  
-
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, nocats, maxind+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, nocats, maxind+1));
-    igraph_matrix_null(sd);
-  }
-  
-  VECTOR(ntkl)[0]=1;
-
-  if (logmax) { *logmax=0.0; }
-
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      double xk=VECTOR(*st)[node]/VECTOR(ntkl)[xidx];
-      double oldm=MATRIX(*kernel, cidx, xidx);
-      MATRIX(*notnull, cidx, xidx) += 1;
-      MATRIX(*kernel, cidx, xidx) += 
-	(xk-oldm)/MATRIX(*notnull, cidx, xidx);
-      if (sd) {
-	MATRIX(*sd, cidx, xidx) += 
-	  (xk-oldm)*(xk-MATRIX(*kernel, cidx, xidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/VECTOR(ntkl)[xidx]); }
-    }
-        
-    /* Update ntkl & co */
-    VECTOR(edges)[cidx] += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      VECTOR(indegree)[to] += 1;
-      VECTOR(ntkl)[xidx] -= 1;
-      if (VECTOR(ntkl)[xidx]==0) {
-	for (j=0; j<nocats; j++) {
-	  MATRIX(*normfact, j, xidx) += (VECTOR(edges)[j]-MATRIX(ch, j, xidx));
-	}
-      }
-      VECTOR(ntkl)[xidx+1] += 1;
-      if (VECTOR(ntkl)[xidx+1]==1) {
-	for (j=0; j<nocats; j++) {
-	  MATRIX(ch, j, xidx+1)=VECTOR(edges)[j];
-	}
-      }
-    }
-    /* new node */
-    VECTOR(ntkl)[0] += 1;
-    if (VECTOR(ntkl)[0]==1) {
-      for (j=0; j<nocats; j++) {
-	MATRIX(ch, j, 0)=VECTOR(edges)[j];
-      }
-    }
-
-    /* Time window updates */
-    if (node+1-window >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node+1-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(long int) VECTOR(indegree)[to];
-	VECTOR(indegree)[to] -= 1;
-	VECTOR(ntkl)[xidx] -= 1;
-	if (VECTOR(ntkl)[xidx]==0) {
-	  for (j=0; j<nocats; j++) {
-	    MATRIX(*normfact, j, xidx) += (VECTOR(edges)[j]-MATRIX(ch, j, xidx));
-	  }
-	}
-	VECTOR(ntkl)[xidx-1] += 1;
-	if (VECTOR(ntkl)[xidx-1]==1) {
-	  for (j=0; j<nocats; j++) {
-	    MATRIX(ch, j, xidx-1)=VECTOR(edges)[j];
-	  }
-	}
-      }
-    }    
-  }
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (j=0; j<nocats; j++) {
-    for (i=0; i<maxind+1; i++) {
-      igraph_real_t oldmean;
-      if (VECTOR(ntkl)[i] != 0) {
-	MATRIX(*normfact, j, i) += (VECTOR(edges)[j]-MATRIX(ch, j, i));
-      }
-      if (MATRIX(*normfact, j, i)==0) {
-	MATRIX(*kernel, j, i)=0;
-	MATRIX(*normfact, j, i)=1;
-      }
-      oldmean=MATRIX(*kernel, j, i);
-      MATRIX(*kernel, j, i) *= 
-	MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i);	  
-      if (sd) {
-	MATRIX(*sd, j, i) +=
-	  oldmean*oldmean*MATRIX(*notnull, j, i)*
-	  (1-MATRIX(*notnull, j, i)/MATRIX(*normfact, j, i));
-	MATRIX(*sd, j, i)=
-	  sqrt(MATRIX(*sd, j, i)/(MATRIX(*normfact, j, i)-1));
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&edges);
-  igraph_matrix_destroy(&ch);
-  igraph_vector_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(5);    
-
-  return 0;
-}
-
-int igraph_revolver_st_ir(const igraph_t *graph,
-			 igraph_vector_t *st,
-			 const igraph_matrix_t *kernel,
-			 igraph_integer_t pwindow,
-			 const igraph_vector_t *cats) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int nocats=igraph_matrix_nrow(kernel);
-  long int window=pwindow;
-
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  igraph_matrix_t allst;
-  
-  long int node, i, j;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_MATRIX_INIT_FINALLY(&allst, nocats, no_of_nodes);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-
-  for (j=0; j<nocats; j++) {
-    MATRIX(allst, j, 0)=MATRIX(*kernel, j, 0);
-  }
-  VECTOR(*st)[0]=MATRIX(allst, (long int) VECTOR(*cats)[0], 0);
-  
-  for (node=1; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    for (j=0; j<nocats; j++) {
-      MATRIX(allst, j, node)=MATRIX(allst, j, node-1)+MATRIX(*kernel, j, 0);
-    }
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      VECTOR(indegree)[to] += 1;
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -MATRIX(*kernel, j, xidx)+MATRIX(*kernel, j, xidx+1);
-      }
-    }
-    
-    /* time window update */
-    if (node-window >=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(long int) VECTOR(indegree)[to];
-	VECTOR(indegree)[to] -= 1;
-	for (j=0; j<nocats; j++) {
-	  MATRIX(allst, j, node) += 
-	    -MATRIX(*kernel, j, xidx)+MATRIX(*kernel, j, xidx-1);
-	}
-      }
-    }
-    
-    /* which one do we need in the next time step? */
-    VECTOR(*st)[node]=MATRIX(allst, (long int)VECTOR(*cats)[node+1], node);
-  }
-  
-  igraph_matrix_destroy(&allst);
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(3);  
-  
-  return 0;
-}
-
-int igraph_revolver_exp_ir(const igraph_t *graph,
-			  igraph_matrix_t *expected,
-			  const igraph_matrix_t *kernel,
-			  const igraph_vector_t *st,
-			  igraph_integer_t pwindow,
-			  const igraph_vector_t *cats,
-			  igraph_integer_t pnocats,
-			  igraph_integer_t pmaxind) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_ir(const igraph_t *graph,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    igraph_integer_t pwindow,
-			    const igraph_vector_t *cats,
-			    igraph_integer_t pnocats,
-			    igraph_integer_t pmaxind,
-			    igraph_real_t *logprob,
-			    igraph_real_t *lognull) { 
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t indegree, neis;
-  long int node, i;
-  long int window=pwindow;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      
-      igraph_real_t prob=MATRIX(*kernel, cidx, xidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-      
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-    /* time window updates */
-    if (node-window+1 >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window+1), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	VECTOR(indegree)[to] -= 1;
-      }
-    }
-
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_ir(const igraph_t *graph,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_integer_t window,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_matrix_nrow(kernel);
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_matrix_ncol(kernel)-1;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_ir(graph, &st, kernel, window, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_ir(graph, kernel, &st, window, cats, nocats,
-					  maxdegree, logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-/***********************************************/
-/* age, recent in-degree, citing category      */
-/***********************************************/
-
-int igraph_revolver_air(const igraph_t *graph,
-		       igraph_integer_t niter,
-		       igraph_integer_t window,
-		       igraph_integer_t agebins,
-		       const igraph_vector_t *cats,
-		       igraph_array3_t *kernel,
-		       igraph_array3_t *sd,
-		       igraph_array3_t *norm,
-		       igraph_array3_t *cites,
-		       igraph_array3_t *expected,
-		       igraph_real_t *logprob,
-		       igraph_real_t *lognull,
-		       igraph_real_t *logmax,
-		       const igraph_matrix_t *debug,
-		       igraph_vector_ptr_t *debugres) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  long int i, j;
-  igraph_integer_t maxdegree=0;
-  igraph_integer_t nocats;
-  igraph_vector_t neis;
-    
-  IGRAPH_PROGRESS("Revolver air", 0, NULL);
-
-  nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  /* determine maximum recent degree, we use st temporarily */
-  for (i=0; i<no_of_nodes; i++) {
-    if (i-window>=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) (i-window),
-				    IGRAPH_OUT));
-      for (j=0; j<igraph_vector_size(&neis); j++) {
-	long int to=(long int) VECTOR(neis)[j];
-	VECTOR(st)[to] -= 1;
-      }
-    }
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) i,
-				  IGRAPH_OUT));
-    for (j=0; j<igraph_vector_size(&neis); j++) {
-      long int to=(long int) VECTOR(neis)[j];
-      VECTOR(st)[to] += 1;
-      if (VECTOR(st)[to] > maxdegree) {
-	maxdegree=(igraph_integer_t) VECTOR(st)[to];
-      }
-    }
-  }
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(1);
-   
-  for (i=0; i<no_of_nodes; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION(); 
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_air(graph, kernel, 0 /*sd*/, 0 /*norm*/,
-					  0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					  0/*logmax*/, &st, window, 
-					  cats, nocats, maxdegree, agebins));
-      
-      /* normalize */
-      igraph_array3_scale(kernel, 1/igraph_array3_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_air(graph, &st, kernel, window, cats));
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_air(graph, kernel, sd, norm, cites, debug,
-					  debugres, logmax, &st, window, 
-					  cats, nocats, 
-					  maxdegree, agebins));
-      
-      /* normalize */
-      igraph_array3_scale(kernel, 1/igraph_array3_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_air(graph, &st, kernel, window, cats));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_air(graph, expected, kernel,
-					    &st, window, 
-					    cats, nocats, maxdegree, agebins)); 
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_air(graph, kernel, &st, window,
-					      cats, nocats, maxdegree, agebins,
-					      logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver air", 100*(i+1)/niter, NULL);
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
-
-int igraph_revolver_mes_air(const igraph_t *graph,
-			   igraph_array3_t *kernel,
-			   igraph_array3_t *sd,
-			   igraph_array3_t *norm,
-			   igraph_array3_t *cites,
-			   const igraph_matrix_t *debug,
-			   igraph_vector_ptr_t *debugres,
-			   igraph_real_t *logmax,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pwindow,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins) {
-
-  long int nocats=pnocats, maxind=pmaxind;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  long int window=pwindow;
-  
-  igraph_vector_t indegree;
-  igraph_matrix_t ntkl;
-  igraph_array3_t ch, v_normfact, *normfact, v_notnull, *notnull;
-  
-  igraph_vector_t neis;
-  
-  long int node, i, j, k;
-  igraph_vector_t edges;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkl, maxind+2, agebins+1);
-  IGRAPH_ARRAY3_INIT_FINALLY(&ch, nocats, maxind+1, agebins);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&edges, nocats);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_array3_resize(normfact, nocats, maxind+1, agebins));
-    igraph_array3_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_ARRAY3_INIT_FINALLY(normfact, nocats, maxind+1, agebins);
-  }
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_array3_resize(normfact, nocats, maxind+1, agebins));
-    igraph_array3_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_ARRAY3_INIT_FINALLY(notnull, nocats, maxind+1, agebins);
-  }  
-
-  IGRAPH_CHECK(igraph_array3_resize(kernel, nocats, maxind+1, agebins));
-  igraph_array3_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_array3_resize(sd, nocats, maxind+1, agebins));
-    igraph_array3_null(sd);
-  }
-  
-  MATRIX(ntkl, 0, binwidth>1 ? 0 : 1)=1;
-
-  if (logmax) { *logmax=0.0; }
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-
-    /* Estimate A() */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      double xk=VECTOR(*st)[node]/MATRIX(ntkl, xidx, yidx);
-      double oldm=ARRAY3(*kernel, cidx, xidx, yidx);
-      ARRAY3(*notnull, cidx, xidx, yidx) += 1;
-      ARRAY3(*kernel, cidx, xidx, yidx) += 
-	(xk-oldm)/ARRAY3(*notnull, cidx, xidx, yidx);
-      if (sd) {
-	ARRAY3(*sd, cidx, xidx, yidx) += 
-	  (xk-oldm)*(xk-ARRAY3(*kernel, cidx, xidx, yidx));
-      }
-      /* TODO: debug */
-      if (logmax) { *logmax += log(1.0/MATRIX(ntkl, xidx, yidx)); }
-    }
-        
-    /* Update ntkl & co */
-    VECTOR(edges)[cidx] += igraph_vector_size(&neis);
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      VECTOR(indegree)[to] += 1;
-      MATRIX(ntkl, xidx, yidx) -= 1;
-      if (MATRIX(ntkl, xidx, yidx)==0) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(*normfact, j, xidx, yidx) += 
-	    (VECTOR(edges)[j]-ARRAY3(ch, j, xidx, yidx));
-	}
-      }
-      MATRIX(ntkl, xidx+1, yidx) += 1;
-      if (MATRIX(ntkl, xidx+1, yidx)==1) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(ch, j, xidx+1, yidx)=VECTOR(edges)[j];
-	}
-      }
-    }
-    /* new node */
-    MATRIX(ntkl, 0, 0) += 1;
-    if (MATRIX(ntkl, 0, 0)==1) {
-      for (j=0; j<nocats; j++) {
-	ARRAY3(ch, j, 0, 0)=VECTOR(edges)[j];
-      }
-    }
-    /* Time window updates */
-    if (node+1-window >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node+1-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(long int) VECTOR(indegree)[to];
-	long int yidx=(node+1-to)/binwidth;
-	VECTOR(indegree)[to] -= 1;
-	MATRIX(ntkl, xidx, yidx) -= 1;
-	if (MATRIX(ntkl, xidx, yidx)==0) {
-	  for (j=0; j<nocats; j++) {
-	    ARRAY3(*normfact, j, xidx, yidx) += 
-	      (VECTOR(edges)[j]-ARRAY3(ch, j, xidx, yidx));
-	  }
-	}
-	MATRIX(ntkl, xidx-1, yidx) += 1;
-	if (MATRIX(ntkl, xidx-1, yidx)==1) {
-	  for (j=0; j<nocats; j++) {
-	    ARRAY3(ch, j, xidx-1, yidx)=VECTOR(edges)[j];
-	  }
-	}
-      }
-    }
-
-    /* aging */
-    for (k=1; node+1-binwidth*k+1>=0; k++) {
-      long int shnode=node+1-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      MATRIX(ntkl, deg, k-1) -= 1;
-      if (MATRIX(ntkl, deg, k-1)==0) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(*normfact, j, deg, k-1) += 
-	    (VECTOR(edges)[j]-ARRAY3(ch, j, deg, k-1));
-	}
-      }
-      MATRIX(ntkl, deg, k) += 1;
-      if (MATRIX(ntkl, deg, k)==1) {
-	for (j=0; j<nocats; j++) {
-	  ARRAY3(ch, j, deg, k)=VECTOR(edges)[j];
-	}
-      }
-    }    
-    
-  } /* node */
-  
-  /* Make normfact up to date, calculate mean, sd */
-  for (j=0; j<nocats; j++) {
-    for (i=0; i<maxind+1; i++) {
-      for (k=0; k<agebins; k++) {
-	igraph_real_t oldmean;
-	if (MATRIX(ntkl, i, k) != 0) {
-	  ARRAY3(*normfact, j, i, k) += (VECTOR(edges)[j]-ARRAY3(ch, j, i, k));
-	}
-	if (ARRAY3(*normfact, j, i, k)==0) {
-	  ARRAY3(*kernel, j, i, k)=0;
-	  ARRAY3(*normfact, j, i, k)=1;
-	}
-	oldmean=ARRAY3(*kernel, j, i, k);
-	ARRAY3(*kernel, j, i, k) *= 
-	  ARRAY3(*notnull, j, i, k)/ARRAY3(*normfact, j, i, k);	  
-	if (sd) {
-	  ARRAY3(*sd, j, i, k) +=
-	    oldmean*oldmean*ARRAY3(*notnull, j, i, k)*
-	    (1-ARRAY3(*notnull, j, i, k)/ARRAY3(*normfact, j, i, k));
-	  ARRAY3(*sd, j, i, k)=
-	    sqrt(ARRAY3(*sd, j, i, k)/(ARRAY3(*normfact, j, i, k)-1));
-	}
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_array3_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_array3_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&edges);
-  igraph_array3_destroy(&ch);
-  igraph_matrix_destroy(&ntkl);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(5);    
-
-  return 0;
-}
-
-int igraph_revolver_st_air(const igraph_t *graph,
-			  igraph_vector_t *st,
-			  const igraph_array3_t *kernel,
-			  igraph_integer_t pwindow,
-			  const igraph_vector_t *cats) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int nocats=igraph_array3_n(kernel, 1);
-  long int agebins=igraph_array3_n(kernel, 3);
-  long int binwidth=no_of_nodes/agebins+1;
-  long int window=pwindow;
-
-  igraph_vector_t indegree;
-  igraph_vector_t neis;
-  igraph_matrix_t allst;
-  
-  long int node, i, j, k;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_MATRIX_INIT_FINALLY(&allst, nocats, no_of_nodes);
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_nodes));
-
-  for (j=0; j<nocats; j++) {
-    MATRIX(allst, j, 0)=ARRAY3(*kernel, j, 0, binwidth>1 ? 0 : 1);
-  }
-  VECTOR(*st)[0]=MATRIX(allst, (long int) VECTOR(*cats)[0], 0);
-  
-  for (node=1; node<no_of_nodes-1; node++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* new node */
-    for (j=0; j<nocats; j++) {
-      MATRIX(allst, j, node)=MATRIX(allst, j, node-1)+ARRAY3(*kernel, j, 0, 0);
-    }
-    
-    /* outgoing edges */
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node,
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      VECTOR(indegree)[to] += 1;
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -ARRAY3(*kernel, j, xidx, yidx)+ARRAY3(*kernel, j, xidx+1, yidx);
-      }
-    }
-
-    /* time window update */
-    if (node-window >=0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	long int xidx=(long int) VECTOR(indegree)[to];
-	long int yidx=(node-to)/binwidth;
-	VECTOR(indegree)[to] -= 1;
-	for (j=0; j<nocats; j++) {
-	  MATRIX(allst, j, node) += 
-	    -ARRAY3(*kernel, j, xidx, yidx)+ARRAY3(*kernel, j, xidx, yidx-1);
-	}
-      }
-    }
-
-    /* aging */
-    for (k=1; node-binwidth*k+1 >= 0; k++) {
-      long int shnode=node-binwidth*k+1;
-      long int deg=(long int) VECTOR(indegree)[shnode];
-      for (j=0; j<nocats; j++) {
-	MATRIX(allst, j, node) += 
-	  -ARRAY3(*kernel, j, deg, k-1) + ARRAY3(*kernel, j, deg, k);
-      }
-    }
-    
-    /* which one do we need in the next time step? */
-    VECTOR(*st)[node]=MATRIX(allst, (long int)VECTOR(*cats)[node+1], node);
-  }
-  
-  igraph_matrix_destroy(&allst);
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(3);
-
-  return 0;
-}
-
-int igraph_revolver_exp_air(const igraph_t *graph,
-			   igraph_array3_t *expected,
-			   const igraph_array3_t *kernel,
-			   const igraph_vector_t *st,
-			   igraph_integer_t pwindow,
-			   const igraph_vector_t *cats,
-			   igraph_integer_t pnocats,
-			   igraph_integer_t pmaxind,
-			   igraph_integer_t pagebins) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_air(const igraph_t *graph,
-			     const igraph_array3_t *kernel,
-			     const igraph_vector_t *st,
-			     igraph_integer_t pwindow,
-			     const igraph_vector_t *cats,
-			     igraph_integer_t pnocats,
-			     igraph_integer_t pmaxind,
-			     igraph_integer_t pagebins,
-			     igraph_real_t *logprob,
-			     igraph_real_t *lognull) { 
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_vector_t indegree, neis;
-  long int node, i;
-  long int window=pwindow;
-
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&indegree, no_of_nodes);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (node=0; node<no_of_nodes-1; node++) {
-    long int cidx=(long int) VECTOR(*cats)[node+1];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) node+1, 
-				  IGRAPH_OUT));
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      long int xidx=(long int) VECTOR(indegree)[to];
-      long int yidx=(node+1-to)/binwidth;
-      
-      igraph_real_t prob=ARRAY3(*kernel, cidx, xidx, yidx) / VECTOR(*st)[node];
-      igraph_real_t nullprob=1.0/(node+1);
-
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-    }
-    
-    /* update */
-    for (i=0; i<igraph_vector_size(&neis); i++) {
-      long int to=(long int) VECTOR(neis)[i];
-      VECTOR(indegree)[to] += 1;
-    }
-    
-    /* time window updates */
-    if (node-window+1 >= 0) {
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) 
-				    (node-window+1), IGRAPH_OUT));
-      for (i=0; i<igraph_vector_size(&neis); i++) {
-	long int to=(long int) VECTOR(neis)[i];
-	VECTOR(indegree)[to] -= 1;
-      }
-    }
-  }
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_destroy(&indegree);
-  IGRAPH_FINALLY_CLEAN(2);
-
-  return 0;
-}
-
-int igraph_revolver_error2_air(const igraph_t *graph,
-			       const igraph_array3_t *kernel,
-			       const igraph_vector_t *cats,
-			       igraph_integer_t window,
-			       igraph_real_t *logprob,
-			       igraph_real_t *lognull) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_vector_t st;
-  igraph_integer_t nocats=(igraph_integer_t) igraph_array3_n(kernel, 1);
-  igraph_integer_t maxdegree=(igraph_integer_t) igraph_array3_n(kernel, 2)-1;
-  igraph_integer_t agebins=(igraph_integer_t) igraph_array3_n(kernel, 3);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_nodes);
-  
-  /* update st */
-  IGRAPH_CHECK(igraph_revolver_st_air(graph, &st, kernel, window, cats));
-  
-  /* error calculation */
-  if (logprob || lognull) {
-    IGRAPH_CHECK(igraph_revolver_error_air(graph, kernel, &st, window, cats, nocats,
-					   maxdegree, agebins,
-					   logprob, lognull));
-  }
-  
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return 0;
-}
diff --git a/src/revolver_grow.c b/src/revolver_grow.c
deleted file mode 100644
index 9b43b3e..0000000
--- a/src/revolver_grow.c
+++ /dev/null
@@ -1,1284 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph R package.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-#include "igraph_revolver.h"
-#include "igraph_interface.h"
-#include "igraph_progress.h"
-#include "igraph_interrupt_internal.h"
-#include "igraph_structural.h"
-#include "config.h"
-
-#include <math.h>
-
-/* This file contains tools for non-citation evolving networks */
-/* Citation networks are in evolver.c */
-
-/***********************************************/
-/* degree + degree                             */
-/***********************************************/
-
-int igraph_revolver_d_d(const igraph_t *graph,
-			igraph_integer_t niter,
-			const igraph_vector_t *vtime,
-			const igraph_vector_t *etime,
-			igraph_matrix_t *kernel,
-			igraph_matrix_t *sd,
-			igraph_matrix_t *norm,
-			igraph_matrix_t *cites,
-			igraph_matrix_t *expected,
-			igraph_real_t *logprob,
-			igraph_real_t *lognull,
-			const igraph_matrix_t *debug,
-			igraph_vector_ptr_t *debugres) {
-  
-  igraph_integer_t no_of_events, vnoev, enoev;
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxdegree;
-  igraph_vector_t vtimeidx, etimeidx;
-  igraph_lazy_inclist_t inclist;
-
-  if (igraph_vector_size(vtime) != igraph_vcount(graph)) {
-    IGRAPH_ERROR("Invalid vtime length", IGRAPH_EINVAL);
-  }
-  if (igraph_vector_size(etime) != igraph_ecount(graph)) {
-    IGRAPH_ERROR("Invalid etime length", IGRAPH_EINVAL);
-  }
-  
-  vnoev=(igraph_integer_t) igraph_vector_max(vtime)+1;
-  enoev=(igraph_integer_t) igraph_vector_max(etime)+1;
-  no_of_events= vnoev > enoev ? vnoev : enoev;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_events);
-  for (i=0; i<no_of_events; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_ALL, IGRAPH_LOOPS));
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&vtimeidx, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&etimeidx, 0);
-  IGRAPH_CHECK(igraph_vector_order1(vtime, &vtimeidx, no_of_events));
-  IGRAPH_CHECK(igraph_vector_order1(etime, &etimeidx, no_of_events));
-  
-  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_ALL));
-  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
-
-  IGRAPH_PROGRESS("Revolver d-d", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_d_d(graph, &inclist, 
-					   kernel, 0 /*sd*/, 0 /*norm*/,
-					   0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					   &st, vtime, &vtimeidx, etime, 
-					   &etimeidx, no_of_events,
-					   maxdegree));
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_d_d(graph, &inclist, 
-					  &st, kernel, vtime, &vtimeidx,
-					  etime, &etimeidx,
-					  no_of_events));
-      
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_d_d(graph, &inclist,
-					   kernel, sd, norm, cites, 
-					   debug, debugres, &st, vtime, &vtimeidx,
-					   etime, &etimeidx,
-					   no_of_events, maxdegree));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_d_d(graph, &inclist,
-					  &st, kernel, vtime, &vtimeidx,
-					  etime, &etimeidx,
-					  no_of_events));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_d_d(graph, &inclist,
-					     expected, kernel, &st,
-					     vtime, &vtimeidx, etime, &etimeidx,
-					     no_of_events, 
-					     maxdegree));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_d_d(graph, &inclist,
-					       kernel, &st,
-					       vtime, &vtimeidx, 
-					       etime, &etimeidx, no_of_events,
-					       maxdegree, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver d-d", 100.0*(i+1)/niter, NULL);
-  }
-
-  igraph_lazy_inclist_destroy(&inclist);
-  igraph_vector_destroy(&etimeidx);
-  igraph_vector_destroy(&vtimeidx);
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(4);
-  
-  return 0;
-}
-
-#define NTKK(xidx, yidx) \
-   ((xidx)==(yidx) ? (VECTOR(ntk)[(xidx)]*(VECTOR(ntk)[(xidx)]-1))/2-MATRIX(ntkk,(xidx),(yidx)) : VECTOR(ntk)[(xidx)]*VECTOR(ntk)[(yidx)]-MATRIX(ntkk,(xidx),(yidx)))
-
-/* int print_ntkk(igraph_matrix_t *ntkk, igraph_vector_long_t *ntk) { */
-/*   long int i, j, r=igraph_matrix_nrow(ntkk), c=igraph_matrix_ncol(ntkk); */
-/*   for (i=0; i<r; i++) { */
-/*     for (j=0; j<c; j++) { */
-/*       long int val=(i==j) ? */
-/* 	(VECTOR(*ntk)[i]*(VECTOR(*ntk)[i]-1)/2-MATRIX(*ntkk,i,j)) : */
-/* 	(VECTOR(*ntk)[i]*VECTOR(*ntk)[j]-MATRIX(*ntkk,i,j)); */
-/*       fprintf(stderr, "%li ", val); */
-/*     } */
-/*     fprintf(stderr, "\n"); */
-/*   } */
-/*   fprintf(stderr, "*************\n"); */
-/*   return 0; */
-/* } */
-
-int igraph_revolver_mes_d_d(const igraph_t *graph, 
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *kernel,
-			    igraph_matrix_t *sd,
-			    igraph_matrix_t *norm,
-			    igraph_matrix_t *cites,
-			    const igraph_matrix_t *debug,
-			    igraph_vector_ptr_t *debugres,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    igraph_integer_t pmaxdegree) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  long int no_of_events=pno_of_events;
-  long int maxdegree=pmaxdegree;
-  
-  igraph_vector_long_t degree;
-  igraph_vector_char_t added;	/* is this edge already in the network? */
-    
-  igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull;
-  igraph_matrix_t ch;
-  
-  igraph_vector_long_t ntk;	/* # of type x vertices */
-  igraph_matrix_t ntkk;	        /* # of connections between type x1, x2 vert. */
-  
-  igraph_vector_t *adjedges;
-
-  long int timestep, i;
-  long int nptr=0, eptr=0;
-  long int nptr_save, eptr_save, eptr_new;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(&igraph_vector_long_destroy, &degree);
-
-  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
-  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
-
-  IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxdegree+1, maxdegree+1);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, maxdegree+1, maxdegree+1);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, maxdegree+1, maxdegree+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, maxdegree+1, maxdegree+1);
-  }
-  
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, maxdegree+1, maxdegree+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, maxdegree+1, maxdegree+1);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, maxdegree+1, maxdegree+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, maxdegree+1, maxdegree+1));
-    igraph_matrix_null(sd);
-  }
-  
-  for (timestep=0; timestep<no_of_events; timestep++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* Add the vertices in the first */
-    nptr_save=nptr;
-    while (nptr < no_of_nodes && 
-	   VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) {
-      nptr++;
-    }
-    VECTOR(ntk)[0] += (nptr-nptr_save);
-
-    /* Update ch accordingly, could be done later as well */
-    if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) {
-      if (nptr-nptr_save >= 2) {
-	MATRIX(ch, 0, 0) = eptr;
-      }
-      for (i=1; i<maxdegree+1; i++) {
-	if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) {
-	  MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr;
-	}
-      }
-    }    
-
-    /* Estimate Akk */
-    eptr_save=eptr;
-    while (eptr < no_of_edges &&
-	   VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(degree)[from];
-      long int yidx=VECTOR(degree)[to];
-      double xk, oldakk;
-      
-      MATRIX(*notnull, xidx, yidx) += 1;
-      MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx);
-      
-      xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx);
-      oldakk=MATRIX(*kernel, xidx, yidx);
-      MATRIX(*kernel, xidx, yidx) +=  (xk-oldakk)/MATRIX(*notnull, xidx, yidx);
-      MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx);
-      if (sd) {
-	MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx));
-	MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx);
-      }
-      /* TODO: debug */
-
-      eptr++;
-    }
-    
-    /* Update ntkk, ntk, ch, normfact, add the edges */
-    eptr_new=eptr;
-    eptr=eptr_save;
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge);
-      long int to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(degree)[from];
-      long int yidx=VECTOR(degree)[to];
-      long int n;
-
-      adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from);
-      n=igraph_vector_size(adjedges);
-      for (i=0; i<n; i++) {
-	long int edge=(long int) VECTOR(*adjedges)[i];
-	if (VECTOR(added)[edge]) {
-	  long int otherv=IGRAPH_OTHER(graph, edge, from); /* other than from */
-	  long int deg=VECTOR(degree)[otherv];
-	  MATRIX(ntkk, xidx, deg) -= 1;
-	  MATRIX(ntkk, deg, xidx) = MATRIX(ntkk, xidx, deg);
-	  if (NTKK(xidx, deg)==1) {
-	    MATRIX(ch, deg, xidx) = eptr_new;
-	    MATRIX(ch, xidx, deg) = MATRIX(ch, deg, xidx);
-	  }
-	  MATRIX(ntkk, xidx+1, deg) += 1;
-	  MATRIX(ntkk, deg, xidx+1) = MATRIX(ntkk, xidx+1, deg);
-	  if (NTKK(xidx+1, deg)==0) {
-	    MATRIX(*normfact, xidx+1, deg) += eptr_new-MATRIX(ch, xidx+1, deg);
-	    MATRIX(*normfact, deg, xidx+1) = MATRIX(*normfact, xidx+1, deg);
-	  }
-	}
-      }
-      adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to);
-      n=igraph_vector_size(adjedges);
-      for (i=0; i<n; i++) {
-	long int edge=(long int) VECTOR(*adjedges)[i];
-	if (VECTOR(added)[edge]) {
-	  long int otherv=IGRAPH_OTHER(graph, edge, to); /* other than to */
-	  long int deg=VECTOR(degree)[otherv];
-	  MATRIX(ntkk, yidx, deg) -= 1;	  
-	  MATRIX(ntkk, deg, yidx) = MATRIX(ntkk, yidx, deg);
-	  if (NTKK(yidx, deg)==1) {
-	    MATRIX(ch, deg, yidx) = eptr_new;
-	    MATRIX(ch, yidx, deg) = MATRIX(ch, deg, yidx);
-	  }
-	  MATRIX(ntkk, yidx+1, deg) += 1;
-	  MATRIX(ntkk, deg, yidx+1) = MATRIX(ntkk, yidx+1, deg);
-	  if (NTKK(yidx+1, deg)==0) {
-	    MATRIX(*normfact, yidx+1, deg) += eptr_new-MATRIX(ch, yidx+1, deg);
-	    MATRIX(*normfact, deg, yidx+1) = MATRIX(*normfact, yidx+1, deg);
-	  }
-	}
-      }
-
-      VECTOR(added)[edge]=1;
-
-      MATRIX(ntkk, xidx+1, yidx+1) += 1;
-      MATRIX(ntkk, yidx+1, xidx+1) = MATRIX(ntkk, xidx+1, yidx+1);      
-      if (NTKK(xidx+1, yidx+1)==0) {
-	MATRIX(*normfact, xidx+1, yidx+1) = eptr_new-MATRIX(ch, xidx+1, yidx+1);
-	MATRIX(*normfact, yidx+1, xidx+1) = MATRIX(*normfact, xidx+1, yidx+1);
-      }
-
-      for (i=0; i<maxdegree+1; i++) {
-	long int before, after;
-	before=(long int) NTKK(xidx,i); 
-	VECTOR(ntk)[xidx] -= 1;
-	after=(long int) NTKK(xidx,i);
-	VECTOR(ntk)[xidx] += 1;
-	if (before > 0 && after==0) {
-	  MATRIX(*normfact, xidx, i) += eptr_new-MATRIX(ch, xidx, i);
-	  MATRIX(*normfact, i, xidx) = MATRIX(*normfact, xidx, i);
-	}
-      }
-      VECTOR(ntk)[xidx]--;
-
-      for (i=0; i<maxdegree+1; i++) {
-	long int before, after;
-	before=(long int) NTKK(yidx, i); 
-	VECTOR(ntk)[yidx] -= 1;
-	after=(long int) NTKK(yidx, i);
-	VECTOR(ntk)[yidx] += 1;
-	if (before > 0 && after==0) {
-	  MATRIX(*normfact, yidx, i) += eptr_new-MATRIX(ch, yidx, i);
-	  MATRIX(*normfact, i, yidx) = MATRIX(*normfact, yidx, i);
-	}
-      }
-      VECTOR(ntk)[yidx]--;
-
-      for (i=0; i<maxdegree+1; i++) {
-	long int before, after;
-	before=(long int) NTKK(xidx+1, i);
-	VECTOR(ntk)[xidx+1] += 1;
-	after=(long int) NTKK(xidx+1, i);
-	VECTOR(ntk)[xidx+1] -= 1;
-	if (before==0 && after > 0) {
-	  MATRIX(ch, xidx+1, i) = eptr_new;
-	  MATRIX(ch, i, xidx+1) = MATRIX(ch, xidx+1, i);
-	}
-      }
-      VECTOR(ntk)[xidx+1]++;
-
-      for (i=0; i<maxdegree+1; i++) {
-	long int before, after;
-	before=(long int) NTKK(yidx+1, i);
-	VECTOR(ntk)[yidx+1] += 1;
-	after=(long int) NTKK(yidx+1, i);
-	VECTOR(ntk)[yidx+1] -= 1;
-	if (before == 0 && after == 0) {
-	  MATRIX(ch, yidx+1, i) = eptr_new;
-	  MATRIX(ch, i, yidx+1) = MATRIX(ch, yidx+1, i);
-	}
-      }
-      VECTOR(ntk)[yidx+1]++;
-            
-      VECTOR(degree)[from]++;
-      VECTOR(degree)[to]++;
-
-      eptr++;
-    }
-    
-  }
-
-  for (i=0; i<maxdegree+1; i++) {
-    igraph_real_t oldakk;
-    long int j;
-    for (j=0; j<=i; j++) {
-      if (NTKK(i, j) != 0) {
-	MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j));
-	MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j);
-      }
-      if (MATRIX(*normfact, i, j)==0) {
-	MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0;
-	MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1;
-      }
-      oldakk=MATRIX(*kernel, i, j);
-      MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
-      MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j);
-      if (sd) {
-	MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) *
-	  (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
-	MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
-	MATRIX(*sd, j, i) = MATRIX(*sd, i, j);
-      }
-    }
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkk);
-  igraph_vector_long_destroy(&ntk);
-  igraph_vector_char_destroy(&added);
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(5);
-  
-  return 0;
-}
-
-#undef NTKK
-
-int igraph_revolver_st_d_d(const igraph_t *graph,
-			   igraph_lazy_inclist_t *inclist,
-			   igraph_vector_t *st,
-			   const igraph_matrix_t *kernel,
-			   const igraph_vector_t *vtime,
-			   const igraph_vector_t *vtimeidx,
-			   const igraph_vector_t *etime,
-			   const igraph_vector_t *etimeidx,
-			   igraph_integer_t pno_of_events) {
-
-  long int no_of_events=pno_of_events;
-  long int maxdegree=igraph_matrix_nrow(kernel)-1;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  long int timestep=0;
-  
-  igraph_vector_long_t degree;
-  igraph_vector_long_t ntk;
-  igraph_vector_char_t added;
-  
-  igraph_vector_t *adjedges;
-
-  long int i;
-  long int nptr=0, eptr=0;
-
-  IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxdegree+1));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
-  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
-  
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_events));
-  VECTOR(*st)[0]=0;
-  
-  for (timestep=0; timestep<no_of_events-1; timestep++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* add the new nodes */
-    while (nptr < no_of_nodes && 
-	   VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
-      for (i=0; i<maxdegree+1; i++) {
-	VECTOR(*st)[timestep] += VECTOR(ntk)[i]*MATRIX(*kernel, i, 0);
-      }
-      VECTOR(ntk)[0]++;
-      nptr++;
-    }
-
-    /* add the new edges as well, but this is for the next timestep
-       already */
-    VECTOR(*st)[timestep+1] = VECTOR(*st)[timestep];
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge);
-      long int to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(degree)[from];
-      long int yidx=VECTOR(degree)[to];
-      igraph_real_t inc=0;
-      long int n;
-      
-      inc -= MATRIX(*kernel, xidx, yidx);
-
-      for (i=0; i<maxdegree+1; i++) {
-	inc += VECTOR(ntk)[i] * (MATRIX(*kernel, i, xidx+1) -
-				 MATRIX(*kernel, i, xidx)   +
-				 MATRIX(*kernel, i, yidx+1) -
-				 MATRIX(*kernel, i, yidx));
-      }
-      inc -= MATRIX(*kernel, xidx+1, xidx+1);
-      inc -= MATRIX(*kernel, yidx+1, yidx+1);
-      inc += MATRIX(*kernel, xidx, xidx);
-      inc += MATRIX(*kernel, yidx, yidx);
-            
-      VECTOR(ntk)[xidx]--;
-      VECTOR(ntk)[yidx]--;
-      VECTOR(ntk)[xidx+1]++;
-      VECTOR(ntk)[yidx+1]++;
-      
-      adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) from);
-      n=igraph_vector_size(adjedges);
-      for (i=0; i<n; i++) {
-	long int edge=(long int) VECTOR(*adjedges)[i];
-	if (VECTOR(added)[edge]) {
-	  long int otherv=IGRAPH_OTHER(graph, edge, from);
-	  long int deg=VECTOR(degree)[otherv];
-	  inc += MATRIX(*kernel, xidx, deg);
-	  inc -= MATRIX(*kernel, xidx+1, deg);
-	}
-      }
-      adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) to);
-      n=igraph_vector_size(adjedges);
-      for (i=0; i<n; i++) {
-	long int edge=(long int) VECTOR(*adjedges)[i];
-	if (VECTOR(added)[edge]) {
-	  long int otherv=IGRAPH_OTHER(graph, edge, to);
-	  long int deg=VECTOR(degree)[otherv];
-	  inc += MATRIX(*kernel, yidx, deg);
-	  inc -= MATRIX(*kernel, yidx+1, deg);
-	}
-      }
-      
-      VECTOR(degree)[from] += 1;
-      VECTOR(degree)[to] += 1;
-      VECTOR(added)[edge]=1;
-      
-      VECTOR(*st)[timestep+1] += inc;
-      
-      eptr++;
-    }        
-  }
-
-  igraph_vector_char_destroy(&added);
-  igraph_vector_long_destroy(&degree);
-  igraph_vector_long_destroy(&ntk);
-  IGRAPH_FINALLY_CLEAN(3);
-
-  return 0;
-}
-
-int igraph_revolver_exp_d_d(const igraph_t *graph,
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *expected,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    igraph_integer_t pmaxdegree) {
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_d_d(const igraph_t *graph,
-			      igraph_lazy_inclist_t *inclist,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *st,
-			      const igraph_vector_t *vtime,
-			      const igraph_vector_t *vtimeidx,
-			      const igraph_vector_t *etime,
-			      const igraph_vector_t *etimeidx,
-			      igraph_integer_t pno_of_events,
-			      igraph_integer_t pmaxdegree, 
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-
-  long int no_of_events=pno_of_events;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  
-  igraph_vector_long_t degree;
-    
-  long int timestep, nptr=0, eptr=0, eptr_save;
-  long int edges=0, vertices=0;
-  
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (timestep=0; timestep<no_of_events; timestep++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    while (nptr < no_of_nodes && 
-	   VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
-      vertices++;
-      nptr++;
-    }
-
-    eptr_save=eptr;
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge);
-      long int to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(degree)[from];
-      long int yidx=VECTOR(degree)[to];
-      
-      igraph_real_t prob=MATRIX(*kernel, xidx, yidx)/VECTOR(*st)[timestep];
-      igraph_real_t nullprob=1.0/(vertices*(vertices-1)/2-eptr_save);
-            
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-      
-      edges++;
-      eptr++;
-    }
-
-    eptr=eptr_save;
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge);
-      long int to=IGRAPH_TO(graph, edge);
-      VECTOR(degree)[from] += 1;
-      VECTOR(degree)[to] += 1;
-      eptr++;
-    }
-  }
-
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(1);
-    
-  return 0;
-}
-
-/***********************************************/
-/* # of papers + # of papers                   */
-/***********************************************/
-
-int igraph_revolver_p_p(const igraph_t *graph,
-			igraph_integer_t niter,
-			const igraph_vector_t *vtime,
-			const igraph_vector_t *etime,
-			const igraph_vector_t *authors,
-			const igraph_vector_t *eventsizes,
-			igraph_matrix_t *kernel,
-			igraph_matrix_t *sd,
-			igraph_matrix_t *norm,
-			igraph_matrix_t *cites,
-			igraph_matrix_t *expected,
-			igraph_real_t *logprob,
-			igraph_real_t *lognull,
-			const igraph_matrix_t *debug,
-			igraph_vector_ptr_t *debugres) {
-  
-  igraph_integer_t no_of_events;
-  igraph_vector_t st;
-  long int i;
-  igraph_integer_t maxpapers=0;
-  igraph_vector_t vtimeidx, etimeidx;
-  igraph_lazy_inclist_t inclist;
-  igraph_vector_long_t papers;
-  
-  if (igraph_vector_size(vtime) != igraph_vcount(graph)) {
-    IGRAPH_ERROR("Invalid vtime length", IGRAPH_EINVAL);
-  }
-  if (igraph_vector_size(etime) != igraph_ecount(graph)) {
-    IGRAPH_ERROR("Invalid etime length", IGRAPH_EINVAL);
-  }
-
-  no_of_events=(igraph_integer_t) igraph_vector_size(eventsizes);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&st, no_of_events);
-  for (i=0; i<no_of_events; i++) {
-    VECTOR(st)[i]=1;
-  }
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&papers, igraph_vcount(graph)));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &papers);
-  for (i=0; i<igraph_vector_size(authors); i++) {
-    long int author=(long int) VECTOR(*authors)[i];
-    VECTOR(papers)[author] += 1;
-    if (VECTOR(papers)[author] > maxpapers) {
-      maxpapers=(igraph_integer_t) VECTOR(papers)[author];
-    }
-  }
-  igraph_vector_long_destroy(&papers);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&vtimeidx, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&etimeidx, 0);
-  IGRAPH_CHECK(igraph_vector_order1(vtime, &vtimeidx, no_of_events));
-  IGRAPH_CHECK(igraph_vector_order1(etime, &etimeidx, no_of_events));
-  
-  IGRAPH_CHECK(igraph_lazy_inclist_init(graph, &inclist, IGRAPH_ALL));
-  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &inclist);
-
-  IGRAPH_PROGRESS("Revolver p-p", 0, NULL);
-  for (i=0; i<niter; i++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    if (i+1 != niter) {		/* not the last iteration */
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_p_p(graph, &inclist, 
-					   kernel, 0 /*sd*/, 0 /*norm*/,
-					   0/*cites*/, 0/*debug*/, 0 /*debugres*/,
-					   &st, vtime, &vtimeidx, etime, 
-					   &etimeidx, no_of_events,
-					   authors, eventsizes,
-					   maxpapers));
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_p_p(graph, &inclist, 
-					  &st, kernel, vtime, &vtimeidx,
-					  etime, &etimeidx,
-					  no_of_events, authors, 
-					  eventsizes, maxpapers));
-      
-    } else {
-      /* measure */
-      IGRAPH_CHECK(igraph_revolver_mes_p_p(graph, &inclist,
-					   kernel, sd, norm, cites, 
-					   debug, debugres, &st, vtime, &vtimeidx,
-					   etime, &etimeidx,
-					   no_of_events, authors,
-					   eventsizes, maxpapers));
-      
-      /* normalize */
-      igraph_matrix_scale(kernel, 1/igraph_matrix_sum(kernel));
-      
-      /* update st */
-      IGRAPH_CHECK(igraph_revolver_st_p_p(graph, &inclist,
-					  &st, kernel, vtime, &vtimeidx,
-					  etime, &etimeidx,
-					  no_of_events, authors, eventsizes,
-					  maxpapers));
-      
-      /* expected number of citations */
-      if (expected) {
-	IGRAPH_CHECK(igraph_revolver_exp_p_p(graph, &inclist,
-					     expected, kernel, &st,
-					     vtime, &vtimeidx, etime, &etimeidx,
-					     no_of_events, authors, eventsizes,
-					     maxpapers));
-      }
-      
-      /* error calculation */
-      if (logprob || lognull) {
-	IGRAPH_CHECK(igraph_revolver_error_p_p(graph, &inclist,
-					       kernel, &st,
-					       vtime, &vtimeidx, 
-					       etime, &etimeidx, no_of_events,
-					       authors, eventsizes,
-					       maxpapers, logprob, lognull));
-      }
-    }
-
-    IGRAPH_PROGRESS("Revolver p-p", 100.0*(i+1)/niter, NULL);
-  }
-
-  igraph_lazy_inclist_destroy(&inclist);
-  igraph_vector_destroy(&etimeidx);
-  igraph_vector_destroy(&vtimeidx);
-  igraph_vector_destroy(&st);
-  IGRAPH_FINALLY_CLEAN(4);
-  
-  return 0;
-}
-
-#define NTKK(xidx, yidx) \
-   ((xidx)==(yidx) ? (VECTOR(ntk)[(xidx)]*(VECTOR(ntk)[(xidx)]-1))/2-MATRIX(ntkk,(xidx),(yidx)) : VECTOR(ntk)[(xidx)]*VECTOR(ntk)[(yidx)]-MATRIX(ntkk,(xidx),(yidx)))
-
-int igraph_revolver_mes_p_p(const igraph_t *graph,
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *kernel,
-			    igraph_matrix_t *sd,
-			    igraph_matrix_t *norm,
-			    igraph_matrix_t *cites,
-			    const igraph_matrix_t *debug,
-			    igraph_vector_ptr_t *debugres,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    const igraph_vector_t *authors,
-			    const igraph_vector_t *eventsizes,
-			    igraph_integer_t pmaxpapers) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  long int no_of_events=pno_of_events;
-  long int maxpapers=pmaxpapers;
-  
-  igraph_vector_long_t papers;
-  igraph_vector_char_t added;
-  
-  igraph_matrix_t v_normfact, *normfact, v_notnull, *notnull;
-  igraph_matrix_t ch;
-  
-  igraph_vector_long_t ntk;
-  igraph_matrix_t ntkk;
-  
-  igraph_vector_t *adjedges;
-  
-  long int timestep, i;
-  long int nptr=0, eptr=0, aptr=0;
-  long int nptr_save, eptr_save, eptr_new;
-
-  IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes));
-  IGRAPH_FINALLY(&igraph_vector_long_destroy, &papers);
-
-  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
-  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
-
-  IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
-  IGRAPH_MATRIX_INIT_FINALLY(&ntkk, maxpapers+1, maxpapers+1);
-  IGRAPH_MATRIX_INIT_FINALLY(&ch, maxpapers+1, maxpapers+1);
-  
-  if (norm) {
-    normfact=norm;
-    IGRAPH_CHECK(igraph_matrix_resize(normfact, maxpapers+1, maxpapers+1));
-    igraph_matrix_null(normfact);
-  } else {
-    normfact=&v_normfact;
-    IGRAPH_MATRIX_INIT_FINALLY(normfact, maxpapers+1, maxpapers+1);
-  }
-  
-  if (cites) {
-    notnull=cites;
-    IGRAPH_CHECK(igraph_matrix_resize(notnull, maxpapers+1, maxpapers+1));
-    igraph_matrix_null(notnull);
-  } else {
-    notnull=&v_notnull;
-    IGRAPH_MATRIX_INIT_FINALLY(notnull, maxpapers+1, maxpapers+1);
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, maxpapers+1, maxpapers+1));
-  igraph_matrix_null(kernel);
-  if (sd) {
-    IGRAPH_CHECK(igraph_matrix_resize(sd, maxpapers+1, maxpapers+1));
-    igraph_matrix_null(sd);
-  }
-  
-  for (timestep=0; timestep<no_of_events; timestep++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-        
-    nptr_save=nptr;
-    while (nptr < no_of_nodes && 
-	   VECTOR(*vtime)[(long int)VECTOR(*vtimeidx)[nptr]]==timestep) {
-      nptr++;
-    }
-    /* If it is a new author then she has no papers yet */
-    VECTOR(ntk)[0] += (nptr-nptr_save);
-
-    /* Update ch accordingly, could be done later as well */
-    if (VECTOR(ntk)[0] == nptr-nptr_save && nptr!=nptr_save) {
-      if (nptr-nptr_save >= 2) {
-	MATRIX(ch, 0, 0) = eptr;
-      }
-      for (i=1; i<maxpapers+1; i++) {
-	if (NTKK(0,i) == (nptr-nptr_save)*VECTOR(ntk)[i]) {
-	  MATRIX(ch, 0, i) = MATRIX(ch, i, 0) = eptr;
-	}
-      }
-    }    
-    
-/*     print_ntkk(&ntkk, &ntk); */
-
-    /* Estimate Akk */
-    eptr_save=eptr;
-    while (eptr < no_of_edges &&
-	   VECTOR(*etime)[(long int)VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(papers)[from];
-      long int yidx=VECTOR(papers)[to];
-      double xk, oldakk;
-
-      MATRIX(*notnull, xidx, yidx) += 1;
-      MATRIX(*notnull, yidx, xidx) = MATRIX(*notnull, xidx, yidx);
-      
-      xk=VECTOR(*st)[timestep]/NTKK(xidx, yidx);
-      oldakk=MATRIX(*kernel, xidx, yidx);
-      MATRIX(*kernel, xidx, yidx) +=  (xk-oldakk)/MATRIX(*notnull, xidx, yidx);
-      MATRIX(*kernel, yidx, xidx) = MATRIX(*kernel, xidx, yidx);
-      if (sd) {
-	MATRIX(*sd, xidx, yidx) += (xk-oldakk)*(xk-MATRIX(*kernel, xidx, yidx));
-	MATRIX(*sd, yidx, xidx) = MATRIX(*sd, xidx, yidx);
-      }
-      /* TODO: debug */
-
-      eptr++;
-    }
-
-    /* update ntkk, the new papers change the type of their authors */
-    eptr_new=eptr;
-    for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) {
-      long int aut=(long int) VECTOR(*authors)[i];
-      long int pap=VECTOR(papers)[aut];
-      long int j, n;
-
-      adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut);
-      n=igraph_vector_size(adjedges);
-      for (j=0; j<n; j++) {
-	long int edge=(long int) VECTOR(*adjedges)[j];
-	if (VECTOR(added)[edge]) {
-	  long int otherv=IGRAPH_OTHER(graph, edge, aut);
-	  long int otherpap=VECTOR(papers)[otherv];
-	  MATRIX(ntkk, pap, otherpap) -= 1;
-	  MATRIX(ntkk, otherpap, pap) = MATRIX(ntkk, pap, otherpap);
-	  if (NTKK(pap, otherpap)==1) {
-	    MATRIX(ch, pap, otherpap) = eptr_new;
-	    MATRIX(ch, otherpap, pap) = MATRIX(ch, pap, otherpap);
-	  }
-	  MATRIX(ntkk, pap+1, otherpap) += 1;
-	  MATRIX(ntkk, otherpap, pap+1) = MATRIX(ntkk, pap+1, otherpap);
-	  if (NTKK(pap+1, otherpap)==0) {
-	    MATRIX(*normfact, pap+1, otherpap) += 
-	      eptr_new-MATRIX(ch, pap+1, otherpap);
-	    MATRIX(*normfact, otherpap, pap+1) = 
-	      MATRIX(*normfact, pap+1, otherpap);
-	  }
-	}
-      }
-
-      /* update ntk too */
-      for (j=0; j<maxpapers+1; j++) {
-	long int before, after;
-	before=(long int) NTKK(pap, j);
-	VECTOR(ntk)[pap]-=1;
-	after=(long int) NTKK(pap, j);
-	VECTOR(ntk)[pap]+=1;
-	if (before > 0 && after==0) {
-	  MATRIX(*normfact, pap, j) += eptr_new-MATRIX(ch, pap, j);
-	  MATRIX(*normfact, j, pap) = MATRIX(*normfact, pap, j);
-	}
-      }
-      VECTOR(ntk)[pap]-=1;
-      
-      for (j=0; j<maxpapers+1; j++) { 
-	long int before, after;
-	before=(long int) NTKK(pap+1, j);
-	VECTOR(ntk)[pap+1] += 1;
-	after=(long int) NTKK(pap+1, j);
-	VECTOR(ntk)[pap+1] -= 1;
-	if (before == 0 && after > 0) {
-	  MATRIX(ch, pap+1, j) = eptr_new;
-	  MATRIX(ch, j, pap+1) = MATRIX(ch, pap+1, j);
-	}
-      }
-      VECTOR(ntk)[pap+1]+=1;
-      
-      VECTOR(papers)[aut] += 1;
-    }
-    aptr += VECTOR(*eventsizes)[timestep];
-    
-    /* For every new edge, we lose one connection possibility, also add the edges*/
-    eptr=eptr_save;
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[(long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge), to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(papers)[from];
-      long int yidx=VECTOR(papers)[to];
-      
-      MATRIX(ntkk, xidx, yidx) += 1;
-      MATRIX(ntkk, yidx, xidx) = MATRIX(ntkk, xidx, yidx);
-      if (NTKK(xidx, yidx)==0) {
-	MATRIX(*normfact, xidx, yidx) += eptr_new-MATRIX(ch, xidx, yidx);
-	MATRIX(*normfact, yidx, xidx) = MATRIX(*normfact, xidx, yidx);
-      }
-
-      VECTOR(added)[edge]=1;
-      eptr++;
-    }
-  }    
-
-  for (i=0; i<maxpapers+1; i++) {
-    igraph_real_t oldakk;
-    long int j;
-    for (j=0; j<=i; j++) {
-      if (NTKK(i, j) != 0) {
-	MATRIX(*normfact, i, j) += (eptr-MATRIX(ch, i, j));
-	MATRIX(*normfact, j, i) = MATRIX(*normfact, i, j);
-      }
-      if (MATRIX(*normfact, i, j)==0) {
-	MATRIX(*kernel, i, j)=MATRIX(*kernel, j, i)=0;
-	MATRIX(*normfact, i, j)=MATRIX(*normfact, j, i)=1;
-      }
-      oldakk=MATRIX(*kernel, i, j);
-      MATRIX(*kernel, i, j) *= MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j);
-      MATRIX(*kernel, j, i) = MATRIX(*kernel, i, j);
-      if (sd) {
-	MATRIX(*sd, i, j) += oldakk * oldakk * MATRIX(*notnull, i, j) *
-	  (1-MATRIX(*notnull, i, j)/MATRIX(*normfact, i, j));
-	MATRIX(*sd, i, j) = sqrt(MATRIX(*sd, i, j)/(MATRIX(*normfact, i, j)-1));
-	MATRIX(*sd, j, i) = MATRIX(*sd, i, j);
-      }
-    }
-  }
-
-  if (!cites) {
-    igraph_matrix_destroy(notnull);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  if (!norm) {
-    igraph_matrix_destroy(normfact);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  igraph_matrix_destroy(&ch);
-  igraph_matrix_destroy(&ntkk);
-  igraph_vector_long_destroy(&ntk);
-  igraph_vector_char_destroy(&added);
-  igraph_vector_long_destroy(&papers);
-  IGRAPH_FINALLY_CLEAN(5);
-  
-  return 0;
-}
-
-#undef NTKK
-
-int igraph_revolver_st_p_p(const igraph_t *graph,
-			   igraph_lazy_inclist_t *inclist,
-			   igraph_vector_t *st,
-			   const igraph_matrix_t *kernel,
-			   const igraph_vector_t *vtime,
-			   const igraph_vector_t *vtimeidx,
-			   const igraph_vector_t *etime,
-			   const igraph_vector_t *etimeidx,
-			   igraph_integer_t pno_of_events,
-			   const igraph_vector_t *authors,
-			   const igraph_vector_t *eventsizes,
-			   igraph_integer_t pmaxpapers) {
-
-  long int no_of_events=pno_of_events;
-  long int maxpapers=igraph_matrix_nrow(kernel)-1;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  long int timestep=0;
-  
-  igraph_vector_long_t papers;
-  igraph_vector_long_t ntk;
-  igraph_vector_char_t added;
-  
-  igraph_vector_t *adjedges;
-  
-  long int i;
-  long int nptr=0, eptr=0, aptr=0, nptr_save;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&ntk, maxpapers+1));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
-  IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &papers);
-  IGRAPH_CHECK(igraph_vector_char_init(&added, no_of_edges));
-  IGRAPH_FINALLY(igraph_vector_char_destroy, &added);
-  
-  IGRAPH_CHECK(igraph_vector_resize(st, no_of_events));
-  VECTOR(*st)[0]=0;
-  
-  for (timestep=0; timestep<no_of_events-1; timestep++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    /* add the new nodes */
-    nptr_save=nptr;
-    while (nptr < no_of_nodes &&
-	   VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
-      nptr++;
-    }
-    nptr_save=nptr-nptr_save;
-    if (nptr_save != 0) {
-      for (i=0; i<maxpapers+1; i++) {
-	VECTOR(*st)[timestep] += VECTOR(ntk)[i]*MATRIX(*kernel, i, 0)*nptr_save;
-      }
-      VECTOR(*st)[timestep] += nptr_save*(nptr_save-1)/2 * MATRIX(*kernel, 0, 0);
-      VECTOR(ntk)[0]+=nptr_save;
-    }    
-    
-    VECTOR(*st)[timestep+1] = VECTOR(*st)[timestep];
-    
-    for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) {
-      long int aut=(long int) VECTOR(*authors)[i];
-      long int pap=VECTOR(papers)[aut];
-      long int j, n;
-      
-      for (j=0; j<maxpapers+1; j++) {
-	VECTOR(*st)[timestep+1] += VECTOR(ntk)[j] * (MATRIX(*kernel, j, pap+1)-
-						     MATRIX(*kernel, j, pap));
-      }
-      
-      VECTOR(*st)[timestep+1] += MATRIX(*kernel, pap, pap);
-      VECTOR(*st)[timestep+1] -= MATRIX(*kernel, pap+1, pap+1);
-
-      VECTOR(ntk)[pap]--;
-      VECTOR(ntk)[pap+1]++;
-
-      adjedges=igraph_lazy_inclist_get(inclist, (igraph_integer_t) aut);
-      n=igraph_vector_size(adjedges);
-      for (j=0; j<n; j++) {
-	long int edge=(long int) VECTOR(*adjedges)[j];
-	if (VECTOR(added)[edge]) {
-	  long int otherv=IGRAPH_OTHER(graph, edge, aut);
-	  long int otherpap=VECTOR(papers)[otherv];
-	  VECTOR(*st)[timestep+1] += MATRIX(*kernel, pap, otherpap);
-	  VECTOR(*st)[timestep+1] -= MATRIX(*kernel, pap+1, otherpap);
-	}
-      }
-
-      VECTOR(papers)[aut] += 1;      
-    }
-    aptr += VECTOR(*eventsizes)[timestep];
-    
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge);
-      long int to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(papers)[from];
-      long int yidx=VECTOR(papers)[to];
-      VECTOR(*st)[timestep+1] -= MATRIX(*kernel, xidx, yidx);
-      VECTOR(added)[edge]=1;
-      eptr++;
-    }
-    
-  }
-  
-  igraph_vector_char_destroy(&added);
-  igraph_vector_long_destroy(&papers);
-  igraph_vector_long_destroy(&ntk);
-  IGRAPH_FINALLY_CLEAN(3);
-  
-  return 0;
-}
-
-int igraph_revolver_exp_p_p(const igraph_t *graph,
-			    igraph_lazy_inclist_t *inclist,
-			    igraph_matrix_t *expected,
-			    const igraph_matrix_t *kernel,
-			    const igraph_vector_t *st,
-			    const igraph_vector_t *vtime,
-			    const igraph_vector_t *vtimeidx,
-			    const igraph_vector_t *etime,
-			    const igraph_vector_t *etimeidx,
-			    igraph_integer_t pno_of_events,
-			    const igraph_vector_t *authors,
-			    const igraph_vector_t *eventsizes,
-			    igraph_integer_t pmaxpapers) {
-
-  /* TODO */
-  return 0;
-}
-
-int igraph_revolver_error_p_p(const igraph_t *graph,
-			      igraph_lazy_inclist_t *inclist,
-			      const igraph_matrix_t *kernel,
-			      const igraph_vector_t *st,
-			      const igraph_vector_t *vtime,
-			      const igraph_vector_t *vtimeidx,
-			      const igraph_vector_t *etime,
-			      const igraph_vector_t *etimeidx,
-			      igraph_integer_t pno_of_events,
-			      const igraph_vector_t *authors,
-			      const igraph_vector_t *eventsizes,
-			      igraph_integer_t pmaxpapers,
-			      igraph_real_t *logprob,
-			      igraph_real_t *lognull) {
-
-  long int no_of_events=pno_of_events;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-
-  igraph_vector_long_t papers;
-  
-  long int timestep, nptr=0, eptr=0, aptr=0, eptr_save;
-  long int edges=0, vertices=0, i;
-  
-  igraph_real_t rlogprob, rlognull, *mylogprob=logprob, *mylognull=lognull;
-
-  IGRAPH_CHECK(igraph_vector_long_init(&papers, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &papers);
-
-  if (!logprob) { mylogprob=&rlogprob; }
-  if (!lognull) { mylognull=&rlognull; }
-  
-  *mylogprob=0;
-  *mylognull=0;
-  
-  for (timestep=0; timestep<no_of_events; timestep++) {
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-  
-    while (nptr < no_of_nodes && 
-	   VECTOR(*vtime)[ (long int) VECTOR(*vtimeidx)[nptr] ] == timestep) {
-      vertices++;
-      nptr++;
-    }
-    
-    eptr_save=eptr;
-    while (eptr < no_of_edges && 
-	   VECTOR(*etime)[ (long int) VECTOR(*etimeidx)[eptr] ] == timestep) {
-      long int edge=(long int) VECTOR(*etimeidx)[eptr];
-      long int from=IGRAPH_FROM(graph, edge);
-      long int to=IGRAPH_TO(graph, edge);
-      long int xidx=VECTOR(papers)[from];
-      long int yidx=VECTOR(papers)[to];
-      
-      igraph_real_t prob=MATRIX(*kernel, xidx, yidx)/VECTOR(*st)[timestep];
-      igraph_real_t nullprob=1.0/(vertices*(vertices-1)/2-eptr_save);
-            
-      *mylogprob += log(prob);
-      *mylognull += log(nullprob);
-      
-      edges++;
-      eptr++;
-    }
-    
-    for (i=aptr; i<aptr+VECTOR(*eventsizes)[timestep]; i++) {
-      long int aut=(long int) VECTOR(*authors)[i];
-      VECTOR(papers)[aut] += 1;
-    }
-    aptr += VECTOR(*eventsizes)[timestep];
-    
-  }
-  
-  igraph_vector_long_destroy(&papers);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return 0;
-}
diff --git a/src/revolver_ml_cit.c b/src/revolver_ml_cit.c
deleted file mode 100644
index 1bdf839..0000000
--- a/src/revolver_ml_cit.c
+++ /dev/null
@@ -1,3548 +0,0 @@
-/* -*- mode: C -*-  */
-/* 
-   IGraph library.
-   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   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
-
-*/
-
-#include "igraph_revolver.h"
-#include "igraph_memory.h"
-#include "igraph_random.h"
-#include "config.h"
-#include "igraph_math.h"
-#include "igraph_interface.h"
-#include "igraph_progress.h"
-#include "igraph_interrupt_internal.h"
-#include "igraph_structural.h"
-#include "igraph_nongraph.h"
-#include "igraph_stack.h"
-
-#include <math.h>
-
-/* This data structure holds the context of the degree based
-   optimizer. */
-
-typedef struct igraph_i_revolver_ml_D_data_t {
-  igraph_scalar_function_t *A;
-  igraph_vector_function_t *dA;  
-  const igraph_t *graph;
-  long int no_of_nodes;
-  igraph_vector_t A_vect;	/* Temporary storage */
-  igraph_vector_ptr_t dA_vects;	/* Temporary storage */
-  igraph_integer_t maxdegree;
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  igraph_vector_t dS;		/* Temporary storage */
-  igraph_vector_t par1;		/* More tmp storage */
-  igraph_vector_t tmpgrad;      /* More... */
-
-  igraph_vector_t lastparam;	/* The parameter values used last time */
-  igraph_real_t lastf;		/* The evaluated function value  */
-  igraph_vector_t lastgrad;	/* The evaluated gradient */
-
-  const igraph_vector_t *filter;
-} igraph_i_revolver_ml_D_data_t;
-
-/* Evaluate the objective function and calculate its gradient too. */
-
-int igraph_i_revolver_ml_D_eval(const igraph_vector_t *par,
-				igraph_i_revolver_ml_D_data_t *data) {
-
-  long int no_of_edges=0;
-  igraph_real_t sum=0.0;
-  long int t, i;
-  int dim=(int) igraph_vector_size(par);
-  igraph_vector_t *grad=&data->lastgrad;
-  igraph_real_t S=0.0;		/* sum N_i^t A(p,x) */
-  
-  /* Init */
-  igraph_vector_long_null(&data->degree);
-  igraph_vector_null(&data->dS);
-  igraph_vector_null(grad);
-
-  /* Calculate all possible A and dA values and store them in A_vect &
-     dA_vects */
-  for (t=0; t<=data->maxdegree; t++) {
-    VECTOR(data->par1)[0] = t;
-    VECTOR(data->A_vect)[t] = data->A(&data->par1, par, 0);
-    data->dA(&data->par1, par, &data->tmpgrad, 0);
-    for (i=0; i<dim; i++) {
-      igraph_vector_t *v=VECTOR(data->dA_vects)[i];
-      VECTOR(*v)[t] = VECTOR(data->tmpgrad)[i];
-    }
-  }
-  
-  for (t=0; t<data->no_of_nodes; t++) {
-    long int n, nneis;
-
-    IGRAPH_ALLOW_INTERRUPTION();
-      
-    IGRAPH_CHECK(igraph_neighbors(data->graph, &data->neis,
-				  (igraph_integer_t) t, IGRAPH_OUT));
-    nneis=igraph_vector_size(&data->neis);
-
-    if (! data->filter || VECTOR(*data->filter)[t] != 0) {
-      
-      /* Update sum(s) */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(data->neis)[n];
-	long int x=VECTOR(data->degree)[to];
-	
-	sum -= log( VECTOR(data->A_vect)[x] );
-	sum += log( S );
-	for (i=0; i<dim; i++) {
-	  igraph_vector_t *v=VECTOR(data->dA_vects)[i];
-	  VECTOR(*grad)[i] -= VECTOR(*v)[x] / VECTOR(data->A_vect)[x];
-	  VECTOR(*grad)[i] += VECTOR(data->dS)[i] / S;
-	}
-	no_of_edges++;
-      }
-
-    }
-
-    /* Update S, data->dS */
-    for (n=0; n<nneis; n++) {
-      long int to=(long int) VECTOR(data->neis)[n];
-      long int x=VECTOR(data->degree)[to];
-      
-      VECTOR(data->degree)[to] += 1;
-      S += VECTOR(data->A_vect)[x+1];
-      S -= VECTOR(data->A_vect)[x];
-      for (i=0; i<dim; i++) {
-	igraph_vector_t *v=VECTOR(data->dA_vects)[i];
-	VECTOR(data->dS)[i] += VECTOR(*v)[x+1];
-	VECTOR(data->dS)[i] -= VECTOR(*v)[x];
-      }
-    }
-    
-    S += VECTOR(data->A_vect)[0];
-    for (i=0; i<dim; i++) {
-      igraph_vector_t *v=VECTOR(data->dA_vects)[i];
-      VECTOR(data->dS)[i] += VECTOR(*v)[0];
-    }
-  }
-
-  igraph_vector_update(&data->lastparam, par);
-  data->lastf=sum / no_of_edges;
-  for (i=0; i<igraph_vector_size(&data->lastgrad); i++) {
-    VECTOR(data->lastgrad)[i] /= no_of_edges;
-  }
-
-  return 0;
-}
-
-/* This function gives the value of the objective function at the 
-   supplied parameter vector. Called by the optimizer.
-*/
-
-igraph_real_t igraph_i_revolver_ml_D_f(const igraph_vector_t *par,
-				       const igraph_vector_t *garbage,
-				       void* extra) {
-
-  igraph_i_revolver_ml_D_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_D_eval(par, data);
-  }
-
-  return data->lastf;
-}
-
-/* This function gives the gradient of the objective function at
-   the supplied parameter vector. Called by the optimizer.
-*/
-
-void igraph_i_revolver_ml_D_df(const igraph_vector_t *par,
-			       const igraph_vector_t *garbage,
-			       igraph_vector_t *res, void *extra) {
-
-  igraph_i_revolver_ml_D_data_t *data=extra;
-
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_D_eval(par, data);
-  }
-
-  igraph_vector_update(res, &data->lastgrad);
-}
-
-void igraph_i_revolver_ml_D_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];
-    if (v) {
-      igraph_vector_destroy(v);
-      igraph_free(v);
-    }
-    VECTOR(*ptr)[i]=0;
-  }
-}
-
-/* This is the general degree-based optimizer. The form of the kernel
-   function is given by A_fun, its first parameter (in the parameter vector) 
-   is the degree and the others are the parameters to fit.
-
-   It just initializes the context data structure and calls the optimizer.
- */
-
-int igraph_revolver_ml_D(const igraph_t *graph,
-			 igraph_vector_t *res,
-			 igraph_real_t *Fmin,
-			 igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			 igraph_scalar_function_t *A_fun,
-			 igraph_vector_function_t *dA_fun, 
-			 const igraph_vector_t *filter,
-			 igraph_integer_t *fncount, igraph_integer_t *grcount) {
-
-  igraph_i_revolver_ml_D_data_t info;
-  igraph_integer_t maxdegree;
-  long int no_of_nodes=igraph_vcount(graph);
-  int dim=(int) igraph_vector_size(res);
-  int ret, i;
-
-  if (filter && igraph_vector_size(filter) != no_of_nodes) {
-    IGRAPH_ERROR("Invalid filter vector", IGRAPH_EINVAL);
-  }
-
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  /* Set up everything */
-  info.A=A_fun;
-  info.dA=dA_fun;
-  info.graph=graph;
-  info.no_of_nodes=no_of_nodes;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.A_vect, maxdegree+1);  
-  IGRAPH_VECTOR_PTR_INIT_FINALLY(&info.dA_vects, dim);
-  IGRAPH_FINALLY(igraph_i_revolver_ml_D_free, &info.dA_vects);
-  for (i=0; i<dim; i++) {
-    igraph_vector_t *v=igraph_Calloc(1, igraph_vector_t);
-    if (!v) { IGRAPH_ERROR("Cannot perform ML D revolver", IGRAPH_ENOMEM); }
-    IGRAPH_CHECK(igraph_vector_init(v, maxdegree+1));
-    VECTOR(info.dA_vects)[i]=v;
-  }
-  info.maxdegree=maxdegree;
-  IGRAPH_CHECK(igraph_vector_long_init(&info.degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &info.degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.dS, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.par1, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.tmpgrad, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastparam, dim);
-  info.lastf=0.0;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastgrad, dim);
-  info.filter=filter;
-
-  igraph_i_revolver_ml_D_eval(res, &info);
-  ret=igraph_bfgs(res, Fmin, igraph_i_revolver_ml_D_f,
-		  igraph_i_revolver_ml_D_df, maxit, 1, abstol, reltol, 1,
-		  &info, fncount, grcount);
-  
-  igraph_vector_destroy(&info.lastgrad);
-  igraph_vector_destroy(&info.lastparam);
-  igraph_vector_destroy(&info.tmpgrad);
-  igraph_vector_destroy(&info.par1);
-  igraph_vector_destroy(&info.dS);
-  igraph_vector_destroy(&info.neis);
-  igraph_vector_long_destroy(&info.degree);
-  igraph_i_revolver_ml_D_free(&info.dA_vects);
-  igraph_vector_ptr_destroy(&info.dA_vects);
-  igraph_vector_destroy(&info.A_vect);
-  IGRAPH_FINALLY_CLEAN(10);
-  
-  return ret;
-}
-
-/* These functions assemble the A(d)=d^alpha+1 kernel function and 
-   calls the general degree-based optimizer.
-*/
-
-igraph_real_t igraph_i_revolver_ml_D_alpha_f(const igraph_vector_t *var, 
-					     const igraph_vector_t *par,
-					     void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t alpha=VECTOR(*par)[0];
-  if (deg != 0) {
-    return pow(deg, alpha) + 1.0;
-  } else {
-    return 1.0;
-  }
-}
-
-void igraph_i_revolver_ml_D_alpha_df(const igraph_vector_t *var,
-				     const igraph_vector_t *par,
-				     igraph_vector_t *res, 
-				     void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t alpha=VECTOR(*par)[0];
-  if (deg != 0) {
-    VECTOR(*res)[0] = log(deg) * pow(deg, alpha);
-  } else {
-    VECTOR(*res)[0] = 0.0;
-  }
-}
-
-int igraph_revolver_ml_D_alpha(const igraph_t *graph,
-			       igraph_real_t *alpha, igraph_real_t *Fmin,
-			       igraph_real_t abstol, igraph_real_t reltol, 
-			       int maxit, const igraph_vector_t *filter,
-			       igraph_integer_t *fncount, 
-			       igraph_integer_t *grcount) {
-  
-  igraph_vector_t res;
-  int ret;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 1);
-  VECTOR(res)[0]=*alpha;
-  
-  ret=igraph_revolver_ml_D(graph, &res, Fmin, abstol, reltol, maxit,
-			   igraph_i_revolver_ml_D_alpha_f,
-			   igraph_i_revolver_ml_D_alpha_df,
-			   filter,
-			   fncount, grcount);
-
-  *alpha=VECTOR(res)[0];
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return ret;
-}
-
-/* These functions assemble the A(d)=d^alpha+a kernel function and 
-   calls the general degree-based optimizer.
-*/
-
-igraph_real_t igraph_i_revolver_ml_D_alpha_a_f(const igraph_vector_t *var,
-					       const igraph_vector_t *par,
-					       void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  if (deg != 0) {
-    return pow(deg, alpha) + a;
-  } else {
-    return a;
-  }  
-}
-
-void igraph_i_revolver_ml_D_alpha_a_df(const igraph_vector_t *var,
-				       const igraph_vector_t *par,
-				       igraph_vector_t *res,
-				       void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t alpha=VECTOR(*par)[0];
-  /* a not needed */
-  if (deg != 0) {
-    VECTOR(*res)[0] = log(deg) * pow(deg, alpha);
-    VECTOR(*res)[1] = 1.0;
-  } else {
-    VECTOR(*res)[0] = 0.0;
-    VECTOR(*res)[0] = 1.0;
-  }    
-}
-
-int igraph_revolver_ml_D_alpha_a(const igraph_t *graph,
-				 igraph_real_t *alpha, igraph_real_t *a,
-				 igraph_real_t *Fmin,
-				 igraph_real_t abstol, igraph_real_t reltol,
-				 int maxit, const igraph_vector_t *filter,
-				 igraph_integer_t *fncount, 
-				 igraph_integer_t *grcount) {
-  igraph_vector_t res;
-  int ret;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 2);
-  VECTOR(res)[0] = *alpha;
-  VECTOR(res)[1] = *a;
-  
-  ret=igraph_revolver_ml_D(graph, &res, Fmin, abstol, reltol, maxit,
-			   igraph_i_revolver_ml_D_alpha_a_f,
-			   igraph_i_revolver_ml_D_alpha_a_df, 
-			   filter,
-			   fncount, grcount);
-  
-  *alpha=VECTOR(res)[0];
-  *a=VECTOR(res)[1];
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-  
-  return ret;
-}
-
-/*------------------------------------------------------------------*/
-
-typedef struct igraph_i_revolver_ml_DE_data_t {
-  igraph_scalar_function_t *A;
-  igraph_vector_function_t *dA;  
-  const igraph_t *graph;
-  const igraph_vector_t *cats;
-  long int no_of_nodes;
-  igraph_matrix_t A_vect;	/* Temporary storage */
-  igraph_vector_ptr_t dA_vects;	/* Temporary storage */
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  igraph_vector_t dS;		/* Temporary storage */
-  igraph_vector_t par1;		/* More tmp storage */
-  igraph_vector_t tmpgrad;      /* More... */  
-
-  igraph_vector_t lastparam;	/* The parameter values used last time */
-  igraph_real_t lastf;		/* The evaluated function value  */
-  igraph_vector_t lastgrad;	/* The evaluated gradient */
-
-  const igraph_vector_t *filter;
-} igraph_i_revolver_ml_DE_data_t;
-
-int igraph_i_revolver_ml_DE_eval(const igraph_vector_t *par,
-				 igraph_i_revolver_ml_DE_data_t *data) {
-  
-  igraph_real_t sum=0.0;
-  long int t, i, j;
-  int dim=(int) igraph_vector_size(par);
-  igraph_vector_t *grad=&data->lastgrad;
-  igraph_real_t S=0.0;
-  long int no_of_edges=0;
-  
-  /* Init */
-  igraph_vector_long_null(&data->degree);
-  igraph_vector_null(&data->dS);
-  igraph_vector_null(grad);
-
-  for (i=0; i<data->nocats; i++) {
-    for (j=0; j<data->maxdegree+1; j++) {
-      long int k;
-      VECTOR(data->par1)[0]=i; VECTOR(data->par1)[1]=j;
-      MATRIX(data->A_vect, i, j) = data->A(&data->par1, par, 0);
-      data->dA(&data->par1, par, &data->tmpgrad, 0);
-      for (k=0; k<dim; k++) {
-	igraph_matrix_t *m=VECTOR(data->dA_vects)[k];
-	MATRIX(*m, i, j)=VECTOR(data->tmpgrad)[k];
-      }
-    }
-  }
-  
-  for (t=0; t<data->no_of_nodes; t++) {
-    long int n, nneis;
-    long int tcat=(long int) VECTOR(*data->cats)[t];
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(data->graph, &data->neis, 
-				  (igraph_integer_t) t, IGRAPH_OUT));
-    nneis=igraph_vector_size(&data->neis);
-
-    if (! data->filter || VECTOR(*data->filter)[t]) {
-
-      /* Update sum(s) */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(data->neis)[n];
-	long int x=(long int) VECTOR(*data->cats)[to];
-	long int y=VECTOR(data->degree)[to];
-	
-/* 	CHECK_VALID(x,y); */
-	sum -= log( MATRIX(data->A_vect, x, y) );
-	sum += log( S );
-	for (i=0; i<dim; i++) {
-	  igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-	  VECTOR(*grad)[i] -= MATRIX(*m, x, y) / MATRIX(data->A_vect, x, y);
-	  VECTOR(*grad)[i] += VECTOR(data->dS)[i] / S;
-	}
-	no_of_edges++;
-      }
-    }
-    
-    /* Update D, data->dS */
-    for (n=0; n<nneis; n++) {
-      long int to=(long int) VECTOR(data->neis)[n];
-      long int x=(long int) VECTOR(*data->cats)[to];
-      long int y=VECTOR(data->degree)[to];
-      
-      VECTOR(data->degree)[to] += 1;
-      S += MATRIX(data->A_vect, x, y+1);
-      S -= MATRIX(data->A_vect, x, y);
-      for (i=0; i<dim; i++) {
-	igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-	VECTOR(data->dS)[i] += MATRIX(*m, x, y+1);
-	VECTOR(data->dS)[i] -= MATRIX(*m, x, y);
-      }
-    }
-    /* New vertex */
-    S += MATRIX(data->A_vect, tcat, 0);
-    for (i=0; i<dim; i++) {
-      igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-      VECTOR(data->dS)[i] += MATRIX(*m, tcat, 0);
-    }
-    
-  }
-  
-  igraph_vector_update(&data->lastparam, par);
-  data->lastf=sum / no_of_edges;
-  for (i=0; i<igraph_vector_size(&data->lastgrad); i++) {
-    VECTOR(data->lastgrad)[i] /= no_of_edges;
-  }
-
-  return 0.0;
-}
-
-igraph_real_t igraph_i_revolver_ml_DE_f(const igraph_vector_t *par,
-					const igraph_vector_t *garbage,
-					void *extra) {
-
-  igraph_i_revolver_ml_DE_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_DE_eval(par, data);
-  }
-
-  if (!igraph_finite(data->lastf)) {
-    IGRAPH_WARNING("Target function evaluated to non-finite value.");
-  }
-  
-  /* printf("eval ("); */
-  /* for (i=0; i<igraph_vector_size(par); i++) { */
-  /*   printf("%f ", VECTOR(*par)[i]); */
-  /* } */
-  /* printf(" ): "); */
-  /* printf("%g\n", data->lastf); */
-  return data->lastf;
-}
-
-void igraph_i_revolver_ml_DE_df(const igraph_vector_t *par,
-				const igraph_vector_t *garbage,
-				igraph_vector_t *res, void *extra) {
-
-  igraph_i_revolver_ml_DE_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_DE_eval(par, data);
-  }
-  
-  igraph_vector_update(res, &data->lastgrad);
-  /* printf("derivative ("); */
-  /* for (i=0; i<igraph_vector_size(par); i++) { */
-  /*   printf("%f ", VECTOR(*par)[i]); */
-  /* } */
-  /* printf(" ): "); */
-  /* for (i=0; i<igraph_vector_size(res); i++) { */
-  /*   printf("%f ", VECTOR(*res)[i]); */
-  /* } */
-  /* printf("\n"); */
-}
-
-void igraph_i_revolver_ml_DE_free(igraph_vector_ptr_t *ptr) {
-  long int i, n=igraph_vector_ptr_size(ptr);
-  for (i=0; i<n; i++) {
-    igraph_matrix_t *v=VECTOR(*ptr)[i];
-    if (v) {
-      igraph_matrix_destroy(v);
-      igraph_free(v);
-    }
-    VECTOR(*ptr)[i]=0;
-  }  
-}
-
-int igraph_revolver_ml_DE(const igraph_t *graph,
-			  const igraph_vector_t *cats,
-			  igraph_vector_t *res,
-			  igraph_real_t *Fmin,
-			  igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			  igraph_scalar_function_t *A_fun,
-			  igraph_vector_function_t *dA_fun,
-			  const igraph_vector_t *filter,
-			  igraph_integer_t *fncount, 
-			  igraph_integer_t *grcount,
-			  igraph_vector_t *lastderiv) {
-  
-  igraph_i_revolver_ml_DE_data_t info;
-  igraph_integer_t maxdegree;
-  long int no_of_nodes=igraph_vcount(graph);
-  int dim=(int) igraph_vector_size(res);
-  int ret, i;
-
-  if (igraph_vector_size(cats) != no_of_nodes) {
-    IGRAPH_ERROR("DE ML Revolver failed, invalid category vector size", 
-		 IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  info.A=A_fun;
-  info.dA=dA_fun;
-  info.graph=graph;
-  info.cats=cats;
-  info.nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  info.no_of_nodes=no_of_nodes;
-  IGRAPH_MATRIX_INIT_FINALLY(&info.A_vect, info.nocats, maxdegree+1);  
-  IGRAPH_VECTOR_PTR_INIT_FINALLY(&info.dA_vects, dim);
-  IGRAPH_FINALLY(igraph_i_revolver_ml_DE_free, &info.dA_vects);
-  for (i=0; i<dim; i++) {
-    igraph_matrix_t *m=igraph_Calloc(1, igraph_matrix_t);
-    if (!m) { IGRAPH_ERROR("Cannot perform ML D revolver", IGRAPH_ENOMEM); }
-    IGRAPH_CHECK(igraph_matrix_init(m, info.nocats, maxdegree+1));
-    VECTOR(info.dA_vects)[i]=m;
-  }
-  info.maxdegree=maxdegree;
-  IGRAPH_CHECK(igraph_vector_long_init(&info.degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &info.degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.dS, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.par1, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.tmpgrad, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastparam, dim);
-  info.lastf=0.0;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastgrad, dim);  
-  info.filter=filter;
-  
-  igraph_i_revolver_ml_DE_eval(res, &info);
-  ret=igraph_bfgs(res, Fmin, igraph_i_revolver_ml_DE_f,
-		  igraph_i_revolver_ml_DE_df, maxit, 1, abstol, reltol, 1, 
-		  &info, fncount, grcount);
-
-  if (lastderiv) {
-    igraph_vector_update(lastderiv, &info.lastgrad);
-  }
-  
-  igraph_vector_destroy(&info.lastgrad);
-  igraph_vector_destroy(&info.lastparam);
-  igraph_vector_destroy(&info.tmpgrad);
-  igraph_vector_destroy(&info.par1);
-  igraph_vector_destroy(&info.dS);
-  igraph_vector_destroy(&info.neis);
-  igraph_vector_long_destroy(&info.degree);
-  igraph_i_revolver_ml_DE_free(&info.dA_vects);
-  igraph_vector_ptr_destroy(&info.dA_vects);
-  igraph_matrix_destroy(&info.A_vect);
-  IGRAPH_FINALLY_CLEAN(10);
-
-  return ret;
-}
- 
-igraph_real_t igraph_i_revolver_ml_DE_alpha_a_f(const igraph_vector_t *var,
-						const igraph_vector_t *par,
-						void *extra) {
-  long int cat=(long int) VECTOR(*var)[0];
-  igraph_real_t deg=VECTOR(*var)[1];
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t c= cat==0 ? 1.0 : VECTOR(*par)[1+cat];
-  if (deg != 0) {
-    return c * (pow(deg, alpha) + a);
-  } else {
-    return c * a;
-  }
-}
-
-void igraph_i_revolver_ml_DE_alpha_a_df(const igraph_vector_t *var,
-					const igraph_vector_t *par,
-					igraph_vector_t *res,
-					void *extra) {
-  long int cat=(long int) VECTOR(*var)[0];
-  igraph_real_t deg=VECTOR(*var)[1];
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t c= cat==0 ? 1.0 : VECTOR(*par)[1+cat];
-  igraph_vector_null(res);
-  if (deg != 0) {
-    igraph_real_t p=pow(deg, alpha);
-    VECTOR(*res)[0] = c * log(deg) * p;
-    VECTOR(*res)[1] = c;
-    VECTOR(*res)[1+cat] = p+a;
-  } else {
-    VECTOR(*res)[0] = 0.0;
-    VECTOR(*res)[1] = c;
-    VECTOR(*res)[1+cat] = a;
-  }
-}
-
-int igraph_revolver_ml_DE_alpha_a(const igraph_t *graph,
-				  const igraph_vector_t *cats,
-				  igraph_real_t *alpha, igraph_real_t *a,
-				  igraph_vector_t *coeffs,
-				  igraph_real_t *Fmin,
-				  igraph_real_t abstol, igraph_real_t reltol,
-				  int maxit, const igraph_vector_t *filter,
-				  igraph_integer_t *fncount,
-				  igraph_integer_t *grcount) {
-  igraph_vector_t res;
-  int ret, i;  
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, igraph_vector_size(coeffs)+2);
-  VECTOR(res)[0] = *alpha;
-  VECTOR(res)[1] = *a;
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(res)[i+2] = VECTOR(*coeffs)[i];
-  }
-  
-  ret=igraph_revolver_ml_DE(graph, cats, &res, Fmin, abstol, reltol, maxit,
-			    igraph_i_revolver_ml_DE_alpha_a_f,
-			    igraph_i_revolver_ml_DE_alpha_a_df,
-			    filter, fncount, grcount, 0);
-  
-  *alpha=VECTOR(res)[0];
-  *a=VECTOR(res)[1];
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(*coeffs)[i]=VECTOR(res)[i+2];
-  }
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-
-  return ret;
-}
-
-/*------------------------------------------------------------------*/
-
-typedef struct igraph_i_revolver_ml_AD_data_t {
-  igraph_scalar_function_t *A;
-  igraph_vector_function_t *dA;
-  const igraph_t *graph;
-  long int no_of_nodes;
-  igraph_matrix_t A_vect;	/* Temporary storage */
-  igraph_vector_ptr_t dA_vects;	/* Temporary storage */
-  igraph_matrix_bool_t A_valid;
-  igraph_integer_t maxdegree;
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  igraph_vector_t dS;		/* Temporary storage */
-  igraph_vector_t par1;		/* More tmp storage */
-  igraph_vector_t tmpgrad;      /* More... */
-  int agebins;
-
-  igraph_vector_t lastparam;	/* The parameter values used last time */
-  igraph_real_t lastf;		/* The evaluated function value  */
-  igraph_vector_t lastgrad;	/* The evaluated gradient */
-  
-  const igraph_vector_t *filter;
-} igraph_i_revolver_ml_AD_data_t;
-
-#define CHECK_VALID(X,Y) \
-  if (!MATRIX(data->A_valid,(X),(Y))) { \
-     int i; \
-     VECTOR(data->par1)[0]=(X); VECTOR(data->par1)[1]=(Y); \
-     MATRIX(data->A_vect, (X), (Y)) = data->A(&data->par1, par, 0); \
-     data->dA(&data->par1, 0, &data->tmpgrad, 0); \
-     for (i=0; i<dim; i++) { \
-       igraph_matrix_t *m=VECTOR(data->dA_vects)[i]; \
-       MATRIX(*m, (X), (Y)) = VECTOR(data->tmpgrad)[i]; \
-     } \
-  }
-
-int igraph_i_revolver_ml_AD_eval(const igraph_vector_t *par,
-				igraph_i_revolver_ml_AD_data_t *data) {
-  igraph_real_t sum=0.0;
-  long int t, i, j;
-  int dim=(int) igraph_vector_size(par);
-  igraph_vector_t *grad=&data->lastgrad;
-  igraph_real_t S=0.0;
-  long int agebins=data->agebins;
-  long int binwidth=data->no_of_nodes/agebins+1;
-  long int no_of_edges=0;
-  
-  /* Init */
-  igraph_vector_long_null(&data->degree);
-  igraph_vector_null(&data->dS);
-  igraph_vector_null(grad);
-  igraph_matrix_bool_null(&data->A_valid);
-
-  for (i=0; i<data->maxdegree+1; i++) {
-    for (j=0; j<agebins; j++) {
-      long int k;
-      VECTOR(data->par1)[0]=(i); VECTOR(data->par1)[1]=(j);
-      MATRIX(data->A_vect, (i), (j)) = data->A(&data->par1, par, 0);
-      data->dA(&data->par1, par, &data->tmpgrad, 0);
-      for (k=0; k<dim; k++) {
-	igraph_matrix_t *m=VECTOR(data->dA_vects)[k];
-	MATRIX(*m, (i), (j)) = VECTOR(data->tmpgrad)[k];
-      }
-    }
-  }      
-
-  for (t=0; t<data->no_of_nodes; t++) {
-    long int n, nneis;
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(data->graph, &data->neis, 
-				  (igraph_integer_t) t, IGRAPH_OUT));
-    nneis=igraph_vector_size(&data->neis);
-
-    if (! data->filter || VECTOR(*data->filter)[t]) {
-
-      /* Update sum(s) */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(data->neis)[n];
-	long int x=VECTOR(data->degree)[to];
-	long int y=(t-to)/binwidth;
-	
-/* 	CHECK_VALID(x,y); */
-	sum -= log( MATRIX(data->A_vect, x, y) );
-	sum += log( S );
-	for (i=0; i<dim; i++) {
-	  igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-	  VECTOR(*grad)[i] -= MATRIX(*m, x, y) / MATRIX(data->A_vect, x, y);
-	  VECTOR(*grad)[i] += VECTOR(data->dS)[i] / S;
-	}
-	no_of_edges++;
-      }
-    }
-    
-    /* Update S, data->dS */
-    for (n=0; n<nneis; n++) {
-      long int to=(long int) VECTOR(data->neis)[n];
-      long int x=VECTOR(data->degree)[to];
-      long int y=(t-to)/binwidth;
-      
-/*       CHECK_VALID(x+1,y);	/\* (x,y) already checked *\/ */
-      VECTOR(data->degree)[to] += 1;
-      S += MATRIX(data->A_vect, x+1, y);
-      S -= MATRIX(data->A_vect, x, y);
-      for (i=0; i<dim; i++) {
-	igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-	VECTOR(data->dS)[i] += MATRIX(*m, x+1, y);
-	VECTOR(data->dS)[i] -= MATRIX(*m, x, y);
-      }
-    }
-    /* New vertex */
-/*     CHECK_VALID(0,0); */
-    S += MATRIX(data->A_vect, 0, 0);
-    for (i=0; i<dim; i++) {
-      igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-      VECTOR(data->dS)[i] += MATRIX(*m, 0, 0);
-    }
-    /* Aging */
-    for (j=1; t-binwidth*j+1>=0; j++) {
-      long int shnode=t-binwidth*j+1;
-      long int deg=VECTOR(data->degree)[shnode];
-/*       CHECK_VALID(deg, j-1); */
-/*       CHECK_VALID(deg, j); */
-      S += MATRIX(data->A_vect, deg, j);
-      S -= MATRIX(data->A_vect, deg, j-1);
-      for (i=0; i<dim; i++) {
-	igraph_matrix_t *m=VECTOR(data->dA_vects)[i];
-	VECTOR(data->dS)[i] += MATRIX(*m, deg, j);
-	VECTOR(data->dS)[i] -= MATRIX(*m, deg, j-1);
-      }
-    }
-    
-  }      
-      
-  igraph_vector_update(&data->lastparam, par);
-  data->lastf=sum / no_of_edges;
-  for (i=0; i<igraph_vector_size(&data->lastgrad); i++) {
-    VECTOR(data->lastgrad)[i] /= no_of_edges;
-  }
-
-  return 0.0;
-}
-
-igraph_real_t igraph_i_revolver_ml_AD_f(const igraph_vector_t *par,
-					const igraph_vector_t *garbage,
-					void *extra) {
-
-  igraph_i_revolver_ml_AD_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_AD_eval(par, data);
-  }
-
-  if (!igraph_finite(data->lastf)) {
-    IGRAPH_WARNING("Target function evaluated to non-finite value.");
-  }
-  
-  /* printf("eval ("); */
-  /* for (i=0; i<igraph_vector_size(par); i++) { */
-  /*   printf("%f ", VECTOR(*par)[i]); */
-  /* } */
-  /* printf(" ): "); */
-  /* printf("%g\n", data->lastf); */
-  return data->lastf;
-}
-
-void igraph_i_revolver_ml_AD_df(const igraph_vector_t *par,
-				const igraph_vector_t *garbage,
-				igraph_vector_t *res, void *extra) {
-
-  igraph_i_revolver_ml_AD_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_AD_eval(par, data);
-  }
-  
-  igraph_vector_update(res, &data->lastgrad);
-  /* printf("derivative ("); */
-  /* for (i=0; i<igraph_vector_size(par); i++) { */
-  /*   printf("%f ", VECTOR(*par)[i]); */
-  /* } */
-  /* printf(" ): "); */
-  /* for (i=0; i<igraph_vector_size(res); i++) { */
-  /*   printf("%f ", VECTOR(*res)[i]); */
-  /* } */
-  /* printf("\n"); */
-}
-
-void igraph_i_revolver_ml_AD_free(igraph_vector_ptr_t *ptr) {
-  long int i, n=igraph_vector_ptr_size(ptr);
-  for (i=0; i<n; i++) {
-    igraph_matrix_t *v=VECTOR(*ptr)[i];
-    if (v) {
-      igraph_matrix_destroy(v);
-      igraph_free(v);
-    }
-    VECTOR(*ptr)[i]=0;
-  }  
-}
-
-int igraph_revolver_ml_AD(const igraph_t *graph,
-			  igraph_vector_t *res,
-			  igraph_real_t *Fmin,
-			  igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			  igraph_scalar_function_t *A_fun,
-			  igraph_vector_function_t *dA_fun,
-			  int agebins, const igraph_vector_t *filter,
-			  igraph_integer_t *fncount, 
-			  igraph_integer_t *grcount,
-			  igraph_vector_t *lastderiv) {
-  
-  igraph_i_revolver_ml_AD_data_t info;
-  igraph_integer_t maxdegree;
-  long int no_of_nodes=igraph_vcount(graph);
-  int dim=(int) igraph_vector_size(res);
-  int ret, i;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  info.A=A_fun;
-  info.dA=dA_fun;
-  info.graph=graph;
-  info.no_of_nodes=no_of_nodes;
-  IGRAPH_MATRIX_INIT_FINALLY(&info.A_vect, maxdegree+1, agebins);  
-  IGRAPH_VECTOR_PTR_INIT_FINALLY(&info.dA_vects, dim);
-  IGRAPH_FINALLY(igraph_i_revolver_ml_AD_free, &info.dA_vects);
-  for (i=0; i<dim; i++) {
-    igraph_matrix_t *m=igraph_Calloc(1, igraph_matrix_t);
-    if (!m) { IGRAPH_ERROR("Cannot perform ML D revolver", IGRAPH_ENOMEM); }
-    IGRAPH_CHECK(igraph_matrix_init(m, maxdegree+1, agebins));
-    VECTOR(info.dA_vects)[i]=m;
-  }
-  IGRAPH_CHECK(igraph_matrix_bool_init(&info.A_valid, maxdegree+1, agebins));
-  IGRAPH_FINALLY(igraph_matrix_bool_destroy, &info.A_valid);
-  info.maxdegree=maxdegree;
-  IGRAPH_CHECK(igraph_vector_long_init(&info.degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &info.degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.dS, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.par1, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.tmpgrad, dim);
-  info.agebins=agebins;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastparam, dim);
-  info.lastf=0.0;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastgrad, dim);  
-  info.filter=filter;
-  
-  igraph_i_revolver_ml_AD_eval(res, &info);
-  ret=igraph_bfgs(res, Fmin, igraph_i_revolver_ml_AD_f,
-		  igraph_i_revolver_ml_AD_df, maxit, 1, abstol, reltol, 1, 
-		  &info, fncount, grcount);
-
-  if (lastderiv) {
-    igraph_vector_update(lastderiv, &info.lastgrad);
-  }
-  
-  igraph_vector_destroy(&info.lastgrad);
-  igraph_vector_destroy(&info.lastparam);
-  igraph_vector_destroy(&info.tmpgrad);
-  igraph_vector_destroy(&info.par1);
-  igraph_vector_destroy(&info.dS);
-  igraph_vector_destroy(&info.neis);
-  igraph_vector_long_destroy(&info.degree);
-  igraph_matrix_bool_destroy(&info.A_valid);
-  igraph_i_revolver_ml_AD_free(&info.dA_vects);
-  igraph_vector_ptr_destroy(&info.dA_vects);
-  igraph_matrix_destroy(&info.A_vect);
-  IGRAPH_FINALLY_CLEAN(11);
-
-  return ret;
-}
-
-igraph_real_t igraph_i_revolver_ml_AD_alpha_a_beta_f(const igraph_vector_t *var,
-						     const igraph_vector_t *par,
-						     void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t age=VECTOR(*var)[1]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t beta=VECTOR(*par)[2];
-  return (pow(deg, alpha) + a) * pow(age, -beta);
-}
-
-void igraph_i_revolver_ml_AD_alpha_a_beta_df(const igraph_vector_t *var,
-					     const igraph_vector_t *par,
-					     igraph_vector_t *res,
-					     void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t age=VECTOR(*var)[1]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t beta=VECTOR(*par)[2];
-  igraph_real_t p1=pow(deg, alpha);
-  igraph_real_t p2=pow(age, -beta);
-  VECTOR(*res)[0]= deg == 0 ? 0.0 : p2*log(deg)*p1;
-  VECTOR(*res)[1]= p2;
-  VECTOR(*res)[2]= -(p1+a)*log(age)*p2;
-}
-
-int igraph_revolver_ml_AD_alpha_a_beta(const igraph_t *graph,
-				       igraph_real_t *alpha, igraph_real_t *a,
-				       igraph_real_t *beta, igraph_real_t *Fmin,
-				       igraph_real_t abstol, igraph_real_t reltol,
-				       int maxit, int agebins, 
-				       const igraph_vector_t *filter,
-				       igraph_integer_t *fncount,
-				       igraph_integer_t *grcount) {
-  igraph_vector_t res;
-  int ret;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 3);
-  VECTOR(res)[0] = *alpha;
-  VECTOR(res)[1] = *a;
-  VECTOR(res)[2] = *beta;
-  
-  ret=igraph_revolver_ml_AD(graph, &res, Fmin, abstol, reltol, maxit,
-			    igraph_i_revolver_ml_AD_alpha_a_beta_f,
-			    igraph_i_revolver_ml_AD_alpha_a_beta_df,
-			    agebins, filter, fncount, grcount, 0);
-  
-  *alpha=VECTOR(res)[0];
-  *a=VECTOR(res)[1];
-  *beta=VECTOR(res)[2];
-
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);  
-  return ret;
-}
-
-igraph_real_t igraph_i_revolver_ml_AD_dpareto_f(const igraph_vector_t *var,
-						const igraph_vector_t *par,
-						void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t age=VECTOR(*var)[1]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t paralpha=VECTOR(*par)[2];
-  igraph_real_t parbeta=VECTOR(*par)[3];
-  igraph_real_t parscale=VECTOR(*par)[4];
-  
-  igraph_real_t res= age < parscale ? 
-    (pow(deg,alpha)+a) * pow(age/parscale, parbeta-1) : 
-    (pow(deg,alpha)+a) * pow(age/parscale, -paralpha-1);
-    
-/*   printf("eval at %f %f, %f %f %f %f %f: %f\n", deg, age, */
-/* 	 alpha, a, paralpha, parbeta, parscale, res); */
-
-  return res;
-}
-
-void igraph_i_revolver_ml_AD_dpareto_df(const igraph_vector_t *var,
-					const igraph_vector_t *par,
-					igraph_vector_t *res,
-					void *extra) {
-  igraph_real_t deg=VECTOR(*var)[0];
-  igraph_real_t age=VECTOR(*var)[1]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t paralpha=VECTOR(*par)[2];
-  igraph_real_t parbeta=VECTOR(*par)[3];
-  igraph_real_t parscale=VECTOR(*par)[4];
-  igraph_real_t exponent= age < parscale ? parbeta : -paralpha;
-  igraph_real_t p1=pow(deg, alpha);  
-  igraph_real_t p2=pow(age/parscale, exponent-1);
-  VECTOR(*res)[0]= deg == 0 ? 0.0 : log(deg)*p1*p2;
-  VECTOR(*res)[1]=p2;
-  VECTOR(*res)[2]= age > parscale ? (p1+a)*log(age/parscale)*p2 : 0;
-  VECTOR(*res)[3]= age < parscale ? (p1+a)*log(age/parscale)*p2 : 0;
-  VECTOR(*res)[4]=-(p1+a)*(exponent-1)*pow(age/parscale, exponent-2)*
-    age/parscale/parscale;
-/*   printf("deriv at %f %f, %f %f %f %f %f: %f %f %f %f %f\n", deg, age, */
-/* 	 alpha, a, paralpha, parbeta, parscale, */
-/* 	 VECTOR(*res)[0], VECTOR(*res)[1], VECTOR(*res)[2], VECTOR(*res)[3], */
-/* 	 VECTOR(*res)[4]); */
-    
-}
-
-int igraph_revolver_ml_AD_dpareto_eval(const igraph_t *graph,
-				       igraph_real_t alpha, igraph_real_t a,
-				       igraph_real_t paralpha, 
-				       igraph_real_t parbeta,
-				       igraph_real_t parscale,
-				       igraph_real_t *value,
-				       igraph_vector_t *deriv,
-				       int agebins,
-				       const igraph_vector_t *filter) {
-  igraph_vector_t res;
-  int ret;
-  igraph_integer_t fncount, grcount;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 5);
-  VECTOR(res)[0] = alpha;
-  VECTOR(res)[1] = a;
-  VECTOR(res)[2] = paralpha;
-  VECTOR(res)[3] = parbeta;
-  VECTOR(res)[4] = parscale;
-  
-  ret=igraph_revolver_ml_AD(graph, &res, value, 0, 0, 0,
-			    igraph_i_revolver_ml_AD_dpareto_f,
-			    igraph_i_revolver_ml_AD_dpareto_df,
-			    agebins, filter, &fncount, &grcount, deriv);
-  
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-  return ret;
-}
-
-int igraph_revolver_ml_AD_dpareto(const igraph_t *graph,
-				  igraph_real_t *alpha, igraph_real_t *a,
-				  igraph_real_t *paralpha, igraph_real_t *parbeta,
-				  igraph_real_t *parscale,
-				  igraph_real_t *Fmin,
-				  igraph_real_t abstol, igraph_real_t reltol,
-				  int maxit, int agebins, 
-				  const igraph_vector_t *filter,
-				  igraph_integer_t *fncount,
-				  igraph_integer_t *grcount) {
-  igraph_vector_t res;
-  int ret;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 5);
-  VECTOR(res)[0] = *alpha;
-  VECTOR(res)[1] = *a;
-  VECTOR(res)[2] = *paralpha;
-  VECTOR(res)[3] = *parbeta;
-  VECTOR(res)[4] = *parscale;
-  
-  ret=igraph_revolver_ml_AD(graph, &res, Fmin, abstol, reltol, maxit,
-			    igraph_i_revolver_ml_AD_dpareto_f,
-			    igraph_i_revolver_ml_AD_dpareto_df,
-			    agebins, filter, fncount, grcount, 0);
-  
-  *alpha=VECTOR(res)[0];
-  *a=VECTOR(res)[1];
-  *paralpha=VECTOR(res)[2];
-  *parbeta=VECTOR(res)[3];
-  *parscale=VECTOR(res)[4];
-
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-  return ret;
-}
-
-/*------------------------------------------------------------------*/
-
-typedef struct igraph_i_revolver_ml_ADE_data_t {
-  igraph_scalar_function_t *A;
-  igraph_vector_function_t *dA;
-  const igraph_t *graph;
-  const igraph_vector_t *cats;
-  long int no_of_nodes;
-  igraph_array3_t A_vect;	/* Temporary storage */
-  igraph_vector_ptr_t dA_vects;	/* Temporary storage */
-  igraph_integer_t maxdegree;
-  igraph_integer_t nocats;
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  igraph_vector_t dS;		/* Temporary storage */
-  igraph_vector_t par1;		/* More tmp storage */
-  igraph_vector_t tmpgrad;      /* More... */
-  int agebins;
-
-  igraph_vector_t lastparam;	/* The parameter values used last time */
-  igraph_real_t lastf;		/* The evaluated function value  */
-  igraph_vector_t lastgrad;	/* The evaluated gradient */
-  
-  const igraph_vector_t *filter;
-} igraph_i_revolver_ml_ADE_data_t;
-
-int igraph_i_revolver_ml_ADE_eval(const igraph_vector_t *par,
-				  igraph_i_revolver_ml_ADE_data_t *data) {
-  igraph_real_t sum=0.;
-  long int t, i, j, c;
-  int dim=(int) igraph_vector_size(par);
-  igraph_vector_t *grad=&data->lastgrad;
-  igraph_real_t S=0.0;
-  long int agebins=data->agebins;
-  long int binwidth=data->no_of_nodes/agebins+1;
-  long int no_of_edges=0;
-  
-  /* Init */
-  igraph_vector_long_null(&data->degree);
-  igraph_vector_null(&data->dS);
-  igraph_vector_null(grad);
-
-  for (c=0; c<data->nocats; c++) {
-    for (i=0; i<data->maxdegree+1; i++) {
-      for (j=0; j<agebins; j++) {
-	long int k;
-	VECTOR(data->par1)[0]=c;
-	VECTOR(data->par1)[1]=i;
-	VECTOR(data->par1)[2]=j;
-	ARRAY3(data->A_vect, c, (i), (j)) = data->A(&data->par1, par, 0);
-	data->dA(&data->par1, par, &data->tmpgrad, 0);
-	for (k=0; k<dim; k++) {
-	  igraph_array3_t *m=VECTOR(data->dA_vects)[k];
-	  ARRAY3(*m, c, i, j) = VECTOR(data->tmpgrad)[k];
-	}
-      }
-    }
-  }
-
-  for (t=0; t<data->no_of_nodes; t++) {
-    long int n, nneis, shnode;
-    long int tcat=(long int) VECTOR(*data->cats)[t];
-
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    IGRAPH_CHECK(igraph_neighbors(data->graph, &data->neis, 
-				  (igraph_integer_t) t, IGRAPH_OUT));
-    nneis=igraph_vector_size(&data->neis);
-
-    if (! data->filter || VECTOR(*data->filter)[t]) {
-
-      /* Update sum(s) */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(data->neis)[n];
-	long int x=(long int) VECTOR(*data->cats)[to];
-	long int y=VECTOR(data->degree)[to];
-	long int z=(t-to)/binwidth;
-	
-/* 	CHECK_VALID(x,y); */
-	sum -= log( ARRAY3(data->A_vect, x, y, z) );
-	sum += log( S );
-	for (i=0; i<dim; i++) {
-	  igraph_array3_t *m=VECTOR(data->dA_vects)[i];
-	  VECTOR(*grad)[i] -= ARRAY3(*m, x, y, z) / ARRAY3(data->A_vect, x, y, z);
-	  VECTOR(*grad)[i] += VECTOR(data->dS)[i] / S;
-	}
-	no_of_edges++;
-      }
-    }
-    
-    /* Update S, data->dS */
-    for (n=0; n<nneis; n++) {
-      long int to=(long int) VECTOR(data->neis)[n];
-      long int x=(long int) VECTOR(*data->cats)[to];
-      long int y=VECTOR(data->degree)[to];
-      long int z=(t-to)/binwidth;
-      
-/*       CHECK_VALID(x+1,y);	/\* (x,y) already checked *\/ */
-      VECTOR(data->degree)[to] += 1;
-      S += ARRAY3(data->A_vect, x, y+1, z);
-      S -= ARRAY3(data->A_vect, x, y, z);
-      for (i=0; i<dim; i++) {
-	igraph_array3_t *m=VECTOR(data->dA_vects)[i];
-	VECTOR(data->dS)[i] += ARRAY3(*m, x, y+1, z);
-	VECTOR(data->dS)[i] -= ARRAY3(*m, x, y, z);
-      }
-    }
-    /* New vertex */
-/*     CHECK_VALID(0,0); */
-    S += ARRAY3(data->A_vect, tcat, 0, 0);
-    for (i=0; i<dim; i++) {
-      igraph_array3_t *m=VECTOR(data->dA_vects)[i];
-      VECTOR(data->dS)[i] += ARRAY3(*m, tcat, 0, 0);
-    }
-    /* Aging */
-    for (j=1, shnode=t-binwidth+1; shnode>=0; j++, shnode-=binwidth) {
-      long int cat=(long int) VECTOR(*data->cats)[shnode];
-      long int deg=VECTOR(data->degree)[shnode];
-/*       CHECK_VALID(deg, j-1); */
-/*       CHECK_VALID(deg, j); */
-      S += ARRAY3(data->A_vect, cat, deg, j);
-      S -= ARRAY3(data->A_vect, cat, deg, j-1);
-      for (i=0; i<dim; i++) {
-	igraph_array3_t *m=VECTOR(data->dA_vects)[i];
-	VECTOR(data->dS)[i] += ARRAY3(*m, cat, deg, j);
-	VECTOR(data->dS)[i] -= ARRAY3(*m, cat, deg, j-1);
-      }
-    }
-    
-  }      
-      
-  igraph_vector_update(&data->lastparam, par);
-  data->lastf=sum / no_of_edges;
-  for (i=0; i<igraph_vector_size(&data->lastgrad); i++) {
-    VECTOR(data->lastgrad)[i] /= no_of_edges;
-  }
-
-  return 0.0;
-}
-
-igraph_real_t igraph_i_revolver_ml_ADE_f(const igraph_vector_t *par,
-					 const igraph_vector_t *garbage,
-					 void *extra) {
-
-  igraph_i_revolver_ml_ADE_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_ADE_eval(par, data);
-  }
-
-  if (!igraph_finite(data->lastf)) {
-    IGRAPH_WARNING("Target function evaluated to non-finite value.");
-  }
-  
-  /* printf("eval ("); */
-  /* for (i=0; i<igraph_vector_size(par); i++) { */
-  /*   printf("%f ", VECTOR(*par)[i]); */
-  /* } */
-  /* printf(" ): "); */
-  /* printf("%g\n", data->lastf); */
-  return data->lastf;
-}
-
-void igraph_i_revolver_ml_ADE_df(const igraph_vector_t *par,
-				 const igraph_vector_t *garbage,
-				 igraph_vector_t *res, void *extra) {
-
-  igraph_i_revolver_ml_ADE_data_t *data=extra;
-  
-  if (!igraph_vector_all_e(par, &data->lastparam)) {
-    igraph_i_revolver_ml_ADE_eval(par, data);
-  }
-  
-  igraph_vector_update(res, &data->lastgrad);
-  /* printf("derivative ("); */
-  /* for (i=0; i<igraph_vector_size(par); i++) { */
-  /*   printf("%f ", VECTOR(*par)[i]); */
-  /* } */
-  /* printf(" ): "); */
-  /* for (i=0; i<igraph_vector_size(res); i++) { */
-  /*   printf("%f ", VECTOR(*res)[i]); */
-  /* } */
-  /* printf("\n"); */
-}
-
-void igraph_i_revolver_ml_ADE_free(igraph_vector_ptr_t *ptr) {
-  long int i, n=igraph_vector_ptr_size(ptr);
-  for (i=0; i<n; i++) {
-    igraph_array3_t *v=VECTOR(*ptr)[i];
-    if (v) {
-      igraph_array3_destroy(v);
-      igraph_free(v);
-    }
-    VECTOR(*ptr)[i]=0;
-  }  
-}
-
-int igraph_revolver_ml_ADE(const igraph_t *graph,
-			   const igraph_vector_t *cats,
-			   igraph_vector_t *res,
-			   igraph_real_t *Fmin,
-			   igraph_real_t abstol, igraph_real_t reltol, int maxit,
-			   igraph_scalar_function_t *A_fun,
-			   igraph_vector_function_t *dA_fun,
-			   int agebins, const igraph_vector_t *filter,
-			   igraph_integer_t *fncount, 
-			   igraph_integer_t *grcount,
-			   igraph_vector_t *lastderiv) {
-  
-  igraph_i_revolver_ml_ADE_data_t info;
-  igraph_integer_t maxdegree;
-  long int no_of_nodes=igraph_vcount(graph);
-  int dim=(int) igraph_vector_size(res);
-  int ret, i;
-  
-  if (igraph_vector_size(cats) != no_of_nodes) {
-    IGRAPH_ERROR("ADE ML Revolver failed: invalid category vector size", 
-		 IGRAPH_ENOMEM);
-  }
-
-  IGRAPH_CHECK(igraph_maxdegree(graph, &maxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  
-  info.A=A_fun;
-  info.dA=dA_fun;
-  info.graph=graph;
-  info.no_of_nodes=no_of_nodes;
-  info.cats=cats;
-  info.nocats=(igraph_integer_t) igraph_vector_max(cats)+1;
-  IGRAPH_ARRAY3_INIT_FINALLY(&info.A_vect, info.nocats, maxdegree+1, agebins);  
-  IGRAPH_VECTOR_PTR_INIT_FINALLY(&info.dA_vects, dim);
-  IGRAPH_FINALLY(igraph_i_revolver_ml_ADE_free, &info.dA_vects);
-  for (i=0; i<dim; i++) {
-    igraph_array3_t *m=igraph_Calloc(1, igraph_array3_t);
-    if (!m) { IGRAPH_ERROR("Cannot perform ML D revolver", IGRAPH_ENOMEM); }
-    IGRAPH_CHECK(igraph_array3_init(m, info.nocats, maxdegree+1, agebins));
-    VECTOR(info.dA_vects)[i]=m;
-  }
-  info.maxdegree=maxdegree;
-  IGRAPH_CHECK(igraph_vector_long_init(&info.degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &info.degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.dS, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.par1, dim);
-  IGRAPH_VECTOR_INIT_FINALLY(&info.tmpgrad, dim);
-  info.agebins=agebins;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastparam, dim);
-  info.lastf=0.0;
-  IGRAPH_VECTOR_INIT_FINALLY(&info.lastgrad, dim);  
-  info.filter=filter;
-  
-  igraph_i_revolver_ml_ADE_eval(res, &info);
-  ret=igraph_bfgs(res, Fmin, igraph_i_revolver_ml_ADE_f,
-		  igraph_i_revolver_ml_ADE_df, maxit, 1, abstol, reltol, 1, 
-		  &info, fncount, grcount);
-
-  if (lastderiv) {
-    igraph_vector_update(lastderiv, &info.lastgrad);
-  }
-  
-  igraph_vector_destroy(&info.lastgrad);
-  igraph_vector_destroy(&info.lastparam);
-  igraph_vector_destroy(&info.tmpgrad);
-  igraph_vector_destroy(&info.par1);
-  igraph_vector_destroy(&info.dS);
-  igraph_vector_destroy(&info.neis);
-  igraph_vector_long_destroy(&info.degree);
-  igraph_i_revolver_ml_ADE_free(&info.dA_vects);
-  igraph_vector_ptr_destroy(&info.dA_vects);
-  igraph_array3_destroy(&info.A_vect);
-  IGRAPH_FINALLY_CLEAN(10);
-
-  return ret;
-}
-
-igraph_real_t igraph_i_revolver_ml_ADE_alpha_a_beta_f(const igraph_vector_t *var,
-						      const igraph_vector_t *par,
-						      void *extra) {
-  long int cat=(long int) VECTOR(*var)[0];
-  igraph_real_t deg=VECTOR(*var)[1];
-  igraph_real_t age=VECTOR(*var)[2]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t beta=VECTOR(*par)[2];  
-  igraph_real_t c= cat==0 ? 1.0 : VECTOR(*par)[2+cat];
-  return c * (pow(deg, alpha) + a) * pow(age, -beta);
-}
-
-void igraph_i_revolver_ml_ADE_alpha_a_beta_df(const igraph_vector_t *var,
-					      const igraph_vector_t *par,
-					      igraph_vector_t *res,
-					      void *extra) {
-  long int cat=(long int) VECTOR(*var)[0];
-  igraph_real_t deg=VECTOR(*var)[1];
-  igraph_real_t age=VECTOR(*var)[2]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t beta=VECTOR(*par)[2];
-  igraph_real_t c= cat==0 ? 1.0 : VECTOR(*par)[2+cat];
-  igraph_real_t p1=pow(deg, alpha);
-  igraph_real_t p2=pow(age, -beta);
-  igraph_vector_null(res);
-  VECTOR(*res)[0]= deg == 0 ? 0.0 : c * p2*log(deg)*p1;
-  VECTOR(*res)[1]= c * p2;
-  VECTOR(*res)[2]= c * -(p1+a)*log(age)*p2;
-  VECTOR(*res)[2+cat] = (p1 + a) * p2;
-}
-
-int igraph_revolver_ml_ADE_alpha_a_beta(const igraph_t *graph,
-					const igraph_vector_t *cats,
-					igraph_real_t *alpha, igraph_real_t *a,
-					igraph_real_t *beta, igraph_vector_t *coeffs,
-					igraph_real_t *Fmin,
-					igraph_real_t abstol, igraph_real_t reltol,
-					int maxit, int agebins, 
-					const igraph_vector_t *filter,
-					igraph_integer_t *fncount,
-					igraph_integer_t *grcount) {
-  igraph_vector_t res;
-  int ret, i;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 3+igraph_vector_size(coeffs));
-  VECTOR(res)[0] = *alpha;
-  VECTOR(res)[1] = *a;
-  VECTOR(res)[2] = *beta;
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(res)[i+3] = VECTOR(*coeffs)[i];
-  }
-  
-  ret=igraph_revolver_ml_ADE(graph, cats, &res, Fmin, abstol, reltol, maxit,
-			     igraph_i_revolver_ml_ADE_alpha_a_beta_f,
-			     igraph_i_revolver_ml_ADE_alpha_a_beta_df,
-			     agebins, filter, fncount, grcount, 0);
-  
-  *alpha=VECTOR(res)[0];
-  *a=VECTOR(res)[1];
-  *beta=VECTOR(res)[2];
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(*coeffs)[i]=VECTOR(res)[i+3];
-  }
-
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);  
-  return ret;
-}
-
-igraph_real_t igraph_i_revolver_ml_ADE_dpareto_f(const igraph_vector_t *var,
-						 const igraph_vector_t *par,
-						 void *extra) {
-  long int cat=(long int) VECTOR(*var)[0];
-  igraph_real_t deg=VECTOR(*var)[1];
-  igraph_real_t age=VECTOR(*var)[2]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t paralpha=VECTOR(*par)[2];
-  igraph_real_t parbeta=VECTOR(*par)[3];
-  igraph_real_t parscale=VECTOR(*par)[4];
-  igraph_real_t c= cat==0 ? 1.0 : VECTOR(*par)[4+cat];
-
-  igraph_real_t res= age < parscale ? 
-    c * (pow(deg,alpha)+a) * pow(age/parscale, parbeta-1) : 
-    c * (pow(deg,alpha)+a) * pow(age/parscale, -paralpha-1);
-    
-/*   printf("eval at %f %f, %f %f %f %f %f: %f\n", deg, age, */
-/* 	 alpha, a, paralpha, parbeta, parscale, res); */
-
-  return res;
-}
-
-void igraph_i_revolver_ml_ADE_dpareto_df(const igraph_vector_t *var,
-					 const igraph_vector_t *par,
-					 igraph_vector_t *res,
-					 void *extra) {
-  long int cat=(long int) VECTOR(*var)[0];
-  igraph_real_t deg=VECTOR(*var)[1];
-  igraph_real_t age=VECTOR(*var)[2]+1;
-  igraph_real_t alpha=VECTOR(*par)[0];
-  igraph_real_t a=VECTOR(*par)[1];
-  igraph_real_t paralpha=VECTOR(*par)[2];
-  igraph_real_t parbeta=VECTOR(*par)[3];
-  igraph_real_t parscale=VECTOR(*par)[4];
-  igraph_real_t exponent= age < parscale ? parbeta : -paralpha;
-  igraph_real_t p1=pow(deg, alpha);  
-  igraph_real_t p2=pow(age/parscale, exponent-1);
-  igraph_real_t c= cat==0 ? 1.0 : VECTOR(*par)[4+cat];
-  igraph_vector_null(res);
-  VECTOR(*res)[0]= deg == 0 ? 0.0 : c * log(deg)*p1*p2;
-  VECTOR(*res)[1]= c * p2;
-  VECTOR(*res)[2]= age > parscale ? c * (p1+a)*log(age/parscale)*p2 : 0;
-  VECTOR(*res)[3]= age < parscale ? c * (p1+a)*log(age/parscale)*p2 : 0;
-  VECTOR(*res)[4]= c * -(p1+a)*(exponent-1)*pow(age/parscale, exponent-2)*
-    age/parscale/parscale;
-  VECTOR(*res)[4+cat] = (p1+a) * p2;
-/*   printf("deriv at %f %f, %f %f %f %f %f: %f %f %f %f %f\n", deg, age, */
-/* 	 alpha, a, paralpha, parbeta, parscale, */
-/* 	 VECTOR(*res)[0], VECTOR(*res)[1], VECTOR(*res)[2], VECTOR(*res)[3], */
-/* 	 VECTOR(*res)[4]); */
-    
-}
-  
-int igraph_revolver_ml_ADE_dpareto_eval(const igraph_t *graph,
-					const igraph_vector_t *cats,
-					igraph_real_t alpha, igraph_real_t a,
-					igraph_real_t paralpha, 
-					igraph_real_t parbeta,
-					igraph_real_t parscale,
-					const igraph_vector_t *coeffs,
-					igraph_real_t *value,
-					igraph_vector_t *deriv,
-					int agebins,
-					const igraph_vector_t *filter) {
-  igraph_vector_t res;
-  int ret, i;
-  igraph_integer_t fncount, grcount;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 5+igraph_vector_size(coeffs));
-  VECTOR(res)[0] = alpha;
-  VECTOR(res)[1] = a;
-  VECTOR(res)[2] = paralpha;
-  VECTOR(res)[3] = parbeta;
-  VECTOR(res)[4] = parscale;
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(res)[5+i] = VECTOR(*coeffs)[i];
-  }
-  
-  ret=igraph_revolver_ml_ADE(graph, cats, &res, value, 0, 0, 0,
-			     igraph_i_revolver_ml_ADE_dpareto_f,
-			     igraph_i_revolver_ml_ADE_dpareto_df,
-			     agebins, filter, &fncount, &grcount, deriv);
-  
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-  return ret;
-}
-
-int igraph_revolver_ml_ADE_dpareto(const igraph_t *graph,
-				   const igraph_vector_t *cats,
-				   igraph_real_t *alpha, igraph_real_t *a,
-				   igraph_real_t *paralpha, igraph_real_t *parbeta,
-				   igraph_real_t *parscale, igraph_vector_t *coeffs,
-				   igraph_real_t *Fmin,
-				   igraph_real_t abstol, igraph_real_t reltol,
-				   int maxit, int agebins, 
-				   const igraph_vector_t *filter,
-				   igraph_integer_t *fncount,
-				   igraph_integer_t *grcount) {
-  igraph_vector_t res;
-  int ret, i;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&res, 5+igraph_vector_size(coeffs));
-  VECTOR(res)[0] = *alpha;
-  VECTOR(res)[1] = *a;
-  VECTOR(res)[2] = *paralpha;
-  VECTOR(res)[3] = *parbeta;
-  VECTOR(res)[4] = *parscale;
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(res)[5+i] = VECTOR(*coeffs)[i];
-  }
-  
-  ret=igraph_revolver_ml_ADE(graph, cats, &res, Fmin, abstol, reltol, maxit,
-			     igraph_i_revolver_ml_ADE_dpareto_f,
-			     igraph_i_revolver_ml_ADE_dpareto_df,
-			     agebins, filter, fncount, grcount, 0);
-  
-  *alpha=VECTOR(res)[0];
-  *a=VECTOR(res)[1];
-  *paralpha=VECTOR(res)[2];
-  *parbeta=VECTOR(res)[3];
-  *parscale=VECTOR(res)[4];
-  for (i=0; i<igraph_vector_size(coeffs); i++) {
-    VECTOR(*coeffs)[i] = VECTOR(res)[5+i];
-  }
-
-  igraph_vector_destroy(&res);
-  IGRAPH_FINALLY_CLEAN(1);
-  return ret;
-}  
-
-void igraph_i_revolver_ml_ADE_dpareto_evalf_free(igraph_vector_ptr_t *p) {
-  long int i, n=igraph_vector_ptr_size(p);
-  for (i=0; i<n; i++) {
-    igraph_array3_t *A=VECTOR(*p)[i];
-    if (A) { 
-      igraph_array3_destroy(A);
-      igraph_Free(A);
-      VECTOR(*p)[i] = 0;
-    }
-  }
-}
-
-int igraph_revolver_ml_ADE_dpareto_evalf(const igraph_t *graph,
-					 const igraph_vector_t *cats,
-					 const igraph_matrix_t *par,
-					 igraph_vector_t *value,
-					 int agebins, 
-					 const igraph_vector_t *filter) {
-  
-  igraph_vector_t S;
-  long int no_of_nodes=igraph_vcount(graph);
-  long int binwidth=no_of_nodes/agebins+1;
-  long int no_of_edges=0;
-  igraph_vector_long_t degree;
-  igraph_vector_ptr_t A_ptr;
-  igraph_vector_t neis;
-  igraph_integer_t pmaxdegree;
-  long int maxdegree;
-  long int nocats=(long int) igraph_vector_max(cats)+1;
-  long int nopar=igraph_matrix_nrow(par);
-  long int c, i, j, t;
-
-  if (filter && igraph_vector_size(filter) != no_of_nodes) {
-    IGRAPH_ERROR("ML ADE dpareto evaf: invalid filter vector size", 
-		 IGRAPH_EINVAL);
-  }
-
-  IGRAPH_CHECK(igraph_maxdegree(graph, &pmaxdegree, igraph_vss_all(), 
-				IGRAPH_IN, /*loops=*/1));
-  maxdegree=pmaxdegree;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_reserve(&neis, maxdegree));
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-
-  IGRAPH_CHECK(igraph_vector_ptr_init(&A_ptr, nopar));
-  IGRAPH_FINALLY(igraph_vector_ptr_destroy, &A_ptr);
-  IGRAPH_FINALLY(igraph_i_revolver_ml_ADE_dpareto_evalf_free, &A_ptr);
-  for (i=0; i<nopar; i++) {
-    igraph_array3_t *A=igraph_Calloc(1, igraph_array3_t);
-    igraph_array3_init(A, nocats, maxdegree+1, agebins);
-    VECTOR(A_ptr)[i] = A;
-  }
-
-  IGRAPH_VECTOR_INIT_FINALLY(&S, nopar);
-  IGRAPH_CHECK(igraph_vector_resize(value, nopar));
-  igraph_vector_null(value);
-
-  for (t=0; t<nopar; t++) {
-    igraph_real_t alpha=MATRIX(*par,t,0);
-    igraph_real_t a=MATRIX(*par,t,1);
-    igraph_real_t paralpha=MATRIX(*par,t,2);
-    igraph_real_t parbeta=MATRIX(*par,t,3);
-    igraph_real_t parscale=MATRIX(*par,t,4);
-    igraph_array3_t *A=VECTOR(A_ptr)[t];
-    for (c=0; c<nocats; c++) {
-      igraph_real_t cc= c==0 ? 1.0 : MATRIX(*par,t,c+4);
-      for (i=0; i<maxdegree+1; i++) {
-	igraph_real_t p1= i==0 ? a : pow(i, alpha)+a;
-	for (j=0; j<agebins; j++) {
-	  igraph_real_t age=j+1;
-	  ARRAY3(*A, c, i, j) = age < parscale ? 
-	    cc * p1 * pow(age/parscale, parbeta-1) :
-	    cc * p1 * pow(age/parscale, -paralpha-1);
-	}
-      }
-    }
-  }    
-
-  for (t=0; t<no_of_nodes; t++) {
-    long int n, nneis, shnode;
-    long int tcat=(long int) VECTOR(*cats)[t];
-    
-    igraph_neighbors(graph, &neis, (igraph_integer_t) t, IGRAPH_OUT);
-    nneis=igraph_vector_size(&neis);
-    
-    if (! filter || VECTOR(*filter)[t]) {
-      
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(neis)[n];
-	long int x=(long int) VECTOR(*cats)[to];
-	long int y=VECTOR(degree)[to];
-	long int z=(t-to)/binwidth;
-	
-	for (i=0; i<nopar; i++) {
-	  igraph_array3_t *A=VECTOR(A_ptr)[i];
-	  VECTOR(*value)[i] -= log(ARRAY3(*A, x, y, z));
-	  VECTOR(*value)[i] += log(VECTOR(S)[i]);
-	}
-	no_of_edges++;
-      }
-    }
-    
-    for (n=0; n<nneis; n++) {
-      long int to=(long int) VECTOR(neis)[n];
-      long int x=(long int) VECTOR(*cats)[to];
-      long int y=VECTOR(degree)[to];
-      long int z=(t-to)/binwidth;
-      
-      VECTOR(degree)[to] += 1;
-      for (i=0; i<nopar; i++) {
-	igraph_array3_t *A=VECTOR(A_ptr)[i];
-	VECTOR(S)[i] += ARRAY3(*A, x, y+1, z);
-	VECTOR(S)[i] -= ARRAY3(*A, x, y, z);
-      }
-    }
-
-    for (i=0; i<nopar; i++) {
-      igraph_array3_t *A=VECTOR(A_ptr)[i];
-      VECTOR(S)[i] += ARRAY3(*A, tcat, 0, 0);
-    }
-    for (j=1, shnode=t-binwidth+1; shnode>=0; j++, shnode-=binwidth) {
-      long int cat=(long int) VECTOR(*cats)[shnode];
-      long int deg=VECTOR(degree)[shnode];
-      for (i=0; i<nopar; i++) {
-	igraph_array3_t *A=VECTOR(A_ptr)[i];
-	VECTOR(S)[i] += ARRAY3(*A, cat, deg, j);
-	VECTOR(S)[i] -= ARRAY3(*A, cat, deg, j-1);
-      }
-    }
-  } /* t < no_of_nodes */
-
-  for (i=0; i<nopar; i++) {
-    VECTOR(*value)[i] /= no_of_edges;
-  }
-
-  igraph_vector_destroy(&S);
-  igraph_i_revolver_ml_ADE_dpareto_evalf_free(&A_ptr);
-  igraph_vector_ptr_destroy(&A_ptr);
-  igraph_vector_long_destroy(&degree);
-  igraph_vector_destroy(&neis);
-  IGRAPH_FINALLY_CLEAN(5);
-  
-  return 0;
-}
-  
-  
-  
-  
-
-/*------------------------------------------------------------------*/
-
-int igraph_revolver_ml_d(const igraph_t *graph,
-			 igraph_integer_t niter,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *cites,
-			 igraph_real_t delta,
-			 const igraph_vector_t *filter,
-			 igraph_real_t *logprob,
-			 igraph_real_t *logmax) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_integer_t imaxdegree;
-  long int maxdegree, actmaxdegree;
-  long int it, t, i;
-  igraph_vector_long_t ptk;
-  igraph_vector_t *mycites, vmycites;
-  igraph_vector_t neis;
-  igraph_vector_long_t degree;
-  igraph_real_t S=0, maxdelta, diff;
-
-  igraph_vector_t vmykernel;
-  igraph_vector_t *kernels[]={ kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_vector_t *fromkernel=kernels[actkernel], 
-    *tokernel=kernels[1-actkernel];
-
-  if (filter && igraph_vector_size(filter) != no_of_nodes) { 
-    IGRAPH_ERROR("ML d evolver: invalid filter vector size", IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &imaxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  maxdegree=imaxdegree;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&ptk, maxdegree+1));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ptk);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&vmykernel, maxdegree+1);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_vector_resize(cites, maxdegree+1));
-    igraph_vector_null(cites);
-    mycites=cites;
-  } else {
-    IGRAPH_VECTOR_INIT_FINALLY(&vmycites, maxdegree+1);
-    mycites=&vmycites;
-  }
-
-  IGRAPH_CHECK(igraph_vector_resize(kernel, maxdegree+1));
-  igraph_vector_fill(kernel, 1);
-
-  IGRAPH_PROGRESS("ML Revolver d", 0, NULL);
-
-  for (it=0; it<niter; it++) {
-    
-    igraph_vector_null(tokernel);
-    igraph_vector_long_null(&ptk);
-    igraph_vector_long_null(&degree);
-    S=0.0;
-    actmaxdegree=0;
-
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-  
-    for (t=0; t<no_of_nodes; t++) {
-      long int n, nneis;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) t, 
-				    IGRAPH_OUT));
-      nneis=igraph_vector_size(&neis);
-
-      IGRAPH_ALLOW_INTERRUPTION();      
-
-      if (!filter || VECTOR(*filter)[t] != 0) {
-	/* Calculate some terms of the sum for the non-zero classes */
-	if (S != 0) {
-	  for (i=0; i<=actmaxdegree; i++) {
-	    VECTOR(*tokernel)[i] += nneis * VECTOR(ptk)[i] / S;
-	  }
-	  
-	  if (logprob || logmax || it==0) {
-	    for (n=0; n<nneis; n++) {
-	      long int to=(long int) VECTOR(neis)[n];
-	      long int x=VECTOR(degree)[to];
-	      if (logprob) { *logprob += log( VECTOR(*fromkernel)[x] / S ); }
-	      if (logmax) { *logmax += log(1.0/t); }
-	      
-	      if (it==0) {
-		VECTOR(*mycites)[x] += 1;
-	      }
-	    }
-	  }
-	}
-      }
-      
-      /* Update ptk for the next time step */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(neis)[n];
-	long int x=VECTOR(degree)[to];
-
-	VECTOR(degree)[to] += 1;
-	if (x==actmaxdegree) { actmaxdegree++; }
-
-	VECTOR(ptk)[x+1] += 1;
-	VECTOR(ptk)[x] -= 1;
-	S += VECTOR(*fromkernel)[x+1];
-	S -= VECTOR(*fromkernel)[x];
-      		
-      }
-      VECTOR(ptk)[0] += 1;
-      S += VECTOR(*fromkernel)[0];
-
-    } /* t<no_of_nodes  */
-    
-    /* final step, Mk/sum */
-    maxdelta=0.0;
-    for (i=0; i<=maxdegree; i++) {
-      if (VECTOR(*tokernel)[i] != 0) {
-	VECTOR(*tokernel)[i] = VECTOR(*mycites)[i] / VECTOR(*tokernel)[i];      
-	if ( (diff=fabs(VECTOR(*tokernel)[i] - VECTOR(*fromkernel)[i])) > maxdelta) {
-	  maxdelta=diff;
-	}
-      }
-    }
-    if (maxdelta < delta) { break; }
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-
-    IGRAPH_PROGRESS("ML Revolver d", 100*(it+1)/niter, NULL);
-
-  } /* it<niter */
-
-  /* switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_vector_clear(kernel);
-    igraph_vector_append(kernel, fromkernel);
-  }
-  VECTOR(*kernel)[maxdegree]=IGRAPH_NAN;
-
-  if (!cites) {
-    igraph_vector_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  igraph_vector_destroy(&vmykernel);
-  igraph_vector_long_destroy(&degree);
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&ptk);
-  IGRAPH_FINALLY_CLEAN(4);
-  return 0;
-}
-			 
-int igraph_random_permutation(igraph_vector_t *v) {
-  long int i, j, n=igraph_vector_size(v);
-  igraph_real_t tmp;
-  for (i=0; i<n; i++) {
-    VECTOR(*v)[i]=i;
-  }
-  for (i=n-1; i>=0; i--) {
-    j=RNG_INTEGER(0,i);
-    tmp=VECTOR(*v)[i];
-    VECTOR(*v)[i] = VECTOR(*v)[j];
-    VECTOR(*v)[j] = tmp;
-  }
-  return 0;
-}
-
-int igraph_revolver_ml_f(const igraph_t *graph,
-			 igraph_integer_t niter,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *cites,
-			 igraph_real_t delta,
-			 igraph_real_t *logprob,
-			 igraph_real_t *logmax) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int it, t;
-  igraph_vector_long_t ptk;
-  igraph_vector_t *mycites, vmycites;
-  igraph_vector_int_t *neis, *neis2;
-  igraph_adjlist_t outadjlist, inadjlist;
-  igraph_vector_long_t marked;
-  
-  igraph_vector_t vmykernel;
-  igraph_vector_t *kernels[]={ kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_vector_t *fromkernel=kernels[actkernel], 
-    *tokernel=kernels[1-actkernel];
-  
-  igraph_vector_t perm;
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&perm, 0);
-  IGRAPH_CHECK(igraph_vector_reserve(&perm, no_of_nodes));
-
-  IGRAPH_CHECK(igraph_vector_long_init(&ptk, 2));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ptk);
-
-  IGRAPH_CHECK(igraph_adjlist_init(graph, &outadjlist, IGRAPH_OUT));
-  IGRAPH_FINALLY(igraph_adjlist_destroy, &outadjlist);
-  IGRAPH_CHECK(igraph_adjlist_init(graph, &inadjlist, IGRAPH_IN));
-  IGRAPH_FINALLY(igraph_adjlist_destroy, &inadjlist);
-
-  IGRAPH_VECTOR_INIT_FINALLY(&vmykernel, 2);
-  IGRAPH_CHECK(igraph_vector_long_init(&marked, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &marked);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_vector_resize(cites, 2));
-    igraph_vector_null(cites);
-    mycites=cites;
-  } else { 
-    IGRAPH_VECTOR_INIT_FINALLY(&vmycites, 2);
-    mycites=&vmycites;
-  }
-  
-  IGRAPH_CHECK(igraph_vector_resize(kernel, 2));
-  igraph_vector_fill(kernel, 1);
-  
-  IGRAPH_PROGRESS("ML revolver f", 0, NULL);
-
-  RNG_BEGIN();
-  
-  for (it=0; it<niter; it++) {
-    
-    igraph_vector_null(tokernel);
-    igraph_vector_long_null(&ptk);
-    igraph_vector_long_null(&marked);
-
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-
-    for (t=0; t<no_of_nodes; t++) {
-      long int nneis, e;
-      neis=igraph_adjlist_get(&outadjlist, t);
-      nneis=igraph_vector_int_size(neis);
-      igraph_vector_resize(&perm, nneis);
-      igraph_random_permutation(&perm);
-      
-      IGRAPH_ALLOW_INTERRUPTION();
-      
-      VECTOR(ptk)[0]=t;
-      VECTOR(ptk)[1]=0;
-      for (e=0; e<nneis; e++) {
-	long int nneis2, j;
-	long int which=(long int) VECTOR(perm)[e];
-	long int to=(long int) VECTOR(*neis)[which];
-	long int x= VECTOR(marked)[to] != t+1 ? 0 : 1;
-	
-	if (e != 0) {
-	  igraph_real_t S=VECTOR(ptk)[0] * VECTOR(*fromkernel)[0] +
-	    VECTOR(ptk)[1] * VECTOR(*fromkernel)[1];
-	  VECTOR(*tokernel)[0] += VECTOR(ptk)[0] / S;
-	  VECTOR(*tokernel)[1] += VECTOR(ptk)[1] / S;
-	  
-	  if (it==0) {
-	    VECTOR(*mycites)[x] += 1;
-	  }
-
-	  if (logprob) { *logprob += log( VECTOR(*fromkernel)[x] / S ); }
-	  if (logmax) { *logmax += log(1.0/t); }
-
-	} else {
-	  if (logprob) { *logprob += log(1.0/t); }
-	  if (logmax) { *logmax += log(1.0/t); }
-	}
-
- 	VECTOR(ptk)[x] -= 1;
-	VECTOR(marked)[to]=t+1;
-
-	/* Update ptk, check the neighbors of 'to' */
-	neis2=igraph_adjlist_get(&inadjlist, to);
-	nneis2=igraph_vector_int_size(neis2);
-	for (j=0; j<nneis2; j++) {
-	  long int nei=(long int) VECTOR(*neis2)[j];
-	  if (nei >= t) { break; }
-	  if (VECTOR(marked)[nei] != t+1) {
-	    VECTOR(marked)[nei] = t+1;
-	    VECTOR(ptk)[0] -= 1;
-	    VECTOR(ptk)[1] += 1;
-	  }
-	}
-	neis2=igraph_adjlist_get(&outadjlist, to);
-	nneis2=igraph_vector_int_size(neis2);
-	for (j=0; j<nneis2; j++) {
-	  long int nei=(long int) VECTOR(*neis2)[j];
-	  if (VECTOR(marked)[nei] != t+1) {
-	    VECTOR(marked)[nei] = t+1;
-	    VECTOR(ptk)[0] -= 1;
-	    VECTOR(ptk)[1] += 1;
-	  }
-	}
-	
-      }
-    }
-      
-    /* Mk/sum */
-    VECTOR(*tokernel)[0] = VECTOR(*mycites)[0] / VECTOR(*tokernel)[0];
-    VECTOR(*tokernel)[1] = VECTOR(*mycites)[1] / VECTOR(*tokernel)[1];
-    
-/*     VECTOR(*tokernel)[1] /= VECTOR(*tokernel)[0]; */
-/*     VECTOR(*tokernel)[0] = 1.0; */
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-
-    IGRAPH_PROGRESS("ML Revolver f", 100*(it+1)/niter, NULL);
-    
-  } /* it<niter */
-
-  RNG_END();
-  
-  /* switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_vector_clear(kernel);
-    igraph_vector_append(kernel, fromkernel);
-  }
-
-  if (!cites) {
-    igraph_vector_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-
-  igraph_vector_long_destroy(&marked);
-  igraph_vector_destroy(&vmykernel);
-  igraph_adjlist_destroy(&inadjlist);
-  igraph_adjlist_destroy(&outadjlist);
-  igraph_vector_long_destroy(&ptk);
-  igraph_vector_destroy(&perm);
-  IGRAPH_FINALLY_CLEAN(6);
-  return 0;
-}
-
-int igraph_revolver_ml_df(const igraph_t *graph,
-			  igraph_integer_t niter,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *cites,
-			  igraph_real_t delta,
-			  igraph_real_t *logprob,
-			  igraph_real_t *logmax) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int it, t, i;
-  igraph_matrix_long_t ptk;
-  igraph_matrix_t *mycites, vmycites;
-  igraph_vector_int_t *neis, *neis2;
-  igraph_adjlist_t outadjlist, inadjlist;
-  igraph_vector_long_t marked;
-  igraph_integer_t imaxdegree, omaxdegree;
-  long int maxdegree;
-  igraph_vector_long_t degree;
-  igraph_real_t S1, S2, S3;
-  long int actmaxdegree;
-  
-  igraph_matrix_t vmykernel;
-  igraph_matrix_t *kernels[] = { kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_matrix_t *fromkernel=kernels[actkernel],
-    *tokernel=kernels[1-actkernel];
-
-  igraph_stack_t stack;
-  igraph_vector_t perm;
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &imaxdegree, igraph_vss_all(), 
-				IGRAPH_IN, IGRAPH_LOOPS));
-  IGRAPH_CHECK(igraph_maxdegree(graph, &omaxdegree, igraph_vss_all(),
-				IGRAPH_OUT, IGRAPH_LOOPS));
-  maxdegree=imaxdegree;
-
-  IGRAPH_VECTOR_INIT_FINALLY(&perm, omaxdegree);
-
-  IGRAPH_CHECK(igraph_stack_init(&stack, maxdegree * maxdegree > no_of_nodes ?
-				      no_of_nodes : maxdegree * maxdegree));
-  IGRAPH_FINALLY(igraph_stack_destroy, &stack);
-
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-
-  IGRAPH_CHECK(igraph_matrix_long_init(&ptk, 2, maxdegree+1));
-  IGRAPH_FINALLY(igraph_matrix_long_destroy, &ptk);
-  
-  IGRAPH_CHECK(igraph_adjlist_init(graph, &outadjlist, IGRAPH_OUT));
-  IGRAPH_FINALLY(igraph_adjlist_destroy, &outadjlist);
-  IGRAPH_CHECK(igraph_adjlist_init(graph, &inadjlist, IGRAPH_IN));
-  IGRAPH_FINALLY(igraph_adjlist_destroy, &inadjlist);
-  
-  IGRAPH_MATRIX_INIT_FINALLY(&vmykernel, 3, maxdegree+1);
-  IGRAPH_CHECK(igraph_vector_long_init(&marked, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &marked);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_matrix_resize(cites, 3, maxdegree+1));
-    igraph_matrix_null(cites);
-    mycites=cites;
-  } else {
-    IGRAPH_MATRIX_INIT_FINALLY(&vmycites, 3, maxdegree+1);
-    mycites=&vmycites;
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, 3, maxdegree+1));
-  igraph_matrix_fill(kernel, 1);
-  
-  IGRAPH_PROGRESS("ML revolver df", 0, NULL);
-
-  RNG_BEGIN();
-  
-  for (it=0; it<niter; it++) {
-    
-    igraph_matrix_null(tokernel);
-    igraph_matrix_long_null(&ptk);
-    igraph_vector_long_null(&marked);
-    igraph_vector_long_null(&degree);
-    S1=0; S2=0; S3=0;
-    actmaxdegree=0;
-    
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-    
-    for (t=0; t<no_of_nodes; t++) {
-      long int nneis, e;
-      neis=igraph_adjlist_get(&outadjlist, t);
-      nneis=igraph_vector_int_size(neis);
-      igraph_vector_resize(&perm, nneis);
-      igraph_random_permutation(&perm);
-      
-      IGRAPH_ALLOW_INTERRUPTION();
-
-      /* Restore ptk */
-      while (! igraph_stack_empty(&stack)) {
-	long int deg=(long int) igraph_stack_pop(&stack);
-	if (deg > 0) {
-	  MATRIX(ptk, 0, deg-1) += 1;
-	  MATRIX(ptk, 1, deg-1) = 0;
-	} else {
-	  MATRIX(ptk, 0, -deg-1) -= 1;
-	  MATRIX(ptk, 1, -deg-1) = 0;
-	}
-      }
-      S2=S3;
-      
-      for (e=0; e<nneis; e++) {
-	long int nneis2, i, j;
-	long int which=(long int) VECTOR(perm)[e];
-	long int to=(long int) VECTOR(*neis)[which];
-	long int x=VECTOR(marked)[to] != t+1 ? 0 : 1;
-	long int y=VECTOR(degree)[to];
-		  
-	if (e == 0) {
-	  /* First citation */
-	  for (i=0; i<=actmaxdegree; i++) {
-	    MATRIX(*tokernel, 0, i) += MATRIX(ptk, 0, i) / S1;
-	  }
-	  
-	  if (it==0) {
-	    MATRIX(*mycites, 0, y) += 1;
-	  }
-	  
-	  if (logprob && MATRIX(*fromkernel, 0, y) != 0) { 
-	    *logprob += log( MATRIX(*fromkernel, 0, y) / S1); 
-	  }
-	  if (logmax) { *logmax += log(1.0 / t); }
-	  
-	} else {
-	  /* Subsequent citations */
-	  for (i=0; i<=actmaxdegree; i++) {
-	    MATRIX(*tokernel, 1, i) += MATRIX(ptk, 0, i) / S2;
-	    MATRIX(*tokernel, 2, i) += MATRIX(ptk, 1, i) / S2;
-	  }
-	  
-	  if (it==0) {
-	    MATRIX(*mycites, x+1, y) += 1;
-	  }
-
-	  if (logprob && MATRIX(*fromkernel, x+1, y) != 0) { 
-	    *logprob += log( MATRIX(*fromkernel, x+1, y) / S2 ); 
-	  }
-	  if (logmax) { *logmax += log(1.0/t); }
-	}
-
-	/* update ptk */
-	VECTOR(marked)[to]=t+1;
-	VECTOR(degree)[to] += 1;
-	if (VECTOR(degree)[to] > actmaxdegree) { actmaxdegree ++; }
-	MATRIX(ptk, x, y) -= 1; /* won't be cited again by this vertex */
-	S1 -= MATRIX(*fromkernel, 0, y);
-	S1 += MATRIX(*fromkernel, 0, y+1);
-	S3 -= MATRIX(*fromkernel, 1, y);
-	S3 += MATRIX(*fromkernel, 1, y+1);
-	S2 -= MATRIX(*fromkernel, x+1, y);
-	if (x==0) {
-	  igraph_stack_push(&stack, y+2);
-	} else {
-	  igraph_stack_push(&stack, -y-1);
-	  igraph_stack_push(&stack, y+2);
-	}
-	
-	/* neighbors of 'to' */
-	neis2=igraph_adjlist_get(&inadjlist, to);
-	nneis2=igraph_vector_int_size(neis2);
-	for (j=0; j<nneis2; j++) {
-	  long int nei=(long int) VECTOR(*neis2)[j];
-	  if (nei >= t) { break; }
-	  if (VECTOR(marked)[nei] != t+1) {
-	    long int neideg=VECTOR(degree)[nei];
-	    VECTOR(marked)[nei] = t+1;
-	    MATRIX(ptk, 0, neideg) -= 1;
-	    MATRIX(ptk, 1, neideg) += 1;
-	    S2 -= MATRIX(*fromkernel, 1, neideg) - MATRIX(*fromkernel, 2, neideg);
-	    igraph_stack_push(&stack, neideg+1);
-	  }
-	}
-	neis2=igraph_adjlist_get(&outadjlist, to);
-	nneis2=igraph_vector_int_size(neis2);
-	for (j=0; j<nneis2; j++) {
-	  long int nei=(long int) VECTOR(*neis2)[j];
-	  if (VECTOR(marked)[nei] != t+1) {
-	    long int neideg=VECTOR(degree)[nei];
-	    VECTOR(marked)[nei] = t+1;
-	    MATRIX(ptk, 0, neideg) -= 1;
-	    MATRIX(ptk, 1, neideg) += 1;
-	    S2 -= MATRIX(*fromkernel, 1, neideg) - MATRIX(*fromkernel, 2, neideg);
-	    igraph_stack_push(&stack, neideg+1);
-	  }
-	}
-	
-      }	/* e < nneis */
-      
-      S1 += MATRIX(*fromkernel, 0, 0);
-      S3 += MATRIX(*fromkernel, 1, 0);
-      MATRIX(ptk, 0, 0) += 1;
-      
-    } /* t < no_of_nodes */
-
-    /* Mk/sum */
-    for (i=0; i<maxdegree+1; i++) {
-      if (MATRIX(*tokernel, 0, i) != 0) {
-	MATRIX(*tokernel, 0, i) = MATRIX(*mycites, 0, i) / MATRIX(*tokernel, 0, i);
-      }
-      if (MATRIX(*tokernel, 1, i) != 0) {
-	MATRIX(*tokernel, 1, i) = MATRIX(*mycites, 1, i) / MATRIX(*tokernel, 1, i);
-      }
-      if (MATRIX(*tokernel, 2, i) != 0) {
-	MATRIX(*tokernel, 2, i) = MATRIX(*mycites, 2, i) / MATRIX(*tokernel, 2, i);
-      }
-    }
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-    
-    IGRAPH_PROGRESS("ML Revolver df", 100*(it+1)/niter, NULL);
-    
-  } /* it < niter */
-
-  RNG_END();
-
-  /* switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_matrix_update(kernel, fromkernel);
-  }
-  if (!cites) {
-    igraph_matrix_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-
-  igraph_vector_long_destroy(&marked);
-  igraph_matrix_destroy(&vmykernel);
-  igraph_adjlist_destroy(&inadjlist);
-  igraph_adjlist_destroy(&outadjlist);
-  igraph_matrix_long_destroy(&ptk);
-  igraph_vector_long_destroy(&degree);
-  igraph_stack_destroy(&stack);
-  igraph_vector_destroy(&perm);
-  IGRAPH_FINALLY_CLEAN(8);
-  
-  return 0;
-}
-
-int igraph_revolver_ml_ad(const igraph_t *graph,
-			  igraph_integer_t niter,
-			  igraph_matrix_t *kernel,
-			  igraph_matrix_t *cites,
-			  igraph_integer_t pagebins,
-			  igraph_real_t delta,
-			  const igraph_vector_t *filter,
-			  igraph_real_t *logprob,
-			  igraph_real_t *logmax) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_integer_t imaxdegree;
-  long int maxdegree, actmaxdegree;
-  long int it, t, i, j;
-  igraph_matrix_long_t ptk;
-  igraph_matrix_t *mycites, vmycites;
-  igraph_vector_t neis;
-  igraph_vector_long_t degree;
-  igraph_real_t S=0, maxdelta, diff;
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_matrix_t vmykernel;
-  igraph_matrix_t *kernels[]= { kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_matrix_t *fromkernel=kernels[actkernel],
-    *tokernel=kernels[1-actkernel];
-
-  if (filter && igraph_vector_size(filter) != no_of_nodes) {
-    IGRAPH_ERROR("ML ad revolver: invalid filter vector size", IGRAPH_EINVAL);
-  }
-
-  IGRAPH_CHECK(igraph_maxdegree(graph, &imaxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  maxdegree=imaxdegree;
-  
-  IGRAPH_CHECK(igraph_matrix_long_init(&ptk, maxdegree+1, agebins));
-  IGRAPH_FINALLY(igraph_matrix_long_destroy, &ptk);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_CHECK(igraph_matrix_init(&vmykernel, maxdegree+1, agebins));
-  IGRAPH_FINALLY(igraph_matrix_destroy, &vmykernel);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_matrix_resize(cites, maxdegree+1, agebins));
-    igraph_matrix_null(cites);
-    mycites=cites;
-  } else {
-    IGRAPH_CHECK(igraph_matrix_init(&vmycites, maxdegree+1, agebins));
-    IGRAPH_FINALLY(igraph_matrix_destroy, &vmycites);
-    mycites=&vmycites;
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, maxdegree+1, agebins));
-  igraph_matrix_fill(kernel, 1);
-  
-  IGRAPH_PROGRESS("ML Revolver ad", 0, NULL);
-  
-  for (it=0; it<niter; it++) {
-   
-    igraph_matrix_null(tokernel);
-    igraph_matrix_long_null(&ptk);
-    igraph_vector_long_null(&degree);
-    S=0.0;
-    actmaxdegree=0;
-    
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-    
-    for (t=0; t<no_of_nodes; t++) {
-      long int n, nneis;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) t, 
-				    IGRAPH_OUT));
-      nneis=igraph_vector_size(&neis);
-      
-      IGRAPH_ALLOW_INTERRUPTION();
-      
-      if (!filter || VECTOR(*filter)[t] != 0) {
-      
-	/* Calculate some terms of the sum for the non-zero classes */
-	if (S != 0) {
-	  for (i=0; i<=actmaxdegree; i++) {
-	    for (j=0; j<=t/binwidth; j++) {
-	      MATRIX(*tokernel, i, j) += nneis * MATRIX(ptk, i, j) / S;
-	    }
-	  }
-	}
-	
-	if (logprob || logmax || it==0) {
-	  for (n=0; n<nneis; n++) {
-	    long int to=(long int) VECTOR(neis)[n];
-	    long int x=VECTOR(degree)[to];
-	    long int y=(t-to)/binwidth;
-	    if (logprob) { *logprob += log( MATRIX(*fromkernel,x,y) / S ); }
-	    if (logmax) { *logmax += log(1.0/t); }
-	    if (it==0) {
-	      MATRIX(*mycites, x, y) += 1;
-	    }
-	  }
-	}
-      }
-
-      /* Update ptk for the next time step */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(neis)[n];
-	long int x=VECTOR(degree)[to];
-	long int y=(t-to)/binwidth;
-
-	VECTOR(degree)[to] += 1;
-	if (x==actmaxdegree) { actmaxdegree++; }
-	
-	MATRIX(ptk, x+1, y) += 1;
-	MATRIX(ptk, x, y) -= 1;
-	S += MATRIX(*fromkernel, x+1, y);
-	S -= MATRIX(*fromkernel, x, y);
-	
-      }
-      /* Aging */
-      for (j=1; t-binwidth*j+1>=0; j++) {
-	long int shnode=t-binwidth*j+1;
-	long int deg=VECTOR(degree)[shnode];
-	MATRIX(ptk, deg, j) += 1;
-	MATRIX(ptk, deg, j-1) -= 1;
-	S += MATRIX(*fromkernel, deg, j);
-	S -= MATRIX(*fromkernel, deg, j-1);
-      }
-      MATRIX(ptk, 0, 0) += 1;
-      S += MATRIX(*fromkernel, 0, 0);
-      
-    } /* t < no_of_nodes */
-    
-    /* Mk/sum */
-    maxdelta=0.0;
-    for (i=0; i<=maxdegree; i++) {
-      for (j=0; j<agebins; j++) {
-	MATRIX(*tokernel, i, j) = MATRIX(*mycites, i, j) / MATRIX(*tokernel, i, j);
-	if ( (diff=fabs(MATRIX(*tokernel,i,j) - MATRIX(*fromkernel,i,j))) > maxdelta){
-	  maxdelta=diff;
-	}
-      }
-    }
-    if (maxdelta < delta) { break; }
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-
-    IGRAPH_PROGRESS("ML Revolver d", 100*(it+1)/niter, NULL);
-
-  } /* it<niter */
-
-  /* switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_matrix_update(kernel, fromkernel);
-  }
-
-  if (!cites) {
-    igraph_matrix_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  igraph_matrix_destroy(&vmykernel);
-  igraph_vector_long_destroy(&degree);
-  igraph_vector_destroy(&neis);
-  igraph_matrix_long_destroy(&ptk);
-  IGRAPH_FINALLY_CLEAN(4);
-  
-  return 0;
-}
-
-int igraph_revolver_ml_de(const igraph_t *graph,
-			  igraph_integer_t niter,
-			  igraph_matrix_t *kernel,
-			  const igraph_vector_t *cats,
-			  igraph_matrix_t *cites,
-			  igraph_real_t delta,
-			  const igraph_vector_t *filter,
-			  igraph_real_t *logprob,
-			  igraph_real_t *logmax) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_integer_t imaxdegree;
-  long int maxdegree, actmaxdegree;
-  long int it, t, i, j;
-  igraph_matrix_long_t ptk;
-  igraph_matrix_t *mycites, vmycites;
-  igraph_vector_t neis;
-  igraph_vector_long_t degree;
-  igraph_real_t S=0, maxdelta, diff;
-  long int no_cats=(long int) igraph_vector_max(cats)+1;
-  
-  igraph_matrix_t vmykernel;
-  igraph_matrix_t *kernels[] = { kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_matrix_t *fromkernel=kernels[actkernel],
-    *tokernel=kernels[1-actkernel];
-
-  if (filter && igraph_vector_size(filter) != no_of_nodes) {
-    IGRAPH_ERROR("ML de evolver failed", IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &imaxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  maxdegree=imaxdegree;
-  
-  IGRAPH_CHECK(igraph_matrix_long_init(&ptk, no_cats, maxdegree+1));
-  IGRAPH_FINALLY(igraph_matrix_long_destroy, &ptk);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_MATRIX_INIT_FINALLY(&vmykernel, no_cats, maxdegree+1);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_matrix_resize(cites, no_cats, maxdegree+1));
-    igraph_matrix_null(cites);
-    mycites=cites;
-  } else {
-    IGRAPH_MATRIX_INIT_FINALLY(&vmycites, no_cats, maxdegree+1);
-    mycites=&vmycites;
-  }
-  
-  IGRAPH_CHECK(igraph_matrix_resize(kernel, no_cats, maxdegree+1));
-  igraph_matrix_fill(kernel, 1);
-  
-  for (it=0; it<niter; it++) {
-    
-    igraph_matrix_null(tokernel);
-    igraph_matrix_long_null(&ptk);
-    igraph_vector_long_null(&degree);
-    S=0.0;
-    actmaxdegree=0;
-    
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-    
-    for (t=0; t<no_of_nodes; t++) {
-      long int n, nneis;
-      long int fromcat=(long int) VECTOR(*cats)[t];
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) t,
-				    IGRAPH_OUT));
-      nneis=igraph_vector_size(&neis);
-      
-      IGRAPH_ALLOW_INTERRUPTION();
-
-      if (!filter || VECTOR(*filter)[t] != 0) {
-      
-	if (S != 0) {
-	  for (i=0; i<no_cats; i++) {
-	    for (j=0; j<=actmaxdegree; j++) {
-	      MATRIX(*tokernel, i, j) += nneis * MATRIX(ptk, i, j) / S;
-	    }
-	  }
-	  
-	  if (logprob || logmax || it==0) {
-	    for (n=0; n<nneis; n++) {
-	      long int to=(long int) VECTOR(neis)[n];
-	      long int x=(long int) VECTOR(*cats)[to];
-	      long int y=VECTOR(degree)[to];
-	      if (logprob) { *logprob += log( MATRIX(*fromkernel,x,y) / S); }
-	      if (logmax) { *logmax += log(1.0/t); }
-	      if (it==0) {
-		MATRIX(*mycites, x, y) += 1;
-	      }
-	    }
-	  }
-	}
-
-      }
-	
-      /* Update ptk for the next time step */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(neis)[n];
-	long int x=(long int) VECTOR(*cats)[to];
-	long int y=VECTOR(degree)[to];
-	
-	VECTOR(degree)[to] += 1;
-	if (y==actmaxdegree) { actmaxdegree++; }
-	
-	MATRIX(ptk, x, y+1) += 1;
-	MATRIX(ptk, x, y) -= 1;
-	S += MATRIX(*fromkernel, x, y+1);
-	S -= MATRIX(*fromkernel, x, y);
-	
-      }
-      
-      MATRIX(ptk, fromcat, 0) += 1;
-      S += MATRIX(*fromkernel, fromcat, 0);
-      
-    } /* t < no_of_nodes */
-  
-    /* Mk/sum */
-    maxdelta=0.0;
-    for (i=0; i<no_cats; i++) {
-      for (j=0; j<=maxdegree; j++) {
-	if (MATRIX(*tokernel, i, j) != 0) {
-	  MATRIX(*tokernel, i, j) = MATRIX(*mycites, i, j) / MATRIX(*tokernel, i, j);
-	  if ( (diff=fabs(MATRIX(*tokernel,i,j)-MATRIX(*fromkernel,i,j))) > maxdelta) {
-	    maxdelta=diff;
-	  }
-	}
-      }
-    }
-    if (maxdelta < delta) { break; }
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-    
-    IGRAPH_PROGRESS("ML Revolver de", 100*(it+1)/niter, NULL);
-    
-  } /* it<niter */
-
-  /* switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_matrix_update(kernel, fromkernel);
-  }
-  
-  if (!cites) {
-    igraph_matrix_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  igraph_matrix_destroy(&vmykernel);
-  igraph_vector_long_destroy(&degree);
-  igraph_vector_destroy(&neis);
-  igraph_matrix_long_destroy(&ptk);
-  IGRAPH_FINALLY_CLEAN(4);
-
-  return 0;
-}
-
-int igraph_revolver_ml_ade(const igraph_t *graph,
-			   igraph_integer_t niter,
-			   igraph_array3_t *kernel,
-			   const igraph_vector_t *cats,
-			   igraph_array3_t *cites,
-			   igraph_integer_t pagebins,
-			   igraph_real_t delta,
-			   const igraph_vector_t *filter,
-			   igraph_real_t *logprob,
-			   igraph_real_t *logmax) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  igraph_integer_t imaxdegree;
-  long int maxdegree, actmaxdegree;
-  long int it, t, i, j, k;
-  igraph_array3_long_t ptk;
-  igraph_array3_t *mycites, vmycites;
-  igraph_vector_t neis;
-  igraph_vector_long_t degree;
-  igraph_real_t S=0, maxdelta, diff;
-  long int no_cats=(long int) igraph_vector_max(cats)+1;
-
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  igraph_array3_t vmykernel;
-  igraph_array3_t *kernels[]= { kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_array3_t *fromkernel=kernels[actkernel],
-    *tokernel=kernels[1-actkernel];
-
-  if (filter && igraph_vector_size(filter) != no_of_nodes) {
-    IGRAPH_ERROR("ML ade revolver: invalid filter vector size", IGRAPH_EINVAL);
-  }
-  
-  IGRAPH_CHECK(igraph_maxdegree(graph, &imaxdegree, igraph_vss_all(),
-				IGRAPH_IN, IGRAPH_LOOPS));
-  maxdegree=imaxdegree;
-  
-  IGRAPH_CHECK(igraph_array3_long_init(&ptk, no_cats, maxdegree+1, agebins));
-  IGRAPH_FINALLY(igraph_array3_long_destroy, &ptk);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_CHECK(igraph_array3_init(&vmykernel, no_cats, maxdegree+1, agebins));
-  IGRAPH_FINALLY(igraph_matrix_destroy, &vmykernel);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_array3_resize(cites, no_cats, maxdegree+1, agebins));
-    igraph_array3_null(cites);
-    mycites=cites;
-  } else {
-    IGRAPH_CHECK(igraph_array3_init(&vmycites, no_cats, maxdegree+1, agebins));
-    IGRAPH_FINALLY(igraph_array3_destroy, &vmycites);
-    mycites=&vmycites;
-  }
-
-  IGRAPH_CHECK(igraph_array3_resize(kernel, no_cats, maxdegree+1, agebins));
-  igraph_array3_fill(kernel, 1);
-  
-  IGRAPH_PROGRESS("ML Revolver ade", 0, NULL);
-  
-  for (it=0; it<niter; it++) {
-    
-    igraph_array3_null(tokernel);
-    igraph_array3_long_null(&ptk);
-    igraph_vector_long_null(&degree);
-    S=0.0;
-    actmaxdegree=0;
-    
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-
-    for (t=0; t<no_of_nodes; t++) {
-      long int n, nneis;
-      long int tcat=(long int) VECTOR(*cats)[t];
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) t,
-				    IGRAPH_OUT));
-      nneis=igraph_vector_size(&neis);
-      
-      IGRAPH_ALLOW_INTERRUPTION();
-
-      if (!filter || VECTOR(*filter)[t] != 0) {
-	
-	/* Calculate some terms of the sum for the non-zero classes */
-	if (S != 0) {
-	  for (i=0; i<no_cats; i++) {
-	    for (j=0; j<=actmaxdegree; j++) {
-	      for (k=0; k<=t/binwidth; k++) {
-		ARRAY3(*tokernel, i, j, k) += nneis * ARRAY3(ptk, i, j, k) / S;
-	      }
-	    }
-	  }
-	  
-	  if (logprob || logmax || it==0) {
-	    for (n=0; n<nneis; n++) {
-	      long int to=(long int) VECTOR(neis)[n];
-	      long int x=(long int) VECTOR(*cats)[to];
-	      long int y=VECTOR(degree)[to];
-	      long int z=(t-to)/binwidth;
-	      if (logprob) { *logprob += log( ARRAY3(*fromkernel, x,y,z) / S); }
-	      if (logmax) { *logmax += log(1.0/t); }
-	      if (it==0) {
-		ARRAY3(*mycites, x, y, z) += 1;
-	      }
-	    }
-	  }
-	}
-      }
-      
-      /* update ptk for the next time step */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(neis)[n];
-	long int x=(long int) VECTOR(*cats)[to];
-	long int y=VECTOR(degree)[to];
-	long int z=(t-to)/binwidth;
-	
-	VECTOR(degree)[to] += 1;
-	if (y==actmaxdegree) { actmaxdegree++; }
-	
-	ARRAY3(ptk, x, y+1, z) += 1;
-	ARRAY3(ptk, x, y, z) -= 1;
-	S += ARRAY3(*fromkernel, x, y+1, z);
-	S -= ARRAY3(*fromkernel, x, y, z);
-	
-      }
-      /* Aging */
-      for (j=1; t-binwidth*j+1>=0; j++) {
-	long int shnode=t-binwidth*j+1;
-	long int cat=(long int) VECTOR(*cats)[shnode];
-	long int deg=VECTOR(degree)[shnode];
-	ARRAY3(ptk, cat, deg, j) += 1;
-	ARRAY3(ptk, cat, deg, j-1) -= 1;
-	S += ARRAY3(*fromkernel, cat, deg, j);
-	S -= ARRAY3(*fromkernel, cat, deg, j-1);
-      }
-      ARRAY3(ptk, tcat, 0, 0) += 1;
-      S += ARRAY3(*fromkernel, tcat, 0, 0);
-      
-    } /* t < no_of_nodes */
-
-    /* Mk/sum */
-    maxdelta=0.0;
-    for (i=0; i<no_cats; i++) {
-      for (j=0; j<=maxdegree; j++) {
-	for (k=0; k<agebins; k++) {
-	  ARRAY3(*tokernel,i,j,k) = ARRAY3(*mycites,i,j,k) / ARRAY3(*tokernel,i,j,k);
-	  if ( (diff=fabs(ARRAY3(*tokernel,i,j,k)-ARRAY3(*fromkernel,i,j,k))) > 
-	       maxdelta) {
-	    maxdelta=diff;
-	  }
-	}
-      }
-    }
-    if (maxdelta < delta) { break; }
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-
-    IGRAPH_PROGRESS("ML Revolver d", 100*(it+1)/niter, NULL);
-
-  } /* it<niter */
-
-  /* switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_array3_update(kernel, fromkernel);
-  }
-
-  if (!cites) {
-    igraph_array3_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  igraph_array3_destroy(&vmykernel);
-  igraph_vector_long_destroy(&degree);
-  igraph_vector_destroy(&neis);
-  igraph_array3_long_destroy(&ptk);
-  IGRAPH_FINALLY_CLEAN(4);
-  
-  return 0;
-}	   
-
-int igraph_revolver_ml_l(const igraph_t *graph,
-			 igraph_integer_t niter,
-			 igraph_vector_t *kernel,
-			 igraph_vector_t *cites,
-			 igraph_integer_t pagebins,
-			 igraph_real_t delta,
-			 igraph_real_t *logprob,
-			 igraph_real_t *logmax) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int agebins=pagebins;
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  long int it, t, i, k;
-  igraph_vector_long_t ptk;
-  igraph_vector_t *mycites, vmycites;
-  igraph_vector_t neis;
-  igraph_real_t S=0, maxdelta, diff;
-  
-  igraph_vector_long_t lastcit;
-  igraph_vector_t vmykernel;
-  igraph_vector_t *kernels[]= { kernel, &vmykernel };
-  long int actkernel=0;
-  igraph_vector_t *fromkernel=kernels[actkernel],
-    *tokernel=kernels[1-actkernel];
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&ptk, agebins+1));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &ptk);
-  
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_CHECK(igraph_vector_long_init(&lastcit, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &lastcit);
-  IGRAPH_VECTOR_INIT_FINALLY(&vmykernel, agebins+1);
-  
-  if (cites) {
-    IGRAPH_CHECK(igraph_vector_resize(cites, agebins+1));
-    igraph_vector_null(cites);
-    mycites=cites;
-  } else {
-    IGRAPH_VECTOR_INIT_FINALLY(&vmycites, agebins+1);
-    mycites=&vmycites;
-  }
-  
-  IGRAPH_CHECK(igraph_vector_resize(kernel, agebins+1));
-  igraph_vector_fill(kernel, 1);
-  
-  IGRAPH_PROGRESS("ML Revolver l", 0, NULL);
-  
-  for (it=0; it<niter; it++) {
-    
-    igraph_vector_null(tokernel);
-    igraph_vector_long_null(&ptk);
-    S=0.0;
-    
-    if (logprob) { *logprob=0.0; }
-    if (logmax) { *logmax=0.0; }
-    
-    for (t=0; t<no_of_nodes; t++) {
-      long int n, nneis;
-      IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) t,
-				    IGRAPH_OUT));
-      nneis=igraph_vector_size(&neis);
-
-      IGRAPH_ALLOW_INTERRUPTION();
-      
-      if (S != 0) {
-	for (i=0; i<agebins+1; i++) {
-	  VECTOR(*tokernel)[i] += nneis * VECTOR(ptk)[i] / S;
-	}
-	
-	if (logprob || logmax) {
-	  for (n=0; n<nneis; n++) {
-	    long int to=(long int) VECTOR(neis)[n];
-	    long int x= VECTOR(lastcit)[to] != 0 ? 
-	      t+2-(long int)VECTOR(lastcit)[to]/binwidth : agebins;
-	    if (logprob) { *logprob += log( VECTOR(*fromkernel)[x] / S ); }
-	    if (logmax) { *logmax += log(1.0/t); }
-	  }
-	}
-      }
-      
-      /* Update ptk for the last time step */
-      for (n=0; n<nneis; n++) {
-	long int to=(long int) VECTOR(neis)[n];
-	long int x=VECTOR(lastcit)[to] != 0 ?
-	  t+2-(long int)VECTOR(lastcit)[to]/binwidth : agebins;
-	
-	VECTOR(lastcit)[to]=t+2;
-	VECTOR(ptk)[x] += 1;
-	S += VECTOR(*fromkernel)[x];
-      }
-      VECTOR(ptk)[agebins] += 1;
-      S += VECTOR(*fromkernel)[agebins];
-      /* should we move some citations to an older bin? */
-      for (k=1; t+1-binwidth*k+1>=0; k++) {
-	long int shnode=t+1-binwidth*k+1;
-	IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) shnode, 
-				      IGRAPH_OUT));
-	nneis=igraph_vector_size(&neis);
-	for (i=0; i<nneis; i++) {
-	  long int cnode=(long int) VECTOR(neis)[i];
-	  if (VECTOR(lastcit)[cnode]==shnode+1) {
-	    VECTOR(ptk)[k-1] -= 1;
-	    VECTOR(ptk)[k] += 1;
-	    S -= VECTOR(*fromkernel)[k-1];
-	    S += VECTOR(*fromkernel)[k];
-	  }
-	}
-      }
-      
-    } /* t < no_of_nodes */
-    
-    /* Mk/sum */
-    maxdelta=0.0;
-    for (i=0; i<agebins+1; i++) {
-      VECTOR(*tokernel)[i] = VECTOR(*mycites)[i] / VECTOR(*tokernel)[i];
-      if ( (diff=fabs(VECTOR(*tokernel)[i]-VECTOR(*fromkernel)[i])) > maxdelta) {
-	maxdelta=diff;
-      }
-    }
-    if (maxdelta < delta) { break; }
-    
-    /* Switch kernels */
-    actkernel=1-actkernel;
-    fromkernel=kernels[actkernel];
-    tokernel=kernels[1-actkernel];
-    
-    IGRAPH_PROGRESS("ML Revolver l", 100*(it+1)/niter, NULL);
-
-  } /* it < niter */
-  
-  /* Switch kernels if needed */
-  if (fromkernel != kernel) {
-    igraph_vector_update(kernel, fromkernel);
-  }
-  
-  if (!cites) { 
-    igraph_vector_destroy(&vmycites);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-  
-  igraph_vector_destroy(&vmykernel);
-  igraph_vector_long_destroy(&lastcit);
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&ptk);
-  IGRAPH_FINALLY_CLEAN(4);
-  
-  return 0;
-}
-
-/* -----------------------------------------------------------*/
-
-int igraph_revolver_probs_d(const igraph_t *graph,
-			    const igraph_vector_t *kernel,
-			    igraph_vector_t *logprobs,
-			    igraph_vector_t *logcited,
-			    igraph_vector_t *logciting,
-			    igraph_bool_t pntk) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  long int t;
-  igraph_real_t S=0.0;
-  igraph_vector_long_t ntk;
-  long int ntksize=igraph_vector_size(kernel);
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-
-  if (pntk) {
-    IGRAPH_CHECK(igraph_vector_long_init(&ntk, ntksize));
-    IGRAPH_FINALLY(igraph_vector_long_destroy, &ntk);
-  }
-
-  if (logprobs) {
-    IGRAPH_CHECK(igraph_vector_resize(logprobs, no_of_edges));
-  }
-  if (logciting) {
-    IGRAPH_CHECK(igraph_vector_resize(logciting, no_of_nodes));
-    igraph_vector_null(logciting);
-  }
-  if (logcited) {
-    IGRAPH_CHECK(igraph_vector_resize(logcited, no_of_nodes));
-    igraph_vector_null(logcited);
-  }
-  
-  for (t=0; t<no_of_nodes; t++) {
-    long int n, nneis;
-    IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) t, 
-				 IGRAPH_OUT));
-    nneis=igraph_vector_size(&neis);    
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=VECTOR(degree)[to];
-      igraph_real_t prob;
-      if (pntk) {
-	prob=log( VECTOR(ntk)[x] * VECTOR(*kernel)[x] / S );
-      } else {
-	prob=log( VECTOR(*kernel)[x] / S );
-      }
-      if (logprobs) {	
-	VECTOR(*logprobs)[edge] = prob;
-      }
-      if (logcited) { 
-	VECTOR(*logcited)[to] += prob;
-      }
-      if (logciting) {
-	VECTOR(*logciting)[t] += prob;
-      }
-    }
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=VECTOR(degree)[to];
-      
-      VECTOR(degree)[to] += 1;
-      if (pntk) {
-	VECTOR(ntk)[x+1] += 1;
-	VECTOR(ntk)[x] -= 1;
-      }
-      S += VECTOR(*kernel)[x+1];
-      S -= VECTOR(*kernel)[x];
-    }
-    if (pntk) {
-      VECTOR(ntk)[0] += 1;
-    }
-    S += VECTOR(*kernel)[0];
-    
-  } /* t < no_of_nodes */
-
-  if (pntk) {
-    igraph_vector_long_destroy(&ntk);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(2);
-  return 0;
-}
-
-int igraph_revolver_probs_ad(const igraph_t *graph,
-			     const igraph_matrix_t *kernel,
-			     igraph_vector_t *logprobs,
-			     igraph_vector_t *logcited,
-			     igraph_vector_t *logciting, 
-			     igraph_bool_t pntk) {
-
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  long int t, j;
-  igraph_real_t S=0.0;
-  long int agebins=igraph_matrix_ncol(kernel);
-  long int binwidth=no_of_nodes/agebins+1;
-  igraph_matrix_long_t ntk;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (pntk) {
-    IGRAPH_CHECK(igraph_matrix_long_init(&ntk, igraph_matrix_nrow(kernel),
-					 igraph_matrix_ncol(kernel)));
-    IGRAPH_FINALLY(igraph_matrix_long_destroy, &ntk);    
-  }
-
-  if (logprobs) {
-    IGRAPH_CHECK(igraph_vector_resize(logprobs, no_of_edges));
-  }
-  if (logcited) {
-    IGRAPH_CHECK(igraph_vector_resize(logcited, no_of_nodes));
-    igraph_vector_null(logcited);
-  }
-  if (logciting) {
-    IGRAPH_CHECK(igraph_vector_resize(logciting, no_of_nodes));
-    igraph_vector_null(logciting);
-  }  
-  
-  for (t=0; t<no_of_nodes; t++) {
-    long int n, nneis;
-    IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) t, 
-				 IGRAPH_OUT));
-    nneis=igraph_vector_size(&neis);
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=VECTOR(degree)[to];
-      long int y=(t-to)/binwidth;
-      igraph_real_t prob;
-      if (pntk) {
-	prob=log( MATRIX(ntk, x, y) * MATRIX(*kernel, x, y) / S );
-      } else {
-	prob=log( MATRIX(*kernel, x, y) / S );
-      }
-      if (logprobs) {
-	VECTOR(*logprobs)[edge] = prob;
-      }
-      if (logcited) {
-	VECTOR(*logcited)[to] += prob;
-      }
-      if (logciting) {
-	VECTOR(*logciting)[t] += prob;
-      }
-    }
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=VECTOR(degree)[to];
-      long int y=(t-to)/binwidth;
-      
-      VECTOR(degree)[to] += 1;
-      if (pntk) {
-	MATRIX(ntk, x+1, y) += 1;
-	MATRIX(ntk, x, y) -= 1;
-      }
-      S += MATRIX(*kernel, x+1, y);
-      S -= MATRIX(*kernel, x, y);
-    }
-    
-    for (j=1; t-binwidth*j+1>=0; j++) {
-      long int shnode=t-binwidth*j+1;
-      long int deg=VECTOR(degree)[shnode];
-      if (pntk) {
-	MATRIX(ntk, deg, j) += 1;
-	MATRIX(ntk, deg, j-1) -= 1;
-      }
-      S += MATRIX(*kernel, deg, j);
-      S -= MATRIX(*kernel, deg, j-1);
-    }
-    if (pntk) {
-      MATRIX(ntk, 0, 0) += 1;
-    }
-    S += MATRIX(*kernel, 0, 0);
-    
-  } /* t < no_of_nodes */
-
-  if (pntk) {
-    igraph_matrix_long_destroy(&ntk);
-    IGRAPH_FINALLY_CLEAN(1);
-  }
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(2);
-  return 0;
-}
-
-int igraph_revolver_probs_de(const igraph_t *graph,
-			     const igraph_matrix_t *kernel,
-			     const igraph_vector_t *cats,
-			     igraph_vector_t *logprobs,
-			     igraph_vector_t *logcited,
-			     igraph_vector_t *logciting) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  long int t;
-  igraph_real_t S=0.0;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (logprobs) {
-    IGRAPH_CHECK(igraph_vector_resize(logprobs, no_of_edges));
-  }
-  if (logcited) {
-    IGRAPH_CHECK(igraph_vector_resize(logcited, no_of_nodes));
-    igraph_vector_null(logcited);
-  }
-  if (logciting) {
-    IGRAPH_CHECK(igraph_vector_resize(logciting, no_of_nodes));
-    igraph_vector_null(logciting);
-  }
-  
-  for (t=0; t<no_of_nodes; t++) {
-    long int n, nneis;
-    IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) t,
-				 IGRAPH_OUT));
-    nneis=igraph_vector_size(&neis);
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=(long int) VECTOR(*cats)[to];
-      long int y=VECTOR(degree)[to];
-      igraph_real_t prob=log( MATRIX(*kernel, x, y) / S );
-      if (logprobs) {
-	VECTOR(*logprobs)[edge] = prob;
-      }
-      if (logcited) {
-	VECTOR(*logcited)[to] += prob;
-      }
-      if (logciting) {
-	VECTOR(*logciting)[t] += prob;
-      }
-    }
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=(long int) VECTOR(*cats)[to];
-      long int y=VECTOR(degree)[to];
-      
-      VECTOR(degree)[to] += 1;
-      S += MATRIX(*kernel, x, y+1);
-      S -= MATRIX(*kernel, x, y);
-    }
-    S += MATRIX(*kernel, 0, 0);
-    
-  } /* t < no_of_nodes */
-  
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(2);
-  return 0;
-}
-
-int igraph_revolver_probs_ade(const igraph_t *graph,
-			      const igraph_array3_t *kernel,
-			      const igraph_vector_t *cats,
-			      igraph_vector_t *logprobs,
-			      igraph_vector_t *logcited,
-			      igraph_vector_t *logciting) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  long int j, t;
-  igraph_real_t S=0.0;
-  long int agebins=igraph_array3_n(kernel,3);
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  
-  if (logprobs) {
-    IGRAPH_CHECK(igraph_vector_resize(logprobs, no_of_edges));
-  }
-  if (logcited) {
-    IGRAPH_CHECK(igraph_vector_resize(logcited, no_of_nodes));
-    igraph_vector_null(logcited);
-  }
-  if (logciting) {
-    IGRAPH_CHECK(igraph_vector_resize(logciting, no_of_nodes));
-    igraph_vector_null(logciting);
-  }
-  
-  for (t=0; t<no_of_nodes; t++) {
-    long int n, nneis;
-    IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) t,
-				 IGRAPH_OUT));
-    nneis=igraph_vector_size(&neis);
-
-    IGRAPH_ALLOW_INTERRUPTION();
-
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=(long int) VECTOR(*cats)[to];
-      long int y=VECTOR(degree)[to];
-      long int z=(t-to)/binwidth;
-      igraph_real_t prob=log( ARRAY3(*kernel, x, y, z) / S );
-      if (logprobs) {
-	VECTOR(*logprobs)[edge] = prob;
-      }
-      if (logcited) {
-	VECTOR(*logcited)[to] += prob;
-      }
-      if (logciting) {
-	VECTOR(*logciting)[t] += prob;
-      }
-    }
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      long int x=(long int) VECTOR(*cats)[to];
-      long int y=VECTOR(degree)[to];
-      long int z=(t-to)/binwidth;
-      
-      VECTOR(degree)[to] += 1;
-      S += ARRAY3(*kernel, x, y+1, z);
-      S -= ARRAY3(*kernel, x, y, z);
-    }
-    
-    for (j=1; t-binwidth*j+1>=0; j++) {
-      long int shnode=t-binwidth*j+1;
-      long int cat=(long int) VECTOR(*cats)[shnode];
-      long int deg=VECTOR(degree)[shnode];
-      S += ARRAY3(*kernel, cat, deg, j);
-      S -= ARRAY3(*kernel, cat, deg, j-1);
-    }
-    S += ARRAY3(*kernel, (long int) VECTOR(*cats)[t], 0, 0);
-    
-  } /* t < no_of_nodes */
-
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(2);
-  return 0;
-}
-
-int igraph_revolver_probs_ADE(const igraph_t *graph,
-			      igraph_scalar_function_t *A_fun,
-			      const igraph_matrix_t *par,
-			      const igraph_vector_t *cats,
-			      const igraph_vector_t *gcats,
-			      int agebins,
-			      igraph_vector_t *logprobs,
-			      igraph_vector_t *logcited,
-			      igraph_vector_t *logciting) {
-  
-  long int no_of_nodes=igraph_vcount(graph);
-  long int no_of_edges=igraph_ecount(graph);
-  igraph_vector_long_t degree;
-  igraph_vector_t neis;
-  igraph_vector_t S;
-  igraph_vector_t gpar;
-  igraph_vector_t var;
-  int parlen=(int) igraph_matrix_nrow(par);
-  int no_gcats=(int) igraph_matrix_ncol(par);
-  long int t, i, j;
-  
-  long int binwidth=no_of_nodes/agebins+1;
-  
-  IGRAPH_CHECK(igraph_vector_long_init(&degree, no_of_nodes));
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &degree);
-  IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);
-  IGRAPH_VECTOR_INIT_FINALLY(&S, no_gcats);
-  IGRAPH_VECTOR_INIT_FINALLY(&var, 3);
-  
-  if (logprobs) {
-    IGRAPH_CHECK(igraph_vector_resize(logprobs, no_of_edges));
-  }
-  if (logcited) {
-    IGRAPH_CHECK(igraph_vector_resize(logcited, no_of_nodes));
-    igraph_vector_null(logcited);
-  }
-  if (logciting) {
-    IGRAPH_CHECK(igraph_vector_resize(logciting, no_of_nodes));
-    igraph_vector_null(logciting);
-  }
-  
-  for (t=0; t<no_of_nodes; t++) {
-    long int n, nneis;
-    long int tcat=(long int) VECTOR(*gcats)[t];
-    igraph_vector_view(&gpar, &MATRIX(*par,0,tcat), parlen);
-    IGRAPH_CHECK(igraph_incident(graph, &neis, (igraph_integer_t) t,
-				 IGRAPH_OUT));
-    nneis=igraph_vector_size(&neis);
-    
-    IGRAPH_ALLOW_INTERRUPTION();
-    
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      igraph_real_t prob;
-      VECTOR(var)[0] = VECTOR(*cats)[to];
-      VECTOR(var)[1] = VECTOR(degree)[to];
-      VECTOR(var)[2] = (t-to)/binwidth;
-      prob=log( A_fun(&var, &gpar, 0) / VECTOR(S)[tcat] );
-      if (logprobs) {
-	VECTOR(*logprobs)[edge] = prob;
-      } 
-      if (logcited) {
-	VECTOR(*logcited)[to] += prob;
-      }
-      if (logciting) {
-	VECTOR(*logciting)[t] += prob;
-      }
-    }
-      
-    for (n=0; n<nneis; n++) {
-      long int edge=(long int) VECTOR(neis)[n];
-      long int to=IGRAPH_OTHER(graph, edge, t);
-      VECTOR(var)[0] = VECTOR(*cats)[to];
-      VECTOR(var)[1] = VECTOR(degree)[to];
-      VECTOR(var)[2] = (t-to)/binwidth;
-      
-      VECTOR(degree)[to] += 1;
-      for (i=0; i<no_gcats; i++) {
-	igraph_vector_view(&gpar, &MATRIX(*par,0,i), parlen);
-	VECTOR(S)[i] -= A_fun(&var, &gpar, 0);
-      }
-      VECTOR(var)[1] += 1;
-      for (i=0; i<no_gcats; i++) {
-	igraph_vector_view(&gpar, &MATRIX(*par,0,i), parlen);
-	VECTOR(S)[i] += A_fun(&var, &gpar, 0);
-      }
-    }
-    
-    for (j=1; t-binwidth*j+1>=0; j++) {
-      long int shnode=t-binwidth*j+1;
-      VECTOR(var)[0] = VECTOR(*cats)[shnode];
-      VECTOR(var)[1] = VECTOR(degree)[shnode];
-      VECTOR(var)[2] = j;
-      for (i=0; i<no_gcats; i++) {
-	igraph_vector_view(&gpar, &MATRIX(*par,0,i), parlen);
-	VECTOR(S)[i] += A_fun(&var, &gpar, 0);
-      }
-      VECTOR(var)[2] = j-1;
-      for (i=0; i<no_gcats; i++) {
-	igraph_vector_view(&gpar, &MATRIX(*par,0,i), parlen);
-	VECTOR(S)[i] += A_fun(&var, &gpar, 0);
-      }
-    }
-    VECTOR(var)[0]=VECTOR(*cats)[t];
-    VECTOR(var)[1]=0;
-    VECTOR(var)[2]=0;
-    for (i=0; i<no_gcats; i++) {
-      igraph_vector_view(&gpar, &MATRIX(*par,0,i), parlen);
-      VECTOR(S)[i] += A_fun(&var, &gpar, 0);
-    }
-  
-  } /* t<no_of_nodes */
-  
-  igraph_vector_destroy(&var);
-  igraph_vector_destroy(&S);
-  igraph_vector_destroy(&neis);
-  igraph_vector_long_destroy(&degree);
-  IGRAPH_FINALLY_CLEAN(4);
-  return 0;
-}
- 
-int igraph_revolver_probs_ADE_dpareto(const igraph_t *graph,
-				      const igraph_matrix_t *par,
-				      const igraph_vector_t *cats,
-				      const igraph_vector_t *gcats,
-				      int agebins,
-				      igraph_vector_t *logprobs,
-				      igraph_vector_t *logcited,
-				      igraph_vector_t *logciting) {
-  
-  return igraph_revolver_probs_ADE(graph, igraph_i_revolver_ml_ADE_dpareto_f,
-				   par, cats, gcats, agebins, logprobs, 
-				   logcited, logciting);
-}
diff --git a/src/rinterface.c b/src/rinterface.c
index c731410..c741854 100644
--- a/src/rinterface.c
+++ b/src/rinterface.c
@@ -30,6 +30,7 @@
 #include <R.h>
 #include <Rinternals.h>
 #include <Rdefines.h>
+#include "rinterface.h"
 
 #include <stdio.h>
 
@@ -37,6 +38,7 @@ int igraph_free(void *p);
 
 SEXP R_igraph_vector_to_SEXP(const igraph_vector_t *v);
 SEXP R_igraph_vector_int_to_SEXP(const igraph_vector_int_t *v);
+SEXP R_igraph_vector_int_to_SEXPp1(const igraph_vector_int_t *v);
 SEXP R_igraph_vector_bool_to_SEXP(const igraph_vector_bool_t *v);
 SEXP R_igraph_vector_long_to_SEXP(const igraph_vector_long_t *v);
 SEXP R_igraph_vector_complex_to_SEXP(const igraph_vector_complex_t* v);
@@ -54,6 +56,8 @@ SEXP R_igraph_vectorlist_int_to_SEXP(const igraph_vector_ptr_t *ptr);
 void R_igraph_vectorlist_int_destroy(igraph_vector_ptr_t *ptr);
 SEXP R_igraph_0orvectorlist_to_SEXP(const igraph_vector_ptr_t *ptr);
 void R_igraph_vectorlist_destroy(igraph_vector_ptr_t *ptr);
+SEXP R_igraph_matrixlist_to_SEXP(const igraph_vector_ptr_t *ptr);
+void R_igraph_matrixlist_destroy(igraph_vector_ptr_t *ptr);
 SEXP R_igraph_graphlist_to_SEXP(const igraph_vector_ptr_t *ptr);
 void R_igraph_graphlist_destroy(igraph_vector_ptr_t *ptr);
 SEXP R_igraph_hrg_to_SEXP(const igraph_hrg_t *hrg);
@@ -79,6 +83,9 @@ int R_SEXP_to_igraph_adjlist(SEXP vectorlist, igraph_adjlist_t *ptr);
 int R_igraph_SEXP_to_0orvectorlist(SEXP vectorlist, 
 				   igraph_vector_ptr_t *ptr);
 int R_igraph_SEXP_to_vectorlist(SEXP vectorlist, igraph_vector_ptr_t *ptr);
+int R_igraph_SEXP_to_vectorlist_int(SEXP vectorlist,
+				    igraph_vector_ptr_t *ptr);
+int R_igraph_SEXP_to_matrixlist(SEXP matrixlist, igraph_vector_ptr_t *ptr);
 int R_SEXP_to_vector_bool(SEXP sv, igraph_vector_bool_t *v);
 int R_SEXP_to_vector_bool_copy(SEXP sv, igraph_vector_bool_t *v);
 int R_SEXP_to_vector_int(SEXP sv, igraph_vector_int_t *v);
@@ -2117,17 +2124,11 @@ int R_igraph_status_handler(const char *message, void *data) {
   return 0;
 }
 
-SEXP R_igraph_init(SEXP progress, SEXP status) {
+SEXP R_init_igraph() {
   igraph_set_error_handler(R_igraph_myhandler);
   igraph_set_warning_handler(R_igraph_warning_handler);
   igraph_set_interruption_handler(R_igraph_interrupt_handler);
   igraph_i_set_attribute_table(&R_igraph_attribute_table);
-  if (LOGICAL(status)[0]) { 
-    igraph_set_status_handler(R_igraph_status_handler);
-  }
-  if (LOGICAL(progress)[0]) {
-    igraph_set_progress_handler(R_igraph_progress_handler);
-  }
   return R_NilValue;
 }
 
@@ -2194,6 +2195,18 @@ SEXP R_igraph_vector_to_SEXPp1(const igraph_vector_t *v) {
   return result;
 }  
 
+SEXP R_igraph_vector_int_to_SEXPp1(const igraph_vector_int_t *v) {
+  SEXP result;
+  long int i, n=igraph_vector_int_size(v);
+
+  PROTECT(result=NEW_INTEGER(n));
+  for (i=0; i<n; i++) {
+    INTEGER(result)[i]=VECTOR(*v)[i]+1;
+  }
+  UNPROTECT(1);
+  return result;
+}  
+
 SEXP R_igraph_0orvector_to_SEXP(const igraph_vector_t *v) {
   SEXP result;
   if (v) {
@@ -2417,7 +2430,7 @@ SEXP R_igraph_to_SEXP(const igraph_t *graph) {
   long int no_of_nodes=igraph_vcount(graph);
   long int no_of_edges=igraph_ecount(graph);
   
-  PROTECT(result=NEW_LIST(9));
+  PROTECT(result=NEW_LIST(10));
   SET_VECTOR_ELT(result, 0, NEW_NUMERIC(1));
   SET_VECTOR_ELT(result, 1, NEW_LOGICAL(1));
   SET_VECTOR_ELT(result, 2, NEW_NUMERIC(no_of_edges));
@@ -2447,6 +2460,10 @@ SEXP R_igraph_to_SEXP(const igraph_t *graph) {
   /* Attributes */
   SET_VECTOR_ELT(result, 8, graph->attr);
   REAL(VECTOR_ELT(graph->attr, 0))[0] += 1;
+
+  /* Environment for vertex/edge seqs */
+  SET_VECTOR_ELT(result, 9, R_NilValue);
+  R_igraph_add_env(result);
   
   UNPROTECT(1);
   return result;
@@ -2557,6 +2574,31 @@ void R_igraph_vectorlist_int_destroy2(igraph_vector_ptr_t *ptr) {
   igraph_vector_ptr_destroy(ptr);
 }
 
+SEXP R_igraph_matrixlist_to_SEXP(const igraph_vector_ptr_t *ptr) {
+  SEXP result;
+  long int i, n=igraph_vector_ptr_size(ptr);
+
+  PROTECT(result=NEW_LIST(n));
+  for (i=0; i<n; i++) {
+    igraph_matrix_t *v=VECTOR(*ptr)[i];
+    SET_VECTOR_ELT(result, i, R_igraph_matrix_to_SEXP(v));
+  }
+
+  UNPROTECT(1);
+  return result;
+}
+
+void R_igraph_matrixlist_destroy(igraph_vector_ptr_t *ptr) {
+  long int i, n=igraph_vector_ptr_size(ptr);
+
+  for (i=0; i<n; i++) {
+    igraph_matrix_t *v=VECTOR(*ptr)[i];
+    igraph_matrix_destroy(v);
+    igraph_free(v);
+  }
+  igraph_vector_ptr_destroy(ptr);
+}
+
 SEXP R_igraph_graphlist_to_SEXP(const igraph_vector_ptr_t *ptr) {
   SEXP result;
   long int i, n=igraph_vector_ptr_size(ptr);
@@ -2856,6 +2898,47 @@ int R_igraph_SEXP_to_vectorlist(SEXP vectorlist, igraph_vector_ptr_t *ptr) {
   return 0;
 }
 
+int R_igraph_SEXP_to_vectorlist_int(SEXP vectorlist,
+				    igraph_vector_ptr_t *ptr) {
+  int length=GET_LENGTH(vectorlist);
+  int i;
+  igraph_vector_int_t *vecs;
+  igraph_vector_int_t **vecsptr;
+
+  vecs = (igraph_vector_int_t *) R_alloc((size_t) length,
+					 sizeof(igraph_vector_int_t));
+  vecsptr = (igraph_vector_int_t **) R_alloc((size_t) length,
+					     sizeof(igraph_vector_int_t*));
+  igraph_vector_ptr_view(ptr, (void**) vecsptr, length);
+  for (i=0; i<length; i++) {
+    igraph_vector_int_t *v=&vecs[i];
+    vecsptr[i] = v;
+    SEXP el=VECTOR_ELT(vectorlist, i);
+    igraph_vector_int_view(v, INTEGER(el), GET_LENGTH(el));
+  }
+  return 0;
+}
+
+int R_igraph_SEXP_to_matrixlist(SEXP matrixlist, igraph_vector_ptr_t *ptr) {
+  int length=GET_LENGTH(matrixlist);
+  int i;
+  igraph_matrix_t *vecs;
+  igraph_matrix_t **vecsptr;
+
+  vecs = (igraph_matrix_t *) R_alloc((size_t) length, sizeof(igraph_matrix_t));
+  vecsptr = (igraph_matrix_t **) R_alloc((size_t) length,
+					 sizeof(igraph_matrix_t*));
+  igraph_vector_ptr_view(ptr, (void**) vecsptr, length);
+  for (i=0; i<length; i++) {
+    igraph_matrix_t *v=&vecs[i];
+    vecsptr[i] = v;
+    SEXP el=VECTOR_ELT(matrixlist, i);
+    SEXP dim=GET_DIM(el);
+    igraph_matrix_view(v, REAL(el), INTEGER(dim)[0], INTEGER(dim)[1]);
+  }
+  return 0;
+}
+
 int R_igraph_SEXP_to_strvector(SEXP rval, igraph_strvector_t *sv) {
   long int i;
   sv->len=GET_LENGTH(rval);
@@ -3881,83 +3964,240 @@ SEXP R_igraph_recent_degree_game(SEXP pn, SEXP ppower, SEXP pwindow,
   UNPROTECT(1);
   return result;
 }
-  
-SEXP R_igraph_layout_kamada_kawai(SEXP graph, SEXP pniter, SEXP pinitemp, 
-				  SEXP pcoolexp, SEXP pkkconst, SEXP psigma, 
-				  SEXP start, SEXP pfixz, SEXP pminx, 
-				  SEXP pmaxx, SEXP pminy, SEXP pmaxy, 
-				  SEXP pminz, SEXP pmaxz) {
-  
-  igraph_t g;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_real_t initemp=REAL(pinitemp)[0];
-  igraph_real_t coolexp=REAL(pcoolexp)[0];
-  igraph_real_t kkconst=REAL(pkkconst)[0];
-  igraph_real_t sigma=REAL(psigma)[0];
-  igraph_vector_t minx, maxx, *ppminx=0, *ppmaxx=0;
-  igraph_vector_t miny, maxy, *ppminy=0, *ppmaxy=0;
-  igraph_matrix_t res;
+
+SEXP R_igraph_layout_fruchterman_reingold(SEXP graph, SEXP coords,
+					  SEXP niter, SEXP start_temp,
+					  SEXP weights,
+					  SEXP minx, SEXP maxx,
+					  SEXP miny, SEXP maxy, SEXP grid) {
+  /* Declarations */
+  igraph_t c_graph;
+  igraph_matrix_t c_coords;
+  igraph_integer_t c_niter;
+  igraph_real_t c_start_temp;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_minx;
+  igraph_vector_t c_maxx;
+  igraph_vector_t c_miny;
+  igraph_vector_t c_maxy;
+  igraph_layout_grid_t c_grid=INTEGER(grid)[0];
+
   SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  if (isNull(start)) {
-    igraph_matrix_init(&res, 0, 0);
+  /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (!isNull(coords)) {
+    if (0 != R_SEXP_to_igraph_matrix_copy(coords, &c_coords)) {
+      igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    }
   } else {
-    R_SEXP_to_igraph_matrix_copy(start, &res);
+    igraph_matrix_init(&c_coords, 0, 0);
   }
-  if (!isNull(pminx)) { ppminx=&minx; R_SEXP_to_vector(pminx, &minx); }
-  if (!isNull(pmaxx)) { ppmaxx=&maxx; R_SEXP_to_vector(pmaxx, &maxx); }  
-  if (!isNull(pminy)) { ppminy=&miny; R_SEXP_to_vector(pminy, &miny); }
-  if (!isNull(pmaxy)) { ppmaxy=&maxy; R_SEXP_to_vector(pmaxy, &maxy); }  
-  igraph_layout_kamada_kawai(&g, &res, niter, sigma, 
-			     initemp, coolexp, kkconst, !isNull(start), 
-			     ppminx, ppmaxx, ppminy, ppmaxy);
-  PROTECT(result=R_igraph_matrix_to_SEXP(&res));
-  igraph_matrix_destroy(&res);
-  
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_coords);
+  c_niter=INTEGER(niter)[0];
+  c_start_temp=REAL(start_temp)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(minx)) { R_SEXP_to_vector(minx, &c_minx); }
+  if (!isNull(maxx)) { R_SEXP_to_vector(maxx, &c_maxx); }
+  if (!isNull(miny)) { R_SEXP_to_vector(miny, &c_miny); }
+  if (!isNull(maxy)) { R_SEXP_to_vector(maxy, &c_maxy); }
+  /* Call igraph */
+  igraph_layout_fruchterman_reingold(&c_graph, &c_coords,
+				     !isNull(coords),
+				     c_niter, c_start_temp, c_grid,
+				     (isNull(weights) ? 0 : &c_weights),
+				     (isNull(minx) ? 0 : &c_minx),
+				     (isNull(maxx) ? 0 : &c_maxx),
+				     (isNull(miny) ? 0 : &c_miny),
+				     (isNull(maxy) ? 0 : &c_maxy));
+
+  /* Convert output */
+  PROTECT(coords=R_igraph_matrix_to_SEXP(&c_coords));
+  igraph_matrix_destroy(&c_coords);
+  IGRAPH_FINALLY_CLEAN(1);
+  result=coords;
+
   UNPROTECT(1);
-  return result;
+  return(result);
 }
 
-SEXP R_igraph_layout_kamada_kawai_3d(SEXP graph, SEXP pniter, SEXP pinitemp,
-				     SEXP pcoolexp, SEXP pkkconst, 
-				     SEXP psigma, SEXP start, SEXP pfixz, 
-				     SEXP pminx, SEXP pmaxx, SEXP pminy, 
-				     SEXP pmaxy, SEXP pminz, SEXP pmaxz) {
-  igraph_t g;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_real_t initemp=REAL(pinitemp)[0];
-  igraph_real_t coolexp=REAL(pcoolexp)[0];
-  igraph_real_t kkconst=REAL(pkkconst)[0];
-  igraph_real_t sigma=REAL(psigma)[0];
-  igraph_bool_t fixz=LOGICAL(pfixz)[0];
-  igraph_vector_t minx, maxx, *ppminx=0, *ppmaxx=0;
-  igraph_vector_t miny, maxy, *ppminy=0, *ppmaxy=0;
-  igraph_vector_t minz, maxz, *ppminz=0, *ppmaxz=0;
-  igraph_matrix_t res;
+SEXP R_igraph_layout_fruchterman_reingold_3d(SEXP graph, SEXP coords,
+					     SEXP niter, SEXP start_temp,
+					     SEXP weights,
+					     SEXP minx, SEXP maxx,
+					     SEXP miny, SEXP maxy,
+					     SEXP minz, SEXP maxz) {
+  /* Declarations */
+  igraph_t c_graph;
+  igraph_matrix_t c_coords;
+  igraph_integer_t c_niter;
+  igraph_real_t c_start_temp;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_minx;
+  igraph_vector_t c_maxx;
+  igraph_vector_t c_miny;
+  igraph_vector_t c_maxy;
+  igraph_vector_t c_minz;
+  igraph_vector_t c_maxz;
+
   SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  if (isNull(start)) {
-    igraph_matrix_init(&res, 0, 0);
+  /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (!isNull(coords)) {
+    if (0 != R_SEXP_to_igraph_matrix_copy(coords, &c_coords)) {
+      igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    }
   } else {
-    R_SEXP_to_igraph_matrix_copy(start, &res);
+    igraph_matrix_init(&c_coords, 0, 0);
   }
-  if (!isNull(pminx)) { ppminx=&minx; R_SEXP_to_vector(pminx, &minx); }
-  if (!isNull(pmaxx)) { ppmaxx=&maxx; R_SEXP_to_vector(pmaxx, &maxx); }  
-  if (!isNull(pminy)) { ppminy=&miny; R_SEXP_to_vector(pminy, &miny); }
-  if (!isNull(pmaxy)) { ppmaxy=&maxy; R_SEXP_to_vector(pmaxy, &maxy); }  
-  if (!isNull(pminz)) { ppminz=&minz; R_SEXP_to_vector(pminz, &minz); }
-  if (!isNull(pmaxz)) { ppmaxz=&maxz; R_SEXP_to_vector(pmaxz, &maxz); }  
-  igraph_layout_kamada_kawai_3d(&g, &res, niter, sigma, 
-				initemp, coolexp, kkconst, !isNull(start), 
-				fixz, ppminx, ppmaxx, ppminy, ppmaxy, 
-				ppminz, ppmaxz);
-  PROTECT(result=R_igraph_matrix_to_SEXP(&res));
-  igraph_matrix_destroy(&res);
-  
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_coords);
+  c_niter=INTEGER(niter)[0];
+  c_start_temp=REAL(start_temp)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(minx)) { R_SEXP_to_vector(minx, &c_minx); }
+  if (!isNull(maxx)) { R_SEXP_to_vector(maxx, &c_maxx); }
+  if (!isNull(miny)) { R_SEXP_to_vector(miny, &c_miny); }
+  if (!isNull(maxy)) { R_SEXP_to_vector(maxy, &c_maxy); }
+  if (!isNull(minz)) { R_SEXP_to_vector(minz, &c_minz); }
+  if (!isNull(maxz)) { R_SEXP_to_vector(maxz, &c_maxz); }
+  /* Call igraph */
+  igraph_layout_fruchterman_reingold_3d(&c_graph, &c_coords, !isNull(coords),
+					c_niter, c_start_temp,
+					(isNull(weights) ? 0 : &c_weights),
+					(isNull(minx) ? 0 : &c_minx),
+					(isNull(maxx) ? 0 : &c_maxx),
+					(isNull(miny) ? 0 : &c_miny),
+					(isNull(maxy) ? 0 : &c_maxy),
+					(isNull(minz) ? 0 : &c_minz),
+					(isNull(maxz) ? 0 : &c_maxz));
+
+  /* Convert output */
+  PROTECT(coords=R_igraph_matrix_to_SEXP(&c_coords));
+  igraph_matrix_destroy(&c_coords);
+  IGRAPH_FINALLY_CLEAN(1);
+  result=coords;
+
   UNPROTECT(1);
-  return result;
+  return(result);
+}
+
+SEXP R_igraph_layout_kamada_kawai(SEXP graph, SEXP coords, SEXP maxiter, 
+				  SEXP epsilon, SEXP kkconst, SEXP weights, 
+				  SEXP minx, SEXP maxx, 
+				  SEXP miny, SEXP maxy) {
+
+  /* Declarations */
+  igraph_t c_graph;
+  igraph_matrix_t c_coords;
+  igraph_bool_t c_use_seed;
+  igraph_integer_t c_maxiter;
+  igraph_real_t c_epsilon;
+  igraph_real_t c_kkconst;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_minx;
+  igraph_vector_t c_maxx;
+  igraph_vector_t c_miny;
+  igraph_vector_t c_maxy;
+
+  SEXP result;
+  /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (!isNull(coords)) {
+    if (0 != R_SEXP_to_igraph_matrix_copy(coords, &c_coords)) { 
+      igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+    }    
+  } else {
+    igraph_matrix_init(&c_coords, 0, 0);
+  }
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_coords);
+  c_maxiter=INTEGER(maxiter)[0];
+  c_epsilon=REAL(epsilon)[0];
+  c_kkconst=REAL(kkconst)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(minx)) { R_SEXP_to_vector(minx, &c_minx); }
+  if (!isNull(maxx)) { R_SEXP_to_vector(maxx, &c_maxx); }
+  if (!isNull(miny)) { R_SEXP_to_vector(miny, &c_miny); }
+  if (!isNull(maxy)) { R_SEXP_to_vector(maxy, &c_maxy); }
+  /* Call igraph */
+  igraph_layout_kamada_kawai(&c_graph, &c_coords, !isNull(coords), 
+			     c_maxiter, c_epsilon, c_kkconst, 
+			     (isNull(weights) ? 0 : &c_weights),
+			     (isNull(minx) ? 0 : &c_minx), 
+			     (isNull(maxx) ? 0 : &c_maxx), 
+			     (isNull(miny) ? 0 : &c_miny), 
+			     (isNull(maxy) ? 0 : &c_maxy));
+
+                                        /* Convert output */
+  PROTECT(coords=R_igraph_matrix_to_SEXP(&c_coords)); 
+  igraph_matrix_destroy(&c_coords); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=coords;
+
+  UNPROTECT(1);
+  return(result);
+}
+
+SEXP R_igraph_layout_kamada_kawai_3d(SEXP graph, SEXP coords, SEXP maxiter, 
+				     SEXP epsilon, SEXP kkconst,
+				     SEXP weights, 
+				     SEXP minx, SEXP maxx, 
+				     SEXP miny, SEXP maxy,
+				     SEXP minz, SEXP maxz) {
+
+  /* Declarations */
+  igraph_t c_graph;
+  igraph_matrix_t c_coords;
+  igraph_bool_t c_use_seed;
+  igraph_integer_t c_maxiter;
+  igraph_real_t c_epsilon;
+  igraph_real_t c_kkconst;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_minx;
+  igraph_vector_t c_maxx;
+  igraph_vector_t c_miny;
+  igraph_vector_t c_maxy;
+  igraph_vector_t c_minz;
+  igraph_vector_t c_maxz;
+
+  SEXP result;
+  /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (!isNull(coords)) {
+    if (0 != R_SEXP_to_igraph_matrix_copy(coords, &c_coords)) { 
+      igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+    }    
+  } else {
+    igraph_matrix_init(&c_coords, 0, 0);
+  }
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_coords);
+  c_maxiter=INTEGER(maxiter)[0];
+  c_epsilon=REAL(epsilon)[0];
+  c_kkconst=REAL(kkconst)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(minx)) { R_SEXP_to_vector(minx, &c_minx); }
+  if (!isNull(maxx)) { R_SEXP_to_vector(maxx, &c_maxx); }
+  if (!isNull(miny)) { R_SEXP_to_vector(miny, &c_miny); }
+  if (!isNull(maxy)) { R_SEXP_to_vector(maxy, &c_maxy); }
+  if (!isNull(minz)) { R_SEXP_to_vector(minz, &c_minz); }
+  if (!isNull(maxz)) { R_SEXP_to_vector(maxz, &c_maxz); }
+  /* Call igraph */
+  igraph_layout_kamada_kawai_3d(&c_graph, &c_coords, !isNull(coords), 
+				c_maxiter, c_epsilon, c_kkconst, 
+				(isNull(weights) ? 0 : &c_weights),
+				(isNull(minx) ? 0 : &c_minx), 
+				(isNull(maxx) ? 0 : &c_maxx), 
+				(isNull(miny) ? 0 : &c_miny), 
+				(isNull(maxy) ? 0 : &c_maxy),
+				(isNull(minz) ? 0 : &c_minz), 
+				(isNull(maxz) ? 0 : &c_maxz));
+
+                                        /* Convert output */
+  PROTECT(coords=R_igraph_matrix_to_SEXP(&c_coords)); 
+  igraph_matrix_destroy(&c_coords); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=coords;
+
+  UNPROTECT(1);
+  return(result);
 }
 
 SEXP R_igraph_layout_graphopt(SEXP graph, SEXP pniter, SEXP pcharge,
@@ -4015,42 +4255,6 @@ SEXP R_igraph_layout_lgl(SEXP graph, SEXP pmaxiter, SEXP pmaxdelta,
   return result;
 }  
 
-SEXP R_igraph_layout_fruchterman_reingold_grid(SEXP graph,
-					       SEXP pniter,
-					       SEXP pmaxdelta, SEXP parea,
-					       SEXP pcoolexp, SEXP prepulserad,
-					       SEXP pcellsize, SEXP start, 
-					       SEXP pweights) {
-
-  igraph_t g;
-  igraph_matrix_t res;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_real_t maxdelta=REAL(pmaxdelta)[0];
-  igraph_real_t area=REAL(parea)[0];
-  igraph_real_t coolexp=REAL(pcoolexp)[0];
-  igraph_real_t repulserad=REAL(prepulserad)[0];
-  igraph_real_t cellsize=REAL(pcellsize)[0];
-  igraph_bool_t use_seed=!isNull(start);
-  igraph_vector_t weights, *ppweights=0;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  if (!isNull(pweights)) { R_SEXP_to_vector(pweights, &weights);ppweights=&weights; }
-  if (use_seed) {
-    R_SEXP_to_igraph_matrix_copy(start, &res);
-  } else {
-    igraph_matrix_init(&res, 0, 0);
-  }
-  igraph_layout_grid_fruchterman_reingold(&g, &res, niter, maxdelta, area,
-					  coolexp, repulserad, cellsize, 
-					  use_seed, ppweights);
-  PROTECT(result=R_igraph_matrix_to_SEXP(&res));
-  igraph_matrix_destroy(&res);
-  
-  UNPROTECT(1);
-  return result;
-}
-
 SEXP R_igraph_minimum_spanning_tree_unweighted(SEXP graph) {
   
   igraph_t g;
@@ -4345,15 +4549,18 @@ SEXP R_igraph_layout_random(SEXP graph) {
   return result;
 }
 
-SEXP R_igraph_layout_circle(SEXP graph) {
+SEXP R_igraph_layout_circle(SEXP graph, SEXP porder) {
   
   igraph_t g;
   igraph_matrix_t res;
+  igraph_vs_t order;
   SEXP result=R_NilValue;
   
   R_SEXP_to_igraph(graph, &g);
   igraph_matrix_init(&res, 0, 0);
-  igraph_layout_circle(&g, &res);
+  R_SEXP_to_igraph_vs(porder, &g, &order);
+  igraph_layout_circle(&g, &res, order);
+  igraph_vs_destroy(&order);
   PROTECT(result=R_igraph_matrix_to_SEXP(&res));
   igraph_matrix_destroy(&res);
   
@@ -4450,87 +4657,6 @@ SEXP R_igraph_get_adjacency(SEXP graph, SEXP ptype, SEXP peids) {
   UNPROTECT(1);
   return result;
 }
-  
-SEXP R_igraph_layout_fruchterman_reingold(SEXP graph, SEXP pniter,
-					  SEXP pmaxdelta, SEXP parea,
-					  SEXP pcoolexp, SEXP prepulserad,
-					  SEXP pweights, SEXP start,
-					  SEXP pminx, SEXP pmaxx,
-					  SEXP pminy, SEXP pmaxy,
-					  SEXP pminz, SEXP pmaxz) {
-  igraph_t g;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_real_t maxdelta=REAL(pmaxdelta)[0];
-  igraph_real_t area=REAL(parea)[0];
-  igraph_real_t coolexp=REAL(pcoolexp)[0];
-  igraph_real_t repulserad=REAL(prepulserad)[0];
-  igraph_vector_t weights, *ppweights=0;
-  igraph_matrix_t res;
-  igraph_vector_t minx, maxx, *ppminx=0, *ppmaxx=0;
-  igraph_vector_t miny, maxy, *ppminy=0, *ppmaxy=0;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  if (!isNull(pweights)) { R_SEXP_to_vector(pweights, &weights);ppweights=&weights; }
-  if (!isNull(pminx)) { ppminx=&minx; R_SEXP_to_vector(pminx, &minx); }
-  if (!isNull(pmaxx)) { ppmaxx=&maxx; R_SEXP_to_vector(pmaxx, &maxx); }
-  if (!isNull(pminy)) { ppminy=&miny; R_SEXP_to_vector(pminy, &miny); }
-  if (!isNull(pmaxy)) { ppmaxy=&maxy; R_SEXP_to_vector(pmaxy, &maxy); }
-  if (isNull(start)) {
-    igraph_matrix_init(&res, 0, 0);
-  } else {
-    R_SEXP_to_igraph_matrix_copy(start, &res);
-  }
-  igraph_layout_fruchterman_reingold(&g, &res, niter, maxdelta, area,
-				     coolexp, repulserad, !isNull(start),
-				     ppweights, ppminx, ppmaxx,
-				     ppminy, ppmaxy);
-  PROTECT(result=R_igraph_matrix_to_SEXP(&res));
-  igraph_matrix_destroy(&res);
-  
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_layout_fruchterman_reingold_3d(SEXP graph, SEXP pniter,
-					     SEXP pmaxdelta, SEXP parea,
-					     SEXP pcoolexp, SEXP prepulserad,
-					     SEXP pweights,
-					     SEXP pminx, SEXP pmaxx,
-					     SEXP pminy, SEXP pmaxy,
-					     SEXP pminz, SEXP pmaxz) {
-  igraph_t g;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_real_t maxdelta=REAL(pmaxdelta)[0];
-  igraph_real_t area=REAL(parea)[0];
-  igraph_real_t coolexp=REAL(pcoolexp)[0];
-  igraph_real_t repulserad=REAL(prepulserad)[0];
-  igraph_vector_t weights, *ppweights=0;
-  igraph_vector_t minx, maxx, *ppminx=0, *ppmaxx=0;
-  igraph_vector_t miny, maxy, *ppminy=0, *ppmaxy=0;
-  igraph_vector_t minz, maxz, *ppminz=0, *ppmaxz=0;
-  igraph_matrix_t res;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  if (!isNull(pweights)) { R_SEXP_to_vector(pweights, &weights);ppweights=&weights; }
-  if (!isNull(pminx)) { ppminx=&minx; R_SEXP_to_vector(pminx, &minx); }
-  if (!isNull(pmaxx)) { ppmaxx=&maxx; R_SEXP_to_vector(pmaxx, &maxx); }
-  if (!isNull(pminy)) { ppminy=&miny; R_SEXP_to_vector(pminy, &miny); }
-  if (!isNull(pmaxy)) { ppmaxy=&maxy; R_SEXP_to_vector(pmaxy, &maxy); }
-  if (!isNull(pminz)) { ppminz=&minz; R_SEXP_to_vector(pminz, &minz); }
-  if (!isNull(pmaxz)) { ppmaxz=&maxz; R_SEXP_to_vector(pmaxz, &maxz); }
-  igraph_matrix_init(&res, 0, 0);
-  igraph_layout_fruchterman_reingold_3d(&g, &res, niter, maxdelta, area,
-					coolexp, repulserad, 0, ppweights,
-					ppminx, ppmaxx, ppminy, ppmaxy,
-					ppminz, ppmaxz);
-  PROTECT(result=R_igraph_matrix_to_SEXP(&res));
-  igraph_matrix_destroy(&res);
-  
-  UNPROTECT(1);
-  return result;
-}
 
 SEXP R_igraph_degree_sequence_game(SEXP pout_seq, SEXP pin_seq,
 				   SEXP pmethod) {
@@ -5680,11 +5806,13 @@ SEXP R_igraph_layout_reingold_tilford(SEXP graph, SEXP proot,
   R_SEXP_to_vector(prootlevel, &rootlevel);
   igraph_matrix_init(&res, 0, 0);
   if (!circ) {
-    igraph_layout_reingold_tilford(&g, &res, (igraph_neimode_t) mode, &root,
+    igraph_layout_reingold_tilford(&g, &res, (igraph_neimode_t) mode,
+				   LENGTH(proot)==0 ? 0 : &root,
 				   &rootlevel);
   } else {
     igraph_layout_reingold_tilford_circular(&g, &res, (igraph_neimode_t) mode,
-					    &root, &rootlevel);
+					    LENGTH(proot)==0 ? 0 : &root,
+					    &rootlevel);
   }
   PROTECT(result=R_igraph_matrix_to_SEXP(&res));
   igraph_matrix_destroy(&res);
@@ -6396,18 +6524,20 @@ SEXP R_igraph_no_clusters(SEXP graph, SEXP pmode) {
 }
 
 SEXP R_igraph_neighborhood_size(SEXP graph, SEXP pvids, SEXP porder, 
-				SEXP pmode) {
+				SEXP pmode, SEXP pmindist) {
   igraph_t g;
   igraph_vs_t vids;
   igraph_integer_t order=(igraph_integer_t) REAL(porder)[0];
   igraph_integer_t mode=(igraph_integer_t) REAL(pmode)[0];
   igraph_vector_t res;
+  igraph_integer_t mindist=INTEGER(pmindist)[0];
   SEXP result;
   
   R_SEXP_to_igraph(graph, &g);
   R_SEXP_to_igraph_vs(pvids, &g, &vids);
   igraph_vector_init(&res, 0);
-  igraph_neighborhood_size(&g, &res, vids, order, (igraph_neimode_t) mode);
+  igraph_neighborhood_size(&g, &res, vids, order, (igraph_neimode_t) mode,
+			   mindist);
   PROTECT(result=NEW_NUMERIC(igraph_vector_size(&res)));
   igraph_vector_copy_to(&res, REAL(result));
   igraph_vector_destroy(&res);
@@ -6418,19 +6548,21 @@ SEXP R_igraph_neighborhood_size(SEXP graph, SEXP pvids, SEXP porder,
 }
 
 SEXP R_igraph_neighborhood(SEXP graph, SEXP pvids, SEXP porder, 
-			   SEXP pmode) {
+			   SEXP pmode, SEXP pmindist) {
   igraph_t g;
   igraph_vs_t vids;
   igraph_integer_t order=(igraph_integer_t) REAL(porder)[0];
   igraph_integer_t mode=(igraph_integer_t) REAL(pmode)[0];
   igraph_vector_ptr_t res;
   long int i;
+  igraph_integer_t mindist=INTEGER(pmindist)[0];
   SEXP result;
   
   R_SEXP_to_igraph(graph, &g);
   R_SEXP_to_igraph_vs(pvids, &g, &vids);
   igraph_vector_ptr_init(&res, 0);
-  igraph_neighborhood(&g, &res, vids, order, (igraph_neimode_t) mode);
+  igraph_neighborhood(&g, &res, vids, order, (igraph_neimode_t) mode,
+		      mindist);
   PROTECT(result=NEW_LIST(igraph_vector_ptr_size(&res)));
   for (i=0; i<igraph_vector_ptr_size(&res); i++) {
     igraph_vector_t *v=VECTOR(res)[i];
@@ -6447,13 +6579,14 @@ SEXP R_igraph_neighborhood(SEXP graph, SEXP pvids, SEXP porder,
 }
 
 SEXP R_igraph_neighborhood_graphs(SEXP graph, SEXP pvids, SEXP porder, 
-				  SEXP pmode) {
+				  SEXP pmode, SEXP pmindist) {
   igraph_t g;
   igraph_vs_t vids;
   igraph_integer_t order=(igraph_integer_t) REAL(porder)[0];
   igraph_integer_t mode=(igraph_integer_t) REAL(pmode)[0];
   igraph_vector_ptr_t res;
   long int i;
+  igraph_integer_t mindist=INTEGER(pmindist)[0];
   SEXP result;
   
   PROTECT(R_igraph_attribute_protected=NEW_LIST(100));
@@ -6463,7 +6596,8 @@ SEXP R_igraph_neighborhood_graphs(SEXP graph, SEXP pvids, SEXP porder,
   R_SEXP_to_igraph(graph, &g);
   R_SEXP_to_igraph_vs(pvids, &g, &vids);
   igraph_vector_ptr_init(&res, 0);
-  igraph_neighborhood_graphs(&g, &res, vids, order, (igraph_neimode_t) mode);
+  igraph_neighborhood_graphs(&g, &res, vids, order, (igraph_neimode_t) mode,
+			     mindist);
   PROTECT(result=NEW_LIST(igraph_vector_ptr_size(&res)));
   for (i=0; i<igraph_vector_ptr_size(&res); i++) {
     igraph_t *g=VECTOR(res)[i];
@@ -8998,1571 +9132,178 @@ SEXP R_igraph_graphlets_project(SEXP graph, SEXP weights, SEXP cliques,
 }
 
 
-SEXP R_igraph_revolver_d(SEXP graph, SEXP pniter, SEXP psd, SEXP pnorm,
-			 SEXP pcites, SEXP pexpected, SEXP perror, 
-			 SEXP pdebug) {
+SEXP R_igraph_adjacency_spectral_embedding(SEXP graph, SEXP no,
+					   SEXP pweights, SEXP pwhich,
+					   SEXP scaled, SEXP cvec,
+					   SEXP options) {
+
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_vector_t weights;
+  igraph_eigen_which_position_t c_which;
+  igraph_integer_t c_no;
+  igraph_bool_t c_scaled;
+  igraph_matrix_t c_X;
+  igraph_matrix_t c_Y;
+  igraph_vector_t c_D;
+  igraph_vector_t c_cvec;
+  igraph_arpack_options_t c_options;
+  SEXP X;
+  SEXP Y;
+  SEXP D;
+  igraph_bool_t directed;
 
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_bool_t sd=LOGICAL(psd)[0];
-  igraph_bool_t norm=LOGICAL(pnorm)[0];
-  igraph_bool_t cites=LOGICAL(pcites)[0];
-  igraph_bool_t expected=LOGICAL(pexpected)[0];
-  igraph_vector_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_vector_t vsd, vnorm, vcites, vexpected;
-  igraph_vector_t *pvsd=0, *pvnorm=0, *pvcites=0, *pvexpected=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
   SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  igraph_vector_init(&kernel, 0);
-  if (sd) { igraph_vector_init(&vsd, 0); pvsd=&vsd; }
-  if (norm) { igraph_vector_init(&vnorm, 0); pvnorm=&vnorm; }
-  if (cites) { igraph_vector_init(&vcites, 0); pvcites=&vcites; }
-  if (expected) { igraph_vector_init(&vexpected, 0); pvexpected=&vexpected; }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_vector(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
+                                        /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  directed=igraph_is_directed(&c_graph);
+  if (!isNull(pweights)) {
+    R_SEXP_to_vector(pweights, &weights);
   }
-
-  igraph_revolver_d(&g, niter, &kernel, pvsd, pvnorm, pvcites, pvexpected,
-		   pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_vector_to_SEXP(&kernel));
-  igraph_vector_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orvector_to_SEXP(pvsd));
-  if (pvsd) { igraph_vector_destroy(pvsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orvector_to_SEXP(pvnorm));
-  if (pvnorm) { igraph_vector_destroy(pvnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orvector_to_SEXP(pvcites));
-  if (pvcites) { igraph_vector_destroy(pvcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orvector_to_SEXP(pvexpected));
-  if (pvexpected) { igraph_vector_destroy(pvexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
+  c_which=INTEGER(pwhich)[0];
+  c_no=INTEGER(no)[0];
+  c_scaled=LOGICAL(scaled)[0];
+  if (0 != igraph_matrix_init(&c_X, 0, 0)) {
+    igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
   }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_X);
+  if (directed) {
+    if (0 != igraph_matrix_init(&c_Y, 0, 0)) {
+      igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_matrix_destroy, &c_Y);
   }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_d(SEXP graph, SEXP pkernel) {
-
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pkernel, &kernel);
-  igraph_revolver_error2_d(&g, &kernel, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}   
-
-SEXP R_igraph_revolver_ad(SEXP graph, SEXP pniter, SEXP pagebins,
-			  SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			  SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_bool_t sd=LOGICAL(psd)[0];
-  igraph_bool_t norm=LOGICAL(pnorm)[0];
-  igraph_bool_t cites=LOGICAL(pcites)[0];
-  igraph_bool_t expected=LOGICAL(pexpected)[0];
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_matrix_t vsd, vnorm, vcites, vexpected;
-  igraph_matrix_t *pvsd=0, *pvnorm=0, *pvcites=0, *pvexpected=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (sd) { igraph_matrix_init(&vsd, 0, 0); pvsd=&vsd; }
-  if (norm) { igraph_matrix_init(&vnorm, 0, 0); pvnorm=&vnorm; }
-  if (cites) { igraph_matrix_init(&vcites, 0, 0); pvcites=&vcites; }
-  if (expected) { igraph_matrix_init(&vexpected, 0, 0); pvexpected=&vexpected; }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-
-  igraph_revolver_ad(&g, niter, agebins, &kernel, pvsd, pvnorm, pvcites,
-		     pvexpected, pplogprob, pplognull, pplogmax, 
-		     ppdebug, ppdebugres);
-
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(pvsd));
-  if (pvsd) { igraph_matrix_destroy(pvsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(pvnorm));
-  if (pvnorm) { igraph_matrix_destroy(pvnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(pvcites));
-  if (pvcites) { igraph_matrix_destroy(pvcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(pvexpected));
-  if (pvexpected) { igraph_matrix_destroy(pvexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-  
-}
-
-SEXP R_igraph_revolver_error2_ad(SEXP graph, SEXP pkernel) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_ad(&g, &kernel, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}   
-
-SEXP R_igraph_revolver_ade(SEXP graph, SEXP pcats, SEXP pniter, SEXP pagebins,
-			   SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			   SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_array3_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_array3_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_array3_init(&kernel, 0, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_array3_init(&vsd, 0, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_array3_init(&vnorm, 0, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_array3_init(&vcites, 0, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_array3_init(&vexpected, 0, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_ade(&g, niter, agebins, &cats, &kernel, ppsd, ppnorm,
-		     ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		     ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_array3_to_SEXP(&kernel));
-  igraph_array3_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orarray3_to_SEXP(ppsd));
-  if (ppsd) { igraph_array3_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orarray3_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_array3_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orarray3_to_SEXP(ppcites));
-  if (ppcites) { igraph_array3_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orarray3_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_array3_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_ade(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_array3_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_igraph_SEXP_to_array3(pkernel, &kernel);
-  igraph_revolver_error2_ade(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}   
-  
-SEXP R_igraph_revolver_e(SEXP graph, SEXP pcats, SEXP pniter, SEXP pst,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_vector_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_vector_t vst, *ppst=0;
-  igraph_vector_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_vector_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_vector_init(&kernel, 0);
-  if (LOGICAL(pst)[0]) { igraph_vector_init(&vst, 0); ppst=&vst; }
-  if (LOGICAL(psd)[0]) { igraph_vector_init(&vsd, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_vector_init(&vnorm, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_vector_init(&vcites, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_vector_init(&vexpected, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_vector(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_e(&g, niter, &cats, &kernel, ppst, ppsd, ppnorm, ppcites, ppexpected,
-		   pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(8));
-  SET_VECTOR_ELT(result, 0, R_igraph_vector_to_SEXP(&kernel));
-  igraph_vector_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orvector_to_SEXP(ppst));
-  if (ppst) { igraph_vector_destroy(ppst); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orvector_to_SEXP(ppsd));
-  if (ppsd) { igraph_vector_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orvector_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_vector_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orvector_to_SEXP(ppcites));
-  if (ppcites) { igraph_vector_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 5, R_igraph_0orvector_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_vector_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 7, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 7))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 7))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 7))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(8));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("st"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 7, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_e(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_SEXP_to_vector(pkernel, &kernel);
-  igraph_revolver_error2_e(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}   
-  
-SEXP R_igraph_revolver_de(SEXP graph, SEXP pcats, SEXP pniter,
-			  SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			  SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_de(&g, niter, &cats, &kernel, ppsd, ppnorm, ppcites,
-		    ppexpected, pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-  
-SEXP R_igraph_revolver_error2_de(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_de(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_l(SEXP graph, SEXP pniter, SEXP pagebins,
-			SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_vector_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_vector_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  igraph_vector_init(&kernel, 0);
-  if (LOGICAL(psd)[0]) { igraph_vector_init(&vsd, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_vector_init(&vnorm, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_vector_init(&vcites, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_vector_init(&vexpected, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_vector(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_l(&g, niter, agebins, &kernel, ppsd, ppnorm, 
-		   ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		   ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_vector_to_SEXP(&kernel));
-  igraph_vector_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orvector_to_SEXP(ppsd));
-  if (ppsd) { igraph_vector_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orvector_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_vector_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orvector_to_SEXP(ppcites));
-  if (ppcites) { igraph_vector_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orvector_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_vector_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_l(SEXP graph, SEXP pkernel) {
-
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pkernel, &kernel);
-  igraph_revolver_error2_l(&g, &kernel, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_dl(SEXP graph, SEXP pniter, SEXP pagebins,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_dl(&g, niter, agebins, &kernel, ppsd, ppnorm, 
-		   ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		   ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-  
-SEXP R_igraph_revolver_error2_dl(SEXP graph, SEXP pkernel) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_dl(&g, &kernel, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_el(SEXP graph, SEXP pcats, SEXP pniter, SEXP pagebins,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_el(&g, niter, &cats, agebins, &kernel, ppsd, ppnorm, 
-		   ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		   ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_el(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_el(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_r(SEXP graph, SEXP pniter, SEXP pwindow,
-			 SEXP psd, SEXP pnorm,
-			 SEXP pcites, SEXP pexpected, SEXP perror, 
-			 SEXP pdebug) {
-
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_bool_t sd=LOGICAL(psd)[0];
-  igraph_bool_t norm=LOGICAL(pnorm)[0];
-  igraph_bool_t cites=LOGICAL(pcites)[0];
-  igraph_bool_t expected=LOGICAL(pexpected)[0];
-  igraph_vector_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_vector_t vsd, vnorm, vcites, vexpected;
-  igraph_vector_t *pvsd=0, *pvnorm=0, *pvcites=0, *pvexpected=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  igraph_vector_init(&kernel, 0);
-  if (sd) { igraph_vector_init(&vsd, 0); pvsd=&vsd; }
-  if (norm) { igraph_vector_init(&vnorm, 0); pvnorm=&vnorm; }
-  if (cites) { igraph_vector_init(&vcites, 0); pvcites=&vcites; }
-  if (expected) { igraph_vector_init(&vexpected, 0); pvexpected=&vexpected; }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_vector(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-
-  igraph_revolver_r(&g, niter, window, &kernel, pvsd, pvnorm, pvcites, pvexpected,
-		   pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_vector_to_SEXP(&kernel));
-  igraph_vector_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orvector_to_SEXP(pvsd));
-  if (pvsd) { igraph_vector_destroy(pvsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orvector_to_SEXP(pvnorm));
-  if (pvnorm) { igraph_vector_destroy(pvnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orvector_to_SEXP(pvcites));
-  if (pvcites) { igraph_vector_destroy(pvcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orvector_to_SEXP(pvexpected));
-  if (pvexpected) { igraph_vector_destroy(pvexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_r(SEXP graph, SEXP pkernel, SEXP pwindow) {
-
-  igraph_t g;
-  igraph_vector_t kernel;
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pkernel, &kernel);
-  igraph_revolver_error2_r(&g, &kernel, window, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_ar(SEXP graph, SEXP pniter, SEXP pagebins, SEXP pwindow,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_matrix_t kernel;  
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];  
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_bool_t sd=LOGICAL(psd)[0];
-  igraph_bool_t norm=LOGICAL(pnorm)[0];
-  igraph_bool_t cites=LOGICAL(pcites)[0];
-  igraph_bool_t expected=LOGICAL(pexpected)[0];
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_matrix_t vsd, vnorm, vcites, vexpected;
-  igraph_matrix_t *pvsd=0, *pvnorm=0, *pvcites=0, *pvexpected=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (sd) { igraph_matrix_init(&vsd, 0, 0); pvsd=&vsd; }
-  if (norm) { igraph_matrix_init(&vnorm, 0, 0); pvnorm=&vnorm; }
-  if (cites) { igraph_matrix_init(&vcites, 0, 0); pvcites=&vcites; }
-  if (expected) { igraph_matrix_init(&vexpected, 0, 0); pvexpected=&vexpected; }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-
-  igraph_revolver_ar(&g, niter, agebins, window, &kernel, pvsd, pvnorm, pvcites,
-		    pvexpected, pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(pvsd));
-  if (pvsd) { igraph_matrix_destroy(pvsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(pvnorm));
-  if (pvnorm) { igraph_matrix_destroy(pvnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(pvcites));
-  if (pvcites) { igraph_matrix_destroy(pvcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(pvexpected));
-  if (pvexpected) { igraph_matrix_destroy(pvexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-  
-}
-
-SEXP R_igraph_revolver_error2_ar(SEXP graph, SEXP pkernel, SEXP pwindow) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_ar(&g, &kernel, window, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_di(SEXP graph, SEXP pcats, SEXP pniter,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_di(&g, niter, &cats, &kernel, ppsd, ppnorm, ppcites,
-		    ppexpected, pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_di(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_di(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_adi(SEXP graph, SEXP pcats, SEXP pniter, SEXP pagebins,
-			  SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			  SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_array3_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_array3_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_array3_init(&kernel, 0, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_array3_init(&vsd, 0, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_array3_init(&vnorm, 0, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_array3_init(&vcites, 0, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_array3_init(&vexpected, 0, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_adi(&g, niter, agebins, &cats, &kernel, ppsd, ppnorm,
-		     ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		     ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_array3_to_SEXP(&kernel));
-  igraph_array3_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orarray3_to_SEXP(ppsd));
-  if (ppsd) { igraph_array3_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orarray3_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_array3_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orarray3_to_SEXP(ppcites));
-  if (ppcites) { igraph_array3_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orarray3_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_array3_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_adi(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_array3_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_igraph_SEXP_to_array3(pkernel, &kernel);
-  igraph_revolver_error2_adi(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_il(SEXP graph, SEXP pcats, SEXP pniter, SEXP pagebins,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_il(&g, niter, agebins, &cats, &kernel, ppsd, ppnorm, 
-		    ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		    ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_il(SEXP graph, SEXP pkernel, SEXP pcats) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_vector_t cats;
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_il(&g, &kernel, &cats, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_ir(SEXP graph, SEXP pcats, SEXP pwindow, SEXP pniter,
-			 SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			 SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_matrix_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_ir(&g, niter, window, &cats, &kernel, ppsd, ppnorm, ppcites,
-		    ppexpected, pplogprob, pplognull, pplogmax, ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_ir(SEXP graph, SEXP pkernel, SEXP pcats, 
-				 SEXP pwindow) {
-
-  igraph_t g;
-  igraph_matrix_t kernel;
-  igraph_vector_t cats;
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_SEXP_to_matrix(pkernel, &kernel);
-  igraph_revolver_error2_ir(&g, &kernel, &cats, window, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
-  UNPROTECT(1);
-  return result;
-}
-
-SEXP R_igraph_revolver_air(SEXP graph, SEXP pcats, SEXP pwindow, 
-			  SEXP pniter, SEXP pagebins,
-			  SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			  SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t cats;
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_array3_t kernel;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_integer_t agebins=(igraph_integer_t) REAL(pagebins)[0];
-  igraph_array3_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0, rlogmax, *pplogmax=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  igraph_array3_init(&kernel, 0, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_array3_init(&vsd, 0, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_array3_init(&vnorm, 0, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_array3_init(&vcites, 0, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_array3_init(&vexpected, 0, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; pplogmax=&rlogmax; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_air(&g, niter, window, agebins, &cats, &kernel, ppsd, ppnorm,
-		     ppcites, ppexpected, pplogprob, pplognull, pplogmax, ppdebug,
-		     ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_array3_to_SEXP(&kernel));
-  igraph_array3_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0orarray3_to_SEXP(ppsd));
-  if (ppsd) { igraph_array3_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0orarray3_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_array3_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0orarray3_to_SEXP(ppcites));
-  if (ppcites) { igraph_array3_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0orarray3_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_array3_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
+  if (0 != igraph_vector_init(&c_D, 0)) {
+    igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
   }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(3));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-    REAL(VECTOR_ELT(result, 6))[2]=*pplogmax;
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_D);
+  R_SEXP_to_vector(cvec, &c_cvec);
+  R_SEXP_to_igraph_arpack_options(options, &c_options);
+
+/* Call igraph */
+  igraph_adjacency_spectral_embedding(&c_graph, c_no,
+				      isNull(pweights) ? 0 : &weights,
+				      c_which, c_scaled, &c_X,
+				      directed ? &c_Y : 0, &c_D,
+				      &c_cvec, &c_options);
+
+  /* Convert output */
+  PROTECT(result=NEW_LIST(4));
+  PROTECT(names=NEW_CHARACTER(4));
+  PROTECT(X=R_igraph_matrix_to_SEXP(&c_X));
+  igraph_matrix_destroy(&c_X);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (directed) {
+    PROTECT(Y=R_igraph_matrix_to_SEXP(&c_Y));
+    igraph_matrix_destroy(&c_Y);
+    IGRAPH_FINALLY_CLEAN(1);
   } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
+    PROTECT(Y=R_NilValue);
   }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
+  PROTECT(D=R_igraph_vector_to_SEXP(&c_D));
+  igraph_vector_destroy(&c_D);
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
+  SET_VECTOR_ELT(result, 0, X);
+  SET_VECTOR_ELT(result, 1, Y);
+  SET_VECTOR_ELT(result, 2, D);
+  SET_VECTOR_ELT(result, 3, options);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("X"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("Y"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("D"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("options"));
   SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
-
-SEXP R_igraph_revolver_error2_air(SEXP graph, SEXP pkernel, SEXP pcats, 
-				  SEXP pwindow) {
+  UNPROTECT(5);
 
-  igraph_t g;
-  igraph_array3_t kernel;
-  igraph_vector_t cats;
-  igraph_integer_t window=(igraph_integer_t) REAL(pwindow)[0];
-  igraph_real_t logprob, lognull;
-  SEXP result;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pcats, &cats);
-  R_igraph_SEXP_to_array3(pkernel, &kernel);
-  igraph_revolver_error2_air(&g, &kernel, &cats, window, &logprob, &lognull);
-  PROTECT(result=NEW_NUMERIC(2));  
-  REAL(result)[0]=logprob;
-  REAL(result)[1]=lognull;
-   
   UNPROTECT(1);
-  return result;
+  return(result);
 }
 
-SEXP R_igraph_revolver_d_d(SEXP graph, SEXP pniter, SEXP pvtime, SEXP petime,
-			   SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			   SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t vtime, etime;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_matrix_t kernel;
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0;
+SEXP R_igraph_laplacian_spectral_embedding(SEXP graph, SEXP no,
+					   SEXP weights, SEXP which,
+					   SEXP degmode, SEXP type,
+					   SEXP scaled, SEXP options) {
+  /* Declarations */
+  igraph_t c_graph;
+  igraph_integer_t c_no;
+  igraph_vector_t c_weights;
+  igraph_eigen_which_position_t c_which;
+  igraph_neimode_t c_degmode;
+  igraph_laplacian_spectral_embedding_type_t c_type;
+  igraph_bool_t c_scaled;
+  igraph_matrix_t c_X;
+  igraph_matrix_t c_Y;
+  igraph_vector_t c_D;
+  igraph_arpack_options_t c_options;
+  SEXP X;
+  SEXP Y;
+  SEXP D;
+  igraph_bool_t directed;
+
   SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pvtime, &vtime);
-  R_SEXP_to_vector(petime, &etime);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_d_d(&g, niter, &vtime, &etime, &kernel, ppsd, ppnorm,
-		      ppcites, ppexpected, pplogprob, pplognull,
-		      ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
+  /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  directed=igraph_is_directed(&c_graph);
+  c_no=INTEGER(no)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_which=INTEGER(which)[0];
+  c_degmode=(igraph_neimode_t) REAL(degmode)[0];
+  c_type=(igraph_laplacian_spectral_embedding_type_t) INTEGER(type)[0];
+  c_scaled=LOGICAL(scaled)[0];
+  if (0 != igraph_matrix_init(&c_X, 0, 0)) {
+    igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_X);
+  if (directed) {
+    if (0 != igraph_matrix_init(&c_Y, 0, 0)) {
+      igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
+    }
+    IGRAPH_FINALLY(igraph_matrix_destroy, &c_Y);
+  }
+  if (0 != igraph_vector_init(&c_D, 0)) {
+    igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM);
   }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(2));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_D);
+  R_SEXP_to_igraph_arpack_options(options, &c_options);
+  /* Call igraph */
+  igraph_laplacian_spectral_embedding(&c_graph, c_no,
+				      (isNull(weights) ? 0 : &c_weights),
+				      c_which, c_degmode, c_type, c_scaled,
+				      &c_X, directed ? &c_Y : 0,
+				      &c_D, &c_options);
+
+  /* Convert output */
+  PROTECT(result=NEW_LIST(4));
+  PROTECT(names=NEW_CHARACTER(4));
+  PROTECT(X=R_igraph_matrix_to_SEXP(&c_X));
+  igraph_matrix_destroy(&c_X);
+  IGRAPH_FINALLY_CLEAN(1);
+  if (directed) {
+    PROTECT(Y=R_igraph_matrix_to_SEXP(&c_Y));
+    igraph_matrix_destroy(&c_Y);
+    IGRAPH_FINALLY_CLEAN(1);
   } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
+    PROTECT(Y=R_NilValue);
   }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
+  PROTECT(D=R_igraph_0orvector_to_SEXP(&c_D));
+  igraph_vector_destroy(&c_D);
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
+  SET_VECTOR_ELT(result, 0, X);
+  SET_VECTOR_ELT(result, 1, Y);
+  SET_VECTOR_ELT(result, 2, D);
+  SET_VECTOR_ELT(result, 3, options);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("X"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("Y"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("D"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("options"));
   SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}
+  UNPROTECT(5);
 
-SEXP R_igraph_evolver_d(SEXP pnodes, SEXP pkernel, SEXP poutseq, 
-			SEXP poutdist, SEXP pm, SEXP pdirected) {
-  
-  igraph_t g;
-  igraph_integer_t nodes=(igraph_integer_t) REAL(pnodes)[0];
-  igraph_vector_t kernel;
-  igraph_vector_t voutseq, *ppoutseq=0;
-  igraph_vector_t voutdist, *ppoutdist=0;
-  igraph_integer_t m=(igraph_integer_t) REAL(pm)[0];
-  igraph_bool_t directed=LOGICAL(pdirected)[0];
-  SEXP result;
-  
-  R_SEXP_to_vector(pkernel, &kernel);
-  if (!isNull(poutseq)) {
-    R_SEXP_to_vector(poutseq, &voutseq);
-    ppoutseq=&voutseq;
-  }
-  if (!isNull(poutdist)) {
-    R_SEXP_to_vector(poutdist, &voutdist);
-    ppoutdist=&voutdist;
-  }
-  
-  igraph_evolver_d(&g, nodes, &kernel, ppoutseq, ppoutdist, m, directed);
-  PROTECT(result=R_igraph_to_SEXP(&g));
-  igraph_destroy(&g);
-  
   UNPROTECT(1);
-  return result;
+  return(result);
 }
-		   
-SEXP R_igraph_revolver_p_p(SEXP graph, SEXP pniter, SEXP pvtime, SEXP petime,
-			   SEXP pauthors, SEXP peventsizes,
-			   SEXP psd, SEXP pnorm, SEXP pcites, SEXP pexpected,
-			   SEXP perror, SEXP pdebug) {
-  igraph_t g;
-  igraph_vector_t vtime, etime;
-  igraph_vector_t authors, eventsizes;
-  igraph_integer_t niter=(igraph_integer_t) REAL(pniter)[0];
-  igraph_matrix_t kernel;
-  igraph_matrix_t vsd, *ppsd=0, vnorm, *ppnorm=0, vcites, *ppcites=0,
-    vexpected, *ppexpected=0;
-  igraph_matrix_t debug, *ppdebug=0;
-  igraph_vector_ptr_t debugres, *ppdebugres=0;
-  igraph_real_t rlogprob, rlognull, *pplogprob=0, *pplognull=0;
-  SEXP result, names;
-  
-  R_SEXP_to_igraph(graph, &g);
-  R_SEXP_to_vector(pvtime, &vtime);
-  R_SEXP_to_vector(petime, &etime);
-  R_SEXP_to_vector(pauthors, &authors);
-  R_SEXP_to_vector(peventsizes, &eventsizes);
-  igraph_matrix_init(&kernel, 0, 0);
-  if (LOGICAL(psd)[0]) { igraph_matrix_init(&vsd, 0, 0); ppsd=&vsd; }
-  if (LOGICAL(pnorm)[0]) { igraph_matrix_init(&vnorm, 0, 0); ppnorm=&vnorm; }
-  if (LOGICAL(pcites)[0]) { igraph_matrix_init(&vcites, 0, 0); ppcites=&vcites; }
-  if (LOGICAL(pexpected)[0]) { 
-    igraph_matrix_init(&vexpected, 0, 0); 
-    ppexpected=&vexpected; 
-  }
-  if (LOGICAL(perror)[0]) { pplogprob=&rlogprob; pplognull=&rlognull; }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug)!=0) {
-    R_SEXP_to_matrix(pdebug, &debug); ppdebug=&debug; 
-    igraph_vector_ptr_init(&debugres, 0); ppdebugres=&debugres;
-  }
-  
-  igraph_revolver_p_p(&g, niter, &vtime, &etime, &authors, &eventsizes,
-		      &kernel, ppsd, ppnorm,
-		      ppcites, ppexpected, pplogprob, pplognull,
-		      ppdebug, ppdebugres);
-  
-  PROTECT(result=NEW_LIST(7));
-  SET_VECTOR_ELT(result, 0, R_igraph_matrix_to_SEXP(&kernel));
-  igraph_matrix_destroy(&kernel);
-  SET_VECTOR_ELT(result, 1, R_igraph_0ormatrix_to_SEXP(ppsd));
-  if (ppsd) { igraph_matrix_destroy(ppsd); }
-  SET_VECTOR_ELT(result, 2, R_igraph_0ormatrix_to_SEXP(ppnorm));
-  if (ppnorm) { igraph_matrix_destroy(ppnorm); }
-  SET_VECTOR_ELT(result, 3, R_igraph_0ormatrix_to_SEXP(ppcites));
-  if (ppcites) { igraph_matrix_destroy(ppcites); }
-  SET_VECTOR_ELT(result, 4, R_igraph_0ormatrix_to_SEXP(ppexpected));
-  if (ppexpected) { igraph_matrix_destroy(ppexpected); }
-  if (!isNull(pdebug) && GET_LENGTH(pdebug) != 0) {
-    /* TODO */
-  } else {
-    SET_VECTOR_ELT(result, 5, R_NilValue);
-  }
-  if (pplogprob) {
-    SET_VECTOR_ELT(result, 6, NEW_NUMERIC(2));
-    REAL(VECTOR_ELT(result, 6))[0]=*pplogprob;
-    REAL(VECTOR_ELT(result, 6))[1]=*pplognull;
-  } else {
-    SET_VECTOR_ELT(result, 6, R_NilValue);
-  }
-  PROTECT(names=NEW_CHARACTER(7));
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("sd"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("norm"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("expected"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("debug"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("error"));
-  SET_NAMES(result, names);
-  
-  UNPROTECT(2);
-  return result;
-}		   
 			 
-
-
 SEXP R_igraph_simple_interconnected_islands_game(SEXP islands_n, SEXP islands_size, SEXP islands_pin, SEXP n_inter) {
   
   igraph_t g;
@@ -10719,300 +9460,133 @@ SEXP R_igraph_bipartite_projection(SEXP graph, SEXP types, SEXP probe1,
   SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("proj2"));
   SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("multiplicity1"));
   SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("multiplicity2"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
-
-  UNPROTECT(1);
-  return(result);
-}
-
-/***********************************************/
-/* THE REST IS GENERATED BY inger.py           */
-/***********************************************/
-
-/*-------------------------------------------/
-/ igraph_empty                               /
-/-------------------------------------------*/
-SEXP R_igraph_empty(SEXP n, SEXP directed) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_n;
-  igraph_bool_t c_directed;
-  SEXP graph;
-
-  SEXP result;
-                                        /* Convert input */
-  c_n=INTEGER(n)[0];
-  c_directed=LOGICAL(directed)[0];
-                                        /* Call igraph */
-  igraph_empty(&c_graph, c_n, c_directed);
-
-                                        /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
-
-  UNPROTECT(1);
-  return(result);
-}
-
-/*-------------------------------------------/
-/ igraph_vcount                              /
-/-------------------------------------------*/
-SEXP R_igraph_vcount(SEXP graph) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_result;
-  SEXP result;
-                                        /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-                                        /* Call igraph */
-  c_result=  igraph_vcount(&c_graph);
-
-                                        /* Convert output */
-
-  PROTECT(result=NEW_INTEGER(1)); 
-  INTEGER(result)[0]=c_result;
-
-  UNPROTECT(1);
-  return(result);
-}
-
-/*-------------------------------------------/
-/ igraph_full_citation                       /
-/-------------------------------------------*/
-SEXP R_igraph_full_citation(SEXP n, SEXP directed) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_n;
-  igraph_bool_t c_directed;
-  SEXP graph;
-
-  SEXP result;
-                                        /* Convert input */
-  c_n=INTEGER(n)[0];
-  c_directed=LOGICAL(directed)[0];
-                                        /* Call igraph */
-  igraph_full_citation(&c_graph, c_n, c_directed);
-
-                                        /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
-
-  UNPROTECT(1);
-  return(result);
-}
-
-/*-------------------------------------------/
-/ igraph_lcf_vector                          /
-/-------------------------------------------*/
-SEXP R_igraph_lcf_vector(SEXP n, SEXP shifts, SEXP repeats) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_n;
-  igraph_vector_t c_shifts;
-  igraph_integer_t c_repeats;
-  SEXP graph;
-
-  SEXP result;
-                                        /* Convert input */
-  c_n=INTEGER(n)[0];
-  R_SEXP_to_vector(shifts, &c_shifts);
-  c_repeats=INTEGER(repeats)[0];
-                                        /* Call igraph */
-  igraph_lcf_vector(&c_graph, c_n, &c_shifts, c_repeats);
-
-                                        /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
-
-  UNPROTECT(1);
-  return(result);
-}
-
-/*-------------------------------------------/
-/ igraph_adjlist                             /
-/-------------------------------------------*/
-SEXP R_igraph_adjlist(SEXP adjlist, SEXP mode, SEXP duplicate) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_adjlist_t c_adjlist;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_duplicate;
-  SEXP graph;
-
-  SEXP result;
-                                        /* Convert input */
-  if (0 != R_SEXP_to_igraph_adjlist(adjlist, &c_adjlist)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  }
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_duplicate=LOGICAL(duplicate)[0];
-                                        /* Call igraph */
-  igraph_adjlist(&c_graph, &c_adjlist, c_mode, c_duplicate);
-
-                                        /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  SET_NAMES(result, names);
+  UNPROTECT(5);
 
   UNPROTECT(1);
   return(result);
 }
 
-/*-------------------------------------------/
-/ igraph_full_bipartite                      /
-/-------------------------------------------*/
-SEXP R_igraph_full_bipartite(SEXP n1, SEXP n2, SEXP directed, SEXP mode) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_integer_t c_n1;
-  igraph_integer_t c_n2;
-  igraph_bool_t c_directed;
-  igraph_neimode_t c_mode;
-  SEXP graph;
-  SEXP types;
+SEXP R_igraph_solve_lsap(SEXP px, SEXP pnc) {
 
-  SEXP result, names;
-                                        /* Convert input */
-  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); 
-  types=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_n1=INTEGER(n1)[0];
-  c_n2=INTEGER(n2)[0];
-  c_directed=LOGICAL(directed)[0];
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-                                        /* Call igraph */
-  igraph_full_bipartite(&c_graph, (isNull(types) ? 0 : &c_types), c_n1, c_n2, c_directed, c_mode);
+  igraph_matrix_t x;
+  igraph_integer_t nc = INTEGER(pnc)[0];
+  igraph_vector_int_t p;
+  SEXP result;
 
-                                        /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(types=R_igraph_0orvector_bool_to_SEXP(&c_types)); 
-  igraph_vector_bool_destroy(&c_types); 
+  R_SEXP_to_matrix(px, &x);
+
+  igraph_vector_int_init(&p, nc);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &p);
+
+  igraph_solve_lsap(&x, nc, &p);
+
+  PROTECT(result = R_igraph_vector_int_to_SEXP(&p));
+  igraph_vector_int_destroy(&p);
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, graph);
-  SET_VECTOR_ELT(result, 1, types);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
 
   UNPROTECT(1);
-  return(result);
+  return result;
 }
 
-/*-------------------------------------------/
-/ igraph_forest_fire_game                    /
-/-------------------------------------------*/
-SEXP R_igraph_forest_fire_game(SEXP nodes, SEXP fw_prob, SEXP bw_factor, SEXP ambs, SEXP directed) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_nodes;
-  igraph_real_t c_fw_prob;
-  igraph_real_t c_bw_factor;
-  igraph_integer_t c_ambs;
-  igraph_bool_t c_directed;
-  SEXP graph;
+SEXP R_igraph_adjacent_vertices(SEXP pgraph, SEXP pv, SEXP pmode) {
 
+  igraph_t graph;
+  igraph_vs_t vs;
+  igraph_vit_t vit;
+  igraph_integer_t mode = (igraph_integer_t) REAL(pmode)[0];
   SEXP result;
-                                        /* Convert input */
-  c_nodes=INTEGER(nodes)[0];
-  c_fw_prob=REAL(fw_prob)[0];
-  c_bw_factor=REAL(bw_factor)[0];
-  c_ambs=INTEGER(ambs)[0];
-  c_directed=LOGICAL(directed)[0];
-                                        /* Call igraph */
-  igraph_forest_fire_game(&c_graph, c_nodes, c_fw_prob, c_bw_factor, c_ambs, c_directed);
+  size_t i, n;
+  igraph_lazy_adjlist_t adjlist;
 
-                                        /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  R_SEXP_to_igraph(pgraph, &graph);
+  R_SEXP_to_igraph_vs(pv, &graph, &vs);
+  IGRAPH_FINALLY(igraph_vs_destroy, &vs);
+
+  igraph_vit_create(&graph, vs, &vit);
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  n = IGRAPH_VIT_SIZE(vit);
+
+  igraph_lazy_adjlist_init(&graph, &adjlist, mode, /* simplify= */ 0);
+  IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);
+
+  PROTECT(result = NEW_LIST(n));
+  for (IGRAPH_VIT_RESET(vit), i=0;
+       !IGRAPH_VIT_END(vit);
+       IGRAPH_VIT_NEXT(vit), i++) {
+    long int vid = IGRAPH_VIT_GET(vit);
+    igraph_vector_t *neis = igraph_lazy_adjlist_get(&adjlist, vid);
+    SET_VECTOR_ELT(result, i, R_igraph_vector_to_SEXP(neis));
+  }
+
+  igraph_lazy_adjlist_destroy(&adjlist);
+  igraph_vit_destroy(&vit);
+  igraph_vs_destroy(&vs);
+  IGRAPH_FINALLY_CLEAN(3);
 
   UNPROTECT(1);
-  return(result);
+  return result;
 }
 
-/*-------------------------------------------/
-/ igraph_static_fitness_game                 /
-/-------------------------------------------*/
-SEXP R_igraph_static_fitness_game(SEXP no_of_edges, SEXP fitness_out, SEXP fitness_in, SEXP loops, SEXP multiple) {
-                                        /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_no_of_edges;
-  igraph_vector_t c_fitness_out;
-  igraph_vector_t c_fitness_in;
-  igraph_bool_t c_loops;
-  igraph_bool_t c_multiple;
-  SEXP graph;
+SEXP R_igraph_incident_edges(SEXP pgraph, SEXP pe, SEXP pmode) {
 
+  igraph_t graph;
+  igraph_vs_t vs;
+  igraph_vit_t vit;
+  igraph_integer_t mode = (igraph_integer_t) REAL(pmode)[0];
   SEXP result;
-                                        /* Convert input */
-  c_no_of_edges=INTEGER(no_of_edges)[0];
-  R_SEXP_to_vector(fitness_out, &c_fitness_out);
-  if (!isNull(fitness_in)) { R_SEXP_to_vector(fitness_in, &c_fitness_in); }
-  c_loops=LOGICAL(loops)[0];
-  c_multiple=LOGICAL(multiple)[0];
-                                        /* Call igraph */
-  igraph_static_fitness_game(&c_graph, c_no_of_edges, &c_fitness_out, (isNull(fitness_in) ? 0 : &c_fitness_in), c_loops, c_multiple);
+  size_t i, n;
+  igraph_lazy_inclist_t adjlist;
 
-                                        /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  R_SEXP_to_igraph(pgraph, &graph);
+  R_SEXP_to_igraph_vs(pe, &graph, &vs);
+  IGRAPH_FINALLY(igraph_vs_destroy, &vs);
+
+  igraph_vit_create(&graph, vs, &vit);
+  IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+  n = IGRAPH_VIT_SIZE(vit);
+
+  igraph_lazy_inclist_init(&graph, &adjlist, mode);
+  IGRAPH_FINALLY(igraph_lazy_inclist_destroy, &adjlist);
+
+  PROTECT(result = NEW_LIST(n));
+  for (IGRAPH_VIT_RESET(vit), i=0;
+       !IGRAPH_VIT_END(vit);
+       IGRAPH_VIT_NEXT(vit), i++) {
+    long int eid = IGRAPH_VIT_GET(vit);
+    igraph_vector_t *neis = igraph_lazy_inclist_get(&adjlist, eid);
+    SET_VECTOR_ELT(result, i, R_igraph_vector_to_SEXP(neis));
+  }
+
+  igraph_lazy_inclist_destroy(&adjlist);
+  igraph_vit_destroy(&vit);
+  igraph_vs_destroy(&vs);
+  IGRAPH_FINALLY_CLEAN(3);
 
   UNPROTECT(1);
-  return(result);
+  return result;
 }
 
+/***********************************************/
+/* THE REST IS GENERATED BY inger.py           */
+/***********************************************/
+
 /*-------------------------------------------/
-/ igraph_static_power_law_game               /
+/ igraph_empty                               /
 /-------------------------------------------*/
-SEXP R_igraph_static_power_law_game(SEXP no_of_nodes, SEXP no_of_edges, SEXP exponent_out, SEXP exponent_in, SEXP loops, SEXP multiple, SEXP finite_size_correction) {
+SEXP R_igraph_empty(SEXP n, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_no_of_nodes;
-  igraph_integer_t c_no_of_edges;
-  igraph_real_t c_exponent_out;
-  igraph_real_t c_exponent_in;
-  igraph_bool_t c_loops;
-  igraph_bool_t c_multiple;
-  igraph_bool_t c_finite_size_correction;
+  igraph_integer_t c_n;
+  igraph_bool_t c_directed;
   SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  c_no_of_nodes=INTEGER(no_of_nodes)[0];
-  c_no_of_edges=INTEGER(no_of_edges)[0];
-  c_exponent_out=REAL(exponent_out)[0];
-  c_exponent_in=REAL(exponent_in)[0];
-  c_loops=LOGICAL(loops)[0];
-  c_multiple=LOGICAL(multiple)[0];
-  c_finite_size_correction=LOGICAL(finite_size_correction)[0];
+  c_n=INTEGER(n)[0];
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_static_power_law_game(&c_graph, c_no_of_nodes, c_no_of_edges, c_exponent_out, c_exponent_in, c_loops, c_multiple, c_finite_size_correction);
+  igraph_empty(&c_graph, c_n, c_directed);
 
                                         /* Convert output */
   IGRAPH_FINALLY(igraph_destroy, &c_graph); 
@@ -11026,59 +9600,43 @@ SEXP R_igraph_static_power_law_game(SEXP no_of_nodes, SEXP no_of_edges, SEXP exp
 }
 
 /*-------------------------------------------/
-/ igraph_k_regular_game                      /
+/ igraph_vcount                              /
 /-------------------------------------------*/
-SEXP R_igraph_k_regular_game(SEXP no_of_nodes, SEXP k, SEXP directed, SEXP multiple) {
+SEXP R_igraph_vcount(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_no_of_nodes;
-  igraph_integer_t c_k;
-  igraph_bool_t c_directed;
-  igraph_bool_t c_multiple;
-  SEXP graph;
-
+  igraph_integer_t c_result;
   SEXP result;
                                         /* Convert input */
-  c_no_of_nodes=INTEGER(no_of_nodes)[0];
-  c_k=INTEGER(k)[0];
-  c_directed=LOGICAL(directed)[0];
-  c_multiple=LOGICAL(multiple)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
                                         /* Call igraph */
-  igraph_k_regular_game(&c_graph, c_no_of_nodes, c_k, c_directed, c_multiple);
+  c_result=  igraph_vcount(&c_graph);
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+
+  PROTECT(result=NEW_INTEGER(1)); 
+  INTEGER(result)[0]=c_result;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_sbm_game                            /
+/ igraph_full_citation                       /
 /-------------------------------------------*/
-SEXP R_igraph_sbm_game(SEXP n, SEXP pref_matrix, SEXP block_sizes, SEXP directed, SEXP loops) {
+SEXP R_igraph_full_citation(SEXP n, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
   igraph_integer_t c_n;
-  igraph_matrix_t c_pref_matrix;
-  igraph_vector_int_t c_block_sizes;
   igraph_bool_t c_directed;
-  igraph_bool_t c_loops;
   SEXP graph;
 
   SEXP result;
                                         /* Convert input */
   c_n=INTEGER(n)[0];
-  R_SEXP_to_matrix(pref_matrix, &c_pref_matrix);
-  R_SEXP_to_vector_int(block_sizes, &c_block_sizes);
   c_directed=LOGICAL(directed)[0];
-  c_loops=LOGICAL(loops)[0];
                                         /* Call igraph */
-  igraph_sbm_game(&c_graph, c_n, &c_pref_matrix, &c_block_sizes, c_directed, c_loops);
+  igraph_full_citation(&c_graph, c_n, c_directed);
 
                                         /* Convert output */
   IGRAPH_FINALLY(igraph_destroy, &c_graph); 
@@ -11092,128 +9650,109 @@ SEXP R_igraph_sbm_game(SEXP n, SEXP pref_matrix, SEXP block_sizes, SEXP directed
 }
 
 /*-------------------------------------------/
-/ igraph_closeness                           /
+/ igraph_lcf_vector                          /
 /-------------------------------------------*/
-SEXP R_igraph_closeness(SEXP graph, SEXP vids, SEXP mode, SEXP weights, SEXP normalized) {
+SEXP R_igraph_lcf_vector(SEXP n, SEXP shifts, SEXP repeats) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_vs_t c_vids;
-  igraph_neimode_t c_mode;
-  igraph_vector_t c_weights;
-  igraph_bool_t c_normalized;
-  SEXP res;
+  igraph_integer_t c_n;
+  igraph_vector_t c_shifts;
+  igraph_integer_t c_repeats;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  c_normalized=LOGICAL(normalized)[0];
+  c_n=INTEGER(n)[0];
+  R_SEXP_to_vector(shifts, &c_shifts);
+  c_repeats=INTEGER(repeats)[0];
                                         /* Call igraph */
-  igraph_closeness(&c_graph, &c_res, c_vids, c_mode, (isNull(weights) ? 0 : &c_weights), c_normalized);
+  igraph_lcf_vector(&c_graph, c_n, &c_shifts, c_repeats);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_closeness_estimate                  /
+/ igraph_adjlist                             /
 /-------------------------------------------*/
-SEXP R_igraph_closeness_estimate(SEXP graph, SEXP vids, SEXP mode, SEXP cutoff, SEXP weights, SEXP normalized) {
+SEXP R_igraph_adjlist(SEXP adjlist, SEXP mode, SEXP duplicate) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_vs_t c_vids;
+  igraph_adjlist_t c_adjlist;
   igraph_neimode_t c_mode;
-  igraph_real_t c_cutoff;
-  igraph_vector_t c_weights;
-  igraph_bool_t c_normalized;
-  SEXP res;
+  igraph_bool_t c_duplicate;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
+  if (0 != R_SEXP_to_igraph_adjlist(adjlist, &c_adjlist)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  }
   c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_cutoff=REAL(cutoff)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  c_normalized=LOGICAL(normalized)[0];
+  c_duplicate=LOGICAL(duplicate)[0];
                                         /* Call igraph */
-  igraph_closeness_estimate(&c_graph, &c_res, c_vids, c_mode, c_cutoff, (isNull(weights) ? 0 : &c_weights), c_normalized);
+  igraph_adjlist(&c_graph, &c_adjlist, c_mode, c_duplicate);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_get_all_shortest_paths              /
+/ igraph_full_bipartite                      /
 /-------------------------------------------*/
-SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP from, SEXP to, SEXP mode) {
+SEXP R_igraph_full_bipartite(SEXP n1, SEXP n2, SEXP directed, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_ptr_t c_res;
-  igraph_vector_t c_nrgeo;
-  igraph_integer_t c_from;
-  igraph_vs_t c_to;
+  igraph_vector_bool_t c_types;
+  igraph_integer_t c_n1;
+  igraph_integer_t c_n2;
+  igraph_bool_t c_directed;
   igraph_neimode_t c_mode;
-  SEXP res;
-  SEXP nrgeo;
+  SEXP graph;
+  SEXP types;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_res);
-  if (0 != igraph_vector_init(&c_nrgeo, 0)) { 
+  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_nrgeo);
-  c_from=(igraph_integer_t) REAL(from)[0];
-  R_SEXP_to_igraph_vs(to, &c_graph, &c_to);
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); 
+  types=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  c_n1=INTEGER(n1)[0];
+  c_n2=INTEGER(n2)[0];
+  c_directed=LOGICAL(directed)[0];
   c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_get_all_shortest_paths(&c_graph, &c_res, &c_nrgeo, c_from, c_to, c_mode);
+  igraph_full_bipartite(&c_graph, (isNull(types) ? 0 : &c_types), c_n1, c_n2, c_directed, c_mode);
 
                                         /* Convert output */
   PROTECT(result=NEW_LIST(2));
   PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(res=R_igraph_vectorlist_to_SEXP_p1(&c_res)); 
-  R_igraph_vectorlist_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(nrgeo=R_igraph_vector_to_SEXP(&c_nrgeo)); 
-  igraph_vector_destroy(&c_nrgeo); 
+  PROTECT(types=R_igraph_0orvector_bool_to_SEXP(&c_types)); 
+  igraph_vector_bool_destroy(&c_types); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_to);
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, nrgeo);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("nrgeo"));
+  SET_VECTOR_ELT(result, 0, graph);
+  SET_VECTOR_ELT(result, 1, types);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
   SET_NAMES(result, names);
   UNPROTECT(3);
 
@@ -11222,380 +9761,317 @@ SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP from, SEXP to, SEXP mode)
 }
 
 /*-------------------------------------------/
-/ igraph_get_all_shortest_paths_dijkstra     /
+/ igraph_forest_fire_game                    /
 /-------------------------------------------*/
-SEXP R_igraph_get_all_shortest_paths_dijkstra(SEXP graph, SEXP from, SEXP to, SEXP weights, SEXP mode) {
+SEXP R_igraph_forest_fire_game(SEXP nodes, SEXP fw_prob, SEXP bw_factor, SEXP ambs, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_ptr_t c_res;
-  igraph_vector_t c_nrgeo;
-  igraph_integer_t c_from;
-  igraph_vs_t c_to;
-  igraph_vector_t c_weights;
-  igraph_neimode_t c_mode;
-  SEXP res;
-  SEXP nrgeo;
+  igraph_integer_t c_nodes;
+  igraph_real_t c_fw_prob;
+  igraph_real_t c_bw_factor;
+  igraph_integer_t c_ambs;
+  igraph_bool_t c_directed;
+  SEXP graph;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_res);
-  if (0 != igraph_vector_init(&c_nrgeo, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_nrgeo);
-  c_from=(igraph_integer_t) REAL(from)[0];
-  R_SEXP_to_igraph_vs(to, &c_graph, &c_to);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_nodes=INTEGER(nodes)[0];
+  c_fw_prob=REAL(fw_prob)[0];
+  c_bw_factor=REAL(bw_factor)[0];
+  c_ambs=INTEGER(ambs)[0];
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_get_all_shortest_paths_dijkstra(&c_graph, &c_res, &c_nrgeo, c_from, c_to, (isNull(weights) ? 0 : &c_weights), c_mode);
+  igraph_forest_fire_game(&c_graph, c_nodes, c_fw_prob, c_bw_factor, c_ambs, c_directed);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(res=R_igraph_vectorlist_to_SEXP_p1(&c_res)); 
-  R_igraph_vectorlist_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(nrgeo=R_igraph_vector_to_SEXP(&c_nrgeo)); 
-  igraph_vector_destroy(&c_nrgeo); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_to);
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, nrgeo);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("nrgeo"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_betweenness_estimate                /
+/ igraph_static_fitness_game                 /
 /-------------------------------------------*/
-SEXP R_igraph_betweenness_estimate(SEXP graph, SEXP vids, SEXP directed, SEXP cutoff, SEXP weights, SEXP nobigint) {
+SEXP R_igraph_static_fitness_game(SEXP no_of_edges, SEXP fitness_out, SEXP fitness_in, SEXP loops, SEXP multiple) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_vs_t c_vids;
-  igraph_bool_t c_directed;
-  igraph_real_t c_cutoff;
-  igraph_vector_t c_weights;
-  igraph_bool_t c_nobigint;
-  SEXP res;
+  igraph_integer_t c_no_of_edges;
+  igraph_vector_t c_fitness_out;
+  igraph_vector_t c_fitness_in;
+  igraph_bool_t c_loops;
+  igraph_bool_t c_multiple;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_directed=LOGICAL(directed)[0];
-  c_cutoff=REAL(cutoff)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  c_nobigint=LOGICAL(nobigint)[0];
+  c_no_of_edges=INTEGER(no_of_edges)[0];
+  R_SEXP_to_vector(fitness_out, &c_fitness_out);
+  if (!isNull(fitness_in)) { R_SEXP_to_vector(fitness_in, &c_fitness_in); }
+  c_loops=LOGICAL(loops)[0];
+  c_multiple=LOGICAL(multiple)[0];
                                         /* Call igraph */
-  igraph_betweenness_estimate(&c_graph, &c_res, c_vids, c_directed, c_cutoff, (isNull(weights) ? 0 : &c_weights), c_nobigint);
+  igraph_static_fitness_game(&c_graph, c_no_of_edges, &c_fitness_out, (isNull(fitness_in) ? 0 : &c_fitness_in), c_loops, c_multiple);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_edge_betweenness                    /
+/ igraph_static_power_law_game               /
 /-------------------------------------------*/
-SEXP R_igraph_edge_betweenness(SEXP graph, SEXP directed, SEXP weights) {
+SEXP R_igraph_static_power_law_game(SEXP no_of_nodes, SEXP no_of_edges, SEXP exponent_out, SEXP exponent_in, SEXP loops, SEXP multiple, SEXP finite_size_correction) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_bool_t c_directed;
-  igraph_vector_t c_weights;
-  SEXP res;
+  igraph_integer_t c_no_of_nodes;
+  igraph_integer_t c_no_of_edges;
+  igraph_real_t c_exponent_out;
+  igraph_real_t c_exponent_in;
+  igraph_bool_t c_loops;
+  igraph_bool_t c_multiple;
+  igraph_bool_t c_finite_size_correction;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  c_directed=LOGICAL(directed)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_no_of_nodes=INTEGER(no_of_nodes)[0];
+  c_no_of_edges=INTEGER(no_of_edges)[0];
+  c_exponent_out=REAL(exponent_out)[0];
+  c_exponent_in=REAL(exponent_in)[0];
+  c_loops=LOGICAL(loops)[0];
+  c_multiple=LOGICAL(multiple)[0];
+  c_finite_size_correction=LOGICAL(finite_size_correction)[0];
                                         /* Call igraph */
-  igraph_edge_betweenness(&c_graph, &c_res, c_directed, (isNull(weights) ? 0 : &c_weights));
+  igraph_static_power_law_game(&c_graph, c_no_of_nodes, c_no_of_edges, c_exponent_out, c_exponent_in, c_loops, c_multiple, c_finite_size_correction);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_edge_betweenness_estimate           /
+/ igraph_k_regular_game                      /
 /-------------------------------------------*/
-SEXP R_igraph_edge_betweenness_estimate(SEXP graph, SEXP directed, SEXP cutoff, SEXP weights) {
+SEXP R_igraph_k_regular_game(SEXP no_of_nodes, SEXP k, SEXP directed, SEXP multiple) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
+  igraph_integer_t c_no_of_nodes;
+  igraph_integer_t c_k;
   igraph_bool_t c_directed;
-  igraph_real_t c_cutoff;
-  igraph_vector_t c_weights;
-  SEXP res;
+  igraph_bool_t c_multiple;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_no_of_nodes=INTEGER(no_of_nodes)[0];
+  c_k=INTEGER(k)[0];
   c_directed=LOGICAL(directed)[0];
-  c_cutoff=REAL(cutoff)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_multiple=LOGICAL(multiple)[0];
                                         /* Call igraph */
-  igraph_edge_betweenness_estimate(&c_graph, &c_res, c_directed, c_cutoff, (isNull(weights) ? 0 : &c_weights));
+  igraph_k_regular_game(&c_graph, c_no_of_nodes, c_k, c_directed, c_multiple);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_pagerank_old                        /
+/ igraph_sbm_game                            /
 /-------------------------------------------*/
-SEXP R_igraph_pagerank_old(SEXP graph, SEXP vids, SEXP directed, SEXP niter, SEXP eps, SEXP damping, SEXP old) {
+SEXP R_igraph_sbm_game(SEXP n, SEXP pref_matrix, SEXP block_sizes, SEXP directed, SEXP loops) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_vs_t c_vids;
+  igraph_integer_t c_n;
+  igraph_matrix_t c_pref_matrix;
+  igraph_vector_int_t c_block_sizes;
   igraph_bool_t c_directed;
-  igraph_integer_t c_niter;
-  igraph_real_t c_eps;
-  igraph_real_t c_damping;
-  igraph_bool_t c_old;
-  SEXP res;
+  igraph_bool_t c_loops;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_n=INTEGER(n)[0];
+  R_SEXP_to_matrix(pref_matrix, &c_pref_matrix);
+  R_SEXP_to_vector_int(block_sizes, &c_block_sizes);
   c_directed=LOGICAL(directed)[0];
-  c_niter=INTEGER(niter)[0];
-  c_eps=REAL(eps)[0];
-  c_damping=REAL(damping)[0];
-  c_old=LOGICAL(old)[0];
+  c_loops=LOGICAL(loops)[0];
                                         /* Call igraph */
-  igraph_pagerank_old(&c_graph, &c_res, c_vids, c_directed, c_niter, c_eps, c_damping, c_old);
+  igraph_sbm_game(&c_graph, c_n, &c_pref_matrix, &c_block_sizes, c_directed, c_loops);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_personalized_pagerank               /
+/ igraph_hsbm_game                           /
 /-------------------------------------------*/
-SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP algo, SEXP vids, SEXP directed, SEXP damping, SEXP personalized, SEXP weights, SEXP options) {
+SEXP R_igraph_hsbm_game(SEXP n, SEXP m, SEXP rho, SEXP C, SEXP p) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_pagerank_algo_t c_algo;
-  igraph_vector_t c_vector;
-  igraph_real_t c_value;
-  igraph_vs_t c_vids;
-  igraph_bool_t c_directed;
-  igraph_real_t c_damping;
-  igraph_vector_t c_personalized;
-  igraph_vector_t c_weights;
-  igraph_pagerank_power_options_t c_options1; 
-  igraph_arpack_options_t c_options2; 
-  void* c_options;
-  SEXP vector;
-  SEXP value;
+  igraph_integer_t c_n;
+  igraph_integer_t c_m;
+  igraph_vector_t c_rho;
+  igraph_matrix_t c_C;
+  igraph_real_t c_p;
+  SEXP graph;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_algo=(igraph_pagerank_algo_t) INTEGER(algo)[0];
-  if (0 != igraph_vector_init(&c_vector, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_directed=LOGICAL(directed)[0];
-  c_damping=REAL(damping)[0];
-  if (!isNull(personalized)) { R_SEXP_to_vector(personalized, &c_personalized); }
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  if (c_algo == IGRAPH_PAGERANK_ALGO_POWER) {          
-  R_SEXP_to_pagerank_power_options(options, &c_options1);    
-  c_options = &c_options1;                                     
-  } else if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) {  
-  R_SEXP_to_igraph_arpack_options(options, &c_options2);     
-  c_options = &c_options2;	                              
-  } else {                                           
-  c_options = 0;                                         
-  }
+  c_n=INTEGER(n)[0];
+  c_m=INTEGER(m)[0];
+  R_SEXP_to_vector(rho, &c_rho);
+  R_SEXP_to_matrix(C, &c_C);
+  c_p=REAL(p)[0];
                                         /* Call igraph */
-  igraph_personalized_pagerank(&c_graph, c_algo, &c_vector, &c_value, c_vids, c_directed, c_damping, (isNull(personalized) ? 0 : &c_personalized), (isNull(weights) ? 0 : &c_weights), c_options);
+  igraph_hsbm_game(&c_graph, c_n, c_m, &c_rho, &c_C, c_p);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
-  igraph_vector_destroy(&c_vector); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  igraph_vs_destroy(&c_vids);
-  if (c_algo == IGRAPH_PAGERANK_ALGO_POWER) {                
-  PROTECT(options);                                          
-  } else if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) {        
-  PROTECT(options = R_igraph_arpack_options_to_SEXP(&c_options2)); 
-  } else {                                                 
-  PROTECT(options);                                          
-  }
-  SET_VECTOR_ELT(result, 0, vector);
-  SET_VECTOR_ELT(result, 1, value);
-  SET_VECTOR_ELT(result, 2, options);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_induced_subgraph                    /
+/ igraph_hsbm_list_game                      /
 /-------------------------------------------*/
-SEXP R_igraph_induced_subgraph(SEXP graph, SEXP vids, SEXP impl) {
+SEXP R_igraph_hsbm_list_game(SEXP n, SEXP mlist, SEXP rholist, SEXP Clist, SEXP p) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_t c_res;
-  igraph_vs_t c_vids;
-  igraph_subgraph_implementation_t c_impl;
-  SEXP res;
+  igraph_integer_t c_n;
+  igraph_vector_int_t c_mlist;
+  igraph_vector_ptr_t c_rholist;
+  igraph_vector_ptr_t c_Clist;
+  igraph_real_t c_p;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_impl=(igraph_subgraph_implementation_t) REAL(impl)[0];
+  c_n=INTEGER(n)[0];
+  R_SEXP_to_vector_int(mlist, &c_mlist);
+  R_igraph_SEXP_to_vectorlist(rholist, &c_rholist);
+  R_igraph_SEXP_to_matrixlist(Clist, &c_Clist);
+  c_p=REAL(p)[0];
                                         /* Call igraph */
-  igraph_induced_subgraph(&c_graph, &c_res, c_vids, c_impl);
+  igraph_hsbm_list_game(&c_graph, c_n, &c_mlist, &c_rholist, &c_Clist, c_p);
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_res); 
-  PROTECT(res=R_igraph_to_SEXP(&c_res));  
-  igraph_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_subgraph_edges                      /
+/ igraph_correlated_game                     /
 /-------------------------------------------*/
-SEXP R_igraph_subgraph_edges(SEXP graph, SEXP eids, SEXP delete_vertices) {
+SEXP R_igraph_correlated_game(SEXP old_graph, SEXP corr, SEXP p, SEXP permutation) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_t c_res;
-  igraph_es_t c_eids;
-  igraph_bool_t c_delete_vertices;
-  SEXP res;
+  igraph_t c_old_graph;
+  igraph_t c_new_graph;
+  igraph_real_t c_corr;
+  igraph_real_t c_p;
+  igraph_vector_t c_permutation;
+  SEXP new_graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_igraph_es(eids, &c_graph, &c_eids);
-  c_delete_vertices=LOGICAL(delete_vertices)[0];
+  R_SEXP_to_igraph(old_graph, &c_old_graph);
+  c_corr=REAL(corr)[0];
+  c_p=REAL(p)[0];
+  if (!isNull(permutation)) { R_SEXP_to_vector(permutation, &c_permutation); }
                                         /* Call igraph */
-  igraph_subgraph_edges(&c_graph, &c_res, c_eids, c_delete_vertices);
+  igraph_correlated_game(&c_old_graph, &c_new_graph, c_corr, c_p, (isNull(permutation) ? 0 : &c_permutation));
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_res); 
-  PROTECT(res=R_igraph_to_SEXP(&c_res));  
-  igraph_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_new_graph); 
+  PROTECT(new_graph=R_igraph_to_SEXP(&c_new_graph));  
+  igraph_destroy(&c_new_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_es_destroy(&c_eids);
-  result=res;
+  result=new_graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_path_length_hist                    /
+/ igraph_correlated_pair_game                /
 /-------------------------------------------*/
-SEXP R_igraph_path_length_hist(SEXP graph, SEXP directed) {
+SEXP R_igraph_correlated_pair_game(SEXP n, SEXP corr, SEXP p, SEXP directed, SEXP permutation) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_real_t c_unconnected;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  int c_n;
+  igraph_real_t c_corr;
+  igraph_real_t c_p;
   igraph_bool_t c_directed;
-  SEXP res;
-  SEXP unconnected;
+  igraph_vector_t c_permutation;
+  SEXP graph1;
+  SEXP graph2;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_n=INTEGER(n)[0];
+  c_corr=REAL(corr)[0];
+  c_p=REAL(p)[0];
   c_directed=LOGICAL(directed)[0];
+  if (!isNull(permutation)) { R_SEXP_to_vector(permutation, &c_permutation); }
                                         /* Call igraph */
-  igraph_path_length_hist(&c_graph, &c_res, &c_unconnected, c_directed);
+  igraph_correlated_pair_game(&c_graph1, &c_graph2, c_n, c_corr, c_p, c_directed, (isNull(permutation) ? 0 : &c_permutation));
 
                                         /* Convert output */
   PROTECT(result=NEW_LIST(2));
   PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(unconnected=NEW_NUMERIC(1)); 
-  REAL(unconnected)[0]=c_unconnected;
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, unconnected);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("unconnected"));
+  IGRAPH_FINALLY(igraph_destroy, &c_graph1); 
+  PROTECT(graph1=R_igraph_to_SEXP(&c_graph1));  
+  igraph_destroy(&c_graph1); 
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, &c_graph2); 
+  PROTECT(graph2=R_igraph_to_SEXP(&c_graph2));  
+  igraph_destroy(&c_graph2); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, graph1);
+  SET_VECTOR_ELT(result, 1, graph2);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph1"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("graph2"));
   SET_NAMES(result, names);
   UNPROTECT(3);
 
@@ -11604,30 +10080,27 @@ SEXP R_igraph_path_length_hist(SEXP graph, SEXP directed) {
 }
 
 /*-------------------------------------------/
-/ igraph_simplify                            /
+/ igraph_dot_product_game                    /
 /-------------------------------------------*/
-SEXP R_igraph_simplify(SEXP graph, SEXP remove_multiple, SEXP remove_loops, SEXP edge_attr_comb) {
+SEXP R_igraph_dot_product_game(SEXP vecs, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_bool_t c_remove_multiple;
-  igraph_bool_t c_remove_loops;
-  igraph_attribute_combination_t c_edge_attr_comb;
+  igraph_matrix_t c_vecs;
+  igraph_bool_t c_directed;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph_copy(graph, &c_graph); 
-  IGRAPH_FINALLY(igraph_destroy, &c_graph);
-  c_remove_multiple=LOGICAL(remove_multiple)[0];
-  c_remove_loops=LOGICAL(remove_loops)[0];
-  R_SEXP_to_attr_comb(edge_attr_comb, &c_edge_attr_comb);
+  R_SEXP_to_matrix(vecs, &c_vecs);
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_simplify(&c_graph, c_remove_multiple, c_remove_loops, &c_edge_attr_comb);
+  igraph_dot_product_game(&c_graph, &c_vecs, c_directed);
 
                                         /* Convert output */
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
   PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
   igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_attribute_combination_destroy(&c_edge_attr_comb);
   result=graph;
 
   UNPROTECT(1);
@@ -11635,23 +10108,34 @@ SEXP R_igraph_simplify(SEXP graph, SEXP remove_multiple, SEXP remove_loops, SEXP
 }
 
 /*-------------------------------------------/
-/ igraph_is_dag                              /
+/ igraph_sample_sphere_surface               /
 /-------------------------------------------*/
-SEXP R_igraph_is_dag(SEXP graph) {
+SEXP R_igraph_sample_sphere_surface(SEXP dim, SEXP n, SEXP radius, SEXP positive) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_bool_t c_res;
+  igraph_integer_t c_dim;
+  igraph_integer_t c_n;
+  igraph_real_t c_radius;
+  igraph_bool_t c_positive;
+  igraph_matrix_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
+  c_dim=INTEGER(dim)[0];
+  c_n=INTEGER(n)[0];
+  c_radius=REAL(radius)[0];
+  c_positive=LOGICAL(positive)[0];
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
                                         /* Call igraph */
-  igraph_is_dag(&c_graph, &c_res);
+  igraph_sample_sphere_surface(c_dim, c_n, c_radius, c_positive, &c_res);
 
                                         /* Convert output */
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
   result=res;
 
   UNPROTECT(1);
@@ -11659,23 +10143,34 @@ SEXP R_igraph_is_dag(SEXP graph) {
 }
 
 /*-------------------------------------------/
-/ igraph_is_simple                           /
+/ igraph_sample_sphere_volume                /
 /-------------------------------------------*/
-SEXP R_igraph_is_simple(SEXP graph) {
+SEXP R_igraph_sample_sphere_volume(SEXP dim, SEXP n, SEXP radius, SEXP positive) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_bool_t c_res;
+  igraph_integer_t c_dim;
+  igraph_integer_t c_n;
+  igraph_real_t c_radius;
+  igraph_bool_t c_positive;
+  igraph_matrix_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
+  c_dim=INTEGER(dim)[0];
+  c_n=INTEGER(n)[0];
+  c_radius=REAL(radius)[0];
+  c_positive=LOGICAL(positive)[0];
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
                                         /* Call igraph */
-  igraph_is_simple(&c_graph, &c_res);
+  igraph_sample_sphere_volume(c_dim, c_n, c_radius, c_positive, &c_res);
 
                                         /* Convert output */
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
   result=res;
 
   UNPROTECT(1);
@@ -11683,23 +10178,30 @@ SEXP R_igraph_is_simple(SEXP graph) {
 }
 
 /*-------------------------------------------/
-/ igraph_has_multiple                        /
+/ igraph_sample_dirichlet                    /
 /-------------------------------------------*/
-SEXP R_igraph_has_multiple(SEXP graph) {
+SEXP R_igraph_sample_dirichlet(SEXP n, SEXP alpha) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_bool_t c_res;
+  igraph_integer_t c_n;
+  igraph_vector_t c_alpha;
+  igraph_matrix_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
+  c_n=INTEGER(n)[0];
+  R_SEXP_to_vector(alpha, &c_alpha);
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
                                         /* Call igraph */
-  igraph_has_multiple(&c_graph, &c_res);
+  igraph_sample_dirichlet(c_n, &c_alpha, &c_res);
 
                                         /* Convert output */
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
   result=res;
 
   UNPROTECT(1);
@@ -11707,190 +10209,182 @@ SEXP R_igraph_has_multiple(SEXP graph) {
 }
 
 /*-------------------------------------------/
-/ igraph_eigenvector_centrality              /
+/ igraph_closeness                           /
 /-------------------------------------------*/
-SEXP R_igraph_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP weights, SEXP options) {
+SEXP R_igraph_closeness(SEXP graph, SEXP vids, SEXP mode, SEXP weights, SEXP normalized) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_vector;
-  igraph_real_t c_value;
-  igraph_bool_t c_directed;
-  igraph_bool_t c_scale;
+  igraph_vector_t c_res;
+  igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
   igraph_vector_t c_weights;
-  igraph_arpack_options_t c_options;
-  SEXP vector;
-  SEXP value;
+  igraph_bool_t c_normalized;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_vector, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
-  c_directed=LOGICAL(directed)[0];
-  c_scale=LOGICAL(scale)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
   if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  R_SEXP_to_igraph_arpack_options(options, &c_options);
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_directed, c_scale, (isNull(weights) ? 0 : &c_weights), &c_options);
+  igraph_closeness(&c_graph, &c_res, c_vids, c_mode, (isNull(weights) ? 0 : &c_weights), c_normalized);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
-  igraph_vector_destroy(&c_vector); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
-  SET_VECTOR_ELT(result, 0, vector);
-  SET_VECTOR_ELT(result, 1, value);
-  SET_VECTOR_ELT(result, 2, options);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  igraph_vs_destroy(&c_vids);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hub_score                           /
+/ igraph_closeness_estimate                  /
 /-------------------------------------------*/
-SEXP R_igraph_hub_score(SEXP graph, SEXP scale, SEXP weights, SEXP options) {
+SEXP R_igraph_closeness_estimate(SEXP graph, SEXP vids, SEXP mode, SEXP cutoff, SEXP weights, SEXP normalized) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_vector;
-  igraph_real_t c_value;
-  igraph_bool_t c_scale;
+  igraph_vector_t c_res;
+  igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
+  igraph_real_t c_cutoff;
   igraph_vector_t c_weights;
-  igraph_arpack_options_t c_options;
-  SEXP vector;
-  SEXP value;
+  igraph_bool_t c_normalized;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_vector, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
-  c_scale=LOGICAL(scale)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_cutoff=REAL(cutoff)[0];
   if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  R_SEXP_to_igraph_arpack_options(options, &c_options);
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_hub_score(&c_graph, &c_vector, &c_value, c_scale, (isNull(weights) ? 0 : &c_weights), &c_options);
+  igraph_closeness_estimate(&c_graph, &c_res, c_vids, c_mode, c_cutoff, (isNull(weights) ? 0 : &c_weights), c_normalized);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
-  igraph_vector_destroy(&c_vector); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
-  SET_VECTOR_ELT(result, 0, vector);
-  SET_VECTOR_ELT(result, 1, value);
-  SET_VECTOR_ELT(result, 2, options);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  igraph_vs_destroy(&c_vids);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_authority_score                     /
+/ igraph_get_all_shortest_paths              /
 /-------------------------------------------*/
-SEXP R_igraph_authority_score(SEXP graph, SEXP scale, SEXP weights, SEXP options) {
+SEXP R_igraph_get_all_shortest_paths(SEXP graph, SEXP from, SEXP to, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_vector;
-  igraph_real_t c_value;
-  igraph_bool_t c_scale;
-  igraph_vector_t c_weights;
-  igraph_arpack_options_t c_options;
-  SEXP vector;
-  SEXP value;
+  igraph_vector_ptr_t c_res;
+  igraph_vector_t c_nrgeo;
+  igraph_integer_t c_from;
+  igraph_vs_t c_to;
+  igraph_neimode_t c_mode;
+  SEXP res;
+  SEXP nrgeo;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_vector, 0)) { 
+  if (0 != igraph_vector_ptr_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
-  c_scale=LOGICAL(scale)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  R_SEXP_to_igraph_arpack_options(options, &c_options);
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_res);
+  if (0 != igraph_vector_init(&c_nrgeo, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_nrgeo);
+  c_from=(igraph_integer_t) REAL(from)[0];
+  R_SEXP_to_igraph_vs(to, &c_graph, &c_to);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_authority_score(&c_graph, &c_vector, &c_value, c_scale, (isNull(weights) ? 0 : &c_weights), &c_options);
+  igraph_get_all_shortest_paths(&c_graph, &c_res, &c_nrgeo, c_from, c_to, c_mode);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
-  igraph_vector_destroy(&c_vector); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(res=R_igraph_vectorlist_to_SEXP_p1(&c_res)); 
+  R_igraph_vectorlist_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
-  SET_VECTOR_ELT(result, 0, vector);
-  SET_VECTOR_ELT(result, 1, value);
-  SET_VECTOR_ELT(result, 2, options);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
+  PROTECT(nrgeo=R_igraph_vector_to_SEXP(&c_nrgeo)); 
+  igraph_vector_destroy(&c_nrgeo); 
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_vs_destroy(&c_to);
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, nrgeo);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("nrgeo"));
   SET_NAMES(result, names);
-  UNPROTECT(4);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_arpack_unpack_complex               /
+/ igraph_get_all_shortest_paths_dijkstra     /
 /-------------------------------------------*/
-SEXP R_igraph_arpack_unpack_complex(SEXP vectors, SEXP values, SEXP nev) {
+SEXP R_igraph_get_all_shortest_paths_dijkstra(SEXP graph, SEXP from, SEXP to, SEXP weights, SEXP mode) {
                                         /* Declarations */
-  igraph_matrix_t c_vectors;
-  igraph_matrix_t c_values;
-  igraph_integer_t c_nev;
+  igraph_t c_graph;
+  igraph_vector_ptr_t c_res;
+  igraph_vector_t c_nrgeo;
+  igraph_integer_t c_from;
+  igraph_vs_t c_to;
+  igraph_vector_t c_weights;
+  igraph_neimode_t c_mode;
+  SEXP res;
+  SEXP nrgeo;
 
   SEXP result, names;
                                         /* Convert input */
-  if (0 != R_SEXP_to_igraph_matrix_copy(vectors, &c_vectors)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_ptr_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_vectors);
-  if (0 != R_SEXP_to_igraph_matrix_copy(values, &c_values)) { 
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_res);
+  if (0 != igraph_vector_init(&c_nrgeo, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_values);
-  c_nev=INTEGER(nev)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_nrgeo);
+  c_from=(igraph_integer_t) REAL(from)[0];
+  R_SEXP_to_igraph_vs(to, &c_graph, &c_to);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_arpack_unpack_complex(&c_vectors, &c_values, c_nev);
+  igraph_get_all_shortest_paths_dijkstra(&c_graph, &c_res, &c_nrgeo, c_from, c_to, (isNull(weights) ? 0 : &c_weights), c_mode);
 
                                         /* Convert output */
   PROTECT(result=NEW_LIST(2));
   PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(vectors=R_igraph_matrix_to_SEXP(&c_vectors)); 
-  igraph_matrix_destroy(&c_vectors); 
+  PROTECT(res=R_igraph_vectorlist_to_SEXP_p1(&c_res)); 
+  R_igraph_vectorlist_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(values=R_igraph_matrix_to_SEXP(&c_values)); 
-  igraph_matrix_destroy(&c_values); 
+  PROTECT(nrgeo=R_igraph_vector_to_SEXP(&c_nrgeo)); 
+  igraph_vector_destroy(&c_nrgeo); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, vectors);
-  SET_VECTOR_ELT(result, 1, values);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vectors"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("values"));
+  igraph_vs_destroy(&c_to);
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, nrgeo);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("nrgeo"));
   SET_NAMES(result, names);
   UNPROTECT(3);
 
@@ -11899,78 +10393,75 @@ SEXP R_igraph_arpack_unpack_complex(SEXP vectors, SEXP values, SEXP nev) {
 }
 
 /*-------------------------------------------/
-/ igraph_unfold_tree                         /
+/ igraph_get_all_simple_paths                /
 /-------------------------------------------*/
-SEXP R_igraph_unfold_tree(SEXP graph, SEXP mode, SEXP roots) {
+SEXP R_igraph_get_all_simple_paths(SEXP graph, SEXP from, SEXP to, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_t c_tree;
+  igraph_vector_int_t c_res;
+  igraph_integer_t c_from;
+  igraph_vs_t c_to;
   igraph_neimode_t c_mode;
-  igraph_vector_t c_roots;
-  igraph_vector_t c_vertex_index;
-  SEXP tree;
-  SEXP vertex_index;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  R_SEXP_to_vector(roots, &c_roots);
-  if (0 != igraph_vector_init(&c_vertex_index, 0)) { 
+  if (0 != igraph_vector_int_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_vertex_index); 
-  vertex_index=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res);
+  c_from=(igraph_integer_t) REAL(from)[0];
+  R_SEXP_to_igraph_vs(to, &c_graph, &c_to);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_unfold_tree(&c_graph, &c_tree, c_mode, &c_roots, (isNull(vertex_index) ? 0 : &c_vertex_index));
+  igraph_get_all_simple_paths(&c_graph, &c_res, c_from, c_to, c_mode);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  IGRAPH_FINALLY(igraph_destroy, &c_tree); 
-  PROTECT(tree=R_igraph_to_SEXP(&c_tree));  
-  igraph_destroy(&c_tree); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(vertex_index=R_igraph_0orvector_to_SEXPp1(&c_vertex_index)); 
-  igraph_vector_destroy(&c_vertex_index); 
+  PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); 
+  igraph_vector_int_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, tree);
-  SET_VECTOR_ELT(result, 1, vertex_index);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("tree"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("vertex_index"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  igraph_vs_destroy(&c_to);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_is_mutual                           /
+/ igraph_betweenness_estimate                /
 /-------------------------------------------*/
-SEXP R_igraph_is_mutual(SEXP graph, SEXP es) {
+SEXP R_igraph_betweenness_estimate(SEXP graph, SEXP vids, SEXP directed, SEXP cutoff, SEXP weights, SEXP nobigint) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_res;
-  igraph_es_t c_es;
+  igraph_vector_t c_res;
+  igraph_vs_t c_vids;
+  igraph_bool_t c_directed;
+  igraph_real_t c_cutoff;
+  igraph_vector_t c_weights;
+  igraph_bool_t c_nobigint;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_bool_init(&c_res, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_res);
-  R_SEXP_to_igraph_es(es, &c_graph, &c_es);
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_directed=LOGICAL(directed)[0];
+  c_cutoff=REAL(cutoff)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_nobigint=LOGICAL(nobigint)[0];
                                         /* Call igraph */
-  igraph_is_mutual(&c_graph, &c_res, c_es);
+  igraph_betweenness_estimate(&c_graph, &c_res, c_vids, c_directed, c_cutoff, (isNull(weights) ? 0 : &c_weights), c_nobigint);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_bool_to_SEXP(&c_res)); 
-  igraph_vector_bool_destroy(&c_res); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_es_destroy(&c_es);
+  igraph_vs_destroy(&c_vids);
   result=res;
 
   UNPROTECT(1);
@@ -11978,113 +10469,86 @@ SEXP R_igraph_is_mutual(SEXP graph, SEXP es) {
 }
 
 /*-------------------------------------------/
-/ igraph_maximum_cardinality_search          /
+/ igraph_edge_betweenness                    /
 /-------------------------------------------*/
-SEXP R_igraph_maximum_cardinality_search(SEXP graph) {
+SEXP R_igraph_edge_betweenness(SEXP graph, SEXP directed, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_alpha;
-  igraph_vector_t c_alpham1;
-  SEXP alpha;
-  SEXP alpham1;
+  igraph_vector_t c_res;
+  igraph_bool_t c_directed;
+  igraph_vector_t c_weights;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_alpha, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_alpha);
-  if (0 != igraph_vector_init(&c_alpham1, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_alpham1); 
-  alpham1=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_directed=LOGICAL(directed)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_maximum_cardinality_search(&c_graph, &c_alpha, (isNull(alpham1) ? 0 : &c_alpham1));
+  igraph_edge_betweenness(&c_graph, &c_res, c_directed, (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(alpha=R_igraph_vector_to_SEXPp1(&c_alpha)); 
-  igraph_vector_destroy(&c_alpha); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(alpham1=R_igraph_0orvector_to_SEXPp1(&c_alpham1)); 
-  igraph_vector_destroy(&c_alpham1); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, alpham1);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("alpham1"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_avg_nearest_neighbor_degree         /
+/ igraph_edge_betweenness_estimate           /
 /-------------------------------------------*/
-SEXP R_igraph_avg_nearest_neighbor_degree(SEXP graph, SEXP vids, SEXP weights) {
+SEXP R_igraph_edge_betweenness_estimate(SEXP graph, SEXP directed, SEXP cutoff, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vs_t c_vids;
-  igraph_vector_t c_knn;
-  igraph_vector_t c_knnk;
+  igraph_vector_t c_res;
+  igraph_bool_t c_directed;
+  igraph_real_t c_cutoff;
   igraph_vector_t c_weights;
-  SEXP knn;
-  SEXP knnk;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  if (0 != igraph_vector_init(&c_knn, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_knn);
-  if (0 != igraph_vector_init(&c_knnk, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_knnk); 
-  knnk=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_directed=LOGICAL(directed)[0];
+  c_cutoff=REAL(cutoff)[0];
   if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_avg_nearest_neighbor_degree(&c_graph, c_vids, &c_knn, (isNull(knnk) ? 0 : &c_knnk), (isNull(weights) ? 0 : &c_weights));
+  igraph_edge_betweenness_estimate(&c_graph, &c_res, c_directed, c_cutoff, (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  igraph_vs_destroy(&c_vids);
-  PROTECT(knn=R_igraph_vector_to_SEXP(&c_knn)); 
-  igraph_vector_destroy(&c_knn); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(knnk=R_igraph_0orvector_to_SEXP(&c_knnk)); 
-  igraph_vector_destroy(&c_knnk); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, knn);
-  SET_VECTOR_ELT(result, 1, knnk);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("knn"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("knnk"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_strength                            /
+/ igraph_pagerank_old                        /
 /-------------------------------------------*/
-SEXP R_igraph_strength(SEXP graph, SEXP vids, SEXP mode, SEXP loops, SEXP weights) {
+SEXP R_igraph_pagerank_old(SEXP graph, SEXP vids, SEXP directed, SEXP niter, SEXP eps, SEXP damping, SEXP old) {
                                         /* Declarations */
   igraph_t c_graph;
   igraph_vector_t c_res;
   igraph_vs_t c_vids;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_loops;
-  igraph_vector_t c_weights;
+  igraph_bool_t c_directed;
+  igraph_integer_t c_niter;
+  igraph_real_t c_eps;
+  igraph_real_t c_damping;
+  igraph_bool_t c_old;
   SEXP res;
 
   SEXP result;
@@ -12095,11 +10559,13 @@ SEXP R_igraph_strength(SEXP graph, SEXP vids, SEXP mode, SEXP loops, SEXP weight
   } 
   IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
   R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_loops=LOGICAL(loops)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_directed=LOGICAL(directed)[0];
+  c_niter=INTEGER(niter)[0];
+  c_eps=REAL(eps)[0];
+  c_damping=REAL(damping)[0];
+  c_old=LOGICAL(old)[0];
                                         /* Call igraph */
-  igraph_strength(&c_graph, &c_res, c_vids, c_mode, c_loops, (isNull(weights) ? 0 : &c_weights));
+  igraph_pagerank_old(&c_graph, &c_res, c_vids, c_directed, c_niter, c_eps, c_damping, c_old);
 
                                         /* Convert output */
   PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
@@ -12113,107 +10579,135 @@ SEXP R_igraph_strength(SEXP graph, SEXP vids, SEXP mode, SEXP loops, SEXP weight
 }
 
 /*-------------------------------------------/
-/ igraph_centralization                      /
+/ igraph_personalized_pagerank               /
 /-------------------------------------------*/
-SEXP R_igraph_centralization(SEXP scores, SEXP theoretical_max, SEXP normalized) {
+SEXP R_igraph_personalized_pagerank(SEXP graph, SEXP algo, SEXP vids, SEXP directed, SEXP damping, SEXP personalized, SEXP weights, SEXP options) {
                                         /* Declarations */
-  igraph_vector_t c_scores;
-  igraph_real_t c_theoretical_max;
-  igraph_bool_t c_normalized;
-  igraph_real_t c_result;
-  SEXP result;
+  igraph_t c_graph;
+  igraph_pagerank_algo_t c_algo;
+  igraph_vector_t c_vector;
+  igraph_real_t c_value;
+  igraph_vs_t c_vids;
+  igraph_bool_t c_directed;
+  igraph_real_t c_damping;
+  igraph_vector_t c_personalized;
+  igraph_vector_t c_weights;
+  igraph_pagerank_power_options_t c_options1; 
+  igraph_arpack_options_t c_options2; 
+  void* c_options;
+  SEXP vector;
+  SEXP value;
+
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_vector(scores, &c_scores);
-  c_theoretical_max=REAL(theoretical_max)[0];
-  c_normalized=LOGICAL(normalized)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
+  c_algo=(igraph_pagerank_algo_t) INTEGER(algo)[0];
+  if (0 != igraph_vector_init(&c_vector, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_directed=LOGICAL(directed)[0];
+  c_damping=REAL(damping)[0];
+  if (!isNull(personalized)) { R_SEXP_to_vector(personalized, &c_personalized); }
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (c_algo == IGRAPH_PAGERANK_ALGO_POWER) {          
+  R_SEXP_to_pagerank_power_options(options, &c_options1);    
+  c_options = &c_options1;                                     
+  } else if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) {  
+  R_SEXP_to_igraph_arpack_options(options, &c_options2);     
+  c_options = &c_options2;	                              
+  } else {                                           
+  c_options = 0;                                         
+  }
                                         /* Call igraph */
-  c_result=  igraph_centralization(&c_scores, c_theoretical_max, c_normalized);
+  igraph_personalized_pagerank(&c_graph, c_algo, &c_vector, &c_value, c_vids, c_directed, c_damping, (isNull(personalized) ? 0 : &c_personalized), (isNull(weights) ? 0 : &c_weights), c_options);
 
                                         /* Convert output */
-
-  PROTECT(result=NEW_NUMERIC(1)); 
-  REAL(result)[0]=c_result;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
+  igraph_vector_destroy(&c_vector); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(value=NEW_NUMERIC(1)); 
+  REAL(value)[0]=c_value;
+  igraph_vs_destroy(&c_vids);
+  if (c_algo == IGRAPH_PAGERANK_ALGO_POWER) {                
+  PROTECT(options);                                          
+  } else if (c_algo == IGRAPH_PAGERANK_ALGO_ARPACK) {        
+  PROTECT(options = R_igraph_arpack_options_to_SEXP(&c_options2)); 
+  } else {                                                 
+  PROTECT(options);                                          
+  }
+  SET_VECTOR_ELT(result, 0, vector);
+  SET_VECTOR_ELT(result, 1, value);
+  SET_VECTOR_ELT(result, 2, options);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_degree               /
+/ igraph_induced_subgraph                    /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_degree(SEXP graph, SEXP mode, SEXP loops, SEXP normalized) {
+SEXP R_igraph_induced_subgraph(SEXP graph, SEXP vids, SEXP impl) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_loops;
-  igraph_real_t c_centralization;
-  igraph_real_t c_theoretical_max;
-  igraph_bool_t c_normalized;
+  igraph_t c_res;
+  igraph_vs_t c_vids;
+  igraph_subgraph_implementation_t c_impl;
   SEXP res;
-  SEXP centralization;
-  SEXP theoretical_max;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_loops=LOGICAL(loops)[0];
-  c_normalized=LOGICAL(normalized)[0];
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_impl=(igraph_subgraph_implementation_t) REAL(impl)[0];
                                         /* Call igraph */
-  igraph_centralization_degree(&c_graph, &c_res, c_mode, c_loops, &c_centralization, &c_theoretical_max, c_normalized);
+  igraph_induced_subgraph(&c_graph, &c_res, c_vids, c_impl);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_res); 
+  PROTECT(res=R_igraph_to_SEXP(&c_res));  
+  igraph_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(centralization=NEW_NUMERIC(1)); 
-  REAL(centralization)[0]=c_centralization;
-  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
-  REAL(theoretical_max)[0]=c_theoretical_max;
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, centralization);
-  SET_VECTOR_ELT(result, 2, theoretical_max);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("centralization"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("theoretical_max"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  igraph_vs_destroy(&c_vids);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_degree_tmax          /
+/ igraph_subgraph_edges                      /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_degree_tmax(SEXP graph, SEXP nodes, SEXP mode, SEXP loops) {
+SEXP R_igraph_subgraph_edges(SEXP graph, SEXP eids, SEXP delete_vertices) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_nodes;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_loops;
-  igraph_real_t c_res;
+  igraph_t c_res;
+  igraph_es_t c_eids;
+  igraph_bool_t c_delete_vertices;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
-  c_nodes=INTEGER(nodes)[0];
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_loops=LOGICAL(loops)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
+  R_SEXP_to_igraph_es(eids, &c_graph, &c_eids);
+  c_delete_vertices=LOGICAL(delete_vertices)[0];
                                         /* Call igraph */
-  igraph_centralization_degree_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_mode, c_loops, &c_res);
+  igraph_subgraph_edges(&c_graph, &c_res, c_eids, c_delete_vertices);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
+  IGRAPH_FINALLY(igraph_destroy, &c_res); 
+  PROTECT(res=R_igraph_to_SEXP(&c_res));  
+  igraph_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_es_destroy(&c_eids);
   result=res;
 
   UNPROTECT(1);
@@ -12221,20 +10715,16 @@ SEXP R_igraph_centralization_degree_tmax(SEXP graph, SEXP nodes, SEXP mode, SEXP
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_betweenness          /
+/ igraph_path_length_hist                    /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_betweenness(SEXP graph, SEXP directed, SEXP nobigint, SEXP normalized) {
+SEXP R_igraph_path_length_hist(SEXP graph, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
   igraph_vector_t c_res;
+  igraph_real_t c_unconnected;
   igraph_bool_t c_directed;
-  igraph_bool_t c_nobigint;
-  igraph_real_t c_centralization;
-  igraph_real_t c_theoretical_max;
-  igraph_bool_t c_normalized;
   SEXP res;
-  SEXP centralization;
-  SEXP theoretical_max;
+  SEXP unconnected;
 
   SEXP result, names;
                                         /* Convert input */
@@ -12244,56 +10734,77 @@ SEXP R_igraph_centralization_betweenness(SEXP graph, SEXP directed, SEXP nobigin
   } 
   IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
   c_directed=LOGICAL(directed)[0];
-  c_nobigint=LOGICAL(nobigint)[0];
-  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_centralization_betweenness(&c_graph, &c_res, c_directed, c_nobigint, &c_centralization, &c_theoretical_max, c_normalized);
+  igraph_path_length_hist(&c_graph, &c_res, &c_unconnected, c_directed);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
   PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
   igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(centralization=NEW_NUMERIC(1)); 
-  REAL(centralization)[0]=c_centralization;
-  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
-  REAL(theoretical_max)[0]=c_theoretical_max;
+  PROTECT(unconnected=NEW_NUMERIC(1)); 
+  REAL(unconnected)[0]=c_unconnected;
   SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, centralization);
-  SET_VECTOR_ELT(result, 2, theoretical_max);
+  SET_VECTOR_ELT(result, 1, unconnected);
   SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("centralization"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("theoretical_max"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("unconnected"));
   SET_NAMES(result, names);
-  UNPROTECT(4);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_betweenness_tmax     /
+/ igraph_simplify                            /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_betweenness_tmax(SEXP graph, SEXP nodes, SEXP directed) {
+SEXP R_igraph_simplify(SEXP graph, SEXP remove_multiple, SEXP remove_loops, SEXP edge_attr_comb) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_nodes;
-  igraph_bool_t c_directed;
-  igraph_real_t c_res;
+  igraph_bool_t c_remove_multiple;
+  igraph_bool_t c_remove_loops;
+  igraph_attribute_combination_t c_edge_attr_comb;
+
+  SEXP result;
+                                        /* Convert input */
+  R_SEXP_to_igraph_copy(graph, &c_graph); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph);
+  c_remove_multiple=LOGICAL(remove_multiple)[0];
+  c_remove_loops=LOGICAL(remove_loops)[0];
+  R_SEXP_to_attr_comb(edge_attr_comb, &c_edge_attr_comb);
+                                        /* Call igraph */
+  igraph_simplify(&c_graph, c_remove_multiple, c_remove_loops, &c_edge_attr_comb);
+
+                                        /* Convert output */
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_attribute_combination_destroy(&c_edge_attr_comb);
+  result=graph;
+
+  UNPROTECT(1);
+  return(result);
+}
+
+/*-------------------------------------------/
+/ igraph_is_dag                              /
+/-------------------------------------------*/
+SEXP R_igraph_is_dag(SEXP graph) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_bool_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
-  c_nodes=INTEGER(nodes)[0];
-  c_directed=LOGICAL(directed)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
                                         /* Call igraph */
-  igraph_centralization_betweenness_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_directed, &c_res);
+  igraph_is_dag(&c_graph, &c_res);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
   result=res;
 
   UNPROTECT(1);
@@ -12301,77 +10812,47 @@ SEXP R_igraph_centralization_betweenness_tmax(SEXP graph, SEXP nodes, SEXP direc
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_closeness            /
+/ igraph_is_simple                           /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_closeness(SEXP graph, SEXP mode, SEXP normalized) {
+SEXP R_igraph_is_simple(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_neimode_t c_mode;
-  igraph_real_t c_centralization;
-  igraph_real_t c_theoretical_max;
-  igraph_bool_t c_normalized;
+  igraph_bool_t c_res;
   SEXP res;
-  SEXP centralization;
-  SEXP theoretical_max;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_centralization_closeness(&c_graph, &c_res, c_mode, &c_centralization, &c_theoretical_max, c_normalized);
+  igraph_is_simple(&c_graph, &c_res);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(centralization=NEW_NUMERIC(1)); 
-  REAL(centralization)[0]=c_centralization;
-  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
-  REAL(theoretical_max)[0]=c_theoretical_max;
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, centralization);
-  SET_VECTOR_ELT(result, 2, theoretical_max);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("centralization"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("theoretical_max"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_closeness_tmax       /
+/ igraph_has_multiple                        /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_closeness_tmax(SEXP graph, SEXP nodes, SEXP mode) {
+SEXP R_igraph_has_multiple(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_nodes;
-  igraph_neimode_t c_mode;
-  igraph_real_t c_res;
+  igraph_bool_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
-  c_nodes=INTEGER(nodes)[0];
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
                                         /* Call igraph */
-  igraph_centralization_closeness_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_mode, &c_res);
+  igraph_has_multiple(&c_graph, &c_res);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
   result=res;
 
   UNPROTECT(1);
@@ -12379,23 +10860,19 @@ SEXP R_igraph_centralization_closeness_tmax(SEXP graph, SEXP nodes, SEXP mode) {
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_eigenvector_centrality /
+/ igraph_eigenvector_centrality              /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP options, SEXP normalized) {
+SEXP R_igraph_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP weights, SEXP options) {
                                         /* Declarations */
   igraph_t c_graph;
   igraph_vector_t c_vector;
   igraph_real_t c_value;
   igraph_bool_t c_directed;
   igraph_bool_t c_scale;
+  igraph_vector_t c_weights;
   igraph_arpack_options_t c_options;
-  igraph_real_t c_centralization;
-  igraph_real_t c_theoretical_max;
-  igraph_bool_t c_normalized;
   SEXP vector;
   SEXP value;
-  SEXP centralization;
-  SEXP theoretical_max;
 
   SEXP result, names;
                                         /* Convert input */
@@ -12406,266 +10883,376 @@ SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP directed, S
   IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
   c_directed=LOGICAL(directed)[0];
   c_scale=LOGICAL(scale)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
   R_SEXP_to_igraph_arpack_options(options, &c_options);
-  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_centralization_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_directed, c_scale, &c_options, &c_centralization, &c_theoretical_max, c_normalized);
+  igraph_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_directed, c_scale, (isNull(weights) ? 0 : &c_weights), &c_options);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(5));
-  PROTECT(names=NEW_CHARACTER(5));
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
   PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
   igraph_vector_destroy(&c_vector); 
   IGRAPH_FINALLY_CLEAN(1);
   PROTECT(value=NEW_NUMERIC(1)); 
   REAL(value)[0]=c_value;
   PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
-  PROTECT(centralization=NEW_NUMERIC(1)); 
-  REAL(centralization)[0]=c_centralization;
-  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
-  REAL(theoretical_max)[0]=c_theoretical_max;
   SET_VECTOR_ELT(result, 0, vector);
   SET_VECTOR_ELT(result, 1, value);
   SET_VECTOR_ELT(result, 2, options);
-  SET_VECTOR_ELT(result, 3, centralization);
-  SET_VECTOR_ELT(result, 4, theoretical_max);
   SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
   SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
   SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("centralization"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("theoretical_max"));
   SET_NAMES(result, names);
-  UNPROTECT(6);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_centralization_eigenvector_centrality_tmax /
+/ igraph_hub_score                           /
 /-------------------------------------------*/
-SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP graph, SEXP nodes, SEXP directed, SEXP scale) {
+SEXP R_igraph_hub_score(SEXP graph, SEXP scale, SEXP weights, SEXP options) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_nodes;
-  igraph_bool_t c_directed;
+  igraph_vector_t c_vector;
+  igraph_real_t c_value;
   igraph_bool_t c_scale;
-  igraph_real_t c_res;
-  SEXP res;
+  igraph_vector_t c_weights;
+  igraph_arpack_options_t c_options;
+  SEXP vector;
+  SEXP value;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
-  c_nodes=INTEGER(nodes)[0];
-  c_directed=LOGICAL(directed)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_vector, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
   c_scale=LOGICAL(scale)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  R_SEXP_to_igraph_arpack_options(options, &c_options);
                                         /* Call igraph */
-  igraph_centralization_eigenvector_centrality_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_directed, c_scale, &c_res);
+  igraph_hub_score(&c_graph, &c_vector, &c_value, c_scale, (isNull(weights) ? 0 : &c_weights), &c_options);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
+  igraph_vector_destroy(&c_vector); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(value=NEW_NUMERIC(1)); 
+  REAL(value)[0]=c_value;
+  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
+  SET_VECTOR_ELT(result, 0, vector);
+  SET_VECTOR_ELT(result, 1, value);
+  SET_VECTOR_ELT(result, 2, options);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_assortativity_nominal               /
+/ igraph_authority_score                     /
 /-------------------------------------------*/
-SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP types, SEXP directed) {
+SEXP R_igraph_authority_score(SEXP graph, SEXP scale, SEXP weights, SEXP options) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_types;
-  igraph_real_t c_res;
-  igraph_bool_t c_directed;
-  SEXP res;
+  igraph_vector_t c_vector;
+  igraph_real_t c_value;
+  igraph_bool_t c_scale;
+  igraph_vector_t c_weights;
+  igraph_arpack_options_t c_options;
+  SEXP vector;
+  SEXP value;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(types, &c_types);
-  c_directed=LOGICAL(directed)[0];
+  if (0 != igraph_vector_init(&c_vector, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
+  c_scale=LOGICAL(scale)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  R_SEXP_to_igraph_arpack_options(options, &c_options);
                                         /* Call igraph */
-  igraph_assortativity_nominal(&c_graph, &c_types, &c_res, c_directed);
+  igraph_authority_score(&c_graph, &c_vector, &c_value, c_scale, (isNull(weights) ? 0 : &c_weights), &c_options);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
+  igraph_vector_destroy(&c_vector); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(value=NEW_NUMERIC(1)); 
+  REAL(value)[0]=c_value;
+  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
+  SET_VECTOR_ELT(result, 0, vector);
+  SET_VECTOR_ELT(result, 1, value);
+  SET_VECTOR_ELT(result, 2, options);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_assortativity                       /
+/ igraph_arpack_unpack_complex               /
 /-------------------------------------------*/
-SEXP R_igraph_assortativity(SEXP graph, SEXP types1, SEXP types2, SEXP directed) {
+SEXP R_igraph_arpack_unpack_complex(SEXP vectors, SEXP values, SEXP nev) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_t c_types1;
-  igraph_vector_t c_types2;
-  igraph_real_t c_res;
-  igraph_bool_t c_directed;
-  SEXP res;
+  igraph_matrix_t c_vectors;
+  igraph_matrix_t c_values;
+  igraph_integer_t c_nev;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(types1, &c_types1);
-  if (!isNull(types2)) { R_SEXP_to_vector(types2, &c_types2); }
-  c_directed=LOGICAL(directed)[0];
+  if (0 != R_SEXP_to_igraph_matrix_copy(vectors, &c_vectors)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_vectors);
+  if (0 != R_SEXP_to_igraph_matrix_copy(values, &c_values)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_values);
+  c_nev=INTEGER(nev)[0];
                                         /* Call igraph */
-  igraph_assortativity(&c_graph, &c_types1, (isNull(types2) ? 0 : &c_types2), &c_res, c_directed);
+  igraph_arpack_unpack_complex(&c_vectors, &c_values, c_nev);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(vectors=R_igraph_matrix_to_SEXP(&c_vectors)); 
+  igraph_matrix_destroy(&c_vectors); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(values=R_igraph_matrix_to_SEXP(&c_values)); 
+  igraph_matrix_destroy(&c_values); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, vectors);
+  SET_VECTOR_ELT(result, 1, values);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vectors"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("values"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_assortativity_degree                /
+/ igraph_unfold_tree                         /
 /-------------------------------------------*/
-SEXP R_igraph_assortativity_degree(SEXP graph, SEXP directed) {
+SEXP R_igraph_unfold_tree(SEXP graph, SEXP mode, SEXP roots) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_res;
-  igraph_bool_t c_directed;
-  SEXP res;
+  igraph_t c_tree;
+  igraph_neimode_t c_mode;
+  igraph_vector_t c_roots;
+  igraph_vector_t c_vertex_index;
+  SEXP tree;
+  SEXP vertex_index;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_directed=LOGICAL(directed)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  R_SEXP_to_vector(roots, &c_roots);
+  if (0 != igraph_vector_init(&c_vertex_index, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_vertex_index); 
+  vertex_index=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_assortativity_degree(&c_graph, &c_res, c_directed);
+  igraph_unfold_tree(&c_graph, &c_tree, c_mode, &c_roots, (isNull(vertex_index) ? 0 : &c_vertex_index));
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  IGRAPH_FINALLY(igraph_destroy, &c_tree); 
+  PROTECT(tree=R_igraph_to_SEXP(&c_tree));  
+  igraph_destroy(&c_tree); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(vertex_index=R_igraph_0orvector_to_SEXPp1(&c_vertex_index)); 
+  igraph_vector_destroy(&c_vertex_index); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, tree);
+  SET_VECTOR_ELT(result, 1, vertex_index);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("tree"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("vertex_index"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_contract_vertices                   /
+/ igraph_is_mutual                           /
 /-------------------------------------------*/
-SEXP R_igraph_contract_vertices(SEXP graph, SEXP mapping, SEXP vertex_attr_comb) {
+SEXP R_igraph_is_mutual(SEXP graph, SEXP es) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_mapping;
-  igraph_attribute_combination_t c_vertex_attr_comb;
+  igraph_vector_bool_t c_res;
+  igraph_es_t c_es;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph_copy(graph, &c_graph); 
-  IGRAPH_FINALLY(igraph_destroy, &c_graph);
-  R_SEXP_to_vector(mapping, &c_mapping);
-  R_SEXP_to_attr_comb(vertex_attr_comb, &c_vertex_attr_comb);
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_bool_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_res);
+  R_SEXP_to_igraph_es(es, &c_graph, &c_es);
                                         /* Call igraph */
-  igraph_contract_vertices(&c_graph, &c_mapping, &c_vertex_attr_comb);
+  igraph_is_mutual(&c_graph, &c_res, c_es);
 
                                         /* Convert output */
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
+  PROTECT(res=R_igraph_vector_bool_to_SEXP(&c_res)); 
+  igraph_vector_bool_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_attribute_combination_destroy(&c_vertex_attr_comb);
-  result=graph;
+  igraph_es_destroy(&c_es);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_eccentricity                        /
+/ igraph_maximum_cardinality_search          /
 /-------------------------------------------*/
-SEXP R_igraph_eccentricity(SEXP graph, SEXP vids, SEXP mode) {
+SEXP R_igraph_maximum_cardinality_search(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_vs_t c_vids;
-  igraph_neimode_t c_mode;
-  SEXP res;
+  igraph_vector_t c_alpha;
+  igraph_vector_t c_alpham1;
+  SEXP alpha;
+  SEXP alpham1;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
+  if (0 != igraph_vector_init(&c_alpha, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_alpha);
+  if (0 != igraph_vector_init(&c_alpham1, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_alpham1); 
+  alpham1=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_eccentricity(&c_graph, &c_res, c_vids, c_mode);
+  igraph_maximum_cardinality_search(&c_graph, &c_alpha, (isNull(alpham1) ? 0 : &c_alpham1));
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(alpha=R_igraph_vector_to_SEXPp1(&c_alpha)); 
+  igraph_vector_destroy(&c_alpha); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  PROTECT(alpham1=R_igraph_0orvector_to_SEXPp1(&c_alpham1)); 
+  igraph_vector_destroy(&c_alpham1); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, alpha);
+  SET_VECTOR_ELT(result, 1, alpham1);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("alpham1"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_radius                              /
+/ igraph_avg_nearest_neighbor_degree         /
 /-------------------------------------------*/
-SEXP R_igraph_radius(SEXP graph, SEXP mode) {
+SEXP R_igraph_avg_nearest_neighbor_degree(SEXP graph, SEXP vids, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_radius;
-  igraph_neimode_t c_mode;
-  SEXP radius;
+  igraph_vs_t c_vids;
+  igraph_vector_t c_knn;
+  igraph_vector_t c_knnk;
+  igraph_vector_t c_weights;
+  SEXP knn;
+  SEXP knnk;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  if (0 != igraph_vector_init(&c_knn, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_knn);
+  if (0 != igraph_vector_init(&c_knnk, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_knnk); 
+  knnk=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_radius(&c_graph, &c_radius, c_mode);
+  igraph_avg_nearest_neighbor_degree(&c_graph, c_vids, &c_knn, (isNull(knnk) ? 0 : &c_knnk), (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  PROTECT(radius=NEW_NUMERIC(1)); 
-  REAL(radius)[0]=c_radius;
-  result=radius;
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  igraph_vs_destroy(&c_vids);
+  PROTECT(knn=R_igraph_vector_to_SEXP(&c_knn)); 
+  igraph_vector_destroy(&c_knn); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(knnk=R_igraph_0orvector_to_SEXP(&c_knnk)); 
+  igraph_vector_destroy(&c_knnk); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, knn);
+  SET_VECTOR_ELT(result, 1, knnk);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("knn"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("knnk"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_diversity                           /
+/ igraph_strength                            /
 /-------------------------------------------*/
-SEXP R_igraph_diversity(SEXP graph, SEXP weights, SEXP vids) {
+SEXP R_igraph_strength(SEXP graph, SEXP vids, SEXP mode, SEXP loops, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_weights;
   igraph_vector_t c_res;
   igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
+  igraph_bool_t c_loops;
+  igraph_vector_t c_weights;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
   if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
   IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
   R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_loops=LOGICAL(loops)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_diversity(&c_graph, (isNull(weights) ? 0 : &c_weights), &c_res, c_vids);
+  igraph_strength(&c_graph, &c_res, c_vids, c_mode, c_loops, (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
   PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
@@ -12679,237 +11266,236 @@ SEXP R_igraph_diversity(SEXP graph, SEXP weights, SEXP vids) {
 }
 
 /*-------------------------------------------/
-/ igraph_is_degree_sequence                  /
-/-------------------------------------------*/
-SEXP R_igraph_is_degree_sequence(SEXP out_deg, SEXP in_deg) {
-                                        /* Declarations */
-  igraph_vector_t c_out_deg;
-  igraph_vector_t c_in_deg;
-  igraph_bool_t c_res;
-  SEXP res;
-
-  SEXP result;
-                                        /* Convert input */
-  R_SEXP_to_vector(out_deg, &c_out_deg);
-  if (!isNull(in_deg)) { R_SEXP_to_vector(in_deg, &c_in_deg); }
-                                        /* Call igraph */
-  igraph_is_degree_sequence(&c_out_deg, (isNull(in_deg) ? 0 : &c_in_deg), &c_res);
-
-                                        /* Convert output */
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
-  result=res;
-
-  UNPROTECT(1);
-  return(result);
-}
-
-/*-------------------------------------------/
-/ igraph_is_graphical_degree_sequence        /
+/ igraph_centralization                      /
 /-------------------------------------------*/
-SEXP R_igraph_is_graphical_degree_sequence(SEXP out_deg, SEXP in_deg) {
+SEXP R_igraph_centralization(SEXP scores, SEXP theoretical_max, SEXP normalized) {
                                         /* Declarations */
-  igraph_vector_t c_out_deg;
-  igraph_vector_t c_in_deg;
-  igraph_bool_t c_res;
-  SEXP res;
-
+  igraph_vector_t c_scores;
+  igraph_real_t c_theoretical_max;
+  igraph_bool_t c_normalized;
+  igraph_real_t c_result;
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_vector(out_deg, &c_out_deg);
-  if (!isNull(in_deg)) { R_SEXP_to_vector(in_deg, &c_in_deg); }
+  R_SEXP_to_vector(scores, &c_scores);
+  c_theoretical_max=REAL(theoretical_max)[0];
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_is_graphical_degree_sequence(&c_out_deg, (isNull(in_deg) ? 0 : &c_in_deg), &c_res);
+  c_result=  igraph_centralization(&c_scores, c_theoretical_max, c_normalized);
 
                                         /* Convert output */
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
-  result=res;
+
+  PROTECT(result=NEW_NUMERIC(1)); 
+  REAL(result)[0]=c_result;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_bipartite_projection_size           /
+/ igraph_centralization_degree               /
 /-------------------------------------------*/
-SEXP R_igraph_bipartite_projection_size(SEXP graph, SEXP types) {
+SEXP R_igraph_centralization_degree(SEXP graph, SEXP mode, SEXP loops, SEXP normalized) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_integer_t c_vcount1;
-  igraph_integer_t c_ecount1;
-  igraph_integer_t c_vcount2;
-  igraph_integer_t c_ecount2;
-  SEXP vcount1;
-  SEXP ecount1;
-  SEXP vcount2;
-  SEXP ecount2;
+  igraph_vector_t c_res;
+  igraph_neimode_t c_mode;
+  igraph_bool_t c_loops;
+  igraph_real_t c_centralization;
+  igraph_real_t c_theoretical_max;
+  igraph_bool_t c_normalized;
+  SEXP res;
+  SEXP centralization;
+  SEXP theoretical_max;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
+  if (0 != igraph_vector_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_loops=LOGICAL(loops)[0];
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_bipartite_projection_size(&c_graph, (isNull(types) ? 0 : &c_types), &c_vcount1, &c_ecount1, &c_vcount2, &c_ecount2);
+  igraph_centralization_degree(&c_graph, &c_res, c_mode, c_loops, &c_centralization, &c_theoretical_max, c_normalized);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(vcount1=NEW_INTEGER(1)); 
-  INTEGER(vcount1)[0]=c_vcount1;
-  PROTECT(ecount1=NEW_INTEGER(1)); 
-  INTEGER(ecount1)[0]=c_ecount1;
-  PROTECT(vcount2=NEW_INTEGER(1)); 
-  INTEGER(vcount2)[0]=c_vcount2;
-  PROTECT(ecount2=NEW_INTEGER(1)); 
-  INTEGER(ecount2)[0]=c_ecount2;
-  SET_VECTOR_ELT(result, 0, vcount1);
-  SET_VECTOR_ELT(result, 1, ecount1);
-  SET_VECTOR_ELT(result, 2, vcount2);
-  SET_VECTOR_ELT(result, 3, ecount2);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vcount1"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("ecount1"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("vcount2"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("ecount2"));
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(centralization=NEW_NUMERIC(1)); 
+  REAL(centralization)[0]=c_centralization;
+  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
+  REAL(theoretical_max)[0]=c_theoretical_max;
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, centralization);
+  SET_VECTOR_ELT(result, 2, theoretical_max);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("centralization"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("theoretical_max"));
   SET_NAMES(result, names);
-  UNPROTECT(5);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_create_bipartite                    /
+/ igraph_centralization_degree_tmax          /
 /-------------------------------------------*/
-SEXP R_igraph_create_bipartite(SEXP types, SEXP edges, SEXP directed) {
+SEXP R_igraph_centralization_degree_tmax(SEXP graph, SEXP nodes, SEXP mode, SEXP loops) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_vector_t c_edges;
-  igraph_bool_t c_directed;
-  SEXP graph;
+  igraph_integer_t c_nodes;
+  igraph_neimode_t c_mode;
+  igraph_bool_t c_loops;
+  igraph_real_t c_res;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_vector_bool(types, &c_types);
-  R_SEXP_to_vector(edges, &c_edges);
-  c_directed=LOGICAL(directed)[0];
+  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
+  c_nodes=INTEGER(nodes)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_loops=LOGICAL(loops)[0];
                                         /* Call igraph */
-  igraph_create_bipartite(&c_graph, &c_types, &c_edges, c_directed);
+  igraph_centralization_degree_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_mode, c_loops, &c_res);
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_incidence                           /
+/ igraph_centralization_betweenness          /
 /-------------------------------------------*/
-SEXP R_igraph_incidence(SEXP incidence, SEXP directed, SEXP mode, SEXP multiple) {
+SEXP R_igraph_centralization_betweenness(SEXP graph, SEXP directed, SEXP nobigint, SEXP normalized) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_matrix_t c_incidence;
+  igraph_vector_t c_res;
   igraph_bool_t c_directed;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_multiple;
-  SEXP graph;
-  SEXP types;
+  igraph_bool_t c_nobigint;
+  igraph_real_t c_centralization;
+  igraph_real_t c_theoretical_max;
+  igraph_bool_t c_normalized;
+  SEXP res;
+  SEXP centralization;
+  SEXP theoretical_max;
 
   SEXP result, names;
                                         /* Convert input */
-  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types);
-  R_SEXP_to_matrix(incidence, &c_incidence);
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
   c_directed=LOGICAL(directed)[0];
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_multiple=LOGICAL(multiple)[0];
+  c_nobigint=LOGICAL(nobigint)[0];
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_incidence(&c_graph, &c_types, &c_incidence, c_directed, c_mode, c_multiple);
+  igraph_centralization_betweenness(&c_graph, &c_res, c_directed, c_nobigint, &c_centralization, &c_theoretical_max, c_normalized);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(types=R_igraph_vector_bool_to_SEXP(&c_types)); 
-  igraph_vector_bool_destroy(&c_types); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, graph);
-  SET_VECTOR_ELT(result, 1, types);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
+  PROTECT(centralization=NEW_NUMERIC(1)); 
+  REAL(centralization)[0]=c_centralization;
+  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
+  REAL(theoretical_max)[0]=c_theoretical_max;
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, centralization);
+  SET_VECTOR_ELT(result, 2, theoretical_max);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("centralization"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("theoretical_max"));
   SET_NAMES(result, names);
-  UNPROTECT(3);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_get_incidence                       /
+/ igraph_centralization_betweenness_tmax     /
 /-------------------------------------------*/
-SEXP R_igraph_get_incidence(SEXP graph, SEXP types) {
+SEXP R_igraph_centralization_betweenness_tmax(SEXP graph, SEXP nodes, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_matrix_t c_res;
-  igraph_vector_t c_row_ids;
-  igraph_vector_t c_col_ids;
+  igraph_integer_t c_nodes;
+  igraph_bool_t c_directed;
+  igraph_real_t c_res;
   SEXP res;
-  SEXP row_ids;
-  SEXP col_ids;
+
+  SEXP result;
+                                        /* Convert input */
+  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
+  c_nodes=INTEGER(nodes)[0];
+  c_directed=LOGICAL(directed)[0];
+                                        /* Call igraph */
+  igraph_centralization_betweenness_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_directed, &c_res);
+
+                                        /* Convert output */
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
+
+  UNPROTECT(1);
+  return(result);
+}
+
+/*-------------------------------------------/
+/ igraph_centralization_closeness            /
+/-------------------------------------------*/
+SEXP R_igraph_centralization_closeness(SEXP graph, SEXP mode, SEXP normalized) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_vector_t c_res;
+  igraph_neimode_t c_mode;
+  igraph_real_t c_centralization;
+  igraph_real_t c_theoretical_max;
+  igraph_bool_t c_normalized;
+  SEXP res;
+  SEXP centralization;
+  SEXP theoretical_max;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  if (0 != igraph_vector_init(&c_row_ids, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_row_ids); 
-  row_ids=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_col_ids, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_col_ids); 
-  col_ids=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_get_incidence(&c_graph, (isNull(types) ? 0 : &c_types), &c_res, (isNull(row_ids) ? 0 : &c_row_ids), (isNull(col_ids) ? 0 : &c_col_ids));
+  igraph_centralization_closeness(&c_graph, &c_res, c_mode, &c_centralization, &c_theoretical_max, c_normalized);
 
-                                        /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(row_ids=R_igraph_0orvector_to_SEXP(&c_row_ids)); 
-  igraph_vector_destroy(&c_row_ids); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(col_ids=R_igraph_0orvector_to_SEXP(&c_col_ids)); 
-  igraph_vector_destroy(&c_col_ids); 
+                                        /* Convert output */
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(centralization=NEW_NUMERIC(1)); 
+  REAL(centralization)[0]=c_centralization;
+  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
+  REAL(theoretical_max)[0]=c_theoretical_max;
   SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, row_ids);
-  SET_VECTOR_ELT(result, 2, col_ids);
+  SET_VECTOR_ELT(result, 1, centralization);
+  SET_VECTOR_ELT(result, 2, theoretical_max);
   SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("row_ids"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("col_ids"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("centralization"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("theoretical_max"));
   SET_NAMES(result, names);
   UNPROTECT(4);
 
@@ -12918,224 +11504,204 @@ SEXP R_igraph_get_incidence(SEXP graph, SEXP types) {
 }
 
 /*-------------------------------------------/
-/ igraph_is_bipartite                        /
+/ igraph_centralization_closeness_tmax       /
 /-------------------------------------------*/
-SEXP R_igraph_is_bipartite(SEXP graph) {
+SEXP R_igraph_centralization_closeness_tmax(SEXP graph, SEXP nodes, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_bool_t c_res;
-  igraph_vector_bool_t c_type;
+  igraph_integer_t c_nodes;
+  igraph_neimode_t c_mode;
+  igraph_real_t c_res;
   SEXP res;
-  SEXP type;
+
+  SEXP result;
+                                        /* Convert input */
+  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
+  c_nodes=INTEGER(nodes)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+                                        /* Call igraph */
+  igraph_centralization_closeness_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_mode, &c_res);
+
+                                        /* Convert output */
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
+
+  UNPROTECT(1);
+  return(result);
+}
+
+/*-------------------------------------------/
+/ igraph_centralization_eigenvector_centrality /
+/-------------------------------------------*/
+SEXP R_igraph_centralization_eigenvector_centrality(SEXP graph, SEXP directed, SEXP scale, SEXP options, SEXP normalized) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_vector_t c_vector;
+  igraph_real_t c_value;
+  igraph_bool_t c_directed;
+  igraph_bool_t c_scale;
+  igraph_arpack_options_t c_options;
+  igraph_real_t c_centralization;
+  igraph_real_t c_theoretical_max;
+  igraph_bool_t c_normalized;
+  SEXP vector;
+  SEXP value;
+  SEXP centralization;
+  SEXP theoretical_max;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_bool_init(&c_type, 0)) { 
+  if (0 != igraph_vector_init(&c_vector, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_type); 
-  type=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_vector);
+  c_directed=LOGICAL(directed)[0];
+  c_scale=LOGICAL(scale)[0];
+  R_SEXP_to_igraph_arpack_options(options, &c_options);
+  c_normalized=LOGICAL(normalized)[0];
                                         /* Call igraph */
-  igraph_is_bipartite(&c_graph, &c_res, (isNull(type) ? 0 : &c_type));
+  igraph_centralization_eigenvector_centrality(&c_graph, &c_vector, &c_value, c_directed, c_scale, &c_options, &c_centralization, &c_theoretical_max, c_normalized);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
-  PROTECT(type=R_igraph_0orvector_bool_to_SEXP(&c_type)); 
-  igraph_vector_bool_destroy(&c_type); 
+  PROTECT(result=NEW_LIST(5));
+  PROTECT(names=NEW_CHARACTER(5));
+  PROTECT(vector=R_igraph_vector_to_SEXP(&c_vector)); 
+  igraph_vector_destroy(&c_vector); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, type);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("type"));
+  PROTECT(value=NEW_NUMERIC(1)); 
+  REAL(value)[0]=c_value;
+  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
+  PROTECT(centralization=NEW_NUMERIC(1)); 
+  REAL(centralization)[0]=c_centralization;
+  PROTECT(theoretical_max=NEW_NUMERIC(1)); 
+  REAL(theoretical_max)[0]=c_theoretical_max;
+  SET_VECTOR_ELT(result, 0, vector);
+  SET_VECTOR_ELT(result, 1, value);
+  SET_VECTOR_ELT(result, 2, options);
+  SET_VECTOR_ELT(result, 3, centralization);
+  SET_VECTOR_ELT(result, 4, theoretical_max);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vector"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("value"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("options"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("centralization"));
+  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("theoretical_max"));
   SET_NAMES(result, names);
-  UNPROTECT(3);
+  UNPROTECT(6);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_bipartite_game_gnp                  /
+/ igraph_centralization_eigenvector_centrality_tmax /
 /-------------------------------------------*/
-SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP mode) {
+SEXP R_igraph_centralization_eigenvector_centrality_tmax(SEXP graph, SEXP nodes, SEXP directed, SEXP scale) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_integer_t c_n1;
-  igraph_integer_t c_n2;
-  igraph_real_t c_p;
+  igraph_integer_t c_nodes;
   igraph_bool_t c_directed;
-  igraph_neimode_t c_mode;
-  SEXP graph;
-  SEXP types;
+  igraph_bool_t c_scale;
+  igraph_real_t c_res;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); 
-  types=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_n1=INTEGER(n1)[0];
-  c_n2=INTEGER(n2)[0];
-  c_p=REAL(p)[0];
+  if (!isNull(graph)) { R_SEXP_to_igraph(graph, &c_graph); }
+  c_nodes=INTEGER(nodes)[0];
   c_directed=LOGICAL(directed)[0];
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_scale=LOGICAL(scale)[0];
                                         /* Call igraph */
-  igraph_bipartite_game_gnp(&c_graph, (isNull(types) ? 0 : &c_types), c_n1, c_n2, c_p, c_directed, c_mode);
+  igraph_centralization_eigenvector_centrality_tmax((isNull(graph) ? 0 : &c_graph), c_nodes, c_directed, c_scale, &c_res);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(types=R_igraph_0orvector_bool_to_SEXP(&c_types)); 
-  igraph_vector_bool_destroy(&c_types); 
-  IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, graph);
-  SET_VECTOR_ELT(result, 1, types);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_bipartite_game_gnm                  /
+/ igraph_assortativity_nominal               /
 /-------------------------------------------*/
-SEXP R_igraph_bipartite_game_gnm(SEXP n1, SEXP n2, SEXP m, SEXP directed, SEXP mode) {
+SEXP R_igraph_assortativity_nominal(SEXP graph, SEXP types, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_integer_t c_n1;
-  igraph_integer_t c_n2;
-  igraph_integer_t c_m;
+  igraph_vector_t c_types;
+  igraph_real_t c_res;
   igraph_bool_t c_directed;
-  igraph_neimode_t c_mode;
-  SEXP graph;
-  SEXP types;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); 
-  types=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_n1=INTEGER(n1)[0];
-  c_n2=INTEGER(n2)[0];
-  c_m=INTEGER(m)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
+  R_SEXP_to_vector(types, &c_types);
   c_directed=LOGICAL(directed)[0];
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_bipartite_game_gnm(&c_graph, (isNull(types) ? 0 : &c_types), c_n1, c_n2, c_m, c_directed, c_mode);
+  igraph_assortativity_nominal(&c_graph, &c_types, &c_res, c_directed);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(types=R_igraph_0orvector_bool_to_SEXP(&c_types)); 
-  igraph_vector_bool_destroy(&c_types); 
-  IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, graph);
-  SET_VECTOR_ELT(result, 1, types);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_clusters                            /
+/ igraph_assortativity                       /
 /-------------------------------------------*/
-SEXP R_igraph_clusters(SEXP graph, SEXP mode) {
+SEXP R_igraph_assortativity(SEXP graph, SEXP types1, SEXP types2, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_membership;
-  igraph_vector_t c_csize;
-  igraph_integer_t c_no;
-  igraph_connectedness_t c_mode;
-  SEXP membership;
-  SEXP csize;
-  SEXP no;
+  igraph_vector_t c_types1;
+  igraph_vector_t c_types2;
+  igraph_real_t c_res;
+  igraph_bool_t c_directed;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_membership, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
-  if (0 != igraph_vector_init(&c_csize, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_csize);
-  c_mode=REAL(mode)[0];
+  R_SEXP_to_vector(types1, &c_types1);
+  if (!isNull(types2)) { R_SEXP_to_vector(types2, &c_types2); }
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_clusters(&c_graph, &c_membership, &c_csize, &c_no, c_mode);
+  igraph_assortativity(&c_graph, &c_types1, (isNull(types2) ? 0 : &c_types2), &c_res, c_directed);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
-  igraph_vector_destroy(&c_membership); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(csize=R_igraph_vector_to_SEXP(&c_csize)); 
-  igraph_vector_destroy(&c_csize); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(no=NEW_INTEGER(1)); 
-  INTEGER(no)[0]=c_no;
-  SET_VECTOR_ELT(result, 0, membership);
-  SET_VECTOR_ELT(result, 1, csize);
-  SET_VECTOR_ELT(result, 2, no);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("csize"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("no"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_articulation_points                 /
+/ igraph_assortativity_degree                /
 /-------------------------------------------*/
-SEXP R_igraph_articulation_points(SEXP graph) {
+SEXP R_igraph_assortativity_degree(SEXP graph, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
+  igraph_real_t c_res;
+  igraph_bool_t c_directed;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_articulation_points(&c_graph, &c_res);
+  igraph_assortativity_degree(&c_graph, &c_res, c_directed);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXPp1(&c_res)); 
-  igraph_vector_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
   result=res;
 
   UNPROTECT(1);
@@ -13143,105 +11709,62 @@ SEXP R_igraph_articulation_points(SEXP graph) {
 }
 
 /*-------------------------------------------/
-/ igraph_biconnected_components              /
+/ igraph_contract_vertices                   /
 /-------------------------------------------*/
-SEXP R_igraph_biconnected_components(SEXP graph) {
+SEXP R_igraph_contract_vertices(SEXP graph, SEXP mapping, SEXP vertex_attr_comb) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_no;
-  igraph_vector_ptr_t c_tree_edges;
-  igraph_vector_ptr_t c_component_edges;
-  igraph_vector_ptr_t c_components;
-  igraph_vector_t c_articulation_points;
-  SEXP no;
-  SEXP tree_edges;
-  SEXP component_edges;
-  SEXP components;
-  SEXP articulation_points;
+  igraph_vector_t c_mapping;
+  igraph_attribute_combination_t c_vertex_attr_comb;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_tree_edges, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_tree_edges);
-  if (0 != igraph_vector_ptr_init(&c_component_edges, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_component_edges);
-  if (0 != igraph_vector_ptr_init(&c_components, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_components);
-  if (0 != igraph_vector_init(&c_articulation_points, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_articulation_points);
+  R_SEXP_to_igraph_copy(graph, &c_graph); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph);
+  R_SEXP_to_vector(mapping, &c_mapping);
+  R_SEXP_to_attr_comb(vertex_attr_comb, &c_vertex_attr_comb);
                                         /* Call igraph */
-  igraph_biconnected_components(&c_graph, &c_no, &c_tree_edges, &c_component_edges, &c_components, &c_articulation_points);
+  igraph_contract_vertices(&c_graph, &c_mapping, &c_vertex_attr_comb);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(5));
-  PROTECT(names=NEW_CHARACTER(5));
-  PROTECT(no=NEW_INTEGER(1)); 
-  INTEGER(no)[0]=c_no;
-  PROTECT(tree_edges=R_igraph_vectorlist_to_SEXP_p1(&c_tree_edges)); 
-  R_igraph_vectorlist_destroy(&c_tree_edges); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(component_edges=R_igraph_vectorlist_to_SEXP_p1(&c_component_edges)); 
-  R_igraph_vectorlist_destroy(&c_component_edges); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(components=R_igraph_vectorlist_to_SEXP_p1(&c_components)); 
-  R_igraph_vectorlist_destroy(&c_components); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(articulation_points=R_igraph_vector_to_SEXPp1(&c_articulation_points)); 
-  igraph_vector_destroy(&c_articulation_points); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, no);
-  SET_VECTOR_ELT(result, 1, tree_edges);
-  SET_VECTOR_ELT(result, 2, component_edges);
-  SET_VECTOR_ELT(result, 3, components);
-  SET_VECTOR_ELT(result, 4, articulation_points);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("no"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("tree_edges"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("component_edges"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("components"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("articulation_points"));
-  SET_NAMES(result, names);
-  UNPROTECT(6);
+  igraph_attribute_combination_destroy(&c_vertex_attr_comb);
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_layout_star                         /
+/ igraph_eccentricity                        /
 /-------------------------------------------*/
-SEXP R_igraph_layout_star(SEXP graph, SEXP center, SEXP order) {
+SEXP R_igraph_eccentricity(SEXP graph, SEXP vids, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_integer_t c_center;
-  igraph_vector_t c_order;
+  igraph_vector_t c_res;
+  igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_center=(igraph_integer_t) REAL(center)[0];
-  if (!isNull(order)) { R_SEXP_to_vector(order, &c_order); }
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_layout_star(&c_graph, &c_res, c_center, (isNull(order) ? 0 : &c_order));
+  igraph_eccentricity(&c_graph, &c_res, c_vids, c_mode);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
+  igraph_vs_destroy(&c_vids);
   result=res;
 
   UNPROTECT(1);
@@ -13249,63 +11772,59 @@ SEXP R_igraph_layout_star(SEXP graph, SEXP center, SEXP order) {
 }
 
 /*-------------------------------------------/
-/ igraph_layout_grid                         /
+/ igraph_radius                              /
 /-------------------------------------------*/
-SEXP R_igraph_layout_grid(SEXP graph, SEXP width) {
+SEXP R_igraph_radius(SEXP graph, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_integer_t c_width;
-  SEXP res;
+  igraph_real_t c_radius;
+  igraph_neimode_t c_mode;
+  SEXP radius;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_width=INTEGER(width)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_layout_grid(&c_graph, &c_res, c_width);
+  igraph_radius(&c_graph, &c_radius, c_mode);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  PROTECT(radius=NEW_NUMERIC(1)); 
+  REAL(radius)[0]=c_radius;
+  result=radius;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_layout_grid_3d                      /
+/ igraph_diversity                           /
 /-------------------------------------------*/
-SEXP R_igraph_layout_grid_3d(SEXP graph, SEXP width, SEXP height) {
+SEXP R_igraph_diversity(SEXP graph, SEXP weights, SEXP vids) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_integer_t c_width;
-  igraph_integer_t c_height;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_res;
+  igraph_vs_t c_vids;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_width=INTEGER(width)[0];
-  c_height=INTEGER(height)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
                                         /* Call igraph */
-  igraph_layout_grid_3d(&c_graph, &c_res, c_width, c_height);
+  igraph_diversity(&c_graph, (isNull(weights) ? 0 : &c_weights), &c_res, c_vids);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
+  igraph_vs_destroy(&c_vids);
   result=res;
 
   UNPROTECT(1);
@@ -13313,71 +11832,62 @@ SEXP R_igraph_layout_grid_3d(SEXP graph, SEXP width, SEXP height) {
 }
 
 /*-------------------------------------------/
-/ igraph_layout_drl                          /
+/ igraph_random_walk                         /
 /-------------------------------------------*/
-SEXP R_igraph_layout_drl(SEXP graph, SEXP res, SEXP use_seed, SEXP options, SEXP weights, SEXP fixed) {
+SEXP R_igraph_random_walk(SEXP graph, SEXP start, SEXP mode, SEXP steps, SEXP stuck) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_bool_t c_use_seed;
-  igraph_layout_drl_options_t c_options;
-  igraph_vector_t c_weights;
-  igraph_vector_bool_t c_fixed;
+  igraph_vector_t c_walk;
+  igraph_integer_t c_start;
+  igraph_neimode_t c_mode;
+  igraph_integer_t c_steps;
+  igraph_random_walk_stuck_t c_stuck;
+  SEXP walk;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != R_SEXP_to_igraph_matrix_copy(res, &c_res)) { 
+  if (0 != igraph_vector_init(&c_walk, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_use_seed=LOGICAL(use_seed)[0];
-  R_SEXP_to_igraph_layout_drl_options(options, &c_options);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  if (!isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); }
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_walk);
+  c_start=(igraph_integer_t) REAL(start)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_steps=INTEGER(steps)[0];
+  c_stuck=(igraph_random_walk_stuck_t) INTEGER(stuck)[0];
                                         /* Call igraph */
-  igraph_layout_drl(&c_graph, &c_res, c_use_seed, &c_options, (isNull(weights) ? 0 : &c_weights), (isNull(fixed) ? 0 : &c_fixed));
+  igraph_random_walk(&c_graph, &c_walk, c_start, c_mode, c_steps, c_stuck);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  PROTECT(walk=R_igraph_vector_to_SEXPp1(&c_walk)); 
+  igraph_vector_destroy(&c_walk); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  result=walk;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_layout_drl_3d                       /
+/ igraph_is_degree_sequence                  /
 /-------------------------------------------*/
-SEXP R_igraph_layout_drl_3d(SEXP graph, SEXP res, SEXP use_seed, SEXP options, SEXP weights, SEXP fixed) {
+SEXP R_igraph_is_degree_sequence(SEXP out_deg, SEXP in_deg) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_bool_t c_use_seed;
-  igraph_layout_drl_options_t c_options;
-  igraph_vector_t c_weights;
-  igraph_vector_bool_t c_fixed;
+  igraph_vector_t c_out_deg;
+  igraph_vector_t c_in_deg;
+  igraph_bool_t c_res;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != R_SEXP_to_igraph_matrix_copy(res, &c_res)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_use_seed=LOGICAL(use_seed)[0];
-  R_SEXP_to_igraph_layout_drl_options(options, &c_options);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  if (!isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); }
+  R_SEXP_to_vector(out_deg, &c_out_deg);
+  if (!isNull(in_deg)) { R_SEXP_to_vector(in_deg, &c_in_deg); }
                                         /* Call igraph */
-  igraph_layout_drl_3d(&c_graph, &c_res, c_use_seed, &c_options, (isNull(weights) ? 0 : &c_weights), (isNull(fixed) ? 0 : &c_fixed));
+  igraph_is_degree_sequence(&c_out_deg, (isNull(in_deg) ? 0 : &c_in_deg), &c_res);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
   result=res;
 
   UNPROTECT(1);
@@ -13385,893 +11895,986 @@ SEXP R_igraph_layout_drl_3d(SEXP graph, SEXP res, SEXP use_seed, SEXP options, S
 }
 
 /*-------------------------------------------/
-/ igraph_layout_sugiyama                     /
+/ igraph_is_graphical_degree_sequence        /
 /-------------------------------------------*/
-SEXP R_igraph_layout_sugiyama(SEXP graph, SEXP layers, SEXP hgap, SEXP vgap, SEXP maxiter, SEXP weights) {
+SEXP R_igraph_is_graphical_degree_sequence(SEXP out_deg, SEXP in_deg) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_t c_extd_graph;
-  igraph_vector_t c_extd_to_orig_eids;
-  igraph_vector_t c_layers;
-  igraph_real_t c_hgap;
-  igraph_real_t c_vgap;
-  igraph_integer_t c_maxiter;
-  igraph_vector_t c_weights;
+  igraph_vector_t c_out_deg;
+  igraph_vector_t c_in_deg;
+  igraph_bool_t c_res;
   SEXP res;
-  SEXP extd_graph;
-  SEXP extd_to_orig_eids;
+
+  SEXP result;
+                                        /* Convert input */
+  R_SEXP_to_vector(out_deg, &c_out_deg);
+  if (!isNull(in_deg)) { R_SEXP_to_vector(in_deg, &c_in_deg); }
+                                        /* Call igraph */
+  igraph_is_graphical_degree_sequence(&c_out_deg, (isNull(in_deg) ? 0 : &c_in_deg), &c_res);
+
+                                        /* Convert output */
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
+  result=res;
+
+  UNPROTECT(1);
+  return(result);
+}
+
+/*-------------------------------------------/
+/ igraph_bipartite_projection_size           /
+/-------------------------------------------*/
+SEXP R_igraph_bipartite_projection_size(SEXP graph, SEXP types) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_vector_bool_t c_types;
+  igraph_integer_t c_vcount1;
+  igraph_integer_t c_ecount1;
+  igraph_integer_t c_vcount2;
+  igraph_integer_t c_ecount2;
+  SEXP vcount1;
+  SEXP ecount1;
+  SEXP vcount2;
+  SEXP ecount2;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  extd_graph=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_extd_to_orig_eids, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_extd_to_orig_eids); 
-  extd_to_orig_eids=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (!isNull(layers)) { R_SEXP_to_vector(layers, &c_layers); }
-  c_hgap=REAL(hgap)[0];
-  c_vgap=REAL(vgap)[0];
-  c_maxiter=INTEGER(maxiter)[0];
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
                                         /* Call igraph */
-  igraph_layout_sugiyama(&c_graph, &c_res, (isNull(extd_graph) ? 0 : &c_extd_graph), (isNull(extd_to_orig_eids) ? 0 : &c_extd_to_orig_eids), (isNull(layers) ? 0 : &c_layers), c_hgap, c_vgap, c_maxiter, (isNull(weights) ? 0 : &c_weights));
+  igraph_bipartite_projection_size(&c_graph, (isNull(types) ? 0 : &c_types), &c_vcount1, &c_ecount1, &c_vcount2, &c_ecount2);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  IGRAPH_FINALLY(igraph_destroy, &c_extd_graph); 
-  PROTECT(extd_graph=R_igraph_to_SEXP(&c_extd_graph));  
-  igraph_destroy(&c_extd_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(extd_to_orig_eids=R_igraph_0orvector_to_SEXPp1(&c_extd_to_orig_eids)); 
-  igraph_vector_destroy(&c_extd_to_orig_eids); 
-  IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, res);
-  SET_VECTOR_ELT(result, 1, extd_graph);
-  SET_VECTOR_ELT(result, 2, extd_to_orig_eids);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("extd_graph"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("extd_to_orig_eids"));
+  PROTECT(result=NEW_LIST(4));
+  PROTECT(names=NEW_CHARACTER(4));
+  PROTECT(vcount1=NEW_INTEGER(1)); 
+  INTEGER(vcount1)[0]=c_vcount1;
+  PROTECT(ecount1=NEW_INTEGER(1)); 
+  INTEGER(ecount1)[0]=c_ecount1;
+  PROTECT(vcount2=NEW_INTEGER(1)); 
+  INTEGER(vcount2)[0]=c_vcount2;
+  PROTECT(ecount2=NEW_INTEGER(1)); 
+  INTEGER(ecount2)[0]=c_ecount2;
+  SET_VECTOR_ELT(result, 0, vcount1);
+  SET_VECTOR_ELT(result, 1, ecount1);
+  SET_VECTOR_ELT(result, 2, vcount2);
+  SET_VECTOR_ELT(result, 3, ecount2);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("vcount1"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("ecount1"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("vcount2"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("ecount2"));
   SET_NAMES(result, names);
-  UNPROTECT(4);
+  UNPROTECT(5);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_layout_mds                          /
+/ igraph_create_bipartite                    /
 /-------------------------------------------*/
-SEXP R_igraph_layout_mds(SEXP graph, SEXP dist, SEXP dim) {
+SEXP R_igraph_create_bipartite(SEXP types, SEXP edges, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_matrix_t c_dist;
-  igraph_integer_t c_dim;
-
-  SEXP res;
+  igraph_vector_bool_t c_types;
+  igraph_vector_t c_edges;
+  igraph_bool_t c_directed;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  if (!isNull(dist)) { R_SEXP_to_matrix(dist, &c_dist); }
-  c_dim=INTEGER(dim)[0];
+  R_SEXP_to_vector_bool(types, &c_types);
+  R_SEXP_to_vector(edges, &c_edges);
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_layout_mds(&c_graph, &c_res, (isNull(dist) ? 0 : &c_dist), c_dim, 0);
+  igraph_create_bipartite(&c_graph, &c_types, &c_edges, c_directed);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_layout_bipartite                    /
+/ igraph_incidence                           /
 /-------------------------------------------*/
-SEXP R_igraph_layout_bipartite(SEXP graph, SEXP types, SEXP hgap, SEXP vgap, SEXP maxiter) {
+SEXP R_igraph_incidence(SEXP incidence, SEXP directed, SEXP mode, SEXP multiple) {
                                         /* Declarations */
   igraph_t c_graph;
   igraph_vector_bool_t c_types;
-  igraph_matrix_t c_res;
-  igraph_real_t c_hgap;
-  igraph_real_t c_vgap;
-  igraph_integer_t c_maxiter;
-  SEXP res;
+  igraph_matrix_t c_incidence;
+  igraph_bool_t c_directed;
+  igraph_neimode_t c_mode;
+  igraph_bool_t c_multiple;
+  SEXP graph;
+  SEXP types;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_hgap=REAL(hgap)[0];
-  c_vgap=REAL(vgap)[0];
-  c_maxiter=INTEGER(maxiter)[0];
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types);
+  R_SEXP_to_matrix(incidence, &c_incidence);
+  c_directed=LOGICAL(directed)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_multiple=LOGICAL(multiple)[0];
                                         /* Call igraph */
-  igraph_layout_bipartite(&c_graph, (isNull(types) ? 0 : &c_types), &c_res, c_hgap, c_vgap, c_maxiter);
+  igraph_incidence(&c_graph, &c_types, &c_incidence, c_directed, c_mode, c_multiple);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  PROTECT(types=R_igraph_vector_bool_to_SEXP(&c_types)); 
+  igraph_vector_bool_destroy(&c_types); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, graph);
+  SET_VECTOR_ELT(result, 1, types);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_similarity_jaccard                  /
+/ igraph_get_incidence                       /
 /-------------------------------------------*/
-SEXP R_igraph_similarity_jaccard(SEXP graph, SEXP vids, SEXP mode, SEXP loops) {
+SEXP R_igraph_get_incidence(SEXP graph, SEXP types) {
                                         /* Declarations */
   igraph_t c_graph;
+  igraph_vector_bool_t c_types;
   igraph_matrix_t c_res;
-  igraph_vs_t c_vids;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_loops;
+  igraph_vector_t c_row_ids;
+  igraph_vector_t c_col_ids;
   SEXP res;
+  SEXP row_ids;
+  SEXP col_ids;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
+  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
   if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
   IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_loops=LOGICAL(loops)[0];
+  if (0 != igraph_vector_init(&c_row_ids, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_row_ids); 
+  row_ids=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_col_ids, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_col_ids); 
+  col_ids=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_similarity_jaccard(&c_graph, &c_res, c_vids, c_mode, c_loops);
+  igraph_get_incidence(&c_graph, (isNull(types) ? 0 : &c_types), &c_res, (isNull(row_ids) ? 0 : &c_row_ids), (isNull(col_ids) ? 0 : &c_col_ids));
 
                                         /* Convert output */
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
   PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
   igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  PROTECT(row_ids=R_igraph_0orvector_to_SEXP(&c_row_ids)); 
+  igraph_vector_destroy(&c_row_ids); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(col_ids=R_igraph_0orvector_to_SEXP(&c_col_ids)); 
+  igraph_vector_destroy(&c_col_ids); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, row_ids);
+  SET_VECTOR_ELT(result, 2, col_ids);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("row_ids"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("col_ids"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_similarity_dice                     /
+/ igraph_is_bipartite                        /
 /-------------------------------------------*/
-SEXP R_igraph_similarity_dice(SEXP graph, SEXP vids, SEXP mode, SEXP loops) {
+SEXP R_igraph_is_bipartite(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_vs_t c_vids;
-  igraph_neimode_t c_mode;
-  igraph_bool_t c_loops;
+  igraph_bool_t c_res;
+  igraph_vector_bool_t c_type;
   SEXP res;
+  SEXP type;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  if (0 != igraph_vector_bool_init(&c_type, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
-  c_loops=LOGICAL(loops)[0];
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_type); 
+  type=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_similarity_dice(&c_graph, &c_res, c_vids, c_mode, c_loops);
+  igraph_is_bipartite(&c_graph, &c_res, (isNull(type) ? 0 : &c_type));
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
+  PROTECT(type=R_igraph_0orvector_bool_to_SEXP(&c_type)); 
+  igraph_vector_bool_destroy(&c_type); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, type);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("type"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_similarity_inverse_log_weighted     /
+/ igraph_bipartite_game_gnp                  /
 /-------------------------------------------*/
-SEXP R_igraph_similarity_inverse_log_weighted(SEXP graph, SEXP vids, SEXP mode) {
+SEXP R_igraph_bipartite_game_gnp(SEXP n1, SEXP n2, SEXP p, SEXP directed, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_matrix_t c_res;
-  igraph_vs_t c_vids;
+  igraph_vector_bool_t c_types;
+  igraph_integer_t c_n1;
+  igraph_integer_t c_n2;
+  igraph_real_t c_p;
+  igraph_bool_t c_directed;
   igraph_neimode_t c_mode;
-  SEXP res;
+  SEXP graph;
+  SEXP types;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); 
+  types=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  c_n1=INTEGER(n1)[0];
+  c_n2=INTEGER(n2)[0];
+  c_p=REAL(p)[0];
+  c_directed=LOGICAL(directed)[0];
   c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_similarity_inverse_log_weighted(&c_graph, &c_res, c_vids, c_mode);
+  igraph_bipartite_game_gnp(&c_graph, (isNull(types) ? 0 : &c_types), c_n1, c_n2, c_p, c_directed, c_mode);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
-  igraph_matrix_destroy(&c_res); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  PROTECT(types=R_igraph_0orvector_bool_to_SEXP(&c_types)); 
+  igraph_vector_bool_destroy(&c_types); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, graph);
+  SET_VECTOR_ELT(result, 1, types);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_compare_communities                 /
+/ igraph_bipartite_game_gnm                  /
 /-------------------------------------------*/
-SEXP R_igraph_compare_communities(SEXP comm1, SEXP comm2, SEXP method) {
+SEXP R_igraph_bipartite_game_gnm(SEXP n1, SEXP n2, SEXP m, SEXP directed, SEXP mode) {
                                         /* Declarations */
-  igraph_vector_t c_comm1;
-  igraph_vector_t c_comm2;
-  igraph_real_t c_res;
-  igraph_community_comparison_t c_method;
-  SEXP res;
+  igraph_t c_graph;
+  igraph_vector_bool_t c_types;
+  igraph_integer_t c_n1;
+  igraph_integer_t c_n2;
+  igraph_integer_t c_m;
+  igraph_bool_t c_directed;
+  igraph_neimode_t c_mode;
+  SEXP graph;
+  SEXP types;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_vector(comm1, &c_comm1);
-  R_SEXP_to_vector(comm2, &c_comm2);
-  c_method=(igraph_community_comparison_t) REAL(method)[0];
+  if (0 != igraph_vector_bool_init(&c_types, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_bool_destroy, &c_types); 
+  types=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  c_n1=INTEGER(n1)[0];
+  c_n2=INTEGER(n2)[0];
+  c_m=INTEGER(m)[0];
+  c_directed=LOGICAL(directed)[0];
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_compare_communities(&c_comm1, &c_comm2, &c_res, c_method);
+  igraph_bipartite_game_gnm(&c_graph, (isNull(types) ? 0 : &c_types), c_n1, c_n2, c_m, c_directed, c_mode);
 
                                         /* Convert output */
-  PROTECT(res=NEW_NUMERIC(1)); 
-  REAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(types=R_igraph_0orvector_bool_to_SEXP(&c_types)); 
+  igraph_vector_bool_destroy(&c_types); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, graph);
+  SET_VECTOR_ELT(result, 1, types);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("graph"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("types"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_le_community_to_membership          /
+/ igraph_clusters                            /
 /-------------------------------------------*/
-SEXP R_igraph_le_community_to_membership(SEXP merges, SEXP steps, SEXP membership) {
+SEXP R_igraph_clusters(SEXP graph, SEXP mode) {
                                         /* Declarations */
-  igraph_matrix_t c_merges;
-  igraph_integer_t c_steps;
+  igraph_t c_graph;
   igraph_vector_t c_membership;
   igraph_vector_t c_csize;
+  igraph_integer_t c_no;
+  igraph_connectedness_t c_mode;
+  SEXP membership;
   SEXP csize;
+  SEXP no;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_matrix(merges, &c_merges);
-  c_steps=INTEGER(steps)[0];
-  if (0 != R_SEXP_to_vector_copy(membership, &c_membership)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_membership, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
   IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
   if (0 != igraph_vector_init(&c_csize, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_csize); 
-  csize=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_csize);
+  c_mode=REAL(mode)[0];
                                         /* Call igraph */
-  igraph_le_community_to_membership(&c_merges, c_steps, &c_membership, (isNull(csize) ? 0 : &c_csize));
+  igraph_clusters(&c_graph, &c_membership, &c_csize, &c_no, c_mode);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
   PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
   igraph_vector_destroy(&c_membership); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(csize=R_igraph_0orvector_to_SEXP(&c_csize)); 
+  PROTECT(csize=R_igraph_vector_to_SEXP(&c_csize)); 
   igraph_vector_destroy(&c_csize); 
   IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(no=NEW_INTEGER(1)); 
+  INTEGER(no)[0]=c_no;
   SET_VECTOR_ELT(result, 0, membership);
   SET_VECTOR_ELT(result, 1, csize);
+  SET_VECTOR_ELT(result, 2, no);
   SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
   SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("csize"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("no"));
   SET_NAMES(result, names);
-  UNPROTECT(3);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_modularity                          /
+/ igraph_articulation_points                 /
 /-------------------------------------------*/
-SEXP R_igraph_modularity(SEXP graph, SEXP membership, SEXP weights) {
+SEXP R_igraph_articulation_points(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_membership;
-  igraph_real_t c_modularity;
-  igraph_vector_t c_weights;
-  SEXP modularity;
+  igraph_vector_t c_res;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(membership, &c_membership);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (0 != igraph_vector_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
                                         /* Call igraph */
-  igraph_modularity(&c_graph, &c_membership, &c_modularity, (isNull(weights) ? 0 : &c_weights));
+  igraph_articulation_points(&c_graph, &c_res);
 
                                         /* Convert output */
-  PROTECT(modularity=NEW_NUMERIC(1)); 
-  REAL(modularity)[0]=c_modularity;
-  result=modularity;
+  PROTECT(res=R_igraph_vector_to_SEXPp1(&c_res)); 
+  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_modularity_matrix                   /
+/ igraph_biconnected_components              /
 /-------------------------------------------*/
-SEXP R_igraph_modularity_matrix(SEXP graph, SEXP membership, SEXP weights) {
+SEXP R_igraph_biconnected_components(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_membership;
-  igraph_matrix_t c_modmat;
-  igraph_vector_t c_weights;
-  SEXP modmat;
+  igraph_integer_t c_no;
+  igraph_vector_ptr_t c_tree_edges;
+  igraph_vector_ptr_t c_component_edges;
+  igraph_vector_ptr_t c_components;
+  igraph_vector_t c_articulation_points;
+  SEXP no;
+  SEXP tree_edges;
+  SEXP component_edges;
+  SEXP components;
+  SEXP articulation_points;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(membership, &c_membership);
-  if (0 != igraph_matrix_init(&c_modmat, 0, 0)) { 
+  if (0 != igraph_vector_ptr_init(&c_tree_edges, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_modmat);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_tree_edges);
+  if (0 != igraph_vector_ptr_init(&c_component_edges, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_component_edges);
+  if (0 != igraph_vector_ptr_init(&c_components, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_components);
+  if (0 != igraph_vector_init(&c_articulation_points, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_articulation_points);
                                         /* Call igraph */
-  igraph_modularity_matrix(&c_graph, &c_membership, &c_modmat, (isNull(weights) ? 0 : &c_weights));
+  igraph_biconnected_components(&c_graph, &c_no, &c_tree_edges, &c_component_edges, &c_components, &c_articulation_points);
 
                                         /* Convert output */
-  PROTECT(modmat=R_igraph_matrix_to_SEXP(&c_modmat)); 
-  igraph_matrix_destroy(&c_modmat); 
+  PROTECT(result=NEW_LIST(5));
+  PROTECT(names=NEW_CHARACTER(5));
+  PROTECT(no=NEW_INTEGER(1)); 
+  INTEGER(no)[0]=c_no;
+  PROTECT(tree_edges=R_igraph_vectorlist_to_SEXP_p1(&c_tree_edges)); 
+  R_igraph_vectorlist_destroy(&c_tree_edges); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=modmat;
+  PROTECT(component_edges=R_igraph_vectorlist_to_SEXP_p1(&c_component_edges)); 
+  R_igraph_vectorlist_destroy(&c_component_edges); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(components=R_igraph_vectorlist_to_SEXP_p1(&c_components)); 
+  R_igraph_vectorlist_destroy(&c_components); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(articulation_points=R_igraph_vector_to_SEXPp1(&c_articulation_points)); 
+  igraph_vector_destroy(&c_articulation_points); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, no);
+  SET_VECTOR_ELT(result, 1, tree_edges);
+  SET_VECTOR_ELT(result, 2, component_edges);
+  SET_VECTOR_ELT(result, 3, components);
+  SET_VECTOR_ELT(result, 4, articulation_points);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("no"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("tree_edges"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("component_edges"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("components"));
+  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("articulation_points"));
+  SET_NAMES(result, names);
+  UNPROTECT(6);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_reindex_membership                  /
+/ igraph_layout_star                         /
 /-------------------------------------------*/
-SEXP R_igraph_reindex_membership(SEXP membership) {
+SEXP R_igraph_layout_star(SEXP graph, SEXP center, SEXP order) {
                                         /* Declarations */
-  igraph_vector_t c_membership;
-  igraph_vector_t c_new_to_old;
-  SEXP new_to_old;
+  igraph_t c_graph;
+  igraph_matrix_t c_res;
+  igraph_integer_t c_center;
+  igraph_vector_t c_order;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  if (0 != R_SEXP_to_vector_copy(membership, &c_membership)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
-  if (0 != igraph_vector_init(&c_new_to_old, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_new_to_old); 
-  new_to_old=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_center=(igraph_integer_t) REAL(center)[0];
+  if (!isNull(order)) { R_SEXP_to_vector(order, &c_order); }
                                         /* Call igraph */
-  igraph_reindex_membership(&c_membership, (isNull(new_to_old) ? 0 : &c_new_to_old));
+  igraph_layout_star(&c_graph, &c_res, c_center, (isNull(order) ? 0 : &c_order));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
-  igraph_vector_destroy(&c_membership); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(new_to_old=R_igraph_0orvector_to_SEXP(&c_new_to_old)); 
-  igraph_vector_destroy(&c_new_to_old); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, membership);
-  SET_VECTOR_ELT(result, 1, new_to_old);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("new_to_old"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_community_label_propagation         /
+/ igraph_layout_grid                         /
 /-------------------------------------------*/
-SEXP R_igraph_community_label_propagation(SEXP graph, SEXP weights, SEXP initial, SEXP fixed) {
+SEXP R_igraph_layout_grid(SEXP graph, SEXP width) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_membership;
-  igraph_vector_t c_weights;
-  igraph_vector_t c_initial;
-  igraph_vector_bool_t c_fixed;
-  igraph_real_t c_modularity;
-  SEXP membership;
-  SEXP modularity;
+  igraph_matrix_t c_res;
+  igraph_integer_t c_width;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_membership, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  if (!isNull(initial)) { R_SEXP_to_vector(initial, &c_initial); }
-  if (!isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); }
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_width=INTEGER(width)[0];
                                         /* Call igraph */
-  igraph_community_label_propagation(&c_graph, &c_membership, (isNull(weights) ? 0 : &c_weights), (isNull(initial) ? 0 : &c_initial), (isNull(fixed) ? 0 : &c_fixed), &c_modularity);
+  igraph_layout_grid(&c_graph, &c_res, c_width);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
-  igraph_vector_destroy(&c_membership); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(modularity=NEW_NUMERIC(1)); 
-  REAL(modularity)[0]=c_modularity;
-  SET_VECTOR_ELT(result, 0, membership);
-  SET_VECTOR_ELT(result, 1, modularity);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("modularity"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_community_multilevel                /
+/ igraph_layout_grid_3d                      /
 /-------------------------------------------*/
-SEXP R_igraph_community_multilevel(SEXP graph, SEXP weights) {
+SEXP R_igraph_layout_grid_3d(SEXP graph, SEXP width, SEXP height) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_weights;
-  igraph_vector_t c_membership;
-  igraph_matrix_t c_memberships;
-  igraph_vector_t c_modularity;
-  SEXP membership;
-  SEXP memberships;
-  SEXP modularity;
+  igraph_matrix_t c_res;
+  igraph_integer_t c_width;
+  igraph_integer_t c_height;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  if (0 != igraph_vector_init(&c_membership, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
-  if (0 != igraph_matrix_init(&c_memberships, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_memberships); 
-  memberships=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_modularity, 0)) { 
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_modularity); 
-  modularity=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_width=INTEGER(width)[0];
+  c_height=INTEGER(height)[0];
                                         /* Call igraph */
-  igraph_community_multilevel(&c_graph, (isNull(weights) ? 0 : &c_weights), &c_membership, (isNull(memberships) ? 0 : &c_memberships), (isNull(modularity) ? 0 : &c_modularity));
+  igraph_layout_grid_3d(&c_graph, &c_res, c_width, c_height);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
-  igraph_vector_destroy(&c_membership); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(memberships=R_igraph_0ormatrix_to_SEXP(&c_memberships)); 
-  igraph_matrix_destroy(&c_memberships); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(modularity=R_igraph_0orvector_to_SEXP(&c_modularity)); 
-  igraph_vector_destroy(&c_modularity); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, membership);
-  SET_VECTOR_ELT(result, 1, memberships);
-  SET_VECTOR_ELT(result, 2, modularity);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("memberships"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("modularity"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_community_optimal_modularity        /
+/ igraph_layout_drl                          /
 /-------------------------------------------*/
-SEXP R_igraph_community_optimal_modularity(SEXP graph, SEXP weights) {
+SEXP R_igraph_layout_drl(SEXP graph, SEXP res, SEXP use_seed, SEXP options, SEXP weights, SEXP fixed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_modularity;
-  igraph_vector_t c_membership;
+  igraph_matrix_t c_res;
+  igraph_bool_t c_use_seed;
+  igraph_layout_drl_options_t c_options;
   igraph_vector_t c_weights;
-  SEXP modularity;
-  SEXP membership;
+  igraph_vector_bool_t c_fixed;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_membership, 0)) { 
+  if (0 != R_SEXP_to_igraph_matrix_copy(res, &c_res)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership); 
-  membership=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_use_seed=LOGICAL(use_seed)[0];
+  R_SEXP_to_igraph_layout_drl_options(options, &c_options);
   if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); }
                                         /* Call igraph */
-  igraph_community_optimal_modularity(&c_graph, &c_modularity, (isNull(membership) ? 0 : &c_membership), (isNull(weights) ? 0 : &c_weights));
+  igraph_layout_drl(&c_graph, &c_res, c_use_seed, &c_options, (isNull(weights) ? 0 : &c_weights), (isNull(fixed) ? 0 : &c_fixed));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(modularity=NEW_NUMERIC(1)); 
-  REAL(modularity)[0]=c_modularity;
-  PROTECT(membership=R_igraph_0orvector_to_SEXP(&c_membership)); 
-  igraph_vector_destroy(&c_membership); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, modularity);
-  SET_VECTOR_ELT(result, 1, membership);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("modularity"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("membership"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hrg_fit                             /
+/ igraph_layout_drl_3d                       /
 /-------------------------------------------*/
-SEXP R_igraph_hrg_fit(SEXP graph, SEXP hrg, SEXP start, SEXP steps) {
+SEXP R_igraph_layout_drl_3d(SEXP graph, SEXP res, SEXP use_seed, SEXP options, SEXP weights, SEXP fixed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_hrg_t c_hrg;
-  igraph_bool_t c_start;
-  int c_steps;
+  igraph_matrix_t c_res;
+  igraph_bool_t c_use_seed;
+  igraph_layout_drl_options_t c_options;
+  igraph_vector_t c_weights;
+  igraph_vector_bool_t c_fixed;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != R_SEXP_to_hrg_copy(hrg, &c_hrg)) { 
+  if (0 != R_SEXP_to_igraph_matrix_copy(res, &c_res)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
-  c_start=LOGICAL(start)[0];
-  c_steps=INTEGER(steps)[0];
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_use_seed=LOGICAL(use_seed)[0];
+  R_SEXP_to_igraph_layout_drl_options(options, &c_options);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); }
                                         /* Call igraph */
-  igraph_hrg_fit(&c_graph, &c_hrg, c_start, c_steps);
+  igraph_layout_drl_3d(&c_graph, &c_res, c_use_seed, &c_options, (isNull(weights) ? 0 : &c_weights), (isNull(fixed) ? 0 : &c_fixed));
 
                                         /* Convert output */
-  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
-  igraph_hrg_destroy(&c_hrg); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=hrg;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hrg_game                            /
+/ igraph_layout_sugiyama                     /
 /-------------------------------------------*/
-SEXP R_igraph_hrg_game(SEXP hrg) {
+SEXP R_igraph_layout_sugiyama(SEXP graph, SEXP layers, SEXP hgap, SEXP vgap, SEXP maxiter, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_hrg_t c_hrg;
-  SEXP graph;
+  igraph_matrix_t c_res;
+  igraph_t c_extd_graph;
+  igraph_vector_t c_extd_to_orig_eids;
+  igraph_vector_t c_layers;
+  igraph_real_t c_hgap;
+  igraph_real_t c_vgap;
+  igraph_integer_t c_maxiter;
+  igraph_vector_t c_weights;
+  SEXP res;
+  SEXP extd_graph;
+  SEXP extd_to_orig_eids;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_hrg(hrg, &c_hrg);
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  extd_graph=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_extd_to_orig_eids, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_extd_to_orig_eids); 
+  extd_to_orig_eids=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (!isNull(layers)) { R_SEXP_to_vector(layers, &c_layers); }
+  c_hgap=REAL(hgap)[0];
+  c_vgap=REAL(vgap)[0];
+  c_maxiter=INTEGER(maxiter)[0];
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_hrg_game(&c_graph, &c_hrg);
+  igraph_layout_sugiyama(&c_graph, &c_res, (isNull(extd_graph) ? 0 : &c_extd_graph), (isNull(extd_to_orig_eids) ? 0 : &c_extd_to_orig_eids), (isNull(layers) ? 0 : &c_layers), c_hgap, c_vgap, c_maxiter, (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  IGRAPH_FINALLY(igraph_destroy, &c_extd_graph); 
+  PROTECT(extd_graph=R_igraph_to_SEXP(&c_extd_graph));  
+  igraph_destroy(&c_extd_graph); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(extd_to_orig_eids=R_igraph_0orvector_to_SEXPp1(&c_extd_to_orig_eids)); 
+  igraph_vector_destroy(&c_extd_to_orig_eids); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, res);
+  SET_VECTOR_ELT(result, 1, extd_graph);
+  SET_VECTOR_ELT(result, 2, extd_to_orig_eids);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("res"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("extd_graph"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("extd_to_orig_eids"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hrg_dendrogram                      /
+/ igraph_layout_mds                          /
 /-------------------------------------------*/
-SEXP R_igraph_hrg_dendrogram(SEXP hrg) {
+SEXP R_igraph_layout_mds(SEXP graph, SEXP dist, SEXP dim) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_hrg_t c_hrg;
-  SEXP graph;
+  igraph_matrix_t c_res;
+  igraph_matrix_t c_dist;
+  igraph_integer_t c_dim;
+
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_hrg(hrg, &c_hrg);
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  if (!isNull(dist)) { R_SEXP_to_matrix(dist, &c_dist); }
+  c_dim=INTEGER(dim)[0];
                                         /* Call igraph */
-  igraph_hrg_dendrogram(&c_graph, &c_hrg);
+  igraph_layout_mds(&c_graph, &c_res, (isNull(dist) ? 0 : &c_dist), c_dim, 0);
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hrg_consensus                       /
+/ igraph_layout_bipartite                    /
 /-------------------------------------------*/
-SEXP R_igraph_hrg_consensus(SEXP graph, SEXP hrg, SEXP start, SEXP num_samples) {
+SEXP R_igraph_layout_bipartite(SEXP graph, SEXP types, SEXP hgap, SEXP vgap, SEXP maxiter) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_parents;
-  igraph_vector_t c_weights;
-  igraph_hrg_t c_hrg;
-  igraph_bool_t c_start;
-  int c_num_samples;
-  SEXP parents;
-  SEXP weights;
+  igraph_vector_bool_t c_types;
+  igraph_matrix_t c_res;
+  igraph_real_t c_hgap;
+  igraph_real_t c_vgap;
+  igraph_integer_t c_maxiter;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_parents, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_parents);
-  if (0 != igraph_vector_init(&c_weights, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_weights);
-  if (0 != R_SEXP_to_hrg_copy(hrg, &c_hrg)) { 
+  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
-  c_start=LOGICAL(start)[0];
-  c_num_samples=INTEGER(num_samples)[0];
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_hgap=REAL(hgap)[0];
+  c_vgap=REAL(vgap)[0];
+  c_maxiter=INTEGER(maxiter)[0];
                                         /* Call igraph */
-  igraph_hrg_consensus(&c_graph, &c_parents, &c_weights, &c_hrg, c_start, c_num_samples);
+  igraph_layout_bipartite(&c_graph, (isNull(types) ? 0 : &c_types), &c_res, c_hgap, c_vgap, c_maxiter);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(parents=R_igraph_vector_to_SEXP(&c_parents)); 
-  igraph_vector_destroy(&c_parents); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(weights=R_igraph_vector_to_SEXP(&c_weights)); 
-  igraph_vector_destroy(&c_weights); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
-  igraph_hrg_destroy(&c_hrg); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, parents);
-  SET_VECTOR_ELT(result, 1, weights);
-  SET_VECTOR_ELT(result, 2, hrg);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("parents"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("weights"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("hrg"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hrg_predict                         /
+/ igraph_layout_gem                          /
 /-------------------------------------------*/
-SEXP R_igraph_hrg_predict(SEXP graph, SEXP hrg, SEXP start, SEXP num_samples, SEXP num_bins) {
+SEXP R_igraph_layout_gem(SEXP graph, SEXP res, SEXP use_seed, SEXP maxiter, SEXP temp_max, SEXP temp_min, SEXP temp_init) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_edges;
-  igraph_vector_t c_prob;
-  igraph_hrg_t c_hrg;
-  igraph_bool_t c_start;
-  int c_num_samples;
-  int c_num_bins;
-  SEXP edges;
-  SEXP prob;
+  igraph_matrix_t c_res;
+  igraph_bool_t c_use_seed;
+  igraph_integer_t c_maxiter;
+  igraph_real_t c_temp_max;
+  igraph_real_t c_temp_min;
+  igraph_real_t c_temp_init;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_edges, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_edges);
-  if (0 != igraph_vector_init(&c_prob, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_prob);
-  if (0 != R_SEXP_to_hrg_copy(hrg, &c_hrg)) { 
+  if (0 != R_SEXP_to_igraph_matrix_copy(res, &c_res)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
-  c_start=LOGICAL(start)[0];
-  c_num_samples=INTEGER(num_samples)[0];
-  c_num_bins=INTEGER(num_bins)[0];
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_use_seed=LOGICAL(use_seed)[0];
+  c_maxiter=INTEGER(maxiter)[0];
+  c_temp_max=REAL(temp_max)[0];
+  c_temp_min=REAL(temp_min)[0];
+  c_temp_init=REAL(temp_init)[0];
                                         /* Call igraph */
-  igraph_hrg_predict(&c_graph, &c_edges, &c_prob, &c_hrg, c_start, c_num_samples, c_num_bins);
+  igraph_layout_gem(&c_graph, &c_res, c_use_seed, c_maxiter, c_temp_max, c_temp_min, c_temp_init);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(edges=R_igraph_vector_to_SEXPp1(&c_edges)); 
-  igraph_vector_destroy(&c_edges); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(prob=R_igraph_vector_to_SEXP(&c_prob)); 
-  igraph_vector_destroy(&c_prob); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
-  igraph_hrg_destroy(&c_hrg); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, edges);
-  SET_VECTOR_ELT(result, 1, prob);
-  SET_VECTOR_ELT(result, 2, hrg);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("edges"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("prob"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("hrg"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_hrg_create                          /
+/ igraph_layout_davidson_harel               /
 /-------------------------------------------*/
-SEXP R_igraph_hrg_create(SEXP graph, SEXP prob) {
+SEXP R_igraph_layout_davidson_harel(SEXP graph, SEXP res, SEXP use_seed, SEXP maxiter, SEXP fineiter, SEXP cool_fact, SEXP weight_node_dist, SEXP weight_border, SEXP weight_edge_lengths, SEXP weight_edge_crossings, SEXP weight_node_edge_dist) {
                                         /* Declarations */
-  igraph_hrg_t c_hrg;
   igraph_t c_graph;
-  igraph_vector_t c_prob;
-  SEXP hrg;
+  igraph_matrix_t c_res;
+  igraph_bool_t c_use_seed;
+  igraph_integer_t c_maxiter;
+  igraph_integer_t c_fineiter;
+  igraph_real_t c_cool_fact;
+  igraph_real_t c_weight_node_dist;
+  igraph_real_t c_weight_border;
+  igraph_real_t c_weight_edge_lengths;
+  igraph_real_t c_weight_edge_crossings;
+  igraph_real_t c_weight_node_edge_dist;
 
   SEXP result;
                                         /* Convert input */
-  if (0 != igraph_hrg_init(&c_hrg, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != R_SEXP_to_igraph_matrix_copy(res, &c_res)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(prob, &c_prob);
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_use_seed=LOGICAL(use_seed)[0];
+  c_maxiter=INTEGER(maxiter)[0];
+  c_fineiter=INTEGER(fineiter)[0];
+  c_cool_fact=REAL(cool_fact)[0];
+  c_weight_node_dist=REAL(weight_node_dist)[0];
+  c_weight_border=REAL(weight_border)[0];
+  c_weight_edge_lengths=REAL(weight_edge_lengths)[0];
+  c_weight_edge_crossings=REAL(weight_edge_crossings)[0];
+  c_weight_node_edge_dist=REAL(weight_node_edge_dist)[0];
                                         /* Call igraph */
-  igraph_hrg_create(&c_hrg, &c_graph, &c_prob);
+  igraph_layout_davidson_harel(&c_graph, &c_res, c_use_seed, c_maxiter, c_fineiter, c_cool_fact, c_weight_node_dist, c_weight_border, c_weight_edge_lengths, c_weight_edge_crossings, c_weight_node_edge_dist);
 
                                         /* Convert output */
-  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
-  igraph_hrg_destroy(&c_hrg); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=hrg;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_community_infomap                   /
+/ igraph_similarity_jaccard                  /
 /-------------------------------------------*/
-SEXP R_igraph_community_infomap(SEXP graph, SEXP e_weights, SEXP v_weights, SEXP nb_trials) {
+SEXP R_igraph_similarity_jaccard(SEXP graph, SEXP vids, SEXP mode, SEXP loops) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_e_weights;
-  igraph_vector_t c_v_weights;
-  int c_nb_trials;
-  igraph_vector_t c_membership;
-  igraph_real_t c_codelength;
-  SEXP membership;
-  SEXP codelength;
+  igraph_matrix_t c_res;
+  igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
+  igraph_bool_t c_loops;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(e_weights)) { R_SEXP_to_vector(e_weights, &c_e_weights); }
-  if (!isNull(v_weights)) { R_SEXP_to_vector(v_weights, &c_v_weights); }
-  c_nb_trials=INTEGER(nb_trials)[0];
-  if (0 != igraph_vector_init(&c_membership, 0)) { 
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_loops=LOGICAL(loops)[0];
                                         /* Call igraph */
-  igraph_community_infomap(&c_graph, (isNull(e_weights) ? 0 : &c_e_weights), (isNull(v_weights) ? 0 : &c_v_weights), c_nb_trials, &c_membership, &c_codelength);
+  igraph_similarity_jaccard(&c_graph, &c_res, c_vids, c_mode, c_loops);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
-  igraph_vector_destroy(&c_membership); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(codelength=NEW_NUMERIC(1)); 
-  REAL(codelength)[0]=c_codelength;
-  SET_VECTOR_ELT(result, 0, membership);
-  SET_VECTOR_ELT(result, 1, codelength);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("codelength"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  igraph_vs_destroy(&c_vids);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_to_undirected                       /
+/ igraph_similarity_dice                     /
 /-------------------------------------------*/
-SEXP R_igraph_to_undirected(SEXP graph, SEXP mode, SEXP edge_attr_comb) {
+SEXP R_igraph_similarity_dice(SEXP graph, SEXP vids, SEXP mode, SEXP loops) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_to_undirected_t c_mode;
-  igraph_attribute_combination_t c_edge_attr_comb;
+  igraph_matrix_t c_res;
+  igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
+  igraph_bool_t c_loops;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph_copy(graph, &c_graph); 
-  IGRAPH_FINALLY(igraph_destroy, &c_graph);
-  c_mode=(igraph_to_undirected_t) REAL(mode)[0];
-  R_SEXP_to_attr_comb(edge_attr_comb, &c_edge_attr_comb);
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  c_loops=LOGICAL(loops)[0];
                                         /* Call igraph */
-  igraph_to_undirected(&c_graph, c_mode, &c_edge_attr_comb);
+  igraph_similarity_dice(&c_graph, &c_res, c_vids, c_mode, c_loops);
 
                                         /* Convert output */
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_attribute_combination_destroy(&c_edge_attr_comb);
-  result=graph;
+  igraph_vs_destroy(&c_vids);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_get_stochastic                      /
+/ igraph_similarity_inverse_log_weighted     /
 /-------------------------------------------*/
-SEXP R_igraph_get_stochastic(SEXP graph, SEXP column_wise) {
+SEXP R_igraph_similarity_inverse_log_weighted(SEXP graph, SEXP vids, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
   igraph_matrix_t c_res;
-  igraph_bool_t c_column_wise;
+  igraph_vs_t c_vids;
+  igraph_neimode_t c_mode;
   SEXP res;
 
   SEXP result;
@@ -14281,14 +12884,16 @@ SEXP R_igraph_get_stochastic(SEXP graph, SEXP column_wise) {
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
   IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
-  c_column_wise=LOGICAL(column_wise)[0];
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_get_stochastic(&c_graph, &c_res, c_column_wise);
+  igraph_similarity_inverse_log_weighted(&c_graph, &c_res, c_vids, c_mode);
 
                                         /* Convert output */
   PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
   igraph_matrix_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
+  igraph_vs_destroy(&c_vids);
   result=res;
 
   UNPROTECT(1);
@@ -14296,984 +12901,1014 @@ SEXP R_igraph_get_stochastic(SEXP graph, SEXP column_wise) {
 }
 
 /*-------------------------------------------/
-/ igraph_get_stochastic_sparsemat            /
+/ igraph_compare_communities                 /
 /-------------------------------------------*/
-SEXP R_igraph_get_stochastic_sparsemat(SEXP graph, SEXP column_wise) {
+SEXP R_igraph_compare_communities(SEXP comm1, SEXP comm2, SEXP method) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_sparsemat_t c_sparsemat;
-  igraph_bool_t c_column_wise;
-  SEXP sparsemat;
+  igraph_vector_t c_comm1;
+  igraph_vector_t c_comm2;
+  igraph_real_t c_res;
+  igraph_community_comparison_t c_method;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  /* Don't need to init. */
-  c_column_wise=LOGICAL(column_wise)[0];
+  R_SEXP_to_vector(comm1, &c_comm1);
+  R_SEXP_to_vector(comm2, &c_comm2);
+  c_method=(igraph_community_comparison_t) REAL(method)[0];
                                         /* Call igraph */
-  igraph_get_stochastic_sparsemat(&c_graph, &c_sparsemat, c_column_wise);
+  igraph_compare_communities(&c_comm1, &c_comm2, &c_res, c_method);
 
                                         /* Convert output */
-  PROTECT(sparsemat=R_igraph_sparsemat_to_SEXP(&c_sparsemat)); 
-  igraph_sparsemat_destroy(&c_sparsemat); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=sparsemat;
+  PROTECT(res=NEW_NUMERIC(1)); 
+  REAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_dyad_census                         /
+/ igraph_modularity                          /
 /-------------------------------------------*/
-SEXP R_igraph_dyad_census(SEXP graph) {
+SEXP R_igraph_modularity(SEXP graph, SEXP membership, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_mut;
-  igraph_integer_t c_asym;
-  igraph_integer_t c_null;
-  SEXP mut;
-  SEXP asym;
-  SEXP null;
+  igraph_vector_t c_membership;
+  igraph_real_t c_modularity;
+  igraph_vector_t c_weights;
+  SEXP modularity;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
+  R_SEXP_to_vector(membership, &c_membership);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_dyad_census(&c_graph, &c_mut, &c_asym, &c_null);
+  igraph_modularity(&c_graph, &c_membership, &c_modularity, (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(mut=NEW_INTEGER(1)); 
-  INTEGER(mut)[0]=c_mut;
-  PROTECT(asym=NEW_INTEGER(1)); 
-  INTEGER(asym)[0]=c_asym;
-  PROTECT(null=NEW_INTEGER(1)); 
-  INTEGER(null)[0]=c_null;
-  SET_VECTOR_ELT(result, 0, mut);
-  SET_VECTOR_ELT(result, 1, asym);
-  SET_VECTOR_ELT(result, 2, null);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("mut"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("asym"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("null"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  PROTECT(modularity=NEW_NUMERIC(1)); 
+  REAL(modularity)[0]=c_modularity;
+  result=modularity;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_triad_census                        /
+/ igraph_modularity_matrix                   /
 /-------------------------------------------*/
-SEXP R_igraph_triad_census(SEXP graph) {
+SEXP R_igraph_modularity_matrix(SEXP graph, SEXP membership, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  SEXP res;
+  igraph_vector_t c_membership;
+  igraph_matrix_t c_modmat;
+  igraph_vector_t c_weights;
+  SEXP modmat;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
+  R_SEXP_to_vector(membership, &c_membership);
+  if (0 != igraph_matrix_init(&c_modmat, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_modmat);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_triad_census(&c_graph, &c_res);
+  igraph_modularity_matrix(&c_graph, &c_membership, &c_modmat, (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  PROTECT(modmat=R_igraph_matrix_to_SEXP(&c_modmat)); 
+  igraph_matrix_destroy(&c_modmat); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  result=modmat;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_adjacent_triangles                  /
+/ igraph_community_label_propagation         /
 /-------------------------------------------*/
-SEXP R_igraph_adjacent_triangles(SEXP graph, SEXP vids) {
+SEXP R_igraph_community_label_propagation(SEXP graph, SEXP weights, SEXP initial, SEXP fixed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_res;
-  igraph_vs_t c_vids;
-  SEXP res;
+  igraph_vector_t c_membership;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_initial;
+  igraph_vector_bool_t c_fixed;
+  igraph_real_t c_modularity;
+  SEXP membership;
+  SEXP modularity;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_res, 0)) { 
+  if (0 != igraph_vector_init(&c_membership, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
-  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(initial)) { R_SEXP_to_vector(initial, &c_initial); }
+  if (!isNull(fixed)) { R_SEXP_to_vector_bool(fixed, &c_fixed); }
                                         /* Call igraph */
-  igraph_adjacent_triangles(&c_graph, &c_res, c_vids);
+  igraph_community_label_propagation(&c_graph, &c_membership, (isNull(weights) ? 0 : &c_weights), (isNull(initial) ? 0 : &c_initial), (isNull(fixed) ? 0 : &c_fixed), &c_modularity);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
-  igraph_vector_destroy(&c_res); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
+  igraph_vector_destroy(&c_membership); 
   IGRAPH_FINALLY_CLEAN(1);
-  igraph_vs_destroy(&c_vids);
-  result=res;
+  PROTECT(modularity=NEW_NUMERIC(1)); 
+  REAL(modularity)[0]=c_modularity;
+  SET_VECTOR_ELT(result, 0, membership);
+  SET_VECTOR_ELT(result, 1, modularity);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("modularity"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_maxflow                             /
+/ igraph_community_multilevel                /
 /-------------------------------------------*/
-SEXP R_igraph_maxflow(SEXP graph, SEXP source, SEXP target, SEXP capacity) {
+SEXP R_igraph_community_multilevel(SEXP graph, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_value;
-  igraph_vector_t c_flow;
-  igraph_vector_t c_cut;
-  igraph_vector_t c_partition1;
-  igraph_vector_t c_partition2;
-  igraph_integer_t c_source;
-  igraph_integer_t c_target;
-  igraph_vector_t c_capacity;
-  igraph_maxflow_stats_t c_stats;
-  SEXP value;
-  SEXP flow;
-  SEXP cut;
-  SEXP partition1;
-  SEXP partition2;
-  SEXP stats;
+  igraph_vector_t c_weights;
+  igraph_vector_t c_membership;
+  igraph_matrix_t c_memberships;
+  igraph_vector_t c_modularity;
+  SEXP membership;
+  SEXP memberships;
+  SEXP modularity;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_flow, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_flow); 
-  flow=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_cut, 0)) { 
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (0 != igraph_vector_init(&c_membership, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_cut); 
-  cut=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_partition1, 0)) { 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
+  if (0 != igraph_matrix_init(&c_memberships, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_partition1); 
-  partition1=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_partition2, 0)) { 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_memberships); 
+  memberships=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_modularity, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_partition2); 
-  partition2=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_source=(igraph_integer_t) REAL(source)[0];
-  c_target=(igraph_integer_t) REAL(target)[0];
-  if (!isNull(capacity)) { R_SEXP_to_vector(capacity, &c_capacity); }
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_modularity); 
+  modularity=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_maxflow(&c_graph, &c_value, (isNull(flow) ? 0 : &c_flow), (isNull(cut) ? 0 : &c_cut), (isNull(partition1) ? 0 : &c_partition1), (isNull(partition2) ? 0 : &c_partition2), c_source, c_target, (isNull(capacity) ? 0 : &c_capacity), &c_stats);
+  igraph_community_multilevel(&c_graph, (isNull(weights) ? 0 : &c_weights), &c_membership, (isNull(memberships) ? 0 : &c_memberships), (isNull(modularity) ? 0 : &c_modularity));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(6));
-  PROTECT(names=NEW_CHARACTER(6));
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(flow=R_igraph_0orvector_to_SEXP(&c_flow)); 
-  igraph_vector_destroy(&c_flow); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cut=R_igraph_0orvector_to_SEXPp1(&c_cut)); 
-  igraph_vector_destroy(&c_cut); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
+  igraph_vector_destroy(&c_membership); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(partition1=R_igraph_0orvector_to_SEXPp1(&c_partition1)); 
-  igraph_vector_destroy(&c_partition1); 
+  PROTECT(memberships=R_igraph_0ormatrix_to_SEXP(&c_memberships)); 
+  igraph_matrix_destroy(&c_memberships); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(partition2=R_igraph_0orvector_to_SEXPp1(&c_partition2)); 
-  igraph_vector_destroy(&c_partition2); 
+  PROTECT(modularity=R_igraph_0orvector_to_SEXP(&c_modularity)); 
+  igraph_vector_destroy(&c_modularity); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(stats=R_igraph_maxflow_stats_to_SEXP(&c_stats));
-  SET_VECTOR_ELT(result, 0, value);
-  SET_VECTOR_ELT(result, 1, flow);
-  SET_VECTOR_ELT(result, 2, cut);
-  SET_VECTOR_ELT(result, 3, partition1);
-  SET_VECTOR_ELT(result, 4, partition2);
-  SET_VECTOR_ELT(result, 5, stats);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("flow"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("cut"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("partition1"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("partition2"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("stats"));
+  SET_VECTOR_ELT(result, 0, membership);
+  SET_VECTOR_ELT(result, 1, memberships);
+  SET_VECTOR_ELT(result, 2, modularity);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("memberships"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("modularity"));
   SET_NAMES(result, names);
-  UNPROTECT(7);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_dominator_tree                      /
+/ igraph_community_optimal_modularity        /
 /-------------------------------------------*/
-SEXP R_igraph_dominator_tree(SEXP graph, SEXP root, SEXP mode) {
+SEXP R_igraph_community_optimal_modularity(SEXP graph, SEXP weights) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_root;
-  igraph_vector_t c_dom;
-  igraph_t c_domtree;
-  igraph_vector_t c_leftout;
-  igraph_neimode_t c_mode;
-  SEXP dom;
-  SEXP domtree;
-  SEXP leftout;
+  igraph_real_t c_modularity;
+  igraph_vector_t c_membership;
+  igraph_vector_t c_weights;
+  SEXP modularity;
+  SEXP membership;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_root=(igraph_integer_t) REAL(root)[0];
-  if (0 != igraph_vector_init(&c_dom, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_dom);
-  domtree=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_leftout, 0)) { 
+  if (0 != igraph_vector_init(&c_membership, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_leftout);
-  c_mode=(igraph_neimode_t) REAL(mode)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership); 
+  membership=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
                                         /* Call igraph */
-  igraph_dominator_tree(&c_graph, c_root, &c_dom, (isNull(domtree) ? 0 : &c_domtree), &c_leftout, c_mode);
+  igraph_community_optimal_modularity(&c_graph, &c_modularity, (isNull(membership) ? 0 : &c_membership), (isNull(weights) ? 0 : &c_weights));
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(dom=R_igraph_vector_to_SEXPp1(&c_dom)); 
-  igraph_vector_destroy(&c_dom); 
-  IGRAPH_FINALLY_CLEAN(1);
-  IGRAPH_FINALLY(igraph_destroy, &c_domtree); 
-  PROTECT(domtree=R_igraph_to_SEXP(&c_domtree));  
-  igraph_destroy(&c_domtree); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(leftout=R_igraph_vector_to_SEXPp1(&c_leftout)); 
-  igraph_vector_destroy(&c_leftout); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(modularity=NEW_NUMERIC(1)); 
+  REAL(modularity)[0]=c_modularity;
+  PROTECT(membership=R_igraph_0orvector_to_SEXP(&c_membership)); 
+  igraph_vector_destroy(&c_membership); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, dom);
-  SET_VECTOR_ELT(result, 1, domtree);
-  SET_VECTOR_ELT(result, 2, leftout);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("dom"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("domtree"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("leftout"));
+  SET_VECTOR_ELT(result, 0, modularity);
+  SET_VECTOR_ELT(result, 1, membership);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("modularity"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("membership"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
+
+  UNPROTECT(1);
+  return(result);
+}
+
+/*-------------------------------------------/
+/ igraph_split_join_distance                 /
+/-------------------------------------------*/
+SEXP R_igraph_split_join_distance(SEXP comm1, SEXP comm2) {
+                                        /* Declarations */
+  igraph_vector_t c_comm1;
+  igraph_vector_t c_comm2;
+  igraph_integer_t c_distance12;
+  igraph_integer_t c_distance21;
+  SEXP distance12;
+  SEXP distance21;
+
+  SEXP result, names;
+                                        /* Convert input */
+  R_SEXP_to_vector(comm1, &c_comm1);
+  R_SEXP_to_vector(comm2, &c_comm2);
+                                        /* Call igraph */
+  igraph_split_join_distance(&c_comm1, &c_comm2, &c_distance12, &c_distance21);
+
+                                        /* Convert output */
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(distance12=NEW_INTEGER(1)); 
+  INTEGER(distance12)[0]=c_distance12;
+  PROTECT(distance21=NEW_INTEGER(1)); 
+  INTEGER(distance21)[0]=c_distance21;
+  SET_VECTOR_ELT(result, 0, distance12);
+  SET_VECTOR_ELT(result, 1, distance21);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("distance12"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("distance21"));
   SET_NAMES(result, names);
-  UNPROTECT(4);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_all_st_cuts                         /
+/ igraph_hrg_fit                             /
 /-------------------------------------------*/
-SEXP R_igraph_all_st_cuts(SEXP graph, SEXP source, SEXP target) {
+SEXP R_igraph_hrg_fit(SEXP graph, SEXP hrg, SEXP start, SEXP steps) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_ptr_t c_cuts;
-  igraph_vector_ptr_t c_partition1s;
-  igraph_integer_t c_source;
-  igraph_integer_t c_target;
-  SEXP cuts;
-  SEXP partition1s;
+  igraph_hrg_t c_hrg;
+  igraph_bool_t c_start;
+  int c_steps;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_cuts, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_cuts);
-  if (0 != igraph_vector_ptr_init(&c_partition1s, 0)) { 
+  if (0 != R_SEXP_to_hrg_copy(hrg, &c_hrg)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_partition1s);
-  c_source=(igraph_integer_t) REAL(source)[0];
-  c_target=(igraph_integer_t) REAL(target)[0];
+  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
+  c_start=LOGICAL(start)[0];
+  c_steps=INTEGER(steps)[0];
                                         /* Call igraph */
-  igraph_all_st_cuts(&c_graph, &c_cuts, &c_partition1s, c_source, c_target);
+  igraph_hrg_fit(&c_graph, &c_hrg, c_start, c_steps);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(cuts=R_igraph_vectorlist_to_SEXP_p1(&c_cuts)); 
-  R_igraph_vectorlist_destroy(&c_cuts); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(partition1s=R_igraph_vectorlist_to_SEXP_p1(&c_partition1s)); 
-  R_igraph_vectorlist_destroy(&c_partition1s); 
+  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
+  igraph_hrg_destroy(&c_hrg); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, cuts);
-  SET_VECTOR_ELT(result, 1, partition1s);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("cuts"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("partition1s"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=hrg;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_all_st_mincuts                      /
+/ igraph_hrg_game                            /
 /-------------------------------------------*/
-SEXP R_igraph_all_st_mincuts(SEXP graph, SEXP source, SEXP target, SEXP capacity) {
+SEXP R_igraph_hrg_game(SEXP hrg) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_value;
-  igraph_vector_ptr_t c_cuts;
-  igraph_vector_ptr_t c_partition1s;
-  igraph_integer_t c_source;
-  igraph_integer_t c_target;
-  igraph_vector_t c_capacity;
-  SEXP value;
-  SEXP cuts;
-  SEXP partition1s;
+  igraph_hrg_t c_hrg;
+  SEXP graph;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_cuts, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_cuts);
-  if (0 != igraph_vector_ptr_init(&c_partition1s, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_partition1s);
-  c_source=(igraph_integer_t) REAL(source)[0];
-  c_target=(igraph_integer_t) REAL(target)[0];
-  if (!isNull(capacity)) { R_SEXP_to_vector(capacity, &c_capacity); }
+  R_SEXP_to_hrg(hrg, &c_hrg);
                                         /* Call igraph */
-  igraph_all_st_mincuts(&c_graph, &c_value, &c_cuts, &c_partition1s, c_source, c_target, (isNull(capacity) ? 0 : &c_capacity));
+  igraph_hrg_game(&c_graph, &c_hrg);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(cuts=R_igraph_vectorlist_to_SEXP_p1(&c_cuts)); 
-  R_igraph_vectorlist_destroy(&c_cuts); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(partition1s=R_igraph_vectorlist_to_SEXP_p1(&c_partition1s)); 
-  R_igraph_vectorlist_destroy(&c_partition1s); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, value);
-  SET_VECTOR_ELT(result, 1, cuts);
-  SET_VECTOR_ELT(result, 2, partition1s);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cuts"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("partition1s"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_is_separator                        /
+/ igraph_hrg_dendrogram                      /
 /-------------------------------------------*/
-SEXP R_igraph_is_separator(SEXP graph, SEXP candidate) {
+SEXP R_igraph_hrg_dendrogram(SEXP hrg) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vs_t c_candidate;
-  igraph_bool_t c_res;
-  SEXP res;
+  igraph_hrg_t c_hrg;
+  SEXP graph;
 
   SEXP result;
                                         /* Convert input */
+  R_SEXP_to_hrg(hrg, &c_hrg);
+                                        /* Call igraph */
+  igraph_hrg_dendrogram(&c_graph, &c_hrg);
+
+                                        /* Convert output */
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=graph;
+
+  UNPROTECT(1);
+  return(result);
+}
+
+/*-------------------------------------------/
+/ igraph_hrg_consensus                       /
+/-------------------------------------------*/
+SEXP R_igraph_hrg_consensus(SEXP graph, SEXP hrg, SEXP start, SEXP num_samples) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_vector_t c_parents;
+  igraph_vector_t c_weights;
+  igraph_hrg_t c_hrg;
+  igraph_bool_t c_start;
+  int c_num_samples;
+  SEXP parents;
+  SEXP weights;
+
+  SEXP result, names;
+                                        /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate);
+  if (0 != igraph_vector_init(&c_parents, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_parents);
+  if (0 != igraph_vector_init(&c_weights, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_weights);
+  if (0 != R_SEXP_to_hrg_copy(hrg, &c_hrg)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
+  c_start=LOGICAL(start)[0];
+  c_num_samples=INTEGER(num_samples)[0];
                                         /* Call igraph */
-  igraph_is_separator(&c_graph, c_candidate, &c_res);
+  igraph_hrg_consensus(&c_graph, &c_parents, &c_weights, &c_hrg, c_start, c_num_samples);
 
                                         /* Convert output */
-  igraph_vs_destroy(&c_candidate);
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(parents=R_igraph_vector_to_SEXP(&c_parents)); 
+  igraph_vector_destroy(&c_parents); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(weights=R_igraph_vector_to_SEXP(&c_weights)); 
+  igraph_vector_destroy(&c_weights); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
+  igraph_hrg_destroy(&c_hrg); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, parents);
+  SET_VECTOR_ELT(result, 1, weights);
+  SET_VECTOR_ELT(result, 2, hrg);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("parents"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("weights"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("hrg"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_is_minimal_separator                /
+/ igraph_hrg_predict                         /
 /-------------------------------------------*/
-SEXP R_igraph_is_minimal_separator(SEXP graph, SEXP candidate) {
+SEXP R_igraph_hrg_predict(SEXP graph, SEXP hrg, SEXP start, SEXP num_samples, SEXP num_bins) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vs_t c_candidate;
-  igraph_bool_t c_res;
-  SEXP res;
+  igraph_vector_t c_edges;
+  igraph_vector_t c_prob;
+  igraph_hrg_t c_hrg;
+  igraph_bool_t c_start;
+  int c_num_samples;
+  int c_num_bins;
+  SEXP edges;
+  SEXP prob;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate);
+  if (0 != igraph_vector_init(&c_edges, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_edges);
+  if (0 != igraph_vector_init(&c_prob, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_prob);
+  if (0 != R_SEXP_to_hrg_copy(hrg, &c_hrg)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
+  c_start=LOGICAL(start)[0];
+  c_num_samples=INTEGER(num_samples)[0];
+  c_num_bins=INTEGER(num_bins)[0];
                                         /* Call igraph */
-  igraph_is_minimal_separator(&c_graph, c_candidate, &c_res);
+  igraph_hrg_predict(&c_graph, &c_edges, &c_prob, &c_hrg, c_start, c_num_samples, c_num_bins);
 
                                         /* Convert output */
-  igraph_vs_destroy(&c_candidate);
-  PROTECT(res=NEW_LOGICAL(1)); 
-  LOGICAL(res)[0]=c_res;
-  result=res;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(edges=R_igraph_vector_to_SEXPp1(&c_edges)); 
+  igraph_vector_destroy(&c_edges); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(prob=R_igraph_vector_to_SEXP(&c_prob)); 
+  igraph_vector_destroy(&c_prob); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
+  igraph_hrg_destroy(&c_hrg); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, edges);
+  SET_VECTOR_ELT(result, 1, prob);
+  SET_VECTOR_ELT(result, 2, hrg);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("edges"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("prob"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("hrg"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_all_minimal_st_separators           /
+/ igraph_hrg_create                          /
 /-------------------------------------------*/
-SEXP R_igraph_all_minimal_st_separators(SEXP graph) {
+SEXP R_igraph_hrg_create(SEXP graph, SEXP prob) {
                                         /* Declarations */
+  igraph_hrg_t c_hrg;
   igraph_t c_graph;
-  igraph_vector_ptr_t c_separators;
-  SEXP separators;
+  igraph_vector_t c_prob;
+  SEXP hrg;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_separators, 0)) { 
+  if (0 != igraph_hrg_init(&c_hrg, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_separators);
+  IGRAPH_FINALLY(igraph_hrg_destroy, &c_hrg);
+  R_SEXP_to_igraph(graph, &c_graph);
+  R_SEXP_to_vector(prob, &c_prob);
                                         /* Call igraph */
-  igraph_all_minimal_st_separators(&c_graph, &c_separators);
+  igraph_hrg_create(&c_hrg, &c_graph, &c_prob);
 
                                         /* Convert output */
-  PROTECT(separators=R_igraph_vectorlist_to_SEXP_p1(&c_separators)); 
-  R_igraph_vectorlist_destroy(&c_separators); 
+  PROTECT(hrg=R_igraph_hrg_to_SEXP(&c_hrg)); 
+  igraph_hrg_destroy(&c_hrg); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=separators;
+  result=hrg;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_minimum_size_separators             /
+/ igraph_community_infomap                   /
 /-------------------------------------------*/
-SEXP R_igraph_minimum_size_separators(SEXP graph) {
+SEXP R_igraph_community_infomap(SEXP graph, SEXP e_weights, SEXP v_weights, SEXP nb_trials) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_ptr_t c_separators;
-  SEXP separators;
+  igraph_vector_t c_e_weights;
+  igraph_vector_t c_v_weights;
+  int c_nb_trials;
+  igraph_vector_t c_membership;
+  igraph_real_t c_codelength;
+  SEXP membership;
+  SEXP codelength;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_ptr_init(&c_separators, 0)) { 
+  if (!isNull(e_weights)) { R_SEXP_to_vector(e_weights, &c_e_weights); }
+  if (!isNull(v_weights)) { R_SEXP_to_vector(v_weights, &c_v_weights); }
+  c_nb_trials=INTEGER(nb_trials)[0];
+  if (0 != igraph_vector_init(&c_membership, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_separators);
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_membership);
                                         /* Call igraph */
-  igraph_minimum_size_separators(&c_graph, &c_separators);
+  igraph_community_infomap(&c_graph, (isNull(e_weights) ? 0 : &c_e_weights), (isNull(v_weights) ? 0 : &c_v_weights), c_nb_trials, &c_membership, &c_codelength);
 
                                         /* Convert output */
-  PROTECT(separators=R_igraph_vectorlist_to_SEXP_p1(&c_separators)); 
-  R_igraph_vectorlist_destroy(&c_separators); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(membership=R_igraph_vector_to_SEXP(&c_membership)); 
+  igraph_vector_destroy(&c_membership); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=separators;
+  PROTECT(codelength=NEW_NUMERIC(1)); 
+  REAL(codelength)[0]=c_codelength;
+  SET_VECTOR_ELT(result, 0, membership);
+  SET_VECTOR_ELT(result, 1, codelength);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("membership"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("codelength"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_isoclass                            /
+/ igraph_to_undirected                       /
 /-------------------------------------------*/
-SEXP R_igraph_isoclass(SEXP graph) {
+SEXP R_igraph_to_undirected(SEXP graph, SEXP mode, SEXP edge_attr_comb) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_isoclass;
-  SEXP isoclass;
+  igraph_to_undirected_t c_mode;
+  igraph_attribute_combination_t c_edge_attr_comb;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
+  R_SEXP_to_igraph_copy(graph, &c_graph); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph);
+  c_mode=(igraph_to_undirected_t) REAL(mode)[0];
+  R_SEXP_to_attr_comb(edge_attr_comb, &c_edge_attr_comb);
                                         /* Call igraph */
-  igraph_isoclass(&c_graph, &c_isoclass);
+  igraph_to_undirected(&c_graph, c_mode, &c_edge_attr_comb);
 
                                         /* Convert output */
-  PROTECT(isoclass=NEW_INTEGER(1)); 
-  INTEGER(isoclass)[0]=c_isoclass;
-  result=isoclass;
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_attribute_combination_destroy(&c_edge_attr_comb);
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_isomorphic                          /
+/ igraph_get_stochastic                      /
 /-------------------------------------------*/
-SEXP R_igraph_isomorphic(SEXP graph1, SEXP graph2) {
+SEXP R_igraph_get_stochastic(SEXP graph, SEXP column_wise) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_bool_t c_iso;
-  SEXP iso;
+  igraph_t c_graph;
+  igraph_matrix_t c_res;
+  igraph_bool_t c_column_wise;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_matrix_init(&c_res, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_res);
+  c_column_wise=LOGICAL(column_wise)[0];
                                         /* Call igraph */
-  igraph_isomorphic(&c_graph1, &c_graph2, &c_iso);
+  igraph_get_stochastic(&c_graph, &c_res, c_column_wise);
 
                                         /* Convert output */
-  PROTECT(iso=NEW_LOGICAL(1)); 
-  LOGICAL(iso)[0]=c_iso;
-  result=iso;
+  PROTECT(res=R_igraph_matrix_to_SEXP(&c_res)); 
+  igraph_matrix_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_isoclass_subgraph                   /
+/ igraph_get_stochastic_sparsemat            /
 /-------------------------------------------*/
-SEXP R_igraph_isoclass_subgraph(SEXP graph, SEXP vids) {
+SEXP R_igraph_get_stochastic_sparsemat(SEXP graph, SEXP column_wise) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_vids;
-  igraph_integer_t c_isoclass;
-  SEXP isoclass;
+  igraph_sparsemat_t c_sparsemat;
+  igraph_bool_t c_column_wise;
+  SEXP sparsemat;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(vids, &c_vids);
+  /* Don't need to init. */
+  c_column_wise=LOGICAL(column_wise)[0];
                                         /* Call igraph */
-  igraph_isoclass_subgraph(&c_graph, &c_vids, &c_isoclass);
+  igraph_get_stochastic_sparsemat(&c_graph, &c_sparsemat, c_column_wise);
 
                                         /* Convert output */
-  PROTECT(isoclass=NEW_INTEGER(1)); 
-  INTEGER(isoclass)[0]=c_isoclass;
-  result=isoclass;
+  PROTECT(sparsemat=R_igraph_sparsemat_to_SEXP(&c_sparsemat)); 
+  igraph_sparsemat_destroy(&c_sparsemat); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=sparsemat;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_isoclass_create                     /
+/ igraph_dyad_census                         /
 /-------------------------------------------*/
-SEXP R_igraph_isoclass_create(SEXP size, SEXP number, SEXP directed) {
+SEXP R_igraph_dyad_census(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_size;
-  igraph_integer_t c_number;
-  igraph_bool_t c_directed;
-  SEXP graph;
+  igraph_integer_t c_mut;
+  igraph_integer_t c_asym;
+  igraph_integer_t c_null;
+  SEXP mut;
+  SEXP asym;
+  SEXP null;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  c_size=INTEGER(size)[0];
-  c_number=INTEGER(number)[0];
-  c_directed=LOGICAL(directed)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
                                         /* Call igraph */
-  igraph_isoclass_create(&c_graph, c_size, c_number, c_directed);
+  igraph_dyad_census(&c_graph, &c_mut, &c_asym, &c_null);
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
-  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
-  igraph_destroy(&c_graph); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=graph;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(mut=NEW_INTEGER(1)); 
+  INTEGER(mut)[0]=c_mut;
+  PROTECT(asym=NEW_INTEGER(1)); 
+  INTEGER(asym)[0]=c_asym;
+  PROTECT(null=NEW_INTEGER(1)); 
+  INTEGER(null)[0]=c_null;
+  SET_VECTOR_ELT(result, 0, mut);
+  SET_VECTOR_ELT(result, 1, asym);
+  SET_VECTOR_ELT(result, 2, null);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("mut"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("asym"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("null"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_isomorphic_vf2                      /
+/ igraph_triad_census                        /
 /-------------------------------------------*/
-SEXP R_igraph_isomorphic_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
+SEXP R_igraph_triad_census(SEXP graph) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_vector_int_t c_vertex_color1;
-  igraph_vector_int_t c_vertex_color2;
-  igraph_vector_int_t c_edge_color1;
-  igraph_vector_int_t c_edge_color2;
-  igraph_bool_t c_iso;
-  igraph_vector_t c_map12;
-  igraph_vector_t c_map21;
-
-
-
-  SEXP iso;
-  SEXP map12;
-  SEXP map21;
+  igraph_t c_graph;
+  igraph_vector_t c_res;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
-  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
-  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
-  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
-  if (0 != igraph_vector_init(&c_map12, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_map12); 
-  map12=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_map21, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_map21); 
-  map21=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
                                         /* Call igraph */
-  igraph_isomorphic_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_iso, (isNull(map12) ? 0 : &c_map12), (isNull(map21) ? 0 : &c_map21), 0, 0, 0);
+  igraph_triad_census(&c_graph, &c_res);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(iso=NEW_LOGICAL(1)); 
-  LOGICAL(iso)[0]=c_iso;
-  PROTECT(map12=R_igraph_0orvector_to_SEXPp1(&c_map12)); 
-  igraph_vector_destroy(&c_map12); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(map21=R_igraph_0orvector_to_SEXPp1(&c_map21)); 
-  igraph_vector_destroy(&c_map21); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, iso);
-  SET_VECTOR_ELT(result, 1, map12);
-  SET_VECTOR_ELT(result, 2, map21);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("iso"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("map12"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("map21"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_count_isomorphisms_vf2              /
+/ igraph_adjacent_triangles                  /
 /-------------------------------------------*/
-SEXP R_igraph_count_isomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
+SEXP R_igraph_adjacent_triangles(SEXP graph, SEXP vids) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_vector_int_t c_vertex_color1;
-  igraph_vector_int_t c_vertex_color2;
-  igraph_vector_int_t c_edge_color1;
-  igraph_vector_int_t c_edge_color2;
-  igraph_integer_t c_count;
+  igraph_t c_graph;
+  igraph_vector_t c_res;
+  igraph_vs_t c_vids;
+  SEXP res;
+
+  SEXP result;
+                                        /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  R_SEXP_to_igraph_vs(vids, &c_graph, &c_vids);
+                                        /* Call igraph */
+  igraph_adjacent_triangles(&c_graph, &c_res, c_vids);
 
+                                        /* Convert output */
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  igraph_vs_destroy(&c_vids);
+  result=res;
 
+  UNPROTECT(1);
+  return(result);
+}
 
-  SEXP count;
+/*-------------------------------------------/
+/ igraph_local_scan_0                        /
+/-------------------------------------------*/
+SEXP R_igraph_local_scan_0(SEXP graph, SEXP weights, SEXP mode) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights;
+  igraph_neimode_t c_mode;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
-  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
-  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
-  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_count_isomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_count, 0, 0, 0);
+  igraph_local_scan_0(&c_graph, &c_res, (isNull(weights) ? 0 : &c_weights), c_mode);
 
                                         /* Convert output */
-  PROTECT(count=NEW_INTEGER(1)); 
-  INTEGER(count)[0]=c_count;
-  result=count;
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_get_isomorphisms_vf2                /
+/ igraph_local_scan_0_them                   /
 /-------------------------------------------*/
-SEXP R_igraph_get_isomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
+SEXP R_igraph_local_scan_0_them(SEXP us, SEXP them, SEXP weights_them, SEXP mode) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_vector_int_t c_vertex_color1;
-  igraph_vector_int_t c_vertex_color2;
-  igraph_vector_int_t c_edge_color1;
-  igraph_vector_int_t c_edge_color2;
-  igraph_vector_ptr_t c_maps;
-
-
-
-  SEXP maps;
+  igraph_t c_us;
+  igraph_t c_them;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights_them;
+  igraph_neimode_t c_mode;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
-  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
-  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
-  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
-  if (0 != igraph_vector_ptr_init(&c_maps, 0)) { 
+  R_SEXP_to_igraph(us, &c_us);
+  R_SEXP_to_igraph(them, &c_them);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_maps);
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights_them)) { R_SEXP_to_vector(weights_them, &c_weights_them); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_get_isomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_maps, 0, 0, 0);
+  igraph_local_scan_0_them(&c_us, &c_them, &c_res, (isNull(weights_them) ? 0 : &c_weights_them), c_mode);
 
                                         /* Convert output */
-  PROTECT(maps=R_igraph_vectorlist_to_SEXP(&c_maps)); 
-  R_igraph_vectorlist_destroy(&c_maps); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=maps;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_subisomorphic_vf2                   /
+/ igraph_local_scan_1_ecount                 /
 /-------------------------------------------*/
-SEXP R_igraph_subisomorphic_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
+SEXP R_igraph_local_scan_1_ecount(SEXP graph, SEXP weights, SEXP mode) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_vector_int_t c_vertex_color1;
-  igraph_vector_int_t c_vertex_color2;
-  igraph_vector_int_t c_edge_color1;
-  igraph_vector_int_t c_edge_color2;
-  igraph_bool_t c_iso;
-  igraph_vector_t c_map12;
-  igraph_vector_t c_map21;
-
-
-
-  SEXP iso;
-  SEXP map12;
-  SEXP map21;
+  igraph_t c_graph;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights;
+  igraph_neimode_t c_mode;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
-  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
-  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
-  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
-  if (0 != igraph_vector_init(&c_map12, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_map12); 
-  map12=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_map21, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_map21); 
-  map21=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_subisomorphic_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_iso, (isNull(map12) ? 0 : &c_map12), (isNull(map21) ? 0 : &c_map21), 0, 0, 0);
+  igraph_local_scan_1_ecount(&c_graph, &c_res, (isNull(weights) ? 0 : &c_weights), c_mode);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(iso=NEW_LOGICAL(1)); 
-  LOGICAL(iso)[0]=c_iso;
-  PROTECT(map12=R_igraph_0orvector_to_SEXPp1(&c_map12)); 
-  igraph_vector_destroy(&c_map12); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(map21=R_igraph_0orvector_to_SEXPp1(&c_map21)); 
-  igraph_vector_destroy(&c_map21); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, iso);
-  SET_VECTOR_ELT(result, 1, map12);
-  SET_VECTOR_ELT(result, 2, map21);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("iso"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("map12"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("map21"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_count_subisomorphisms_vf2           /
+/ igraph_local_scan_1_ecount_them            /
 /-------------------------------------------*/
-SEXP R_igraph_count_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
+SEXP R_igraph_local_scan_1_ecount_them(SEXP us, SEXP them, SEXP weights_them, SEXP mode) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_vector_int_t c_vertex_color1;
-  igraph_vector_int_t c_vertex_color2;
-  igraph_vector_int_t c_edge_color1;
-  igraph_vector_int_t c_edge_color2;
-  igraph_integer_t c_count;
-
-
-
-  SEXP count;
+  igraph_t c_us;
+  igraph_t c_them;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights_them;
+  igraph_neimode_t c_mode;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
-  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
-  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
-  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
+  R_SEXP_to_igraph(us, &c_us);
+  R_SEXP_to_igraph(them, &c_them);
+  if (0 != igraph_vector_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights_them)) { R_SEXP_to_vector(weights_them, &c_weights_them); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_count_subisomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_count, 0, 0, 0);
+  igraph_local_scan_1_ecount_them(&c_us, &c_them, &c_res, (isNull(weights_them) ? 0 : &c_weights_them), c_mode);
 
                                         /* Convert output */
-  PROTECT(count=NEW_INTEGER(1)); 
-  INTEGER(count)[0]=c_count;
-  result=count;
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_get_subisomorphisms_vf2             /
+/ igraph_local_scan_k_ecount                 /
 /-------------------------------------------*/
-SEXP R_igraph_get_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
+SEXP R_igraph_local_scan_k_ecount(SEXP graph, SEXP k, SEXP weights, SEXP mode) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_vector_int_t c_vertex_color1;
-  igraph_vector_int_t c_vertex_color2;
-  igraph_vector_int_t c_edge_color1;
-  igraph_vector_int_t c_edge_color2;
-  igraph_vector_ptr_t c_maps;
-
-
-
-  SEXP maps;
+  igraph_t c_graph;
+  int c_k;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights;
+  igraph_neimode_t c_mode;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
-  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
-  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
-  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
-  if (0 != igraph_vector_ptr_init(&c_maps, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  c_k=INTEGER(k)[0];
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_maps);
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_get_subisomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_maps, 0, 0, 0);
+  igraph_local_scan_k_ecount(&c_graph, c_k, &c_res, (isNull(weights) ? 0 : &c_weights), c_mode);
 
                                         /* Convert output */
-  PROTECT(maps=R_igraph_vectorlist_to_SEXP(&c_maps)); 
-  R_igraph_vectorlist_destroy(&c_maps); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=maps;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_isomorphic_34                       /
+/ igraph_local_scan_k_ecount_them            /
 /-------------------------------------------*/
-SEXP R_igraph_isomorphic_34(SEXP graph1, SEXP graph2) {
+SEXP R_igraph_local_scan_k_ecount_them(SEXP us, SEXP them, SEXP k, SEXP weights_them, SEXP mode) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_bool_t c_iso;
-  SEXP iso;
+  igraph_t c_us;
+  igraph_t c_them;
+  int c_k;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights_them;
+  igraph_neimode_t c_mode;
+  SEXP res;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
+  R_SEXP_to_igraph(us, &c_us);
+  R_SEXP_to_igraph(them, &c_them);
+  c_k=INTEGER(k)[0];
+  if (0 != igraph_vector_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights_them)) { R_SEXP_to_vector(weights_them, &c_weights_them); }
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_isomorphic_34(&c_graph1, &c_graph2, &c_iso);
+  igraph_local_scan_k_ecount_them(&c_us, &c_them, c_k, &c_res, (isNull(weights_them) ? 0 : &c_weights_them), c_mode);
 
                                         /* Convert output */
-  PROTECT(iso=NEW_LOGICAL(1)); 
-  LOGICAL(iso)[0]=c_iso;
-  result=iso;
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_canonical_permutation               /
+/ igraph_local_scan_neighborhood_ecount      /
 /-------------------------------------------*/
-SEXP R_igraph_canonical_permutation(SEXP graph, SEXP sh) {
+SEXP R_igraph_local_scan_neighborhood_ecount(SEXP graph, SEXP weights, SEXP neighborhoods) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_labeling;
-  igraph_bliss_sh_t c_sh;
-  igraph_bliss_info_t c_info;
-  SEXP labeling;
-  SEXP info;
+  igraph_vector_t c_res;
+  igraph_vector_t c_weights;
+  igraph_vector_ptr_t c_neighborhoods;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (0 != igraph_vector_init(&c_labeling, 0)) { 
+  if (0 != igraph_vector_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_labeling);
-  c_sh=REAL(sh)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_res);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  if (!isNull(neighborhoods)) { R_igraph_SEXP_to_vectorlist_int(neighborhoods, &c_neighborhoods); }
                                         /* Call igraph */
-  igraph_canonical_permutation(&c_graph, &c_labeling, c_sh, &c_info);
+  igraph_local_scan_neighborhood_ecount(&c_graph, &c_res, (isNull(weights) ? 0 : &c_weights), &c_neighborhoods);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(labeling=R_igraph_vector_to_SEXPp1(&c_labeling)); 
-  igraph_vector_destroy(&c_labeling); 
+  PROTECT(res=R_igraph_vector_to_SEXP(&c_res)); 
+  igraph_vector_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(info=R_igraph_bliss_info_to_SEXP(&c_info)); 
-  if (c_info.group_size) { free(c_info.group_size); }
-  SET_VECTOR_ELT(result, 0, labeling);
-  SET_VECTOR_ELT(result, 1, info);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("labeling"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("info"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_permute_vertices                    /
+/ igraph_list_triangles                      /
 /-------------------------------------------*/
-SEXP R_igraph_permute_vertices(SEXP graph, SEXP permutation) {
+SEXP R_igraph_list_triangles(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_t c_res;
-  igraph_vector_t c_permutation;
+  igraph_vector_int_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(permutation, &c_permutation);
+  if (0 != igraph_vector_int_init(&c_res, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &c_res);
                                         /* Call igraph */
-  igraph_permute_vertices(&c_graph, &c_res, &c_permutation);
+  igraph_list_triangles(&c_graph, &c_res);
 
                                         /* Convert output */
-  IGRAPH_FINALLY(igraph_destroy, &c_res); 
-  PROTECT(res=R_igraph_to_SEXP(&c_res));  
-  igraph_destroy(&c_res); 
+  PROTECT(res=R_igraph_vector_int_to_SEXPp1(&c_res)); 
+  igraph_vector_int_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
   result=res;
 
@@ -15282,201 +13917,274 @@ SEXP R_igraph_permute_vertices(SEXP graph, SEXP permutation) {
 }
 
 /*-------------------------------------------/
-/ igraph_isomorphic_bliss                    /
+/ igraph_maxflow                             /
 /-------------------------------------------*/
-SEXP R_igraph_isomorphic_bliss(SEXP graph1, SEXP graph2, SEXP sh1, SEXP sh2) {
+SEXP R_igraph_maxflow(SEXP graph, SEXP source, SEXP target, SEXP capacity) {
                                         /* Declarations */
-  igraph_t c_graph1;
-  igraph_t c_graph2;
-  igraph_bool_t c_iso;
-  igraph_vector_t c_map12;
-  igraph_vector_t c_map21;
-  igraph_bliss_sh_t c_sh1;
-  igraph_bliss_sh_t c_sh2;
-  igraph_bliss_info_t c_info1;
-  igraph_bliss_info_t c_info2;
-  SEXP iso;
-  SEXP map12;
-  SEXP map21;
-  SEXP info1;
-  SEXP info2;
+  igraph_t c_graph;
+  igraph_real_t c_value;
+  igraph_vector_t c_flow;
+  igraph_vector_t c_cut;
+  igraph_vector_t c_partition1;
+  igraph_vector_t c_partition2;
+  igraph_integer_t c_source;
+  igraph_integer_t c_target;
+  igraph_vector_t c_capacity;
+  igraph_maxflow_stats_t c_stats;
+  SEXP value;
+  SEXP flow;
+  SEXP cut;
+  SEXP partition1;
+  SEXP partition2;
+  SEXP stats;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph1, &c_graph1);
-  R_SEXP_to_igraph(graph2, &c_graph2);
-  if (0 != igraph_vector_init(&c_map12, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_init(&c_flow, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_map12); 
-  map12=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_map21, 0)) { 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_flow); 
+  flow=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_cut, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_map21); 
-  map21=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_sh1=REAL(sh1)[0];
-  c_sh2=REAL(sh2)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_cut); 
+  cut=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_partition1, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_partition1);
+  if (0 != igraph_vector_init(&c_partition2, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_partition2);
+  c_source=(igraph_integer_t) REAL(source)[0];
+  c_target=(igraph_integer_t) REAL(target)[0];
+  if (!isNull(capacity)) { R_SEXP_to_vector(capacity, &c_capacity); }
                                         /* Call igraph */
-  igraph_isomorphic_bliss(&c_graph1, &c_graph2, &c_iso, (isNull(map12) ? 0 : &c_map12), (isNull(map21) ? 0 : &c_map21), c_sh1, c_sh2, &c_info1, &c_info2);
+  igraph_maxflow(&c_graph, &c_value, (isNull(flow) ? 0 : &c_flow), (isNull(cut) ? 0 : &c_cut), &c_partition1, &c_partition2, c_source, c_target, (isNull(capacity) ? 0 : &c_capacity), &c_stats);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(5));
-  PROTECT(names=NEW_CHARACTER(5));
-  PROTECT(iso=NEW_LOGICAL(1)); 
-  LOGICAL(iso)[0]=c_iso;
-  PROTECT(map12=R_igraph_0orvector_to_SEXPp1(&c_map12)); 
-  igraph_vector_destroy(&c_map12); 
+  PROTECT(result=NEW_LIST(6));
+  PROTECT(names=NEW_CHARACTER(6));
+  PROTECT(value=NEW_NUMERIC(1)); 
+  REAL(value)[0]=c_value;
+  PROTECT(flow=R_igraph_0orvector_to_SEXP(&c_flow)); 
+  igraph_vector_destroy(&c_flow); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(map21=R_igraph_0orvector_to_SEXPp1(&c_map21)); 
-  igraph_vector_destroy(&c_map21); 
+  PROTECT(cut=R_igraph_0orvector_to_SEXPp1(&c_cut)); 
+  igraph_vector_destroy(&c_cut); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(info1=R_igraph_bliss_info_to_SEXP(&c_info1)); 
-  if (c_info1.group_size) { free(c_info1.group_size); }
-  PROTECT(info2=R_igraph_bliss_info_to_SEXP(&c_info2)); 
-  if (c_info2.group_size) { free(c_info2.group_size); }
-  SET_VECTOR_ELT(result, 0, iso);
-  SET_VECTOR_ELT(result, 1, map12);
-  SET_VECTOR_ELT(result, 2, map21);
-  SET_VECTOR_ELT(result, 3, info1);
-  SET_VECTOR_ELT(result, 4, info2);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("iso"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("map12"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("map21"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("info1"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("info2"));
+  PROTECT(partition1=R_igraph_vector_to_SEXPp1(&c_partition1)); 
+  igraph_vector_destroy(&c_partition1); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(partition2=R_igraph_vector_to_SEXPp1(&c_partition2)); 
+  igraph_vector_destroy(&c_partition2); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(stats=R_igraph_maxflow_stats_to_SEXP(&c_stats));
+  SET_VECTOR_ELT(result, 0, value);
+  SET_VECTOR_ELT(result, 1, flow);
+  SET_VECTOR_ELT(result, 2, cut);
+  SET_VECTOR_ELT(result, 3, partition1);
+  SET_VECTOR_ELT(result, 4, partition2);
+  SET_VECTOR_ELT(result, 5, stats);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("value"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("flow"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("cut"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("partition1"));
+  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("partition2"));
+  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("stats"));
   SET_NAMES(result, names);
-  UNPROTECT(6);
+  UNPROTECT(7);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_automorphisms                       /
+/ igraph_dominator_tree                      /
 /-------------------------------------------*/
-SEXP R_igraph_automorphisms(SEXP graph, SEXP sh) {
+SEXP R_igraph_dominator_tree(SEXP graph, SEXP root, SEXP mode) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_bliss_sh_t c_sh;
-  igraph_bliss_info_t c_info;
-  SEXP info;
+  igraph_integer_t c_root;
+  igraph_vector_t c_dom;
+  igraph_t c_domtree;
+  igraph_vector_t c_leftout;
+  igraph_neimode_t c_mode;
+  SEXP dom;
+  SEXP domtree;
+  SEXP leftout;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_sh=REAL(sh)[0];
+  c_root=(igraph_integer_t) REAL(root)[0];
+  if (0 != igraph_vector_init(&c_dom, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_dom);
+  domtree=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_leftout, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_leftout);
+  c_mode=(igraph_neimode_t) REAL(mode)[0];
                                         /* Call igraph */
-  igraph_automorphisms(&c_graph, c_sh, &c_info);
+  igraph_dominator_tree(&c_graph, c_root, &c_dom, (isNull(domtree) ? 0 : &c_domtree), &c_leftout, c_mode);
 
                                         /* Convert output */
-  PROTECT(info=R_igraph_bliss_info_to_SEXP(&c_info)); 
-  if (c_info.group_size) { free(c_info.group_size); }
-  result=info;
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(dom=R_igraph_vector_to_SEXPp1(&c_dom)); 
+  igraph_vector_destroy(&c_dom); 
+  IGRAPH_FINALLY_CLEAN(1);
+  IGRAPH_FINALLY(igraph_destroy, &c_domtree); 
+  PROTECT(domtree=R_igraph_to_SEXP(&c_domtree));  
+  igraph_destroy(&c_domtree); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(leftout=R_igraph_vector_to_SEXPp1(&c_leftout)); 
+  igraph_vector_destroy(&c_leftout); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, dom);
+  SET_VECTOR_ELT(result, 1, domtree);
+  SET_VECTOR_ELT(result, 2, leftout);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("dom"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("domtree"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("leftout"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_scg_grouping                        /
+/ igraph_all_st_cuts                         /
 /-------------------------------------------*/
-SEXP R_igraph_scg_grouping(SEXP V, SEXP nt, SEXP nt_vec, SEXP mtype, SEXP algo, SEXP p, SEXP maxiter) {
+SEXP R_igraph_all_st_cuts(SEXP graph, SEXP source, SEXP target) {
                                         /* Declarations */
-  igraph_matrix_t c_V;
-  igraph_vector_t c_groups;
-  igraph_integer_t c_nt;
-  igraph_vector_t c_nt_vec;
-  igraph_scg_matrix_t c_mtype;
-  igraph_scg_algorithm_t c_algo;
-  igraph_vector_t c_p;
-  igraph_integer_t c_maxiter;
-  SEXP groups;
+  igraph_t c_graph;
+  igraph_vector_ptr_t c_cuts;
+  igraph_vector_ptr_t c_partition1s;
+  igraph_integer_t c_source;
+  igraph_integer_t c_target;
+  SEXP cuts;
+  SEXP partition1s;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_matrix(V, &c_V);
-  if (0 != igraph_vector_init(&c_groups, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_ptr_init(&c_cuts, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_groups);
-  c_nt=INTEGER(nt)[0];
-  if (!isNull(nt_vec)) { R_SEXP_to_vector(nt_vec, &c_nt_vec); }
-  c_mtype=(igraph_scg_matrix_t) REAL(mtype)[0];
-  c_algo=(igraph_scg_algorithm_t) REAL(algo)[0];
-  if (!isNull(p)) { R_SEXP_to_vector(p, &c_p); }
-  c_maxiter=INTEGER(maxiter)[0];
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_cuts);
+  if (0 != igraph_vector_ptr_init(&c_partition1s, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_partition1s);
+  c_source=(igraph_integer_t) REAL(source)[0];
+  c_target=(igraph_integer_t) REAL(target)[0];
                                         /* Call igraph */
-  igraph_scg_grouping(&c_V, &c_groups, c_nt, (isNull(nt_vec) ? 0 : &c_nt_vec), c_mtype, c_algo, (isNull(p) ? 0 : &c_p), c_maxiter);
+  igraph_all_st_cuts(&c_graph, &c_cuts, &c_partition1s, c_source, c_target);
 
                                         /* Convert output */
-  PROTECT(groups=R_igraph_vector_to_SEXPp1(&c_groups)); 
-  igraph_vector_destroy(&c_groups); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(cuts=R_igraph_vectorlist_to_SEXP_p1(&c_cuts)); 
+  R_igraph_vectorlist_destroy(&c_cuts); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=groups;
+  PROTECT(partition1s=R_igraph_vectorlist_to_SEXP_p1(&c_partition1s)); 
+  R_igraph_vectorlist_destroy(&c_partition1s); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, cuts);
+  SET_VECTOR_ELT(result, 1, partition1s);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("cuts"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("partition1s"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
-/*-------------------------------------------/
-/ igraph_scg_norm_eps                        /
-/-------------------------------------------*/
-SEXP R_igraph_scg_norm_eps(SEXP V, SEXP groups, SEXP mtype, SEXP p, SEXP norm) {
-                                        /* Declarations */
-  igraph_matrix_t c_V;
-  igraph_vector_t c_groups;
-  igraph_vector_t c_eps;
-  igraph_scg_matrix_t c_mtype;
-  igraph_vector_t c_p;
-  igraph_scg_norm_t c_norm;
-  SEXP eps;
+/*-------------------------------------------/
+/ igraph_all_st_mincuts                      /
+/-------------------------------------------*/
+SEXP R_igraph_all_st_mincuts(SEXP graph, SEXP source, SEXP target, SEXP capacity) {
+                                        /* Declarations */
+  igraph_t c_graph;
+  igraph_real_t c_value;
+  igraph_vector_ptr_t c_cuts;
+  igraph_vector_ptr_t c_partition1s;
+  igraph_integer_t c_source;
+  igraph_integer_t c_target;
+  igraph_vector_t c_capacity;
+  SEXP value;
+  SEXP cuts;
+  SEXP partition1s;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_matrix(V, &c_V);
-  R_SEXP_to_vector(groups, &c_groups);
-  if (0 != igraph_vector_init(&c_eps, 0)) { 
+  R_SEXP_to_igraph(graph, &c_graph);
+  if (0 != igraph_vector_ptr_init(&c_cuts, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_eps);
-  c_mtype=(igraph_scg_matrix_t) REAL(mtype)[0];
-  if (!isNull(p)) { R_SEXP_to_vector(p, &c_p); }
-  c_norm=(igraph_scg_norm_t) REAL(norm)[0];
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_cuts);
+  if (0 != igraph_vector_ptr_init(&c_partition1s, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_partition1s);
+  c_source=(igraph_integer_t) REAL(source)[0];
+  c_target=(igraph_integer_t) REAL(target)[0];
+  if (!isNull(capacity)) { R_SEXP_to_vector(capacity, &c_capacity); }
                                         /* Call igraph */
-  igraph_scg_norm_eps(&c_V, &c_groups, &c_eps, c_mtype, (isNull(p) ? 0 : &c_p), c_norm);
+  igraph_all_st_mincuts(&c_graph, &c_value, &c_cuts, &c_partition1s, c_source, c_target, (isNull(capacity) ? 0 : &c_capacity));
 
                                         /* Convert output */
-  PROTECT(eps=R_igraph_vector_to_SEXP(&c_eps)); 
-  igraph_vector_destroy(&c_eps); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(value=NEW_NUMERIC(1)); 
+  REAL(value)[0]=c_value;
+  PROTECT(cuts=R_igraph_vectorlist_to_SEXP_p1(&c_cuts)); 
+  R_igraph_vectorlist_destroy(&c_cuts); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=eps;
+  PROTECT(partition1s=R_igraph_vectorlist_to_SEXP_p1(&c_partition1s)); 
+  R_igraph_vectorlist_destroy(&c_partition1s); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, value);
+  SET_VECTOR_ELT(result, 1, cuts);
+  SET_VECTOR_ELT(result, 2, partition1s);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("value"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cuts"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("partition1s"));
+  SET_NAMES(result, names);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_is_matching                         /
+/ igraph_is_separator                        /
 /-------------------------------------------*/
-SEXP R_igraph_is_matching(SEXP graph, SEXP types, SEXP matching) {
+SEXP R_igraph_is_separator(SEXP graph, SEXP candidate) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_vector_long_t c_matching;
+  igraph_vs_t c_candidate;
   igraph_bool_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
-  R_SEXP_to_vector_long_copy(matching, &c_matching);
+  R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate);
                                         /* Call igraph */
-  igraph_is_matching(&c_graph, (isNull(types) ? 0 : &c_types), &c_matching, &c_res);
+  igraph_is_separator(&c_graph, c_candidate, &c_res);
 
                                         /* Convert output */
-  igraph_vector_long_destroy(&c_matching);
+  igraph_vs_destroy(&c_candidate);
   PROTECT(res=NEW_LOGICAL(1)); 
   LOGICAL(res)[0]=c_res;
   result=res;
@@ -15486,26 +14194,24 @@ SEXP R_igraph_is_matching(SEXP graph, SEXP types, SEXP matching) {
 }
 
 /*-------------------------------------------/
-/ igraph_is_maximal_matching                 /
+/ igraph_is_minimal_separator                /
 /-------------------------------------------*/
-SEXP R_igraph_is_maximal_matching(SEXP graph, SEXP types, SEXP matching) {
+SEXP R_igraph_is_minimal_separator(SEXP graph, SEXP candidate) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_vector_long_t c_matching;
+  igraph_vs_t c_candidate;
   igraph_bool_t c_res;
   SEXP res;
 
   SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
-  R_SEXP_to_vector_long_copy(matching, &c_matching);
+  R_SEXP_to_igraph_vs(candidate, &c_graph, &c_candidate);
                                         /* Call igraph */
-  igraph_is_maximal_matching(&c_graph, (isNull(types) ? 0 : &c_types), &c_matching, &c_res);
+  igraph_is_minimal_separator(&c_graph, c_candidate, &c_res);
 
                                         /* Convert output */
-  igraph_vector_long_destroy(&c_matching);
+  igraph_vs_destroy(&c_candidate);
   PROTECT(res=NEW_LOGICAL(1)); 
   LOGICAL(res)[0]=c_res;
   result=res;
@@ -15515,341 +14221,228 @@ SEXP R_igraph_is_maximal_matching(SEXP graph, SEXP types, SEXP matching) {
 }
 
 /*-------------------------------------------/
-/ igraph_maximum_bipartite_matching          /
+/ igraph_all_minimal_st_separators           /
 /-------------------------------------------*/
-SEXP R_igraph_maximum_bipartite_matching(SEXP graph, SEXP types, SEXP weights, SEXP eps) {
+SEXP R_igraph_all_minimal_st_separators(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_bool_t c_types;
-  igraph_integer_t c_matching_size;
-  igraph_real_t c_matching_weight;
-  igraph_vector_long_t c_matching;
-  igraph_vector_t c_weights;
-  igraph_real_t c_eps;
-  SEXP matching_size;
-  SEXP matching_weight;
-  SEXP matching;
+  igraph_vector_ptr_t c_separators;
+  SEXP separators;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
-  if (0 != igraph_vector_long_init(&c_matching, 0)) { 
+  if (0 != igraph_vector_ptr_init(&c_separators, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_long_destroy, &c_matching);
-  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
-  c_eps=REAL(eps)[0];
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_separators);
                                         /* Call igraph */
-  igraph_maximum_bipartite_matching(&c_graph, (isNull(types) ? 0 : &c_types), &c_matching_size, &c_matching_weight, &c_matching, (isNull(weights) ? 0 : &c_weights), c_eps);
+  igraph_all_minimal_st_separators(&c_graph, &c_separators);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(matching_size=NEW_INTEGER(1)); 
-  INTEGER(matching_size)[0]=c_matching_size;
-  PROTECT(matching_weight=NEW_NUMERIC(1)); 
-  REAL(matching_weight)[0]=c_matching_weight;
-  PROTECT(matching=R_igraph_vector_long_to_SEXPp1(&c_matching)); 
-  igraph_vector_long_destroy(&c_matching); 
+  PROTECT(separators=R_igraph_vectorlist_to_SEXP_p1(&c_separators)); 
+  R_igraph_vectorlist_destroy(&c_separators); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, matching_size);
-  SET_VECTOR_ELT(result, 1, matching_weight);
-  SET_VECTOR_ELT(result, 2, matching);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("matching_size"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("matching_weight"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("matching"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=separators;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_eigen_adjacency                     /
+/ igraph_minimum_size_separators             /
 /-------------------------------------------*/
-SEXP R_igraph_eigen_adjacency(SEXP graph, SEXP algorithm, SEXP which, SEXP options) {
+SEXP R_igraph_minimum_size_separators(SEXP graph) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_algorithm;
-  igraph_eigen_which_t c_which;
-  igraph_arpack_options_t c_options;
-
-  igraph_vector_t c_values;
-  igraph_matrix_t c_vectors;
-
-
-  SEXP values;
-  SEXP vectors;
+  igraph_vector_ptr_t c_separators;
+  SEXP separators;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_algorithm=REAL(algorithm)[0];
-  R_SEXP_to_igraph_eigen_which(which, &c_which);
-  R_SEXP_to_igraph_arpack_options(options, &c_options);
-  if (0 != igraph_vector_init(&c_values, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_values);
-  if (0 != igraph_matrix_init(&c_vectors, 0, 0)) { 
+  if (0 != igraph_vector_ptr_init(&c_separators, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_vectors);
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_separators);
                                         /* Call igraph */
-  igraph_eigen_adjacency(&c_graph, c_algorithm, &c_which, &c_options, 0, &c_values, &c_vectors, 0, 0);
+  igraph_minimum_size_separators(&c_graph, &c_separators);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
-  PROTECT(values=R_igraph_vector_to_SEXP(&c_values)); 
-  igraph_vector_destroy(&c_values); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(vectors=R_igraph_matrix_to_SEXP(&c_vectors)); 
-  igraph_matrix_destroy(&c_vectors); 
+  PROTECT(separators=R_igraph_vectorlist_to_SEXP_p1(&c_separators)); 
+  R_igraph_vectorlist_destroy(&c_separators); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, options);
-  SET_VECTOR_ELT(result, 1, values);
-  SET_VECTOR_ELT(result, 2, vectors);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("options"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("values"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("vectors"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=separators;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_power_law_fit                       /
+/ igraph_isoclass                            /
 /-------------------------------------------*/
-SEXP R_igraph_power_law_fit(SEXP data, SEXP xmin, SEXP force_continuous) {
+SEXP R_igraph_isoclass(SEXP graph) {
                                         /* Declarations */
-  igraph_vector_t c_data;
-  igraph_plfit_result_t c_res;
-  igraph_real_t c_xmin;
-  igraph_bool_t c_force_continuous;
-  SEXP res;
+  igraph_t c_graph;
+  igraph_integer_t c_isoclass;
+  SEXP isoclass;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_vector(data, &c_data);
-  c_xmin=REAL(xmin)[0];
-  c_force_continuous=LOGICAL(force_continuous)[0];
+  R_SEXP_to_igraph(graph, &c_graph);
                                         /* Call igraph */
-  igraph_power_law_fit(&c_data, &c_res, c_xmin, c_force_continuous);
+  igraph_isoclass(&c_graph, &c_isoclass);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_plfit_result_to_SEXP(&c_res));
-  result=res;
+  PROTECT(isoclass=NEW_INTEGER(1)); 
+  INTEGER(isoclass)[0]=c_isoclass;
+  result=isoclass;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_sir                                 /
+/ igraph_isomorphic                          /
 /-------------------------------------------*/
-SEXP R_igraph_sir(SEXP graph, SEXP beta, SEXP gamma, SEXP no_sim) {
+SEXP R_igraph_isomorphic(SEXP graph1, SEXP graph2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_real_t c_beta;
-  igraph_real_t c_gamma;
-  igraph_integer_t c_no_sim;
-  igraph_vector_ptr_t c_res;
-  SEXP res;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_bool_t c_iso;
+  SEXP iso;
 
   SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_beta=REAL(beta)[0];
-  c_gamma=REAL(gamma)[0];
-  c_no_sim=INTEGER(no_sim)[0];
-  if (0 != igraph_vector_ptr_init(&c_res, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(R_igraph_sirlist_destroy, &c_res);
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
                                         /* Call igraph */
-  igraph_sir(&c_graph, c_beta, c_gamma, c_no_sim, &c_res);
+  igraph_isomorphic(&c_graph1, &c_graph2, &c_iso);
 
                                         /* Convert output */
-  PROTECT(res=R_igraph_sirlist_to_SEXP(&c_res)); 
-  R_igraph_sirlist_destroy(&c_res); 
-  IGRAPH_FINALLY_CLEAN(1);
-  result=res;
+  PROTECT(iso=NEW_LOGICAL(1)); 
+  LOGICAL(iso)[0]=c_iso;
+  result=iso;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_convex_hull                         /
+/ igraph_isoclass_subgraph                   /
 /-------------------------------------------*/
-SEXP R_igraph_convex_hull(SEXP data) {
+SEXP R_igraph_isoclass_subgraph(SEXP graph, SEXP vids) {
                                         /* Declarations */
-  igraph_matrix_t c_data;
-  igraph_vector_t c_resverts;
-  igraph_matrix_t c_rescoords;
-  SEXP resverts;
-  SEXP rescoords;
-
-  SEXP result, names;
-                                        /* Convert input */
-  R_SEXP_to_matrix(data, &c_data);
-  if (0 != igraph_vector_init(&c_resverts, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_resverts);
-  if (0 != igraph_matrix_init(&c_rescoords, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_rescoords);
+  igraph_t c_graph;
+  igraph_vector_t c_vids;
+  igraph_integer_t c_isoclass;
+  SEXP isoclass;
+
+  SEXP result;
+                                        /* Convert input */
+  R_SEXP_to_igraph(graph, &c_graph);
+  R_SEXP_to_vector(vids, &c_vids);
                                         /* Call igraph */
-  igraph_convex_hull(&c_data, &c_resverts, &c_rescoords);
+  igraph_isoclass_subgraph(&c_graph, &c_vids, &c_isoclass);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(resverts=R_igraph_vector_to_SEXP(&c_resverts)); 
-  igraph_vector_destroy(&c_resverts); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(rescoords=R_igraph_matrix_to_SEXP(&c_rescoords)); 
-  igraph_matrix_destroy(&c_rescoords); 
-  IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, resverts);
-  SET_VECTOR_ELT(result, 1, rescoords);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("resverts"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("rescoords"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  PROTECT(isoclass=NEW_INTEGER(1)); 
+  INTEGER(isoclass)[0]=c_isoclass;
+  result=isoclass;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_d                       /
+/ igraph_isoclass_create                     /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_d(SEXP graph, SEXP niter, SEXP delta, SEXP filter) {
+SEXP R_igraph_isoclass_create(SEXP size, SEXP number, SEXP directed) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_vector_t c_kernel;
-  igraph_vector_t c_cites;
-  igraph_real_t c_delta;
-  igraph_vector_t c_filter;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_integer_t c_size;
+  igraph_integer_t c_number;
+  igraph_bool_t c_directed;
+  SEXP graph;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_vector_init(&c_kernel, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_kernel);
-  if (0 != igraph_vector_init(&c_cites, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_delta=REAL(delta)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  c_size=INTEGER(size)[0];
+  c_number=INTEGER(number)[0];
+  c_directed=LOGICAL(directed)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_d(&c_graph, c_niter, &c_kernel, (isNull(cites) ? 0 : &c_cites), c_delta, (isNull(filter) ? 0 : &c_filter), &c_logprob, &c_logmax);
+  igraph_isoclass_create(&c_graph, c_size, c_number, c_directed);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_vector_to_SEXP(&c_kernel)); 
-  igraph_vector_destroy(&c_kernel); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0orvector_to_SEXP(&c_cites)); 
-  igraph_vector_destroy(&c_cites); 
+  IGRAPH_FINALLY(igraph_destroy, &c_graph); 
+  PROTECT(graph=R_igraph_to_SEXP(&c_graph));  
+  igraph_destroy(&c_graph); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
+  result=graph;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_probs_d                    /
+/ igraph_isomorphic_vf2                      /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_probs_d(SEXP graph, SEXP kernel, SEXP ntk) {
+SEXP R_igraph_isomorphic_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_t c_kernel;
-  igraph_vector_t c_probs;
-  igraph_vector_t c_citedprobs;
-  igraph_vector_t c_citingprobs;
-  igraph_bool_t c_ntk;
-  SEXP probs;
-  SEXP citedprobs;
-  SEXP citingprobs;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_vector_int_t c_vertex_color1;
+  igraph_vector_int_t c_vertex_color2;
+  igraph_vector_int_t c_edge_color1;
+  igraph_vector_int_t c_edge_color2;
+  igraph_bool_t c_iso;
+  igraph_vector_t c_map12;
+  igraph_vector_t c_map21;
+
+
+
+  SEXP iso;
+  SEXP map12;
+  SEXP map21;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(kernel, &c_kernel);
-  if (0 != igraph_vector_init(&c_probs, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_probs); 
-  probs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_citedprobs, 0)) { 
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
+  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
+  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
+  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
+  if (0 != igraph_vector_init(&c_map12, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_citedprobs); 
-  citedprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_citingprobs, 0)) { 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_map12); 
+  map12=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_map21, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_citingprobs); 
-  citingprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_ntk=LOGICAL(ntk)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_map21); 
+  map21=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_revolver_probs_d(&c_graph, &c_kernel, (isNull(probs) ? 0 : &c_probs), (isNull(citedprobs) ? 0 : &c_citedprobs), (isNull(citingprobs) ? 0 : &c_citingprobs), c_ntk);
+  igraph_isomorphic_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_iso, (isNull(map12) ? 0 : &c_map12), (isNull(map21) ? 0 : &c_map21), 0, 0, 0);
 
                                         /* Convert output */
   PROTECT(result=NEW_LIST(3));
   PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(probs=R_igraph_0orvector_to_SEXP(&c_probs)); 
-  igraph_vector_destroy(&c_probs); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(citedprobs=R_igraph_0orvector_to_SEXP(&c_citedprobs)); 
-  igraph_vector_destroy(&c_citedprobs); 
+  PROTECT(iso=NEW_LOGICAL(1)); 
+  LOGICAL(iso)[0]=c_iso;
+  PROTECT(map12=R_igraph_0orvector_to_SEXPp1(&c_map12)); 
+  igraph_vector_destroy(&c_map12); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(citingprobs=R_igraph_0orvector_to_SEXP(&c_citingprobs)); 
-  igraph_vector_destroy(&c_citingprobs); 
+  PROTECT(map21=R_igraph_0orvector_to_SEXPp1(&c_map21)); 
+  igraph_vector_destroy(&c_map21); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, probs);
-  SET_VECTOR_ELT(result, 1, citedprobs);
-  SET_VECTOR_ELT(result, 2, citingprobs);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("probs"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("citedprobs"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("citingprobs"));
+  SET_VECTOR_ELT(result, 0, iso);
+  SET_VECTOR_ELT(result, 1, map12);
+  SET_VECTOR_ELT(result, 2, map21);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("iso"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("map12"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("map21"));
   SET_NAMES(result, names);
   UNPROTECT(4);
 
@@ -15858,1306 +14451,793 @@ SEXP R_igraph_revolver_probs_d(SEXP graph, SEXP kernel, SEXP ntk) {
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_de                      /
+/ igraph_count_isomorphisms_vf2              /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_de(SEXP graph, SEXP niter, SEXP cats, SEXP delta, SEXP filter) {
+SEXP R_igraph_count_isomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_matrix_t c_kernel;
-  igraph_vector_t c_cats;
-  igraph_matrix_t c_cites;
-  igraph_real_t c_delta;
-  igraph_vector_t c_filter;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_vector_int_t c_vertex_color1;
+  igraph_vector_int_t c_vertex_color2;
+  igraph_vector_int_t c_edge_color1;
+  igraph_vector_int_t c_edge_color2;
+  igraph_integer_t c_count;
 
-  SEXP result, names;
+
+
+  SEXP count;
+
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_matrix_init(&c_kernel, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_kernel);
-  R_SEXP_to_vector(cats, &c_cats);
-  if (0 != igraph_matrix_init(&c_cites, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_delta=REAL(delta)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
+  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
+  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
+  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
                                         /* Call igraph */
-  igraph_revolver_ml_de(&c_graph, c_niter, &c_kernel, &c_cats, (isNull(cites) ? 0 : &c_cites), c_delta, (isNull(filter) ? 0 : &c_filter), &c_logprob, &c_logmax);
+  igraph_count_isomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_count, 0, 0, 0);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_matrix_to_SEXP(&c_kernel)); 
-  igraph_matrix_destroy(&c_kernel); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0ormatrix_to_SEXP(&c_cites)); 
-  igraph_matrix_destroy(&c_cites); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
+  PROTECT(count=NEW_INTEGER(1)); 
+  INTEGER(count)[0]=c_count;
+  result=count;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_probs_de                   /
+/ igraph_get_isomorphisms_vf2                /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_probs_de(SEXP graph, SEXP kernel, SEXP cats) {
+SEXP R_igraph_get_isomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_matrix_t c_kernel;
-  igraph_vector_t c_cats;
-  igraph_vector_t c_logprobs;
-  igraph_vector_t c_logcited;
-  igraph_vector_t c_logciting;
-  SEXP logprobs;
-  SEXP logcited;
-  SEXP logciting;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_vector_int_t c_vertex_color1;
+  igraph_vector_int_t c_vertex_color2;
+  igraph_vector_int_t c_edge_color1;
+  igraph_vector_int_t c_edge_color2;
+  igraph_vector_ptr_t c_maps;
 
-  SEXP result, names;
+
+
+  SEXP maps;
+
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_matrix(kernel, &c_kernel);
-  R_SEXP_to_vector(cats, &c_cats);
-  if (0 != igraph_vector_init(&c_logprobs, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logprobs); 
-  logprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_logcited, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logcited); 
-  logcited=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_logciting, 0)) { 
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
+  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
+  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
+  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
+  if (0 != igraph_vector_ptr_init(&c_maps, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logciting); 
-  logciting=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_maps);
                                         /* Call igraph */
-  igraph_revolver_probs_de(&c_graph, &c_kernel, &c_cats, (isNull(logprobs) ? 0 : &c_logprobs), (isNull(logcited) ? 0 : &c_logcited), (isNull(logciting) ? 0 : &c_logciting));
+  igraph_get_isomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_maps, 0, 0, 0);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(logprobs=R_igraph_0orvector_to_SEXP(&c_logprobs)); 
-  igraph_vector_destroy(&c_logprobs); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logcited=R_igraph_0orvector_to_SEXP(&c_logcited)); 
-  igraph_vector_destroy(&c_logcited); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logciting=R_igraph_0orvector_to_SEXP(&c_logciting)); 
-  igraph_vector_destroy(&c_logciting); 
+  PROTECT(maps=R_igraph_vectorlist_to_SEXP(&c_maps)); 
+  R_igraph_vectorlist_destroy(&c_maps); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, logprobs);
-  SET_VECTOR_ELT(result, 1, logcited);
-  SET_VECTOR_ELT(result, 2, logciting);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("logprobs"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("logcited"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logciting"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  result=maps;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_ade                     /
+/ igraph_subisomorphic_vf2                   /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_ade(SEXP graph, SEXP niter, SEXP cats, SEXP agebins, SEXP delta, SEXP filter) {
+SEXP R_igraph_subisomorphic_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_array3_t c_kernel;
-  igraph_vector_t c_cats;
-  igraph_array3_t c_cites;
-  igraph_integer_t c_agebins;
-  igraph_real_t c_delta;
-  igraph_vector_t c_filter;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_vector_int_t c_vertex_color1;
+  igraph_vector_int_t c_vertex_color2;
+  igraph_vector_int_t c_edge_color1;
+  igraph_vector_int_t c_edge_color2;
+  igraph_bool_t c_iso;
+  igraph_vector_t c_map12;
+  igraph_vector_t c_map21;
+
+
+
+  SEXP iso;
+  SEXP map12;
+  SEXP map21;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_array3_init(&c_kernel, 0, 0, 0)) { 
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
+  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
+  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
+  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
+  if (0 != igraph_vector_init(&c_map12, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_array3_destroy, &c_kernel);
-  R_SEXP_to_vector(cats, &c_cats);
-  if (0 != igraph_array3_init(&c_cites, 0, 0, 0)) { 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_map12); 
+  map12=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_map21, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_array3_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_agebins=INTEGER(agebins)[0];
-  c_delta=REAL(delta)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_map21); 
+  map21=NEW_NUMERIC(0); /* hack to have a non-NULL value */
                                         /* Call igraph */
-  igraph_revolver_ml_ade(&c_graph, c_niter, &c_kernel, &c_cats, (isNull(cites) ? 0 : &c_cites), c_agebins, c_delta, (isNull(filter) ? 0 : &c_filter), &c_logprob, &c_logmax);
+  igraph_subisomorphic_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_iso, (isNull(map12) ? 0 : &c_map12), (isNull(map21) ? 0 : &c_map21), 0, 0, 0);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_array3_to_SEXP(&c_kernel)); 
-  igraph_array3_destroy(&c_kernel); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(iso=NEW_LOGICAL(1)); 
+  LOGICAL(iso)[0]=c_iso;
+  PROTECT(map12=R_igraph_0orvector_to_SEXPp1(&c_map12)); 
+  igraph_vector_destroy(&c_map12); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0orarray3_to_SEXP(&c_cites)); 
-  igraph_array3_destroy(&c_cites); 
+  PROTECT(map21=R_igraph_0orvector_to_SEXPp1(&c_map21)); 
+  igraph_vector_destroy(&c_map21); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
+  SET_VECTOR_ELT(result, 0, iso);
+  SET_VECTOR_ELT(result, 1, map12);
+  SET_VECTOR_ELT(result, 2, map21);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("iso"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("map12"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("map21"));
   SET_NAMES(result, names);
-  UNPROTECT(5);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_probs_ade                  /
+/ igraph_count_subisomorphisms_vf2           /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_probs_ade(SEXP graph, SEXP kernel, SEXP cats) {
+SEXP R_igraph_count_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_array3_t c_kernel;
-  igraph_vector_t c_cats;
-  igraph_vector_t c_logprobs;
-  igraph_vector_t c_logcited;
-  igraph_vector_t c_logciting;
-  SEXP logprobs;
-  SEXP logcited;
-  SEXP logciting;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_vector_int_t c_vertex_color1;
+  igraph_vector_int_t c_vertex_color2;
+  igraph_vector_int_t c_edge_color1;
+  igraph_vector_int_t c_edge_color2;
+  igraph_integer_t c_count;
 
-  SEXP result, names;
-                                        /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_igraph_SEXP_to_array3(kernel, &c_kernel);
-  R_SEXP_to_vector(cats, &c_cats);
-  if (0 != igraph_vector_init(&c_logprobs, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logprobs); 
-  logprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_logcited, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logcited); 
-  logcited=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_logciting, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logciting); 
-  logciting=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+
+
+  SEXP count;
+
+  SEXP result;
+                                        /* Convert input */
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
+  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
+  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
+  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
                                         /* Call igraph */
-  igraph_revolver_probs_ade(&c_graph, &c_kernel, &c_cats, (isNull(logprobs) ? 0 : &c_logprobs), (isNull(logcited) ? 0 : &c_logcited), (isNull(logciting) ? 0 : &c_logciting));
+  igraph_count_subisomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_count, 0, 0, 0);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(logprobs=R_igraph_0orvector_to_SEXP(&c_logprobs)); 
-  igraph_vector_destroy(&c_logprobs); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logcited=R_igraph_0orvector_to_SEXP(&c_logcited)); 
-  igraph_vector_destroy(&c_logcited); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logciting=R_igraph_0orvector_to_SEXP(&c_logciting)); 
-  igraph_vector_destroy(&c_logciting); 
-  IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, logprobs);
-  SET_VECTOR_ELT(result, 1, logcited);
-  SET_VECTOR_ELT(result, 2, logciting);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("logprobs"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("logcited"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logciting"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  PROTECT(count=NEW_INTEGER(1)); 
+  INTEGER(count)[0]=c_count;
+  result=count;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_f                       /
+/ igraph_get_subisomorphisms_vf2             /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_f(SEXP graph, SEXP niter, SEXP delta) {
+SEXP R_igraph_get_subisomorphisms_vf2(SEXP graph1, SEXP graph2, SEXP vertex_color1, SEXP vertex_color2, SEXP edge_color1, SEXP edge_color2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_vector_t c_kernel;
-  igraph_vector_t c_cites;
-  igraph_real_t c_delta;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_vector_int_t c_vertex_color1;
+  igraph_vector_int_t c_vertex_color2;
+  igraph_vector_int_t c_edge_color1;
+  igraph_vector_int_t c_edge_color2;
+  igraph_vector_ptr_t c_maps;
 
-  SEXP result, names;
+
+
+  SEXP maps;
+
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_vector_init(&c_kernel, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_kernel);
-  if (0 != igraph_vector_init(&c_cites, 0)) { 
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (!isNull(vertex_color1)) { R_SEXP_to_vector_int(vertex_color1, &c_vertex_color1); }
+  if (!isNull(vertex_color2)) { R_SEXP_to_vector_int(vertex_color2, &c_vertex_color2); }
+  if (!isNull(edge_color1)) { R_SEXP_to_vector_int(edge_color1, &c_edge_color1); }
+  if (!isNull(edge_color2)) { R_SEXP_to_vector_int(edge_color2, &c_edge_color2); }
+  if (0 != igraph_vector_ptr_init(&c_maps, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_delta=REAL(delta)[0];
+  IGRAPH_FINALLY(R_igraph_vectorlist_destroy, &c_maps);
                                         /* Call igraph */
-  igraph_revolver_ml_f(&c_graph, c_niter, &c_kernel, (isNull(cites) ? 0 : &c_cites), c_delta, &c_logprob, &c_logmax);
+  igraph_get_subisomorphisms_vf2(&c_graph1, &c_graph2, (isNull(vertex_color1) ? 0 : &c_vertex_color1), (isNull(vertex_color2) ? 0 : &c_vertex_color2), (isNull(edge_color1) ? 0 : &c_edge_color1), (isNull(edge_color2) ? 0 : &c_edge_color2), &c_maps, 0, 0, 0);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_vector_to_SEXP(&c_kernel)); 
-  igraph_vector_destroy(&c_kernel); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0orvector_to_SEXP(&c_cites)); 
-  igraph_vector_destroy(&c_cites); 
+  PROTECT(maps=R_igraph_vectorlist_to_SEXP(&c_maps)); 
+  R_igraph_vectorlist_destroy(&c_maps); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
+  result=maps;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_df                      /
+/ igraph_isomorphic_34                       /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_df(SEXP graph, SEXP niter, SEXP delta) {
+SEXP R_igraph_isomorphic_34(SEXP graph1, SEXP graph2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_matrix_t c_kernel;
-  igraph_matrix_t c_cites;
-  igraph_real_t c_delta;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_bool_t c_iso;
+  SEXP iso;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_matrix_init(&c_kernel, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_kernel);
-  if (0 != igraph_matrix_init(&c_cites, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_delta=REAL(delta)[0];
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
                                         /* Call igraph */
-  igraph_revolver_ml_df(&c_graph, c_niter, &c_kernel, (isNull(cites) ? 0 : &c_cites), c_delta, &c_logprob, &c_logmax);
+  igraph_isomorphic_34(&c_graph1, &c_graph2, &c_iso);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_matrix_to_SEXP(&c_kernel)); 
-  igraph_matrix_destroy(&c_kernel); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0ormatrix_to_SEXP(&c_cites)); 
-  igraph_matrix_destroy(&c_cites); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
+  PROTECT(iso=NEW_LOGICAL(1)); 
+  LOGICAL(iso)[0]=c_iso;
+  result=iso;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_l                       /
+/ igraph_canonical_permutation               /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_l(SEXP graph, SEXP niter, SEXP agebins, SEXP delta) {
+SEXP R_igraph_canonical_permutation(SEXP graph, SEXP sh) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_vector_t c_kernel;
-  igraph_vector_t c_cites;
-  igraph_integer_t c_agebins;
-  igraph_real_t c_delta;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_vector_t c_labeling;
+  igraph_bliss_sh_t c_sh;
+  igraph_bliss_info_t c_info;
+  SEXP labeling;
+  SEXP info;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_vector_init(&c_kernel, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_kernel);
-  if (0 != igraph_vector_init(&c_cites, 0)) { 
+  if (0 != igraph_vector_init(&c_labeling, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_agebins=INTEGER(agebins)[0];
-  c_delta=REAL(delta)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_labeling);
+  c_sh=REAL(sh)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_l(&c_graph, c_niter, &c_kernel, (isNull(cites) ? 0 : &c_cites), c_agebins, c_delta, &c_logprob, &c_logmax);
+  igraph_canonical_permutation(&c_graph, &c_labeling, c_sh, &c_info);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_vector_to_SEXP(&c_kernel)); 
-  igraph_vector_destroy(&c_kernel); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0orvector_to_SEXP(&c_cites)); 
-  igraph_vector_destroy(&c_cites); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(labeling=R_igraph_vector_to_SEXPp1(&c_labeling)); 
+  igraph_vector_destroy(&c_labeling); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
+  PROTECT(info=R_igraph_bliss_info_to_SEXP(&c_info)); 
+  if (c_info.group_size) { free(c_info.group_size); }
+  SET_VECTOR_ELT(result, 0, labeling);
+  SET_VECTOR_ELT(result, 1, info);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("labeling"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("info"));
   SET_NAMES(result, names);
-  UNPROTECT(5);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_ad                      /
+/ igraph_permute_vertices                    /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_ad(SEXP graph, SEXP niter, SEXP agebins, SEXP delta, SEXP filter) {
+SEXP R_igraph_permute_vertices(SEXP graph, SEXP permutation) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_integer_t c_niter;
-  igraph_matrix_t c_kernel;
-  igraph_matrix_t c_cites;
-  igraph_integer_t c_agebins;
-  igraph_real_t c_delta;
-  igraph_vector_t c_filter;
-  igraph_real_t c_logprob;
-  igraph_real_t c_logmax;
-  SEXP kernel;
-  SEXP cites;
-  SEXP logprob;
-  SEXP logmax;
+  igraph_t c_res;
+  igraph_vector_t c_permutation;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_niter=INTEGER(niter)[0];
-  if (0 != igraph_matrix_init(&c_kernel, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_kernel);
-  if (0 != igraph_matrix_init(&c_cites, 0, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_matrix_destroy, &c_cites); 
-  cites=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_agebins=INTEGER(agebins)[0];
-  c_delta=REAL(delta)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  R_SEXP_to_vector(permutation, &c_permutation);
                                         /* Call igraph */
-  igraph_revolver_ml_ad(&c_graph, c_niter, &c_kernel, (isNull(cites) ? 0 : &c_cites), c_agebins, c_delta, (isNull(filter) ? 0 : &c_filter), &c_logprob, &c_logmax);
+  igraph_permute_vertices(&c_graph, &c_res, &c_permutation);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(kernel=R_igraph_matrix_to_SEXP(&c_kernel)); 
-  igraph_matrix_destroy(&c_kernel); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(cites=R_igraph_0ormatrix_to_SEXP(&c_cites)); 
-  igraph_matrix_destroy(&c_cites); 
+  IGRAPH_FINALLY(igraph_destroy, &c_res); 
+  PROTECT(res=R_igraph_to_SEXP(&c_res));  
+  igraph_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logprob=NEW_NUMERIC(1)); 
-  REAL(logprob)[0]=c_logprob;
-  PROTECT(logmax=NEW_NUMERIC(1)); 
-  REAL(logmax)[0]=c_logmax;
-  SET_VECTOR_ELT(result, 0, kernel);
-  SET_VECTOR_ELT(result, 1, cites);
-  SET_VECTOR_ELT(result, 2, logprob);
-  SET_VECTOR_ELT(result, 3, logmax);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("kernel"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("cites"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logprob"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("logmax"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_probs_ad                   /
+/ igraph_isomorphic_bliss                    /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_probs_ad(SEXP graph, SEXP kernel, SEXP ntk) {
+SEXP R_igraph_isomorphic_bliss(SEXP graph1, SEXP graph2, SEXP sh1, SEXP sh2) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_matrix_t c_kernel;
-  igraph_vector_t c_probs;
-  igraph_vector_t c_citedprobs;
-  igraph_vector_t c_citingprobs;
-  igraph_bool_t c_ntk;
-  SEXP probs;
-  SEXP citedprobs;
-  SEXP citingprobs;
+  igraph_t c_graph1;
+  igraph_t c_graph2;
+  igraph_bool_t c_iso;
+  igraph_vector_t c_map12;
+  igraph_vector_t c_map21;
+  igraph_bliss_sh_t c_sh1;
+  igraph_bliss_sh_t c_sh2;
+  igraph_bliss_info_t c_info1;
+  igraph_bliss_info_t c_info2;
+  SEXP iso;
+  SEXP map12;
+  SEXP map21;
+  SEXP info1;
+  SEXP info2;
 
   SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_matrix(kernel, &c_kernel);
-  if (0 != igraph_vector_init(&c_probs, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_probs); 
-  probs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_citedprobs, 0)) { 
+  R_SEXP_to_igraph(graph1, &c_graph1);
+  R_SEXP_to_igraph(graph2, &c_graph2);
+  if (0 != igraph_vector_init(&c_map12, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_citedprobs); 
-  citedprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_citingprobs, 0)) { 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_map12); 
+  map12=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  if (0 != igraph_vector_init(&c_map21, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_citingprobs); 
-  citingprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  c_ntk=LOGICAL(ntk)[0];
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_map21); 
+  map21=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  c_sh1=REAL(sh1)[0];
+  c_sh2=REAL(sh2)[0];
                                         /* Call igraph */
-  igraph_revolver_probs_ad(&c_graph, &c_kernel, (isNull(probs) ? 0 : &c_probs), (isNull(citedprobs) ? 0 : &c_citedprobs), (isNull(citingprobs) ? 0 : &c_citingprobs), c_ntk);
+  igraph_isomorphic_bliss(&c_graph1, &c_graph2, &c_iso, (isNull(map12) ? 0 : &c_map12), (isNull(map21) ? 0 : &c_map21), c_sh1, c_sh2, &c_info1, &c_info2);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(probs=R_igraph_0orvector_to_SEXP(&c_probs)); 
-  igraph_vector_destroy(&c_probs); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(citedprobs=R_igraph_0orvector_to_SEXP(&c_citedprobs)); 
-  igraph_vector_destroy(&c_citedprobs); 
+  PROTECT(result=NEW_LIST(5));
+  PROTECT(names=NEW_CHARACTER(5));
+  PROTECT(iso=NEW_LOGICAL(1)); 
+  LOGICAL(iso)[0]=c_iso;
+  PROTECT(map12=R_igraph_0orvector_to_SEXPp1(&c_map12)); 
+  igraph_vector_destroy(&c_map12); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(citingprobs=R_igraph_0orvector_to_SEXP(&c_citingprobs)); 
-  igraph_vector_destroy(&c_citingprobs); 
+  PROTECT(map21=R_igraph_0orvector_to_SEXPp1(&c_map21)); 
+  igraph_vector_destroy(&c_map21); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, probs);
-  SET_VECTOR_ELT(result, 1, citedprobs);
-  SET_VECTOR_ELT(result, 2, citingprobs);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("probs"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("citedprobs"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("citingprobs"));
+  PROTECT(info1=R_igraph_bliss_info_to_SEXP(&c_info1)); 
+  if (c_info1.group_size) { free(c_info1.group_size); }
+  PROTECT(info2=R_igraph_bliss_info_to_SEXP(&c_info2)); 
+  if (c_info2.group_size) { free(c_info2.group_size); }
+  SET_VECTOR_ELT(result, 0, iso);
+  SET_VECTOR_ELT(result, 1, map12);
+  SET_VECTOR_ELT(result, 2, map21);
+  SET_VECTOR_ELT(result, 3, info1);
+  SET_VECTOR_ELT(result, 4, info2);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("iso"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("map12"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("map21"));
+  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("info1"));
+  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("info2"));
   SET_NAMES(result, names);
-  UNPROTECT(4);
+  UNPROTECT(6);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_D_alpha                 /
+/ igraph_automorphisms                       /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_D_alpha(SEXP graph, SEXP alpha, SEXP abstol, SEXP reltol, SEXP maxit, SEXP filter) {
+SEXP R_igraph_automorphisms(SEXP graph, SEXP sh) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_alpha;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_bliss_sh_t c_sh;
+  igraph_bliss_info_t c_info;
+  SEXP info;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_alpha=REAL(alpha)[0];
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  c_sh=REAL(sh)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_D_alpha(&c_graph, &c_alpha, &c_Fmin, c_abstol, c_reltol, c_maxit, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_automorphisms(&c_graph, c_sh, &c_info);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(4));
-  PROTECT(names=NEW_CHARACTER(4));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, Fmin);
-  SET_VECTOR_ELT(result, 2, fncount);
-  SET_VECTOR_ELT(result, 3, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("grcount"));
-  SET_NAMES(result, names);
-  UNPROTECT(5);
+  PROTECT(info=R_igraph_bliss_info_to_SEXP(&c_info)); 
+  if (c_info.group_size) { free(c_info.group_size); }
+  result=info;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_D_alpha_a               /
+/ igraph_scg_grouping                        /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_D_alpha_a(SEXP graph, SEXP alpha, SEXP a, SEXP abstol, SEXP reltol, SEXP maxit, SEXP filter) {
+SEXP R_igraph_scg_grouping(SEXP V, SEXP nt, SEXP nt_vec, SEXP mtype, SEXP algo, SEXP p, SEXP maxiter) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_matrix_t c_V;
+  igraph_vector_t c_groups;
+  igraph_integer_t c_nt;
+  igraph_vector_t c_nt_vec;
+  igraph_scg_matrix_t c_mtype;
+  igraph_scg_algorithm_t c_algo;
+  igraph_vector_t c_p;
+  igraph_integer_t c_maxiter;
+  SEXP groups;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  R_SEXP_to_matrix(V, &c_V);
+  if (0 != igraph_vector_init(&c_groups, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_groups);
+  c_nt=INTEGER(nt)[0];
+  if (!isNull(nt_vec)) { R_SEXP_to_vector(nt_vec, &c_nt_vec); }
+  c_mtype=(igraph_scg_matrix_t) REAL(mtype)[0];
+  c_algo=(igraph_scg_algorithm_t) REAL(algo)[0];
+  if (!isNull(p)) { R_SEXP_to_vector(p, &c_p); }
+  c_maxiter=INTEGER(maxiter)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_D_alpha_a(&c_graph, &c_alpha, &c_a, &c_Fmin, c_abstol, c_reltol, c_maxit, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_scg_grouping(&c_V, &c_groups, c_nt, (isNull(nt_vec) ? 0 : &c_nt_vec), c_mtype, c_algo, (isNull(p) ? 0 : &c_p), c_maxiter);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(5));
-  PROTECT(names=NEW_CHARACTER(5));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(a=NEW_NUMERIC(1)); 
-  REAL(a)[0]=c_a;
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, a);
-  SET_VECTOR_ELT(result, 2, Fmin);
-  SET_VECTOR_ELT(result, 3, fncount);
-  SET_VECTOR_ELT(result, 4, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("a"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("grcount"));
-  SET_NAMES(result, names);
-  UNPROTECT(6);
+  PROTECT(groups=R_igraph_vector_to_SEXPp1(&c_groups)); 
+  igraph_vector_destroy(&c_groups); 
+  IGRAPH_FINALLY_CLEAN(1);
+  result=groups;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_DE_alpha_a              /
+/ igraph_scg_norm_eps                        /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_DE_alpha_a(SEXP graph, SEXP cats, SEXP alpha, SEXP a, SEXP coeffs, SEXP abstol, SEXP reltol, SEXP maxit, SEXP filter) {
+SEXP R_igraph_scg_norm_eps(SEXP V, SEXP groups, SEXP mtype, SEXP p, SEXP norm) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_t c_cats;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_vector_t c_coeffs;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_matrix_t c_V;
+  igraph_vector_t c_groups;
+  igraph_vector_t c_eps;
+  igraph_scg_matrix_t c_mtype;
+  igraph_vector_t c_p;
+  igraph_scg_norm_t c_norm;
+  SEXP eps;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(cats, &c_cats);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  if (0 != R_SEXP_to_vector_copy(coeffs, &c_coeffs)) { 
+  R_SEXP_to_matrix(V, &c_V);
+  R_SEXP_to_vector(groups, &c_groups);
+  if (0 != igraph_vector_init(&c_eps, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_coeffs);
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_eps);
+  c_mtype=(igraph_scg_matrix_t) REAL(mtype)[0];
+  if (!isNull(p)) { R_SEXP_to_vector(p, &c_p); }
+  c_norm=(igraph_scg_norm_t) REAL(norm)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_DE_alpha_a(&c_graph, &c_cats, &c_alpha, &c_a, &c_coeffs, &c_Fmin, c_abstol, c_reltol, c_maxit, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_scg_norm_eps(&c_V, &c_groups, &c_eps, c_mtype, (isNull(p) ? 0 : &c_p), c_norm);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(6));
-  PROTECT(names=NEW_CHARACTER(6));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(a=NEW_NUMERIC(1)); 
-  REAL(a)[0]=c_a;
-  PROTECT(coeffs=R_igraph_vector_to_SEXP(&c_coeffs)); 
-  igraph_vector_destroy(&c_coeffs); 
+  PROTECT(eps=R_igraph_vector_to_SEXP(&c_eps)); 
+  igraph_vector_destroy(&c_eps); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, a);
-  SET_VECTOR_ELT(result, 2, coeffs);
-  SET_VECTOR_ELT(result, 3, Fmin);
-  SET_VECTOR_ELT(result, 4, fncount);
-  SET_VECTOR_ELT(result, 5, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("a"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("coeffs"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("grcount"));
-  SET_NAMES(result, names);
-  UNPROTECT(7);
+  result=eps;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_AD_alpha_a_beta         /
+/ igraph_is_matching                         /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_AD_alpha_a_beta(SEXP graph, SEXP alpha, SEXP a, SEXP beta, SEXP abstol, SEXP reltol, SEXP maxit, SEXP agebins, SEXP filter) {
+SEXP R_igraph_is_matching(SEXP graph, SEXP types, SEXP matching) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_beta;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_vector_bool_t c_types;
+  igraph_vector_long_t c_matching;
+  igraph_bool_t c_res;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_beta=REAL(beta)[0];
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
+  R_SEXP_to_vector_long_copy(matching, &c_matching);
                                         /* Call igraph */
-  igraph_revolver_ml_AD_alpha_a_beta(&c_graph, &c_alpha, &c_a, &c_beta, &c_Fmin, c_abstol, c_reltol, c_maxit, c_agebins, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_is_matching(&c_graph, (isNull(types) ? 0 : &c_types), &c_matching, &c_res);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(6));
-  PROTECT(names=NEW_CHARACTER(6));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(a=NEW_NUMERIC(1)); 
-  REAL(a)[0]=c_a;
-  PROTECT(beta=NEW_NUMERIC(1)); 
-  REAL(beta)[0]=c_beta;
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, a);
-  SET_VECTOR_ELT(result, 2, beta);
-  SET_VECTOR_ELT(result, 3, Fmin);
-  SET_VECTOR_ELT(result, 4, fncount);
-  SET_VECTOR_ELT(result, 5, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("a"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("beta"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("grcount"));
-  SET_NAMES(result, names);
-  UNPROTECT(7);
+  igraph_vector_long_destroy(&c_matching);
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_AD_dpareto              /
+/ igraph_is_maximal_matching                 /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_AD_dpareto(SEXP graph, SEXP alpha, SEXP a, SEXP paralpha, SEXP parbeta, SEXP parscale, SEXP abstol, SEXP reltol, SEXP maxit, SEXP agebins, SEXP filter) {
+SEXP R_igraph_is_maximal_matching(SEXP graph, SEXP types, SEXP matching) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_paralpha;
-  igraph_real_t c_parbeta;
-  igraph_real_t c_parscale;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_vector_bool_t c_types;
+  igraph_vector_long_t c_matching;
+  igraph_bool_t c_res;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_paralpha=REAL(paralpha)[0];
-  c_parbeta=REAL(parbeta)[0];
-  c_parscale=REAL(parscale)[0];
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
+  R_SEXP_to_vector_long_copy(matching, &c_matching);
                                         /* Call igraph */
-  igraph_revolver_ml_AD_dpareto(&c_graph, &c_alpha, &c_a, &c_paralpha, &c_parbeta, &c_parscale, &c_Fmin, c_abstol, c_reltol, c_maxit, c_agebins, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_is_maximal_matching(&c_graph, (isNull(types) ? 0 : &c_types), &c_matching, &c_res);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(8));
-  PROTECT(names=NEW_CHARACTER(8));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(a=NEW_NUMERIC(1)); 
-  REAL(a)[0]=c_a;
-  PROTECT(paralpha=NEW_NUMERIC(1)); 
-  REAL(paralpha)[0]=c_paralpha;
-  PROTECT(parbeta=NEW_NUMERIC(1)); 
-  REAL(parbeta)[0]=c_parbeta;
-  PROTECT(parscale=NEW_NUMERIC(1)); 
-  REAL(parscale)[0]=c_parscale;
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, a);
-  SET_VECTOR_ELT(result, 2, paralpha);
-  SET_VECTOR_ELT(result, 3, parbeta);
-  SET_VECTOR_ELT(result, 4, parscale);
-  SET_VECTOR_ELT(result, 5, Fmin);
-  SET_VECTOR_ELT(result, 6, fncount);
-  SET_VECTOR_ELT(result, 7, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("a"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("paralpha"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("parbeta"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("parscale"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 7, CREATE_STRING_VECTOR("grcount"));
-  SET_NAMES(result, names);
-  UNPROTECT(9);
+  igraph_vector_long_destroy(&c_matching);
+  PROTECT(res=NEW_LOGICAL(1)); 
+  LOGICAL(res)[0]=c_res;
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_AD_dpareto_eval         /
+/ igraph_maximum_bipartite_matching          /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_AD_dpareto_eval(SEXP graph, SEXP alpha, SEXP a, SEXP paralpha, SEXP parbeta, SEXP parscale, SEXP agebins, SEXP filter) {
+SEXP R_igraph_maximum_bipartite_matching(SEXP graph, SEXP types, SEXP weights, SEXP eps) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_paralpha;
-  igraph_real_t c_parbeta;
-  igraph_real_t c_parscale;
-  igraph_real_t c_value;
-  igraph_vector_t c_deriv;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  SEXP value;
-  SEXP deriv;
+  igraph_vector_bool_t c_types;
+  igraph_integer_t c_matching_size;
+  igraph_real_t c_matching_weight;
+  igraph_vector_long_t c_matching;
+  igraph_vector_t c_weights;
+  igraph_real_t c_eps;
+  SEXP matching_size;
+  SEXP matching_weight;
+  SEXP matching;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_paralpha=REAL(paralpha)[0];
-  c_parbeta=REAL(parbeta)[0];
-  c_parscale=REAL(parscale)[0];
-  if (0 != igraph_vector_init(&c_deriv, 0)) { 
+  if (!isNull(types)) { R_SEXP_to_vector_bool(types, &c_types); }
+  if (0 != igraph_vector_long_init(&c_matching, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_deriv);
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  IGRAPH_FINALLY(igraph_vector_long_destroy, &c_matching);
+  if (!isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); }
+  c_eps=REAL(eps)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_AD_dpareto_eval(&c_graph, c_alpha, c_a, c_paralpha, c_parbeta, c_parscale, &c_value, &c_deriv, c_agebins, (isNull(filter) ? 0 : &c_filter));
+  igraph_maximum_bipartite_matching(&c_graph, (isNull(types) ? 0 : &c_types), &c_matching_size, &c_matching_weight, &c_matching, (isNull(weights) ? 0 : &c_weights), c_eps);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(deriv=R_igraph_vector_to_SEXP(&c_deriv)); 
-  igraph_vector_destroy(&c_deriv); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(matching_size=NEW_INTEGER(1)); 
+  INTEGER(matching_size)[0]=c_matching_size;
+  PROTECT(matching_weight=NEW_NUMERIC(1)); 
+  REAL(matching_weight)[0]=c_matching_weight;
+  PROTECT(matching=R_igraph_vector_long_to_SEXPp1(&c_matching)); 
+  igraph_vector_long_destroy(&c_matching); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, value);
-  SET_VECTOR_ELT(result, 1, deriv);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("deriv"));
+  SET_VECTOR_ELT(result, 0, matching_size);
+  SET_VECTOR_ELT(result, 1, matching_weight);
+  SET_VECTOR_ELT(result, 2, matching);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("matching_size"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("matching_weight"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("matching"));
   SET_NAMES(result, names);
-  UNPROTECT(3);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_ADE_alpha_a_beta        /
+/ igraph_eigen_adjacency                     /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_ADE_alpha_a_beta(SEXP graph, SEXP cats, SEXP alpha, SEXP a, SEXP beta, SEXP coeffs, SEXP abstol, SEXP reltol, SEXP maxit, SEXP agebins, SEXP filter) {
+SEXP R_igraph_eigen_adjacency(SEXP graph, SEXP algorithm, SEXP which, SEXP options) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_cats;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_beta;
-  igraph_vector_t c_coeffs;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_integer_t c_algorithm;
+  igraph_eigen_which_t c_which;
+  igraph_arpack_options_t c_options;
+
+  igraph_vector_t c_values;
+  igraph_matrix_t c_vectors;
+
+
+  SEXP values;
+  SEXP vectors;
 
   SEXP result, names;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(cats, &c_cats);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_beta=REAL(beta)[0];
-  if (0 != R_SEXP_to_vector_copy(coeffs, &c_coeffs)) { 
+  c_algorithm=REAL(algorithm)[0];
+  R_SEXP_to_igraph_eigen_which(which, &c_which);
+  R_SEXP_to_igraph_arpack_options(options, &c_options);
+  if (0 != igraph_vector_init(&c_values, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_coeffs);
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_values);
+  if (0 != igraph_matrix_init(&c_vectors, 0, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_vectors);
                                         /* Call igraph */
-  igraph_revolver_ml_ADE_alpha_a_beta(&c_graph, &c_cats, &c_alpha, &c_a, &c_beta, &c_coeffs, &c_Fmin, c_abstol, c_reltol, c_maxit, c_agebins, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_eigen_adjacency(&c_graph, c_algorithm, &c_which, &c_options, 0, &c_values, &c_vectors, 0, 0);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(7));
-  PROTECT(names=NEW_CHARACTER(7));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(a=NEW_NUMERIC(1)); 
-  REAL(a)[0]=c_a;
-  PROTECT(beta=NEW_NUMERIC(1)); 
-  REAL(beta)[0]=c_beta;
-  PROTECT(coeffs=R_igraph_vector_to_SEXP(&c_coeffs)); 
-  igraph_vector_destroy(&c_coeffs); 
+  PROTECT(result=NEW_LIST(3));
+  PROTECT(names=NEW_CHARACTER(3));
+  PROTECT(options=R_igraph_arpack_options_to_SEXP(&c_options));
+  PROTECT(values=R_igraph_vector_to_SEXP(&c_values)); 
+  igraph_vector_destroy(&c_values); 
   IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, a);
-  SET_VECTOR_ELT(result, 2, beta);
-  SET_VECTOR_ELT(result, 3, coeffs);
-  SET_VECTOR_ELT(result, 4, Fmin);
-  SET_VECTOR_ELT(result, 5, fncount);
-  SET_VECTOR_ELT(result, 6, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("a"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("beta"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("coeffs"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("grcount"));
+  PROTECT(vectors=R_igraph_matrix_to_SEXP(&c_vectors)); 
+  igraph_matrix_destroy(&c_vectors); 
+  IGRAPH_FINALLY_CLEAN(1);
+  SET_VECTOR_ELT(result, 0, options);
+  SET_VECTOR_ELT(result, 1, values);
+  SET_VECTOR_ELT(result, 2, vectors);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("options"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("values"));
+  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("vectors"));
   SET_NAMES(result, names);
-  UNPROTECT(8);
+  UNPROTECT(4);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_ADE_dpareto             /
+/ igraph_power_law_fit                       /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_ADE_dpareto(SEXP graph, SEXP cats, SEXP alpha, SEXP a, SEXP paralpha, SEXP parbeta, SEXP parscale, SEXP coeffs, SEXP abstol, SEXP reltol, SEXP maxit, SEXP agebins, SEXP filter) {
+SEXP R_igraph_power_law_fit(SEXP data, SEXP xmin, SEXP force_continuous) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_t c_cats;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_paralpha;
-  igraph_real_t c_parbeta;
-  igraph_real_t c_parscale;
-  igraph_vector_t c_coeffs;
-  igraph_real_t c_Fmin;
-  igraph_real_t c_abstol;
-  igraph_real_t c_reltol;
-  int c_maxit;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  igraph_integer_t c_fncount;
-  igraph_integer_t c_grcount;
-  SEXP Fmin;
-  SEXP fncount;
-  SEXP grcount;
+  igraph_vector_t c_data;
+  igraph_plfit_result_t c_res;
+  igraph_real_t c_xmin;
+  igraph_bool_t c_force_continuous;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(cats, &c_cats);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_paralpha=REAL(paralpha)[0];
-  c_parbeta=REAL(parbeta)[0];
-  c_parscale=REAL(parscale)[0];
-  if (0 != R_SEXP_to_vector_copy(coeffs, &c_coeffs)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_coeffs);
-  c_abstol=REAL(abstol)[0];
-  c_reltol=REAL(reltol)[0];
-  c_maxit=INTEGER(maxit)[0];
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  R_SEXP_to_vector(data, &c_data);
+  c_xmin=REAL(xmin)[0];
+  c_force_continuous=LOGICAL(force_continuous)[0];
                                         /* Call igraph */
-  igraph_revolver_ml_ADE_dpareto(&c_graph, &c_cats, &c_alpha, &c_a, &c_paralpha, &c_parbeta, &c_parscale, &c_coeffs, &c_Fmin, c_abstol, c_reltol, c_maxit, c_agebins, (isNull(filter) ? 0 : &c_filter), &c_fncount, &c_grcount);
+  igraph_power_law_fit(&c_data, &c_res, c_xmin, c_force_continuous);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(9));
-  PROTECT(names=NEW_CHARACTER(9));
-  PROTECT(alpha=NEW_NUMERIC(1)); 
-  REAL(alpha)[0]=c_alpha;
-  PROTECT(a=NEW_NUMERIC(1)); 
-  REAL(a)[0]=c_a;
-  PROTECT(paralpha=NEW_NUMERIC(1)); 
-  REAL(paralpha)[0]=c_paralpha;
-  PROTECT(parbeta=NEW_NUMERIC(1)); 
-  REAL(parbeta)[0]=c_parbeta;
-  PROTECT(parscale=NEW_NUMERIC(1)); 
-  REAL(parscale)[0]=c_parscale;
-  PROTECT(coeffs=R_igraph_vector_to_SEXP(&c_coeffs)); 
-  igraph_vector_destroy(&c_coeffs); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(Fmin=NEW_NUMERIC(1)); 
-  REAL(Fmin)[0]=c_Fmin;
-  PROTECT(fncount=NEW_INTEGER(1)); 
-  INTEGER(fncount)[0]=c_fncount;
-  PROTECT(grcount=NEW_INTEGER(1)); 
-  INTEGER(grcount)[0]=c_grcount;
-  SET_VECTOR_ELT(result, 0, alpha);
-  SET_VECTOR_ELT(result, 1, a);
-  SET_VECTOR_ELT(result, 2, paralpha);
-  SET_VECTOR_ELT(result, 3, parbeta);
-  SET_VECTOR_ELT(result, 4, parscale);
-  SET_VECTOR_ELT(result, 5, coeffs);
-  SET_VECTOR_ELT(result, 6, Fmin);
-  SET_VECTOR_ELT(result, 7, fncount);
-  SET_VECTOR_ELT(result, 8, grcount);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("alpha"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("a"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("paralpha"));
-  SET_STRING_ELT(names, 3, CREATE_STRING_VECTOR("parbeta"));
-  SET_STRING_ELT(names, 4, CREATE_STRING_VECTOR("parscale"));
-  SET_STRING_ELT(names, 5, CREATE_STRING_VECTOR("coeffs"));
-  SET_STRING_ELT(names, 6, CREATE_STRING_VECTOR("Fmin"));
-  SET_STRING_ELT(names, 7, CREATE_STRING_VECTOR("fncount"));
-  SET_STRING_ELT(names, 8, CREATE_STRING_VECTOR("grcount"));
-  SET_NAMES(result, names);
-  UNPROTECT(10);
+  PROTECT(res=R_igraph_plfit_result_to_SEXP(&c_res));
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_ADE_dpareto_eval        /
+/ igraph_sir                                 /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_ADE_dpareto_eval(SEXP graph, SEXP cats, SEXP alpha, SEXP a, SEXP paralpha, SEXP parbeta, SEXP parscale, SEXP coeffs, SEXP agebins, SEXP filter) {
+SEXP R_igraph_sir(SEXP graph, SEXP beta, SEXP gamma, SEXP no_sim) {
                                         /* Declarations */
   igraph_t c_graph;
-  igraph_vector_t c_cats;
-  igraph_real_t c_alpha;
-  igraph_real_t c_a;
-  igraph_real_t c_paralpha;
-  igraph_real_t c_parbeta;
-  igraph_real_t c_parscale;
-  igraph_vector_t c_coeffs;
-  igraph_real_t c_value;
-  igraph_vector_t c_deriv;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  SEXP value;
-  SEXP deriv;
+  igraph_real_t c_beta;
+  igraph_real_t c_gamma;
+  igraph_integer_t c_no_sim;
+  igraph_vector_ptr_t c_res;
+  SEXP res;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
   R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(cats, &c_cats);
-  c_alpha=REAL(alpha)[0];
-  c_a=REAL(a)[0];
-  c_paralpha=REAL(paralpha)[0];
-  c_parbeta=REAL(parbeta)[0];
-  c_parscale=REAL(parscale)[0];
-  R_SEXP_to_vector(coeffs, &c_coeffs);
-  if (0 != igraph_vector_init(&c_deriv, 0)) { 
+  c_beta=REAL(beta)[0];
+  c_gamma=REAL(gamma)[0];
+  c_no_sim=INTEGER(no_sim)[0];
+  if (0 != igraph_vector_ptr_init(&c_res, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_deriv);
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  IGRAPH_FINALLY(R_igraph_sirlist_destroy, &c_res);
                                         /* Call igraph */
-  igraph_revolver_ml_ADE_dpareto_eval(&c_graph, &c_cats, c_alpha, c_a, c_paralpha, c_parbeta, c_parscale, &c_coeffs, &c_value, &c_deriv, c_agebins, (isNull(filter) ? 0 : &c_filter));
+  igraph_sir(&c_graph, c_beta, c_gamma, c_no_sim, &c_res);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(2));
-  PROTECT(names=NEW_CHARACTER(2));
-  PROTECT(value=NEW_NUMERIC(1)); 
-  REAL(value)[0]=c_value;
-  PROTECT(deriv=R_igraph_vector_to_SEXP(&c_deriv)); 
-  igraph_vector_destroy(&c_deriv); 
+  PROTECT(res=R_igraph_sirlist_to_SEXP(&c_res)); 
+  R_igraph_sirlist_destroy(&c_res); 
   IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, value);
-  SET_VECTOR_ELT(result, 1, deriv);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("value"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("deriv"));
-  SET_NAMES(result, names);
-  UNPROTECT(3);
+  result=res;
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_ml_ADE_dpareto_evalf       /
+/ igraph_convex_hull                         /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_ml_ADE_dpareto_evalf(SEXP graph, SEXP cats, SEXP par, SEXP agebins, SEXP filter) {
+SEXP R_igraph_convex_hull(SEXP data) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_vector_t c_cats;
-  igraph_matrix_t c_par;
-  igraph_vector_t c_value;
-  int c_agebins;
-  igraph_vector_t c_filter;
-  SEXP value;
+  igraph_matrix_t c_data;
+  igraph_vector_t c_resverts;
+  igraph_matrix_t c_rescoords;
+  SEXP resverts;
+  SEXP rescoords;
 
-  SEXP result;
+  SEXP result, names;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_vector(cats, &c_cats);
-  R_SEXP_to_matrix(par, &c_par);
-  if (0 != igraph_vector_init(&c_value, 0)) { 
+  R_SEXP_to_matrix(data, &c_data);
+  if (0 != igraph_vector_init(&c_resverts, 0)) { 
+  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
+  } 
+  IGRAPH_FINALLY(igraph_vector_destroy, &c_resverts);
+  if (0 != igraph_matrix_init(&c_rescoords, 0, 0)) { 
   igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
   } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_value);
-  c_agebins=INTEGER(agebins)[0];
-  if (!isNull(filter)) { R_SEXP_to_vector(filter, &c_filter); }
+  IGRAPH_FINALLY(igraph_matrix_destroy, &c_rescoords);
                                         /* Call igraph */
-  igraph_revolver_ml_ADE_dpareto_evalf(&c_graph, &c_cats, &c_par, &c_value, c_agebins, (isNull(filter) ? 0 : &c_filter));
+  igraph_convex_hull(&c_data, &c_resverts, &c_rescoords);
 
                                         /* Convert output */
-  PROTECT(value=R_igraph_vector_to_SEXP(&c_value)); 
-  igraph_vector_destroy(&c_value); 
+  PROTECT(result=NEW_LIST(2));
+  PROTECT(names=NEW_CHARACTER(2));
+  PROTECT(resverts=R_igraph_vector_to_SEXP(&c_resverts)); 
+  igraph_vector_destroy(&c_resverts); 
+  IGRAPH_FINALLY_CLEAN(1);
+  PROTECT(rescoords=R_igraph_matrix_to_SEXP(&c_rescoords)); 
+  igraph_matrix_destroy(&c_rescoords); 
   IGRAPH_FINALLY_CLEAN(1);
-  result=value;
+  SET_VECTOR_ELT(result, 0, resverts);
+  SET_VECTOR_ELT(result, 1, rescoords);
+  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("resverts"));
+  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("rescoords"));
+  SET_NAMES(result, names);
+  UNPROTECT(3);
 
   UNPROTECT(1);
   return(result);
 }
 
 /*-------------------------------------------/
-/ igraph_revolver_probs_ADE_dpareto          /
+/ igraph_dim_select                          /
 /-------------------------------------------*/
-SEXP R_igraph_revolver_probs_ADE_dpareto(SEXP graph, SEXP par, SEXP cats, SEXP gcats, SEXP agebins) {
+SEXP R_igraph_dim_select(SEXP sv) {
                                         /* Declarations */
-  igraph_t c_graph;
-  igraph_matrix_t c_par;
-  igraph_vector_t c_cats;
-  igraph_vector_t c_gcats;
-  int c_agebins;
-  igraph_vector_t c_logprobs;
-  igraph_vector_t c_logcited;
-  igraph_vector_t c_logciting;
-  SEXP logprobs;
-  SEXP logcited;
-  SEXP logciting;
+  igraph_vector_t c_sv;
+  igraph_integer_t c_dim;
+  SEXP dim;
 
-  SEXP result, names;
+  SEXP result;
                                         /* Convert input */
-  R_SEXP_to_igraph(graph, &c_graph);
-  R_SEXP_to_matrix(par, &c_par);
-  R_SEXP_to_vector(cats, &c_cats);
-  R_SEXP_to_vector(gcats, &c_gcats);
-  c_agebins=INTEGER(agebins)[0];
-  if (0 != igraph_vector_init(&c_logprobs, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logprobs); 
-  logprobs=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_logcited, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logcited); 
-  logcited=NEW_NUMERIC(0); /* hack to have a non-NULL value */
-  if (0 != igraph_vector_init(&c_logciting, 0)) { 
-  igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); 
-  } 
-  IGRAPH_FINALLY(igraph_vector_destroy, &c_logciting); 
-  logciting=NEW_NUMERIC(0); /* hack to have a non-NULL value */
+  R_SEXP_to_vector(sv, &c_sv);
                                         /* Call igraph */
-  igraph_revolver_probs_ADE_dpareto(&c_graph, &c_par, &c_cats, &c_gcats, c_agebins, (isNull(logprobs) ? 0 : &c_logprobs), (isNull(logcited) ? 0 : &c_logcited), (isNull(logciting) ? 0 : &c_logciting));
+  igraph_dim_select(&c_sv, &c_dim);
 
                                         /* Convert output */
-  PROTECT(result=NEW_LIST(3));
-  PROTECT(names=NEW_CHARACTER(3));
-  PROTECT(logprobs=R_igraph_0orvector_to_SEXP(&c_logprobs)); 
-  igraph_vector_destroy(&c_logprobs); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logcited=R_igraph_0orvector_to_SEXP(&c_logcited)); 
-  igraph_vector_destroy(&c_logcited); 
-  IGRAPH_FINALLY_CLEAN(1);
-  PROTECT(logciting=R_igraph_0orvector_to_SEXP(&c_logciting)); 
-  igraph_vector_destroy(&c_logciting); 
-  IGRAPH_FINALLY_CLEAN(1);
-  SET_VECTOR_ELT(result, 0, logprobs);
-  SET_VECTOR_ELT(result, 1, logcited);
-  SET_VECTOR_ELT(result, 2, logciting);
-  SET_STRING_ELT(names, 0, CREATE_STRING_VECTOR("logprobs"));
-  SET_STRING_ELT(names, 1, CREATE_STRING_VECTOR("logcited"));
-  SET_STRING_ELT(names, 2, CREATE_STRING_VECTOR("logciting"));
-  SET_NAMES(result, names);
-  UNPROTECT(4);
+  PROTECT(dim=NEW_INTEGER(1)); 
+  INTEGER(dim)[0]=c_dim;
+  result=dim;
 
   UNPROTECT(1);
   return(result);
diff --git a/src/rinterface.h b/src/rinterface.h
index b2cc84f..e890f09 100644
--- a/src/rinterface.h
+++ b/src/rinterface.h
@@ -21,3 +21,9 @@
 
 */
 
+#include "uuid/uuid.h"
+
+#define R_IGRAPH_TYPE_VERSION "0.8.0"
+#define R_IGRAPH_VERSION_VAR ".__igraph_version__."
+
+SEXP R_igraph_add_env(SEXP graph);
diff --git a/src/rinterface_extra.c b/src/rinterface_extra.c
index 876756d..3d74a2b 100644
--- a/src/rinterface_extra.c
+++ b/src/rinterface_extra.c
@@ -28,6 +28,8 @@
 #include <Rinternals.h>
 #include <Rdefines.h>
 
+#include "rinterface.h"
+
 #include <stdlib.h>
 
 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++C */
@@ -205,8 +207,115 @@ SEXP R_igraph_psumtree_draw(SEXP plength, SEXP howmany, SEXP prob) {
   return result;
 }
 
-SEXP R_igraph_srand(SEXP pseed) {
-  unsigned seed=INTEGER(AS_INTEGER(pseed))[0];
-  srand(seed);
+SEXP R_igraph_get_all_simple_paths_pp(SEXP vector) {
+  SEXP result;
+  int i, no=0, n=GET_LENGTH(vector);
+  int *vec=INTEGER(vector), *p=vec, *pp=vec;
+  for (i=0; i<n; i++) {
+    if (vec[i] == 0) { no++; }
+  }
+
+  PROTECT(result=NEW_LIST(no));
+  for (i=0; i<no; i++) {
+    SEXP svec;
+    while (*p != 0) { p++; }
+    SET_VECTOR_ELT(result, i, svec=NEW_INTEGER(p-pp));
+    memcpy(INTEGER(svec), pp, (p-pp) * sizeof(int));
+    pp = ++p;
+  }
+
+  UNPROTECT(1);
+  return result;
+}
+
+SEXP R_igraph_address(SEXP object) {
+  char s[64];
+  snprintf(s, 64, "%p", object);
+  return ScalarString(mkChar(s));
+}
+
+SEXP R_igraph_make_weak_ref(SEXP key, SEXP value, SEXP finalizer) {
+  return R_MakeWeakRef(key, value, finalizer, isNull(finalizer) ? 0 : 1);
+}
+
+SEXP R_igraph_weak_ref_key(SEXP ref) {
+  return R_WeakRefKey(ref);
+}
+
+SEXP R_igraph_weak_ref_value(SEXP ref) {
+  return R_WeakRefValue(ref);
+}
+
+SEXP R_igraph_weak_ref_run_finalizer(SEXP ref) {
+  R_RunWeakRefFinalizer(ref);
   return R_NilValue;
 }
+
+SEXP R_igraph_identical_graphs(SEXP g1, SEXP g2) {
+  int i;
+  for (i = 0; i < 9 ; i++) {
+    if (!R_compute_identical(VECTOR_ELT(g1, i), VECTOR_ELT(g2, i), 0)) {
+      return ScalarLogical(0);
+    }
+  }
+  return ScalarLogical(1);
+}
+
+SEXP R_igraph_graph_version(SEXP graph) {
+  if (GET_LENGTH(graph) == 10 && isEnvironment(VECTOR_ELT(graph, 9))) {
+    SEXP ver = findVar(install(R_IGRAPH_VERSION_VAR), VECTOR_ELT(graph, 9));
+    if (ver != R_UnboundValue) {
+      return ver;
+    } else {
+      return mkString("0.7.999");
+    }
+  } else {
+    return mkString("0.4.0");
+  }
+}
+
+SEXP R_igraph_add_version_to_env(SEXP graph) {
+  uuid_t my_id;
+  char my_id_chr[40];
+
+  PROTECT(graph = duplicate(graph));
+
+  uuid_generate(my_id);
+  uuid_unparse_lower(my_id, my_id_chr);
+  defineVar(install("myid"), mkString(my_id_chr), VECTOR_ELT(graph, 9));
+  defineVar(install(R_IGRAPH_VERSION_VAR), mkString(R_IGRAPH_TYPE_VERSION),
+	    VECTOR_ELT(graph, 9));
+
+  UNPROTECT(1);
+  return graph;
+}
+
+SEXP R_igraph_add_env(SEXP graph) {
+  SEXP result = graph;
+  int i;
+  uuid_t my_id;
+  char my_id_chr[40];
+
+  if (GET_LENGTH(result) != 10) {
+    PROTECT(result = NEW_LIST(10));
+    for (i = 0; i < 9; i++) {
+      SET_VECTOR_ELT(result, i, duplicate(VECTOR_ELT(graph, i)));
+    }
+    SET_ATTRIB(result, duplicate(ATTRIB(graph)));
+    SET_CLASS(result, duplicate(GET_CLASS(graph)));
+  }
+  SET_VECTOR_ELT(result, 9, allocSExp(ENVSXP));
+
+  uuid_generate(my_id);
+  uuid_unparse_lower(my_id, my_id_chr);
+  defineVar(install("myid"), mkString(my_id_chr), VECTOR_ELT(result, 9));
+  defineVar(install(R_IGRAPH_VERSION_VAR), mkString(R_IGRAPH_TYPE_VERSION),
+	    VECTOR_ELT(result, 9));
+
+  if (result != graph) { UNPROTECT(1); }
+  return result;
+}
+
+SEXP R_igraph_get_graph_id(SEXP graph) {
+  return findVar(install("myid"), VECTOR_ELT(graph, 9));
+}
diff --git a/src/sbm.c b/src/sbm.c
index da18afb..385f2ef 100644
--- a/src/sbm.c
+++ b/src/sbm.c
@@ -29,6 +29,9 @@
 #include "igraph_constructors.h"
 #include "igraph_games.h"
 
+#include <float.h>		/* for DBL_EPSILON */
+#include <math.h> 		/* for sqrt */
+
 /**
  * \function igraph_sbm_game
  * Sample from a stochastic block model
@@ -212,3 +215,387 @@ int igraph_sbm_game(igraph_t *graph, igraph_integer_t n,
 
   return 0;
 }
+
+/**
+ * \function igraph_hsbm_game
+ * Hierarchical stochastic block model
+ *
+ * The function generates a random graph according to the hierarchical
+ * stochastic block model.
+ *
+ * \param graph The generated graph is stored here.
+ * \param n The number of vertices in the graph.
+ * \param m The number of vertices per block. n/m must be integer.
+ * \param rho The fraction of vertices per cluster,
+ *        within a block. Must sum up to 1, and rho * m must be integer
+ *        for all elements of rho.
+ * \param C A square, symmetric numeric matrix, the Bernoulli rates for
+ *        the clusters within a block. Its size must mach the size of the
+ *        \code{rho} vector.
+ * \param p The Bernoulli rate of connections between
+ *        vertices in different blocks.
+ * \return Error code.
+ *
+ * \sa \ref igraph_sbm_game() for the classic stochastic block model,
+ * \ref igraph_hsbm_list_game() for a more general version.
+ */
+
+int igraph_hsbm_game(igraph_t *graph, igraph_integer_t n, 
+		     igraph_integer_t m, const igraph_vector_t *rho,
+		     const igraph_matrix_t *C, igraph_real_t p) {
+  
+  int b, i, k=igraph_vector_size(rho);
+  igraph_vector_t csizes;
+  igraph_real_t sq_dbl_epsilon=sqrt(DBL_EPSILON);
+  int no_blocks=n / m;
+  igraph_vector_t edges;
+  int offset=0;
+
+  if (n < 1) { 
+    IGRAPH_ERROR("`n' must be positive for HSBM", IGRAPH_EINVAL); 
+  }
+  if (m < 1) {
+    IGRAPH_ERROR("`m' must be positive for HSBM", IGRAPH_EINVAL);
+  }
+  if ((long) n  % (long) m) {
+    IGRAPH_ERROR("`n' must be a multiple of `m' for HSBM", IGRAPH_EINVAL);
+  }
+  if (!igraph_vector_isininterval(rho, 0, 1)) {
+    IGRAPH_ERROR("`rho' must be between zero and one for HSBM", 
+		 IGRAPH_EINVAL);
+  }
+  if (igraph_matrix_min(C) < 0 || igraph_matrix_max(C) > 1) {
+    IGRAPH_ERROR("`C' must be between zero and one for HSBM", IGRAPH_EINVAL);
+  }
+  if (fabs(igraph_vector_sum(rho) - 1.0) > sq_dbl_epsilon) {
+    IGRAPH_ERROR("`rho' must sum up to 1 for HSBM", IGRAPH_EINVAL);
+  }
+  if (igraph_matrix_nrow(C) != k || igraph_matrix_ncol(C) != k) {
+    IGRAPH_ERROR("`C' dimensions must match `rho' dimensions in HSBM",
+		 IGRAPH_EINVAL);
+  }
+  if (!igraph_matrix_is_symmetric(C)) {
+    IGRAPH_ERROR("`C' must be a symmetric matrix", IGRAPH_EINVAL);
+  }
+  if (p < 0 || p > 1) {
+    IGRAPH_ERROR("`p' must be a probability for HSBM", IGRAPH_EINVAL);
+  }
+  for (i=0; i<k; i++) {
+    igraph_real_t s=VECTOR(*rho)[i] * m;
+    if (fabs(round(s)-s) > sq_dbl_epsilon) {
+      IGRAPH_ERROR("`rho' * `m' is not integer in HSBM", IGRAPH_EINVAL);
+    }
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&csizes, k);
+  for (i=0; i<k; i++) {
+    VECTOR(csizes)[i] = round(VECTOR(*rho)[i] * m);
+  }
+  
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+
+  RNG_BEGIN();
+
+  /* Block models first */
+
+  for (b=0; b<no_blocks; b++) {
+    int from, to, fromoff=0;
+    
+    for (from = 0; from < k; from++) {
+      int fromsize = VECTOR(csizes)[from];
+      int i, tooff=0;
+      for (i=0; i<from; i++) {
+	tooff += VECTOR(csizes)[i];
+      }
+      for (to = from; to < k; to++) {
+	int tosize = VECTOR(csizes)[to];
+	igraph_real_t prob=MATRIX(*C, from, to);
+	igraph_real_t maxedges;
+	igraph_real_t last=RNG_GEOM(prob);
+	if (from != to) {
+	  maxedges = fromsize * tosize;	
+	  while (last < maxedges) {
+	    int vto=floor(last/fromsize);
+	    int vfrom=last - (igraph_real_t)vto * fromsize;
+	    igraph_vector_push_back(&edges, offset + fromoff + vfrom);
+	    igraph_vector_push_back(&edges, offset + tooff + vto);
+	    last += RNG_GEOM(prob);
+	    last += 1;
+	  }
+	} else /* from==to */ {
+	  maxedges = fromsize * (fromsize-1) / 2.0;
+	  while (last < maxedges) {
+	    int vto=floor((sqrt(8*last+1)+1)/2);
+	    int vfrom=last-(((igraph_real_t)vto)*(vto-1))/2;
+	    igraph_vector_push_back(&edges, offset + fromoff + vfrom);
+	    igraph_vector_push_back(&edges, offset + tooff + vto);
+	    last += RNG_GEOM(prob);
+	    last += 1;
+	  }
+	}
+
+	tooff += tosize;
+      }
+      fromoff += fromsize;
+    }
+    
+    offset += m;
+  }
+
+  /* And now the rest, if not a special case */
+
+  if (p == 1) {
+    int fromoff=0, tooff=m;
+    for (b=0; b<no_blocks; b++) {
+      igraph_real_t fromsize = m;
+      igraph_real_t tosize = n - tooff;
+      int from, to;
+      for (from=0; from<fromsize; from++) {
+	for (to=0; to<tosize; to++) {
+	  igraph_vector_push_back(&edges, fromoff + from);
+	  igraph_vector_push_back(&edges, tooff + to);
+	}
+      }
+      fromoff += m;
+      tooff += m;
+    }
+  } else if (p > 0) {
+    int fromoff=0, tooff=m;
+    for (b=0; b<no_blocks; b++) {
+      igraph_real_t fromsize = m;
+      igraph_real_t tosize = n - tooff;
+      igraph_real_t maxedges= fromsize * tosize;
+      igraph_real_t last=RNG_GEOM(p);
+      while (last < maxedges) {
+	int vto = floor(last/fromsize);
+	int vfrom = last - (igraph_real_t) vto * fromsize;
+	igraph_vector_push_back(&edges, fromoff + vfrom);
+	igraph_vector_push_back(&edges, tooff + vto);
+	last += RNG_GEOM(p);
+	last += 1;
+      }
+      
+      fromoff += m;
+      tooff += m;
+    }
+  }
+
+  RNG_END();
+
+  igraph_create(graph, &edges, n, /*directed=*/ 0);
+
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&csizes);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_hsbm_list_game
+ * Hierarchical stochastic block model, more general version
+ *
+ * The function generates a random graph according to the hierarchical
+ * stochastic block model.
+ *
+ * \param graph The generated graph is stored here.
+ * \param n The number of vertices in the graph.
+ * \param mlist An integer vector of block sizes.
+ * \param rholist A list of rho vectors (\c igraph_vector_t objects), one
+ *        for each block.
+ * \param Clist A list of square matrices (\c igraph_matrix_t objects),
+ *        one for each block, giving the Bernoulli rates of connections
+ *        within the block.
+ * \param p The Bernoulli rate of connections between
+ *        vertices in different blocks.
+ * \return Error code.
+ *
+ * \sa \ref igraph_sbm_game() for the classic stochastic block model,
+ * \ref igraph_hsbm_game() for a simpler general version.
+ */
+
+int igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n,
+			  const igraph_vector_int_t *mlist,
+			  const igraph_vector_ptr_t *rholist,
+			  const igraph_vector_ptr_t *Clist,
+			  igraph_real_t p) {
+
+  int i, no_blocks=igraph_vector_ptr_size(rholist);
+  igraph_real_t sq_dbl_epsilon=sqrt(DBL_EPSILON);
+  igraph_vector_t csizes, edges;
+  int b, offset=0;
+
+  if (n < 1) { 
+    IGRAPH_ERROR("`n' must be positive for HSBM", IGRAPH_EINVAL); 
+  }
+  if (no_blocks == 0) {
+    IGRAPH_ERROR("`rholist' empty for HSBM", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_ptr_size(Clist) != no_blocks && 
+      igraph_vector_int_size(mlist) != no_blocks) {
+    IGRAPH_ERROR("`rholist' must have same length as `Clist' and `m' "
+		 "for HSBM", IGRAPH_EINVAL);
+  }
+  if (p < 0 || p > 1) {
+    IGRAPH_ERROR("`p' must be a probability for HSBM", IGRAPH_EINVAL);
+  }
+  /* Checks for m's */
+  if (igraph_vector_int_sum(mlist) != n) {
+    IGRAPH_ERROR("`m' must sum up to `n' for HSBM", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_int_min(mlist) < 1) { 
+    IGRAPH_ERROR("`m' must be positive for HSBM", IGRAPH_EINVAL);
+  }
+  /* Checks for the rhos */
+  for (i=0; i<no_blocks; i++) {
+    const igraph_vector_t *rho=VECTOR(*rholist)[i];
+    if (!igraph_vector_isininterval(rho, 0, 1)) {
+      IGRAPH_ERROR("`rho' must be between zero and one for HSBM", 
+		   IGRAPH_EINVAL);
+    }
+    if (fabs(igraph_vector_sum(rho) - 1.0) > sq_dbl_epsilon) {
+      IGRAPH_ERROR("`rho' must sum up to 1 for HSBM", IGRAPH_EINVAL);
+    }
+  }
+  /* Checks for the Cs */
+  for (i=0; i<no_blocks; i++) {
+    const igraph_matrix_t *C=VECTOR(*Clist)[i];
+    if (igraph_matrix_min(C) < 0 || igraph_matrix_max(C) > 1) {
+      IGRAPH_ERROR("`C' must be between zero and one for HSBM", 
+		   IGRAPH_EINVAL);
+    }
+    if (!igraph_matrix_is_symmetric(C)) {
+      IGRAPH_ERROR("`C' must be a symmetric matrix", IGRAPH_EINVAL);
+    }
+  }
+  /* Check that C and rho sizes match */
+  for (i=0; i<no_blocks; i++) {
+    const igraph_vector_t *rho=VECTOR(*rholist)[i];
+    const igraph_matrix_t *C=VECTOR(*Clist)[i];
+    int k=igraph_vector_size(rho);
+    if (igraph_matrix_nrow(C) != k || igraph_matrix_ncol(C) != k) {
+      IGRAPH_ERROR("`C' dimensions must match `rho' dimensions in HSBM",
+		   IGRAPH_EINVAL);
+    }
+  }
+  /* Check that rho * m is integer */
+  for (i=0; i<no_blocks; i++) {
+    const igraph_vector_t *rho=VECTOR(*rholist)[i];
+    igraph_real_t m=VECTOR(*mlist)[i];
+    int j, k=igraph_vector_size(rho);
+    for (j=0; j<k; j++) {
+      igraph_real_t s=VECTOR(*rho)[j] * m;
+      if (fabs(round(s)-s) > sq_dbl_epsilon) {
+	IGRAPH_ERROR("`rho' * `m' is not integer in HSBM", IGRAPH_EINVAL);
+      }
+    }
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&csizes, 0);
+  IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);
+  
+  RNG_BEGIN();
+
+  /* Block models first */
+  
+  for (b=0; b<no_blocks; b++) {
+    int from, to, fromoff=0;
+    const igraph_vector_t *rho=VECTOR(*rholist)[b];
+    const igraph_matrix_t *C=VECTOR(*Clist)[b];
+    igraph_real_t m=VECTOR(*mlist)[b];
+    int k=igraph_vector_size(rho);
+    
+    igraph_vector_resize(&csizes, k);
+    for (i=0; i<k; i++) {
+      VECTOR(csizes)[i] = round(VECTOR(*rho)[i] * m);
+    }
+    
+    for (from=0; from < k; from++) {
+      int fromsize=VECTOR(csizes)[from];
+      int i, tooff=0;
+      for (i=0; i<from; i++) {
+	tooff += VECTOR(csizes)[i];
+      }
+      for (to = from; to < k; to++) {
+	int tosize = VECTOR(csizes)[to];
+	igraph_real_t prob=MATRIX(*C, from, to);
+	igraph_real_t maxedges;
+	igraph_real_t last=RNG_GEOM(prob);
+	if (from != to) {
+	  maxedges = fromsize * tosize;	
+	  while (last < maxedges) {
+	    int vto=floor(last/fromsize);
+	    int vfrom=last - (igraph_real_t)vto * fromsize;
+	    igraph_vector_push_back(&edges, offset + fromoff + vfrom);
+	    igraph_vector_push_back(&edges, offset + tooff + vto);
+	    last += RNG_GEOM(prob);
+	    last += 1;
+	  }
+	} else /* from==to */ {
+	  maxedges = fromsize * (fromsize-1) / 2.0;
+	  while (last < maxedges) {
+	    int vto=floor((sqrt(8*last+1)+1)/2);
+	    int vfrom=last-(((igraph_real_t)vto)*(vto-1))/2;
+	    igraph_vector_push_back(&edges, offset + fromoff + vfrom);
+	    igraph_vector_push_back(&edges, offset + tooff + vto);
+	    last += RNG_GEOM(prob);
+	    last += 1;
+	  }
+	}
+
+	tooff += tosize;
+      }
+      fromoff += fromsize;
+    }
+    
+    offset += m;
+  }
+
+  /* And now the rest, if not a special case */
+
+  if (p == 1) {    
+    int fromoff=0, tooff=VECTOR(*mlist)[0];
+    for (b=0; b<no_blocks; b++) {
+      igraph_real_t fromsize = VECTOR(*mlist)[b];
+      igraph_real_t tosize = n - tooff;
+      int from, to;
+      for (from=0; from<fromsize; from++) {
+	for (to=0; to<tosize; to++) {
+	  igraph_vector_push_back(&edges, fromoff + from);
+	  igraph_vector_push_back(&edges, tooff + to);
+	}
+      }
+      fromoff += fromsize;
+      if (b+1 < no_blocks) { tooff += VECTOR(*mlist)[b+1]; }
+    }    
+  } else if (p > 0) {    
+    int fromoff=0, tooff=VECTOR(*mlist)[0];
+    for (b=0; b<no_blocks; b++) {
+      igraph_real_t fromsize = VECTOR(*mlist)[b];
+      igraph_real_t tosize = n - tooff;
+      igraph_real_t maxedges= fromsize * tosize;
+      igraph_real_t last=RNG_GEOM(p);
+      while (last < maxedges) {
+	int vto = floor(last/fromsize);
+	int vfrom = last - (igraph_real_t) vto * fromsize;
+	igraph_vector_push_back(&edges, fromoff + vfrom);
+	igraph_vector_push_back(&edges, tooff + vto);
+	last += RNG_GEOM(p);
+	last += 1;
+      }
+      
+      fromoff += fromsize;
+      if (b+1 < no_blocks) { tooff += VECTOR(*mlist)[b+1]; }
+    }
+  }
+  
+  RNG_END();
+
+  igraph_create(graph, &edges, n, /*directed=*/ 0);
+
+  igraph_vector_destroy(&edges);
+  igraph_vector_destroy(&csizes);
+  IGRAPH_FINALLY_CLEAN(2);  
+  
+  return 0;
+}
diff --git a/src/scan.c b/src/scan.c
new file mode 100644
index 0000000..dddda20
--- /dev/null
+++ b/src/scan.c
@@ -0,0 +1,859 @@
+/* -*- mode: C -*-  */
+/* 
+   IGraph library.
+   Copyright (C) 2013  Gabor Csardi <csardi.gabor at gmail.com>
+   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
+
+*/
+
+#include "igraph_scan.h"
+#include "igraph_interface.h"
+#include "igraph_adjlist.h"
+#include "igraph_memory.h"
+#include "igraph_interrupt_internal.h"
+#include "igraph_arpack.h"
+#include "igraph_eigen.h"
+#include "igraph_centrality.h"
+#include "igraph_operators.h"
+#include "igraph_dqueue.h"
+#include "igraph_stack.h"
+
+/**
+ * \function igraph_local_scan_0
+ * Local scan-statistics, k=0
+ * 
+ * K=0 scan-statistics is arbitrarily defined as the vertex degree for
+ * unweighted, and the vertex strength for weighted graphs. See \ref
+ * igraph_degree() and \ref igraph_strength().
+ * 
+ * \param graph The input graph
+ * \param res An initialized vector, the results are stored here.
+ * \param weights Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,
+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.
+ * \return Error code.
+ * 
+ */
+
+int igraph_local_scan_0(const igraph_t *graph, igraph_vector_t *res,
+			const igraph_vector_t *weights,
+			igraph_neimode_t mode) {
+  if (weights) {
+    igraph_strength(graph, res, igraph_vss_all(), mode, /*loops=*/ 1,
+		    weights);
+  } else {
+    igraph_degree(graph, res, igraph_vss_all(), mode, /*loops=*/ 1);
+  }
+  return 0;
+}
+
+/* From triangles.c */
+
+int igraph_i_trans4_al_simplify(igraph_adjlist_t *al,
+				const igraph_vector_int_t *rank);
+
+/* This removes loop, multiple edges and edges that point
+   "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) {
+
+  long int i;
+  long int n=il->length;
+  igraph_vector_int_t mark;
+  igraph_vector_int_init(&mark, n);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &mark);
+
+  for (i=0; i<n; i++) {
+    igraph_vector_int_t *v=&il->incs[i];
+    int j, l=igraph_vector_int_size(v);
+    int irank=VECTOR(*rank)[i];
+    VECTOR(mark)[i] = i+1;
+    for (j=0; j<l; /* nothing */) {
+      long int edge=(long int) VECTOR(*v)[j];
+      long int e=IGRAPH_OTHER(graph, edge, i);
+      if (VECTOR(*rank)[e] > irank && VECTOR(mark)[e] != i+1) {
+	VECTOR(mark)[e]=i+1;
+	j++;
+      } else {
+	VECTOR(*v)[j] = igraph_vector_int_tail(v);
+	igraph_vector_int_pop_back(v);
+	l--;
+      }
+    }
+  }
+
+  igraph_vector_int_destroy(&mark);
+  IGRAPH_FINALLY_CLEAN(1);
+  return 0;
+
+}
+
+/* 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) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  igraph_inclist_t incs;
+  int i, node;
+
+  igraph_vector_int_t neis;
+
+  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, mode));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);
+
+  igraph_vector_int_init(&neis, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);
+
+  igraph_vector_resize(res, no_of_nodes);
+  igraph_vector_null(res);
+
+  for (node=0; node < no_of_nodes; node++) {
+    igraph_vector_int_t *edges1=igraph_inclist_get(&incs, node);
+    int edgeslen1=igraph_vector_int_size(edges1);
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    /* Mark neighbors and self*/
+    VECTOR(neis)[node] = node+1;
+    for (i=0; i<edgeslen1; i++) {
+      int e=VECTOR(*edges1)[i];
+      int nei=IGRAPH_OTHER(graph, e, node);
+      igraph_real_t w= weights ? VECTOR(*weights)[e] : 1;
+      VECTOR(neis)[nei] = node+1;
+      VECTOR(*res)[node] += w;
+    }
+
+    /* Crawl neighbors */
+    for (i=0; i<edgeslen1; i++) {
+      int e2=VECTOR(*edges1)[i];
+      int nei=IGRAPH_OTHER(graph, e2, node);
+      igraph_vector_int_t *edges2=igraph_inclist_get(&incs, nei);
+      int j, edgeslen2=igraph_vector_int_size(edges2);
+      for (j=0; j<edgeslen2; j++) {
+	int e2=VECTOR(*edges2)[j];
+	int nei2=IGRAPH_OTHER(graph, e2, nei);
+	igraph_real_t w2= weights ? VECTOR(*weights)[e2] : 1;
+	if (VECTOR(neis)[nei2] == node+1) {
+	  VECTOR(*res)[node] += w2;
+	}
+      }
+    }
+
+  } /* node < no_of_nodes */
+
+  igraph_vector_int_destroy(&neis);
+  igraph_inclist_destroy(&incs);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+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;
+  int i, node;
+
+  igraph_vector_int_t neis;
+
+  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);
+
+  igraph_vector_int_init(&neis, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);
+
+  igraph_vector_resize(res, no_of_nodes);
+  igraph_vector_null(res);
+
+  for (node=0; node < no_of_nodes; node++) {
+    igraph_vector_int_t *edges1=igraph_inclist_get(&incs, node);
+    int edgeslen1=igraph_vector_int_size(edges1);
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    /* Mark neighbors. We also count the edges that are incident to ego.
+       Note that this time we do not mark ego, because we don't want to
+       double count its incident edges later, when we are going over the
+       incident edges of ego's neighbors. */
+    for (i=0; i<edgeslen1; i++) {
+      int e=VECTOR(*edges1)[i];
+      int nei=IGRAPH_OTHER(graph, e, node);
+      igraph_real_t w= weights ? VECTOR(*weights)[e] : 1;
+      VECTOR(neis)[nei] = node+1;
+      VECTOR(*res)[node] += w;
+    }
+
+    /* Crawl neighbors. We make sure that each neighbor of 'node' is
+       only crawed once. We count all qualifying edges of ego, and
+       then unmark ego to avoid double counting. */
+    for (i=0; i<edgeslen1; i++) {
+      int e2=VECTOR(*edges1)[i];
+      int nei=IGRAPH_OTHER(graph, e2, node);
+      if (VECTOR(neis)[nei] != node+1) { continue; }
+      igraph_vector_int_t *edges2=igraph_inclist_get(&incs, nei);
+      int j, edgeslen2=igraph_vector_int_size(edges2);
+      for (j=0; j<edgeslen2; j++) {
+	int e2=VECTOR(*edges2)[j];
+	int nei2=IGRAPH_OTHER(graph, e2, nei);
+	igraph_real_t w2= weights ? VECTOR(*weights)[e2] : 1;
+	if (VECTOR(neis)[nei2] == node+1) {
+	  VECTOR(*res)[node] += w2;
+	}
+      }
+      VECTOR(neis)[nei] = 0;
+    }
+
+  } /* node < no_of_nodes */
+
+  igraph_vector_int_destroy(&neis);
+  igraph_inclist_destroy(&incs);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+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;
+  igraph_inclist_t allinc;
+  igraph_vector_int_t *neis1, *neis2;
+  long int neilen1, neilen2;
+  long int *neis;
+  long int maxdegree;
+
+  igraph_vector_int_t order;
+  igraph_vector_int_t rank;
+  igraph_vector_t degree, *edge1=°ree; /* reuse degree as edge1 */
+
+  if (igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);
+  }
+
+  igraph_vector_int_init(&order, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &order);
+  IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);
+
+  IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), IGRAPH_ALL,
+			     IGRAPH_LOOPS));
+  maxdegree=(long int) igraph_vector_max(&degree)+1;
+  igraph_vector_order1_int(&degree, &order, maxdegree);
+  igraph_vector_int_init(&rank, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &rank);
+  for (i=0; i<no_of_nodes; i++) {
+    VECTOR(rank)[ VECTOR(order)[i] ] = no_of_nodes-i-1;
+  }
+
+  IGRAPH_CHECK(igraph_inclist_init(graph, &allinc, IGRAPH_ALL));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &allinc);
+  IGRAPH_CHECK(igraph_i_trans4_il_simplify(graph, &allinc, &rank));
+
+  neis=igraph_Calloc(no_of_nodes, long int);
+  if (neis==0) {
+    IGRAPH_ERROR("undirected local transitivity failed", IGRAPH_ENOMEM);
+  }
+  IGRAPH_FINALLY(igraph_free, neis);
+
+  IGRAPH_CHECK(igraph_strength(graph, res, igraph_vss_all(), IGRAPH_ALL,
+			       IGRAPH_LOOPS, weights));
+
+  for (nn=no_of_nodes-1; nn>=0; nn--) {
+    node=VECTOR(order)[nn];
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    neis1=igraph_inclist_get(&allinc, node);
+    neilen1=igraph_vector_int_size(neis1);
+
+    /* Mark the neighbors of the node */
+    for (i=0; i<neilen1; i++) {
+      int edge = VECTOR(*neis1)[i];
+      int nei = IGRAPH_OTHER(graph, edge, node);
+      VECTOR(*edge1)[nei] = VECTOR(*weights)[edge];
+      neis[nei] = node+1;
+    }
+
+    for (i=0; i<neilen1; i++) {
+      long int edge=VECTOR(*neis1)[i];
+      long int nei=IGRAPH_OTHER(graph, edge, node);
+      igraph_real_t w=VECTOR(*weights)[edge];
+      neis2=igraph_inclist_get(&allinc, nei);
+      neilen2=igraph_vector_int_size(neis2);
+      for (j=0; j<neilen2; j++) {
+	long int edge2=VECTOR(*neis2)[j];
+	long int nei2=IGRAPH_OTHER(graph, edge2, nei);
+	igraph_real_t w2=VECTOR(*weights)[edge2];
+	if (neis[nei2] == node+1) {
+	  VECTOR(*res)[node] += w2;
+	  VECTOR(*res)[nei2] += w;
+	  VECTOR(*res)[nei] += VECTOR(*edge1)[nei2];
+	}
+      }
+    }
+  }
+
+  igraph_free(neis);
+  igraph_inclist_destroy(&allinc);
+  igraph_vector_int_destroy(&rank);
+  igraph_vector_destroy(&degree);
+  igraph_vector_int_destroy(&order);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \function igraph_local_scan_1_ecount
+ * Local scan-statistics, k=1, edge count and sum of weights
+ * 
+ * Count the number of edges or the sum the edge weights in the
+ * 1-neighborhood of vertices.
+ * 
+ * \param graph The input graph
+ * \param res An initialized vector, the results are stored here.
+ * \param weights Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,
+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.
+ * \return Error code.
+ * 
+ */
+
+int igraph_local_scan_1_ecount(const igraph_t *graph, igraph_vector_t *res,
+			       const igraph_vector_t *weights,
+			       igraph_neimode_t mode) {
+
+  if (igraph_is_directed(graph)) {
+    if (mode != IGRAPH_ALL) {
+      return igraph_i_local_scan_1_directed(graph, res, weights, mode);
+    } else {
+      return igraph_i_local_scan_1_directed_all(graph, res, weights);
+    }
+  } else {
+    if (weights) {
+      return igraph_i_local_scan_1_sumweights(graph, res, weights);
+    } else {
+
+#define TRIEDGES
+#include "triangles_template.h"
+#undef TRIEDGES
+
+    }
+  }
+
+  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) {
+
+  igraph_t is;
+  igraph_vector_t map2;
+  int i, m;
+
+  if (!weights_them) {
+    IGRAPH_ERROR("Edge weights not given for weighted scan-0",
+		 IGRAPH_EINVAL);
+  }
+  if (igraph_vector_size(weights_them) != igraph_ecount(them)) {
+    IGRAPH_ERROR("Invalid weights length for scan-0", IGRAPH_EINVAL);
+  }
+
+  IGRAPH_VECTOR_INIT_FINALLY(&map2, 0);
+  igraph_intersection(&is, us, them, /*map1=*/ 0, &map2);
+  IGRAPH_FINALLY(igraph_destroy, &is);
+
+  /* Rewrite the map as edge weights */
+  m=igraph_vector_size(&map2);
+  for (i=0; i<m; i++) {
+    VECTOR(map2)[i] = VECTOR(*weights_them)[ (int) VECTOR(map2)[i] ];
+  }
+
+  igraph_strength(&is, res, igraph_vss_all(), mode, IGRAPH_LOOPS,
+		  /*weights=*/ &map2);
+
+  igraph_destroy(&is);
+  igraph_vector_destroy(&map2);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
+
+/**
+ * \function igraph_local_scan_0_them
+ * Local THEM scan-statistics, k=0
+ * 
+ * K=0 scan-statistics is arbitrarily defined as the vertex degree for
+ * unweighted, and the vertex strength for weighted graphs. See \ref
+ * igraph_degree() and \ref igraph_strength().
+ * 
+ * \param us The input graph, to use to extract the neighborhoods.
+ * \param them The input graph to use for the actually counting.
+ * \param res An initialized vector, the results are stored here.
+ * \param weights_them Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,
+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.
+ * \return Error code.
+ * 
+ */
+
+int igraph_local_scan_0_them(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;
+
+  if (igraph_vcount(us) != igraph_vcount(them)) {
+    IGRAPH_ERROR("Number of vertices don't match in scan-0", IGRAPH_EINVAL);
+  }
+  if (igraph_is_directed(us) != igraph_is_directed(them)) {
+    IGRAPH_ERROR("Directedness don't match in scan-0", IGRAPH_EINVAL);
+  }
+
+  if (weights_them) {
+    return igraph_i_local_scan_0_them_w(us, them, res, weights_them, mode);
+  }
+
+  igraph_intersection(&is, us, them, /*edgemap1=*/ 0, /*edgemap2=*/ 0);
+  IGRAPH_FINALLY(igraph_destroy, &is);
+
+  igraph_degree(&is, res, igraph_vss_all(), mode, IGRAPH_LOOPS);
+
+  igraph_destroy(&is);
+  IGRAPH_FINALLY_CLEAN(1);
+
+  return 0;
+}
+
+/**
+ * \function igraph_local_scan_1_ecount_them
+ * Local THEM scan-statistics, k=1, edge count and sum of weights
+ * 
+ * Count the number of edges or the sum the edge weights in the
+ * 1-neighborhood of vertices.
+ * 
+ * \param us The input graph to extract the neighborhoods.
+ * \param them The input graph to perform the counting.
+ * \param weights_them Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,
+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_local_scan_1_ecount() for the US statistics.
+ */
+
+int igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_t *them,
+				    igraph_vector_t *res,
+				    const igraph_vector_t *weights_them,
+				    igraph_neimode_t mode) {
+
+  int no_of_nodes=igraph_vcount(us);
+  igraph_adjlist_t adj_us;
+  igraph_inclist_t incs_them;
+  igraph_vector_int_t neis;
+  int node;
+
+  if (igraph_vcount(them) != no_of_nodes) {
+    IGRAPH_ERROR("Number of vertices must match in scan-1", IGRAPH_EINVAL);
+  }
+  if (igraph_is_directed(us) != igraph_is_directed(them)) {
+    IGRAPH_ERROR("Directedness must match in scan-1", IGRAPH_EINVAL);
+  }
+  if (weights_them &&
+      igraph_vector_size(weights_them) != igraph_ecount(them)) {
+    IGRAPH_ERROR("Invalid weight vector length in scan-1 (them)",
+		 IGRAPH_EINVAL);
+  }
+
+  igraph_adjlist_init(us, &adj_us, mode);
+  IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_us);
+  igraph_adjlist_simplify(&adj_us);
+  igraph_inclist_init(them, &incs_them, mode);
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs_them);
+
+  igraph_vector_int_init(&neis, no_of_nodes);
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);
+
+  igraph_vector_resize(res, no_of_nodes);
+  igraph_vector_null(res);
+
+  for (node=0; node < no_of_nodes; node++) {
+    igraph_vector_int_t *neis_us=igraph_adjlist_get(&adj_us, node);
+    igraph_vector_int_t *edges1_them=igraph_inclist_get(&incs_them, node);
+    int len1_us=igraph_vector_int_size(neis_us);
+    int len1_them=igraph_vector_int_size(edges1_them);
+    int i;
+
+    IGRAPH_ALLOW_INTERRUPTION();
+
+    /* Mark neighbors and self in us */
+    VECTOR(neis)[node] = node+1;
+    for (i = 0; i < len1_us; i++) {
+      int nei=VECTOR(*neis_us)[i];
+      VECTOR(neis)[nei] = node+1;
+    }
+
+    /* Crawl neighbors in them, first ego */
+    for (i = 0; i < len1_them; i++) {
+      int e=VECTOR(*edges1_them)[i];
+      int nei=IGRAPH_OTHER(them, e, node);
+      if (VECTOR(neis)[nei] == node+1) {
+	igraph_real_t w=weights_them ? VECTOR(*weights_them)[e] : 1;
+	VECTOR(*res)[node] += w;
+      }
+    }
+    /* Then the rest */
+    for (i = 0; i < len1_us; i++) {
+      int nei=VECTOR(*neis_us)[i];
+      igraph_vector_int_t *edges2_them=igraph_inclist_get(&incs_them, nei);
+      int j, len2_them=igraph_vector_int_size(edges2_them);
+      for (j = 0; j < len2_them; j++) {
+	int e2=VECTOR(*edges2_them)[j];
+	int nei2=IGRAPH_OTHER(them, e2, nei);
+	if (VECTOR(neis)[nei2] == node+1) {
+	  igraph_real_t w=weights_them ? VECTOR(*weights_them)[e2] : 1;
+	  VECTOR(*res)[node] += w;
+	}
+      }
+    }
+
+    /* For undirected, it was double counted */
+    if (mode == IGRAPH_ALL || ! igraph_is_directed(us)) {
+      VECTOR(*res)[node] /= 2.0;
+    }
+
+  } /* node < no_of_nodes */
+
+  igraph_vector_int_destroy(&neis);
+  igraph_inclist_destroy(&incs_them);
+  igraph_adjlist_destroy(&adj_us);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \function igraph_local_scan_k_ecount
+ * Local scan-statistics, general function, edge count and sum of weights
+ * 
+ * Count the number of edges or the sum the edge weights in the
+ * k-neighborhood of vertices.
+ * 
+ * \param graph The input graph
+ * \param k The size of the neighborhood, non-negative integer. 
+ *        The k=0 case is special, see \ref igraph_local_scan_0().
+ * \param res An initialized vector, the results are stored here.
+ * \param weights Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,
+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.
+ * \return Error code.
+ * 
+ */
+
+int igraph_local_scan_k_ecount(const igraph_t *graph, int k,
+			       igraph_vector_t *res,
+			       const igraph_vector_t *weights,
+			       igraph_neimode_t mode) {
+
+  int no_of_nodes=igraph_vcount(graph);
+  int node;
+  igraph_dqueue_int_t Q;
+  igraph_vector_int_t marked;
+  igraph_inclist_t incs;
+
+  if (k < 0) {
+    IGRAPH_ERROR("k must be non-negative in k-scan", IGRAPH_EINVAL);
+  }
+  if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length in k-scan", IGRAPH_EINVAL);
+  }
+
+  if (k==0) { return igraph_local_scan_0(graph, res, weights, mode); }
+  if (k==1) { return igraph_local_scan_1_ecount(graph, res, weights, mode); }
+
+  /* We do a BFS form each node, and simply count the number
+     of edges on the way */
+
+  IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q);
+  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
+  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, mode));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+  igraph_vector_null(res);
+
+  for (node=0 ; node < no_of_nodes ; node++) {
+    igraph_dqueue_int_push(&Q, node);
+    igraph_dqueue_int_push(&Q, 0);
+    VECTOR(marked)[node] = node+1;
+    while (!igraph_dqueue_int_empty(&Q)) {
+      int act=igraph_dqueue_int_pop(&Q);
+      int dist=igraph_dqueue_int_pop(&Q) + 1;
+      igraph_vector_int_t *edges=igraph_inclist_get(&incs, act);
+      int i, edgeslen=igraph_vector_int_size(edges);
+      for (i=0; i<edgeslen; i++) {
+	int edge=VECTOR(*edges)[i];
+	int nei=IGRAPH_OTHER(graph, edge, act);
+	if (dist <= k || VECTOR(marked)[nei] == node+1) {
+	  igraph_real_t w=weights ? VECTOR(*weights)[edge] : 1;
+	  VECTOR(*res)[node] += w;
+	}
+	if (dist <= k && VECTOR(marked)[nei] != node+1) {
+	  igraph_dqueue_int_push(&Q, nei);
+	  igraph_dqueue_int_push(&Q, dist);
+	  VECTOR(marked)[nei] = node+1;
+	}
+      }
+    }
+
+    if (mode == IGRAPH_ALL || ! igraph_is_directed(graph)) {
+      VECTOR(*res)[node] /= 2.0;
+    }
+
+  } /* node < no_of_nodes */
+
+  igraph_inclist_destroy(&incs);
+  igraph_vector_int_destroy(&marked);
+  igraph_dqueue_int_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(3);
+
+  return 0;
+}
+
+/**
+ * \function igraph_local_scan_k_ecount_them
+ * Local THEM scan-statistics, general function, edge count and sum of weights
+ *
+ * Count the number of edges or the sum the edge weights in the
+ * k-neighborhood of vertices.
+ * 
+ * \param us The input graph to extract the neighborhoods.
+ * \param them The input graph to perform the counting.
+ * \param k The size of the neighborhood, non-negative integer. 
+ *        The k=0 case is special, see \ref igraph_local_scan_0_them().
+ * \param weights_them Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,
+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.
+ * \return Error code.
+ * 
+ * \sa \ref igraph_local_scan_1_ecount() for the US statistics.
+ */
+
+int igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them,
+				    int k, igraph_vector_t *res,
+				    const igraph_vector_t *weights_them,
+				    igraph_neimode_t mode) {
+
+  int no_of_nodes=igraph_vcount(us);
+  int node;
+  igraph_dqueue_int_t Q;
+  igraph_vector_int_t marked;
+  igraph_stack_int_t ST;
+  igraph_inclist_t incs_us, incs_them;
+
+  if (igraph_vcount(them) != no_of_nodes) {
+    IGRAPH_ERROR("Number of vertices must match in scan-k", IGRAPH_EINVAL);
+  }
+  if (igraph_is_directed(us) != igraph_is_directed(them)) {
+    IGRAPH_ERROR("Directedness must match in scan-k", IGRAPH_EINVAL);
+  }
+  if (k < 0) {
+    IGRAPH_ERROR("k must be non-negative in k-scan", IGRAPH_EINVAL);
+  }
+  if (weights_them &&
+      igraph_vector_size(weights_them) != igraph_ecount(them)) {
+    IGRAPH_ERROR("Invalid weight vector length in k-scan (them)",
+		 IGRAPH_EINVAL);
+  }
+
+  if (k==0) {
+    return igraph_local_scan_0_them(us, them, res, weights_them, mode);
+  }
+  if (k==1) {
+    return igraph_local_scan_1_ecount_them(us, them, res, weights_them, mode);
+  }
+
+  /* We mark the nodes in US in a BFS. Then we check the outgoing edges
+     of all marked nodes in THEM. */
+
+  IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100));
+  IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q);
+  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
+  IGRAPH_CHECK(igraph_inclist_init(us, &incs_us, mode));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs_us);
+  IGRAPH_CHECK(igraph_inclist_init(them, &incs_them, mode));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs_them);
+  IGRAPH_CHECK(igraph_stack_int_init(&ST, 100));
+  IGRAPH_FINALLY(igraph_stack_int_destroy, &ST);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+  igraph_vector_null(res);
+
+  for (node=0; node < no_of_nodes; node++) {
+
+    /* BFS to mark the nodes in US */
+    IGRAPH_CHECK(igraph_dqueue_int_push(&Q, node));
+    IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0));
+    IGRAPH_CHECK(igraph_stack_int_push(&ST, node));
+    VECTOR(marked)[node] = node+1;
+    while (!igraph_dqueue_int_empty(&Q)) {
+      int act=igraph_dqueue_int_pop(&Q);
+      int dist=igraph_dqueue_int_pop(&Q) + 1;
+      igraph_vector_int_t *edges=igraph_inclist_get(&incs_us, act);
+      int i, edgeslen=igraph_vector_int_size(edges);
+      for (i=0; i<edgeslen; i++) {
+	int edge=VECTOR(*edges)[i];
+	int nei=IGRAPH_OTHER(us, edge, act);
+	if (dist <= k && VECTOR(marked)[nei] != node+1) {
+	  igraph_dqueue_int_push(&Q, nei);
+	  igraph_dqueue_int_push(&Q, dist);
+	  VECTOR(marked)[nei] = node+1;
+	  igraph_stack_int_push(&ST, nei);
+	}
+      }
+    }
+
+    /* Now check the edges of all nodes in THEM */
+    while (!igraph_stack_int_empty(&ST)) {
+      int act=igraph_stack_int_pop(&ST);
+      igraph_vector_int_t *edges=igraph_inclist_get(&incs_them, act);
+      int i, edgeslen=igraph_vector_int_size(edges);
+      for (i=0; i<edgeslen; i++) {
+	int edge=VECTOR(*edges)[i];
+	int nei=IGRAPH_OTHER(them, edge, act);
+	if (VECTOR(marked)[nei] == node+1) {
+	  igraph_real_t w=weights_them ? VECTOR(*weights_them)[edge] : 1;
+	  VECTOR(*res)[node] += w;
+	}
+      }
+    }
+
+    if (mode == IGRAPH_ALL || ! igraph_is_directed(us)) {
+      VECTOR(*res)[node] /= 2;
+    }
+
+  } /* node < no_of_nodes */
+
+  igraph_stack_int_destroy(&ST);
+  igraph_inclist_destroy(&incs_them);
+  igraph_inclist_destroy(&incs_us);
+  igraph_vector_int_destroy(&marked);
+  igraph_dqueue_int_destroy(&Q);
+  IGRAPH_FINALLY_CLEAN(5);
+
+  return 0;
+}
+
+/**
+ * \function igraph_local_scan_neighborhood_ecount
+ * Local scan-statistics with pre-calculated neighborhoods
+ * 
+ * Count the number of edges, or sum the edge weigths in 
+ * neighborhoods given as a parameter.
+ * 
+ * \param graph The graph to perform the counting/summing in.
+ * \param res Initialized vector, the result is stored here.
+ * \param weights Weight vector for weighted graphs, null pointer for
+ *        unweighted graphs.
+ * \param neighborhoods List of <code>igraph_vector_int_t</code>
+ *        objects, the neighborhoods, one for each vertex in the
+ *        graph.
+ * \return Error code.
+ */
+
+int igraph_local_scan_neighborhood_ecount(const igraph_t *graph,
+			  igraph_vector_t *res,
+			  const igraph_vector_t *weights,
+			  const igraph_vector_ptr_t *neighborhoods) {
+
+  int node, no_of_nodes=igraph_vcount(graph);
+  igraph_inclist_t incs;
+  igraph_vector_int_t marked;
+  igraph_bool_t directed=igraph_is_directed(graph);
+
+  if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {
+    IGRAPH_ERROR("Invalid weight vector length in local scan", IGRAPH_EINVAL);
+  }
+  if (igraph_vector_ptr_size(neighborhoods) != no_of_nodes) {
+    IGRAPH_ERROR("Invalid neighborhood list length in local scan",
+		 IGRAPH_EINVAL);
+  }
+
+  IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));
+  IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);
+  IGRAPH_CHECK(igraph_inclist_init(graph, &incs, IGRAPH_OUT));
+  IGRAPH_FINALLY(igraph_inclist_destroy, &incs);
+
+  IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
+  igraph_vector_null(res);
+
+  for (node=0; node < no_of_nodes; node++) {
+    igraph_vector_int_t *nei=VECTOR(*neighborhoods)[node];
+    int i, neilen=igraph_vector_int_size(nei);
+    VECTOR(marked)[node] = node + 1;
+    for (i=0; i<neilen; i++) {
+      int vertex=VECTOR(*nei)[i];
+      if (vertex < 0 || vertex >= no_of_nodes) {
+	IGRAPH_ERROR("Invalid vertex id in neighborhood list in local scan",
+		     IGRAPH_EINVAL);
+      }
+      VECTOR(marked)[vertex] = node + 1;
+    }
+
+    for (i=0; i<neilen; i++) {
+      int vertex=VECTOR(*nei)[i];
+      igraph_vector_int_t *edges=igraph_inclist_get(&incs, vertex);
+      int j, edgeslen=igraph_vector_int_size(edges);
+      for (j=0; j<edgeslen; j++) {
+	int edge=VECTOR(*edges)[j];
+	int nei2=IGRAPH_OTHER(graph, edge, vertex);
+	if (VECTOR(marked)[nei2] == node+1) {
+	  igraph_real_t w = weights ? VECTOR(*weights)[edge] : 1;
+	  VECTOR(*res)[node] += w;
+	}
+      }
+    }
+    if (!directed) { VECTOR(*res)[node] /= 2.0; }
+  }
+
+  igraph_inclist_destroy(&incs);
+  igraph_vector_int_destroy(&marked);
+  IGRAPH_FINALLY_CLEAN(2);
+
+  return 0;
+}
diff --git a/src/Color.cpp b/src/simpleraytracer/Color.cpp
similarity index 100%
rename from src/Color.cpp
rename to src/simpleraytracer/Color.cpp
diff --git a/src/Color.h b/src/simpleraytracer/Color.h
similarity index 100%
rename from src/Color.h
rename to src/simpleraytracer/Color.h
diff --git a/src/Light.cpp b/src/simpleraytracer/Light.cpp
similarity index 100%
rename from src/Light.cpp
rename to src/simpleraytracer/Light.cpp
diff --git a/src/Light.h b/src/simpleraytracer/Light.h
similarity index 100%
rename from src/Light.h
rename to src/simpleraytracer/Light.h
diff --git a/src/Point.cpp b/src/simpleraytracer/Point.cpp
similarity index 100%
rename from src/Point.cpp
rename to src/simpleraytracer/Point.cpp
diff --git a/src/Point.h b/src/simpleraytracer/Point.h
similarity index 100%
rename from src/Point.h
rename to src/simpleraytracer/Point.h
diff --git a/src/RIgraphRay.cpp b/src/simpleraytracer/RIgraphRay.cpp
similarity index 100%
rename from src/RIgraphRay.cpp
rename to src/simpleraytracer/RIgraphRay.cpp
diff --git a/src/Ray.cpp b/src/simpleraytracer/Ray.cpp
similarity index 100%
rename from src/Ray.cpp
rename to src/simpleraytracer/Ray.cpp
diff --git a/src/Ray.h b/src/simpleraytracer/Ray.h
similarity index 100%
rename from src/Ray.h
rename to src/simpleraytracer/Ray.h
diff --git a/src/RayTracer.cpp b/src/simpleraytracer/RayTracer.cpp
similarity index 100%
rename from src/RayTracer.cpp
rename to src/simpleraytracer/RayTracer.cpp
diff --git a/src/RayTracer.h b/src/simpleraytracer/RayTracer.h
similarity index 100%
rename from src/RayTracer.h
rename to src/simpleraytracer/RayTracer.h
diff --git a/src/RayVector.cpp b/src/simpleraytracer/RayVector.cpp
similarity index 100%
rename from src/RayVector.cpp
rename to src/simpleraytracer/RayVector.cpp
diff --git a/src/RayVector.h b/src/simpleraytracer/RayVector.h
similarity index 100%
rename from src/RayVector.h
rename to src/simpleraytracer/RayVector.h
diff --git a/src/Shape.cpp b/src/simpleraytracer/Shape.cpp
similarity index 100%
rename from src/Shape.cpp
rename to src/simpleraytracer/Shape.cpp
diff --git a/src/Shape.h b/src/simpleraytracer/Shape.h
similarity index 100%
rename from src/Shape.h
rename to src/simpleraytracer/Shape.h
diff --git a/src/Sphere.cpp b/src/simpleraytracer/Sphere.cpp
similarity index 100%
rename from src/Sphere.cpp
rename to src/simpleraytracer/Sphere.cpp
diff --git a/src/Sphere.h b/src/simpleraytracer/Sphere.h
similarity index 100%
rename from src/Sphere.h
rename to src/simpleraytracer/Sphere.h
diff --git a/src/Triangle.cpp b/src/simpleraytracer/Triangle.cpp
similarity index 100%
rename from src/Triangle.cpp
rename to src/simpleraytracer/Triangle.cpp
diff --git a/src/Triangle.h b/src/simpleraytracer/Triangle.h
similarity index 100%
rename from src/Triangle.h
rename to src/simpleraytracer/Triangle.h
diff --git a/src/unit_limiter.cpp b/src/simpleraytracer/unit_limiter.cpp
similarity index 100%
rename from src/unit_limiter.cpp
rename to src/simpleraytracer/unit_limiter.cpp
diff --git a/src/unit_limiter.h b/src/simpleraytracer/unit_limiter.h
similarity index 100%
rename from src/unit_limiter.h
rename to src/simpleraytracer/unit_limiter.h
diff --git a/src/sparsemat.c b/src/sparsemat.c
index f96d022..c040900 100644
--- a/src/sparsemat.c
+++ b/src/sparsemat.c
@@ -2234,6 +2234,323 @@ int igraph_sparsemat_rowsums(const igraph_sparsemat_t *A,
   }
 }
 
+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;
+  double inf=IGRAPH_INFINITY;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  igraph_vector_fill(res, inf);
+  
+  for (i=0; i<A->cs->nz; i++, pi++, px++) {
+    if (*px < VECTOR(*res)[ *pi ]) { VECTOR(*res)[ *pi ] = *px; }
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_rowmins_cc(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;
+  double inf=IGRAPH_INFINITY;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  igraph_vector_fill(res, inf);
+  
+  for (; pi < A->cs->i+ne; pi++, px++) {
+    if (*px < VECTOR(*res)[ *pi ]) { VECTOR(*res)[ *pi ] = *px; }
+  }
+
+  return 0;
+}
+
+int igraph_sparsemat_rowmins(igraph_sparsemat_t *A, 
+			     igraph_vector_t *res) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_rowmins_triplet(A, res);
+  } else {
+    return igraph_i_sparsemat_rowmins_cc(A, res);
+  }
+}
+
+
+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;
+  double inf=IGRAPH_NEGINFINITY;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  igraph_vector_fill(res, inf);
+  
+  for (i=0; i<A->cs->nz; i++, pi++, px++) {
+    if (*px > VECTOR(*res)[ *pi ]) { VECTOR(*res)[ *pi ] = *px; }
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_rowmaxs_cc(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;
+  double inf=IGRAPH_NEGINFINITY;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+  
+
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  igraph_vector_fill(res, inf);
+  
+  for (; pi < A->cs->i+ne; pi++, px++) {
+    if (*px > VECTOR(*res)[ *pi ]) { VECTOR(*res)[ *pi ] = *px; }
+  }
+
+  return 0;
+}
+
+int igraph_sparsemat_rowmaxs(igraph_sparsemat_t *A, 
+			     igraph_vector_t *res) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_rowmaxs_triplet(A, res);
+  } else {
+    return igraph_i_sparsemat_rowmaxs_cc(A, res);
+  }
+}
+
+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;
+  double inf=IGRAPH_INFINITY;
+
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));
+  igraph_vector_fill(res, inf);
+  
+  for (i=0; i<A->cs->nz; i++, pp++, px++) {
+    if (*px < VECTOR(*res)[ *pp ]) { VECTOR(*res)[ *pp ] = *px; }
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_colmins_cc(igraph_sparsemat_t *A,
+				  igraph_vector_t *res) {
+  int n=A->cs->n;
+  double *px=A->cs->x;
+  int *pp=A->cs->p;
+  int *pi=A->cs->i;
+  double *pr;
+  double inf=IGRAPH_INFINITY;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+    
+  IGRAPH_CHECK(igraph_vector_resize(res, n));
+  igraph_vector_fill(res, inf);
+  pr=VECTOR(*res);
+  
+  for (; pp < A->cs->p + n; pp++, pr++) {
+    for (; pi < A->cs->i + *(pp+1); pi++, px++) {
+      if (*px < *pr) { *pr = *px; }
+    }
+  }
+  return 0;
+}
+
+int igraph_sparsemat_colmins(igraph_sparsemat_t *A, 
+			     igraph_vector_t *res) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_colmins_triplet(A, res);
+  } else {
+    return igraph_i_sparsemat_colmins_cc(A, res);
+  }
+}
+
+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;
+  double inf=IGRAPH_NEGINFINITY;
+
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));
+  igraph_vector_fill(res, inf);
+  
+  for (i=0; i<A->cs->nz; i++, pp++, px++) {
+    if (*px > VECTOR(*res)[ *pp ]) { VECTOR(*res)[ *pp ] = *px; }
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_colmaxs_cc(igraph_sparsemat_t *A,
+				  igraph_vector_t *res) {
+  int n=A->cs->n;
+  double *px=A->cs->x;
+  int *pp=A->cs->p;
+  int *pi=A->cs->i;
+  double *pr;
+  double inf=IGRAPH_NEGINFINITY;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+    
+  IGRAPH_CHECK(igraph_vector_resize(res, n));
+  igraph_vector_fill(res, inf);
+  pr=VECTOR(*res);
+  
+  for (; pp < A->cs->p + n; pp++, pr++) {
+    for (; pi < A->cs->i + *(pp+1); pi++, px++) {
+      if (*px > *pr) { *pr = *px; }
+    }
+  }
+  return 0;
+}
+
+int igraph_sparsemat_colmaxs(igraph_sparsemat_t *A, 
+			     igraph_vector_t *res) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_colmaxs_triplet(A, res);
+  } else {
+    return igraph_i_sparsemat_colmaxs_cc(A, res);
+  }
+}
+
+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;
+  double *px = A->cs->x;
+  double inf = IGRAPH_INFINITY;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  IGRAPH_CHECK(igraph_vector_int_resize(pos, A->cs->m));
+  igraph_vector_fill(res, inf);
+  igraph_vector_int_null(pos);
+  
+  for (i = 0; i < A->cs->nz; i++, pi++, px++, pp++) {
+    if (*px < VECTOR(*res)[ *pi ]) {
+      VECTOR(*res)[ *pi ] = *px;
+      VECTOR(*pos)[ *pi ] = *pp;
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_which_min_rows_cc(igraph_sparsemat_t *A,
+					 igraph_vector_t *res,
+					 igraph_vector_int_t *pos) {
+  int n=A->cs->n;
+  double *px = A->cs->x;
+  int *pp=A->cs->p;
+  int *pi = A->cs->i;
+  double inf = IGRAPH_INFINITY;
+  int j;
+  
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));
+  IGRAPH_CHECK(igraph_vector_int_resize(pos, A->cs->m));
+  igraph_vector_fill(res, inf);
+  igraph_vector_int_null(pos);
+
+  for (j=0; pp < A->cs->p + n; pp++, j++) {
+    for (; pi < A->cs->i + *(pp+1); pi++, px++) {
+      if (*px < VECTOR(*res)[ *pi ]) {
+	VECTOR(*res)[ *pi ] = *px;
+	VECTOR(*pos)[ *pi ] = j;
+      }
+    }
+   }
+
+  return 0;
+}
+
+int igraph_sparsemat_which_min_rows(igraph_sparsemat_t *A,
+				    igraph_vector_t *res,
+				    igraph_vector_int_t *pos) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_which_min_rows_triplet(A, res, pos);
+  } else {
+    return igraph_i_sparsemat_which_min_rows_cc(A, res, pos);
+  }
+}
+
+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;
+  int *pp = A->cs->p;
+  double *px = A->cs->x;
+  double inf = IGRAPH_INFINITY;
+  
+  IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));
+  IGRAPH_CHECK(igraph_vector_int_resize(pos, A->cs->n));
+  igraph_vector_fill(res, inf);
+  igraph_vector_int_null(pos);
+  
+  for (i = 0; i < A->cs->nz; i++, pi++, pp++, px++) {
+    if (*px < VECTOR(*res)[ *pp ]) {
+      VECTOR(*res)[ *pp ] = *px;
+      VECTOR(*pos)[ *pp ] = *pi;
+    }
+  }
+  
+  return 0;
+}
+
+int igraph_i_sparsemat_which_min_cols_cc(igraph_sparsemat_t *A,
+					 igraph_vector_t *res,
+					 igraph_vector_int_t *pos) {
+  int n=A->cs->n, j, p;
+  double *px=A->cs->x;
+  double *pr;
+  int *ppos;
+  double inf=IGRAPH_INFINITY;
+
+  IGRAPH_CHECK(igraph_sparsemat_dupl(A));
+    
+  IGRAPH_CHECK(igraph_vector_resize(res, n));
+  igraph_vector_fill(res, inf);
+  pr=VECTOR(*res);
+  IGRAPH_CHECK(igraph_vector_int_resize(pos, n));
+  igraph_vector_int_null(pos);
+  ppos=VECTOR(*pos);
+  
+  for (j = 0; j < A->cs->n; j++, pr++, ppos++) {
+    for (p = A->cs->p[j]; p < A->cs->p[j+1]; p++, px++) {
+      if (*px < *pr) { 
+	*pr = *px;
+	*ppos = A->cs->i[p];
+      }
+    }
+  }
+  return 0;
+}
+
+int igraph_sparsemat_which_min_cols(igraph_sparsemat_t *A,
+				    igraph_vector_t *res,
+				    igraph_vector_int_t *pos) {
+  if (igraph_sparsemat_is_triplet(A)) {
+    return igraph_i_sparsemat_which_min_cols_triplet(A, res, pos);
+  } else {
+    return igraph_i_sparsemat_which_min_cols_cc(A, res, pos);
+  }
+}
+
 int igraph_i_sparsemat_colsums_triplet(const igraph_sparsemat_t *A,
 				       igraph_vector_t *res) {
   int i;
diff --git a/src/stack.pmt b/src/stack.pmt
index e8b8eaa..fcaac08 100644
--- a/src/stack.pmt
+++ b/src/stack.pmt
@@ -23,7 +23,6 @@
 
 #include "igraph_types.h"
 #include "igraph_memory.h"
-#include "igraph_random.h"
 #include "igraph_error.h"
 #include "config.h"
 
diff --git a/src/structural_properties.c b/src/structural_properties.c
index 61a264f..2bac756 100644
--- a/src/structural_properties.c
+++ b/src/structural_properties.c
@@ -1577,7 +1577,7 @@ int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode) {
     if (num_swaps % 1000 == 0) {
       snprintf(message, sizeof(message),
           "Random rewiring (%.2f%% of the trials were successful)",
-          (100.0 * num_successful_swaps) / num_swaps);
+          num_swaps > 0 ? ((100.0 * num_successful_swaps) / num_swaps) : 0.0);
       IGRAPH_PROGRESS(message, (100.0 * num_swaps) / n, 0);
     }
     
@@ -2574,7 +2574,7 @@ int igraph_constraint(const igraph_t *graph, igraph_vector_t *res,
 
     /* add the indirect contributions, in-in, in-out, out-in, out-out */
     for (b=0; b<igraph_vector_size(&ineis_in); b++) {
-      edge=(igraph_integer_t) VECTOR(ineis_out)[b];
+      edge=(igraph_integer_t) VECTOR(ineis_in)[b];
       igraph_edge(graph, edge, &from, &to);
       if (to==i) { to=from; }
       j=to;
@@ -2826,6 +2826,9 @@ int igraph_density(const igraph_t *graph, igraph_real_t *res,
  *   all vertices from which the source vertex is reachable in at most
  *   \c 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
+ *   two, then its neighbors are not counted, either, etc.
  * \return Error code.
  * 
  * \sa \ref igraph_neighborhood() for calculating the actual neighborhood, 
@@ -2838,7 +2841,8 @@ int igraph_density(const igraph_t *graph, igraph_real_t *res,
 
 int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
 			     igraph_vs_t vids, igraph_integer_t order,
-			     igraph_neimode_t mode) {
+			     igraph_neimode_t mode,
+			     igraph_integer_t mindist) {
 
   long int no_of_nodes=igraph_vcount(graph);
   igraph_dqueue_t q;
@@ -2851,6 +2855,11 @@ int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
     IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
   }
 
+  if (mindist < 0 || mindist > order) {
+    IGRAPH_ERROR("Minimum distance should be between zero and order",
+		 IGRAPH_EINVAL);
+  }
+
   added=igraph_Calloc(no_of_nodes, long int);
   if (added==0) {
     IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
@@ -2864,7 +2873,7 @@ int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
   
   for (i=0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {
     long int node=IGRAPH_VIT_GET(vit);
-    long int size=1;
+    long int size=mindist==0 ? 1 : 0;
     added[node]=i+1;
     igraph_dqueue_clear(&q);
     if (order > 0) {
@@ -2887,7 +2896,7 @@ int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
 	    added[nei]=i+1;
 	    IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
 	    IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
-	    size++;
+	    if (actdist+1 >= mindist) { size++; }
 	  }
 	}
       } else {
@@ -2896,7 +2905,7 @@ int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
 	  long int nei=(long int) VECTOR(neis)[j];
 	  if (added[nei] != i+1) {
 	    added[nei]=i+1;
-	    size++;
+	    if (actdist+1 >= mindist) { size++; }
 	  }
 	}
       }
@@ -2941,6 +2950,9 @@ int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
  *   all vertices from which the source vertex is reachable in at most
  *   \c 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
+ *   two, then its neighbors are not counted, either, etc.
  * \return Error code.
  * 
  * \sa \ref igraph_neighborhood_size() to calculate the size of the
@@ -2954,7 +2966,7 @@ int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,
 
 int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
 			igraph_vs_t vids, igraph_integer_t order,
-			igraph_neimode_t mode) {
+			igraph_neimode_t mode, igraph_integer_t mindist) {
   
   long int no_of_nodes=igraph_vcount(graph);
   igraph_dqueue_t q;
@@ -2969,6 +2981,11 @@ int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
     IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
   }
   
+  if (mindist < 0 || mindist > order) {
+    IGRAPH_ERROR("Minimum distance should be between zero and order",
+		 IGRAPH_EINVAL);
+  }
+
   added=igraph_Calloc(no_of_nodes, long int);
   if (added==0) {
     IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);
@@ -2985,7 +3002,7 @@ int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
     long int node=IGRAPH_VIT_GET(vit);
     added[node]=i+1;
     igraph_vector_clear(&tmp);
-    IGRAPH_CHECK(igraph_vector_push_back(&tmp, node));
+    if (mindist == 0) { IGRAPH_CHECK(igraph_vector_push_back(&tmp, node)); }
     if (order > 0) {
       igraph_dqueue_push(&q, node);
       igraph_dqueue_push(&q, 0);
@@ -3006,7 +3023,9 @@ int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
 	    added[nei]=i+1;
 	    IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
 	    IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
-	    IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    if (actdist+1 >= mindist) { 
+	      IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    }
 	  }
 	}
       } else {
@@ -3015,7 +3034,9 @@ int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
 	  long int nei=(long int) VECTOR(neis)[j];
 	  if (added[nei] != i+1) {
 	    added[nei]=i+1;
-	    IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    if (actdist+1 >= mindist) { 
+	      IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    }
 	  }
 	}
       }
@@ -3072,6 +3093,9 @@ int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
  *   all vertices from which the source vertex is reachable in at most
  *   \c 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
+ *   two, then its neighbors are not counted, either, etc.
  * \return Error code.
  * 
  * \sa \ref igraph_neighborhood_size() for calculating the neighborhood
@@ -3085,7 +3109,8 @@ int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,
 
 int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
 			       igraph_vs_t vids, igraph_integer_t order,
-			       igraph_neimode_t mode) {
+			       igraph_neimode_t mode,
+			       igraph_integer_t mindist) {
   long int no_of_nodes=igraph_vcount(graph);
   igraph_dqueue_t q;
   igraph_vit_t vit;
@@ -3098,6 +3123,11 @@ int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
   if (order < 0) {
     IGRAPH_ERROR("Negative order in neighborhood size", IGRAPH_EINVAL);
   }
+
+  if (mindist < 0 || mindist > order) {
+    IGRAPH_ERROR("Minimum distance should be between zero and order",
+		 IGRAPH_EINVAL);
+  }
   
   added=igraph_Calloc(no_of_nodes, long int);
   if (added==0) {
@@ -3115,7 +3145,7 @@ int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
     long int node=IGRAPH_VIT_GET(vit);
     added[node]=i+1;
     igraph_vector_clear(&tmp);
-    IGRAPH_CHECK(igraph_vector_push_back(&tmp, node));
+    if (mindist == 0) { IGRAPH_CHECK(igraph_vector_push_back(&tmp, node)); }
     if (order > 0) {
       igraph_dqueue_push(&q, node);
       igraph_dqueue_push(&q, 0);
@@ -3136,7 +3166,9 @@ int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
 	    added[nei]=i+1;
 	    IGRAPH_CHECK(igraph_dqueue_push(&q, nei));
 	    IGRAPH_CHECK(igraph_dqueue_push(&q, actdist+1));
-	    IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    if (actdist+1 >= mindist) {
+	      IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    }
 	  }
 	}
       } else {
@@ -3145,7 +3177,9 @@ int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,
 	  long int nei=(long int) VECTOR(neis)[j];
 	  if (added[nei] != i+1) {
 	    added[nei]=i+1;
-	    IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    if (actdist+1 >= mindist) {
+	      IGRAPH_CHECK(igraph_vector_push_back(&tmp, nei));
+	    }
 	  }
 	}
       }
@@ -3980,7 +4014,8 @@ int igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result,
   long int no_of_edges = igraph_ecount(graph);
   long int i, j, k, n;
   long int *geodist;
-  igraph_vector_t *eids, *ins_p, *outs_p, ins_v, outs_v;
+  igraph_vector_int_t *eids;
+  igraph_vector_t *ins_p, *outs_p, ins_v, outs_v;
   igraph_dqueue_t q;
   igraph_inclist_t inclist;
   igraph_bool_t directed = igraph_is_directed(graph);
@@ -4032,7 +4067,7 @@ int igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result,
         long int actdist=(long int) igraph_dqueue_pop(&q);
         IGRAPH_ALLOW_INTERRUPTION();
         eids=igraph_inclist_get(&inclist, actnode);
-        n=igraph_vector_size(eids);
+        n=igraph_vector_int_size(eids);
         for (j=0; j<n; j++) {
           long int neighbor = IGRAPH_OTHER(graph, VECTOR(*eids)[j], actnode);
           if (geodist[neighbor] != 0) {
@@ -6034,7 +6069,7 @@ int igraph_diameter_dijkstra(const igraph_t *graph,
     while (!igraph_indheap_empty(&Q)) {
       long int minnei=igraph_indheap_max_index(&Q);
       igraph_real_t mindist=-igraph_indheap_delete_max(&Q);
-      igraph_vector_t *neis;
+      igraph_vector_int_t *neis;
       long int nlen, j;
       
       if (mindist > res) {
@@ -6043,7 +6078,7 @@ int igraph_diameter_dijkstra(const igraph_t *graph,
       nodes_reached++;
 
       neis=igraph_inclist_get(&inclist, minnei);
-      nlen=igraph_vector_size(neis);
+      nlen=igraph_vector_int_size(neis);
       for (j=0; j<nlen; j++) {
 	long int edge=(long int) VECTOR(*neis)[j];
 	long int tto=IGRAPH_OTHER(graph, edge, minnei);
diff --git a/src/triangles.c b/src/triangles.c
index f5859fa..60dd738 100644
--- a/src/triangles.c
+++ b/src/triangles.c
@@ -83,7 +83,7 @@ int igraph_transitivity_avglocal_undirected(const igraph_t *graph,
   igraph_adjlist_t allneis;
   igraph_vector_int_t *neis1, *neis2;
   long int neilen1, neilen2;
-  igraph_integer_t triples;
+  igraph_real_t triples;
   long int *neis;
   long int maxdegree;
 
@@ -126,7 +126,7 @@ int igraph_transitivity_avglocal_undirected(const igraph_t *graph,
     
     neis1=igraph_adjlist_get(&allneis, node);
     neilen1=igraph_vector_int_size(neis1);
-    triples = (igraph_integer_t) ((double)neilen1 * (neilen1-1) / 2);
+    triples = ((double)neilen1) * (neilen1 - 1) / 2.0;
     /* Mark the neighbors of 'node' */
     for (i=0; i<neilen1; i++) {
       neis[ (long int)VECTOR(*neis1)[i] ] = node+1;
@@ -517,6 +517,21 @@ int igraph_adjacent_triangles4(const igraph_t *graph,
   return 0;
 }
 
+/**
+ * \function igraph_adjacent_triangles
+ * Count the number of triangles a vertex is part of
+ *
+ * \param graph The input graph. Edge directions are ignored.
+ * \param res Initiliazed vector, the results are stored here.
+ * \param vids The vertices to perform the calculation for.
+ * \return Error mode.
+ *
+ * \sa \ref igraph_list_triangles() to list them.
+ *
+ * Time complexity: O(d^2 n), d is the average vertex degree of the
+ * queried vertices, n is their number.
+ */
+
 int igraph_adjacent_triangles(const igraph_t *graph,
 			      igraph_vector_t *res,
 			      const igraph_vs_t vids) {
@@ -531,6 +546,33 @@ int igraph_adjacent_triangles(const igraph_t *graph,
 }
 
 /**
+ * \function igraph_list_triangles
+ * Find all triangles in a graph
+ *
+ * \param graph The input graph, edge directions are ignored.
+ * \param res Pointer to an initialized integer vector, the result
+ *        is stored here, in a long list of triples of vertex ids.
+ *        Each triple is a triangle in the graph. Each triangle is
+ *        listed exactly once.
+ * \return Error code.
+ *
+ * \sa \ref igraph_transitivity_undirected() to count the triangles,
+ * \ref igraph_adjacent_triangles() to count the triangles a vertex
+ * participates in.
+ *
+ * Time complexity: O(d^2 n), d is the average degree, n is the number
+ * of vertices.
+ */
+
+int igraph_list_triangles(const igraph_t *graph,
+			  igraph_vector_int_t *res) {
+# define TRIANGLES
+# include "triangles_template.h"
+# undef TRIANGLES
+  return 0;
+}
+
+/**
  * \ingroup structural
  * \function igraph_transitivity_undirected
  * \brief Calculates the transitivity (clustering coefficient) of a graph.
@@ -773,7 +815,7 @@ int igraph_transitivity_barrat4(const igraph_t *graph,
   long int maxdegree;
   igraph_inclist_t incident;
   igraph_vector_long_t neis;
-  igraph_vector_t *adj1, *adj2;
+  igraph_vector_int_t *adj1, *adj2;
   igraph_vector_t actw;
   long int i, nn;
   
@@ -821,7 +863,7 @@ int igraph_transitivity_barrat4(const igraph_t *graph,
     IGRAPH_ALLOW_INTERRUPTION();
     
     adj1=igraph_inclist_get(&incident, node);
-    adjlen1=igraph_vector_size(adj1);
+    adjlen1=igraph_vector_int_size(adj1);
     triples = VECTOR(degree)[node] * (adjlen1-1) / 2.0;
     /* Mark the neighbors of the node */
     for (i=0; i<adjlen1; i++) {
@@ -838,7 +880,7 @@ int igraph_transitivity_barrat4(const igraph_t *graph,
       long int j;
       if (VECTOR(rank)[nei] > VECTOR(rank)[node]) {
 				adj2=igraph_inclist_get(&incident, nei);
-				adjlen2=igraph_vector_size(adj2);
+				adjlen2=igraph_vector_int_size(adj2);
 				for (j=0; j<adjlen2; j++) {
 					long int edge2=(long int) VECTOR(*adj2)[j];
 					igraph_real_t weight2=VECTOR(*weights)[edge2];
diff --git a/src/triangles_template.h b/src/triangles_template.h
index 6b9bd1a..a3137be 100644
--- a/src/triangles_template.h
+++ b/src/triangles_template.h
@@ -28,7 +28,7 @@
   igraph_vector_int_t *neis1, *neis2;
   long int neilen1, neilen2, deg1;
 #ifdef TRIPLES
-  igraph_integer_t triples;
+  igraph_real_t triples;
 #endif
   long int *neis;
   long int maxdegree;
@@ -36,7 +36,7 @@
   igraph_vector_int_t order;
   igraph_vector_int_t rank;
   igraph_vector_t degree;
-  
+
 	igraph_vector_int_init(&order, no_of_nodes);
 	IGRAPH_FINALLY(igraph_vector_int_destroy, &order);
   IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);
@@ -61,9 +61,13 @@
   }
   IGRAPH_FINALLY(igraph_free, neis);
 
+#ifndef TRIANGLES
   IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
   igraph_vector_null(res);
-  
+#else
+  igraph_vector_int_clear(res);
+#endif
+
   for (nn=no_of_nodes-1; nn>=0; nn--) {
     node=VECTOR(order)[nn];
     
@@ -73,7 +77,7 @@
     neilen1=igraph_vector_int_size(neis1);
     deg1=(long int) VECTOR(degree)[node];
 #ifdef TRIPLES
-    triples=(igraph_integer_t) ((double)deg1*(deg1-1)/2);
+    triples= ((double)deg1*(deg1-1)/2);
 #endif
     /* Mark the neighbors of the node */
     for (i=0; i<neilen1; i++) {
@@ -87,9 +91,15 @@
       for (j=0; j<neilen2; j++) {
 	long int nei2=(long int) VECTOR(*neis2)[j];
 	if (neis[nei2] == node+1) {
+#ifndef TRIANGLES
 	  VECTOR(*res)[nei2] += 1;
 	  VECTOR(*res)[nei] += 1;
 	  VECTOR(*res)[node] += 1;
+#else
+	  IGRAPH_CHECK(igraph_vector_int_push_back(res, node));
+	  IGRAPH_CHECK(igraph_vector_int_push_back(res, nei));
+	  IGRAPH_CHECK(igraph_vector_int_push_back(res, nei2));
+#endif
 	}
       }
     }
@@ -100,6 +110,9 @@
     else
       VECTOR(*res)[node] /= triples;
 #endif
+#ifdef TRIEDGES
+		VECTOR(*res)[node] += deg1;
+#endif
   }
 
   igraph_free(neis);
diff --git a/src/triangles_template1.h b/src/triangles_template1.h
index 6f77fd2..3fa74b6 100644
--- a/src/triangles_template1.h
+++ b/src/triangles_template1.h
@@ -70,10 +70,10 @@
       neis2=igraph_lazy_adjlist_get(&adjlist, (igraph_integer_t) v);
       neilen2=igraph_vector_size(neis2);
       for (k=0; k<neilen2; k++) {
-				long int v2=(long int) VECTOR(*neis2)[k];
-				if (neis[v2] == i+1) {
-					triangles += 1.0;
-				}
+	long int v2=(long int) VECTOR(*neis2)[k];
+	if (neis[v2] == i+1) {
+	  triangles += 1.0;
+	}
       }
     }
 
@@ -82,8 +82,8 @@
       VECTOR(*res)[i] = 0.0;
     else
       VECTOR(*res)[i] = triangles/triples;
-#else 
-		VECTOR(*res)[i] = triangles/2;
+#else
+    VECTOR(*res)[i] = triangles/2;
 #endif
   }
 
diff --git a/src/type_indexededgelist.c b/src/type_indexededgelist.c
index f292ceb..8bf559d 100644
--- a/src/type_indexededgelist.c
+++ b/src/type_indexededgelist.c
@@ -1030,15 +1030,14 @@ int igraph_degree(const igraph_t *graph, igraph_vector_t *res,
 
 int igraph_edge(const igraph_t *graph, igraph_integer_t eid, 
 		igraph_integer_t *from, igraph_integer_t *to) {
-  
-  *from = (igraph_integer_t) VECTOR(graph->from)[(long int)eid];
-  *to   = (igraph_integer_t) VECTOR(graph->to  )[(long int)eid];
-  
-  if (! igraph_is_directed(graph) && *from > *to) {
-    igraph_integer_t tmp=*from;
-    *from=*to;
-    *to=tmp;
-  }
+
+  if (igraph_is_directed(graph)) {
+    *from = (igraph_integer_t) VECTOR(graph->from)[(long int)eid];
+    *to   = (igraph_integer_t) VECTOR(graph->to  )[(long int)eid];
+  } else {
+    *from = (igraph_integer_t) VECTOR(graph->to  )[(long int)eid];
+    *to   = (igraph_integer_t) VECTOR(graph->from)[(long int)eid];
+  }    
 
   return 0;
 }
@@ -1053,10 +1052,18 @@ int igraph_edges(const igraph_t *graph, igraph_es_t eids,
   IGRAPH_FINALLY(igraph_eit_destroy, &eit);
   n=IGRAPH_EIT_SIZE(eit);
   IGRAPH_CHECK(igraph_vector_resize(edges, n*2));
-  for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
-    long int e=IGRAPH_EIT_GET(eit);
-    VECTOR(*edges)[ptr++]=IGRAPH_FROM(graph, e);
-    VECTOR(*edges)[ptr++]=IGRAPH_TO(graph, e);
+  if (igraph_is_directed(graph)) {
+    for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
+      long int e=IGRAPH_EIT_GET(eit);
+      VECTOR(*edges)[ptr++]=IGRAPH_FROM(graph, e);
+      VECTOR(*edges)[ptr++]=IGRAPH_TO(graph, e);
+    }
+  } else {
+    for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {
+      long int e=IGRAPH_EIT_GET(eit);
+      VECTOR(*edges)[ptr++]=IGRAPH_TO(graph, e);
+      VECTOR(*edges)[ptr++]=IGRAPH_FROM(graph, e);
+    }
   }
   
   igraph_eit_destroy(&eit);
diff --git a/src/uuid/COPYING b/src/uuid/COPYING
new file mode 100644
index 0000000..e7a8054
--- /dev/null
+++ b/src/uuid/COPYING
@@ -0,0 +1,28 @@
+This library is free software; you can redistribute it and/or
+modify it under the terms of the Modified BSD License:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, and the entire permission notice in its entirety,
+   including the disclaimer of warranties.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote
+   products derived from this software without specific prior
+   written permission.
+
+THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/src/uuid/Makevars.in b/src/uuid/Makevars.in
new file mode 100644
index 0000000..0ab302b
--- /dev/null
+++ b/src/uuid/Makevars.in
@@ -0,0 +1,2 @@
+PKG_CPPFLAGS=@CPPFLAGS@
+PKG_LIBS=@LIBS@
diff --git a/src/uuid/Makevars.win b/src/uuid/Makevars.win
new file mode 100644
index 0000000..248e1ce
--- /dev/null
+++ b/src/uuid/Makevars.win
@@ -0,0 +1 @@
+PKG_CPPFLAGS=-Iwin32
diff --git a/src/uuid/R.c b/src/uuid/R.c
new file mode 100644
index 0000000..b956b8d
--- /dev/null
+++ b/src/uuid/R.c
@@ -0,0 +1,25 @@
+#include "uuid.h"
+
+#include <Rinternals.h>
+#include "igraph_random.h"
+
+SEXP UUID_gen(SEXP sTime) {
+
+    RNG_BEGIN();
+
+    uuid_t u;
+    char c[40];
+    int use_time = asInteger(sTime);
+    if (use_time == TRUE)
+	uuid_generate_time(u);
+    else if (use_time == FALSE)
+	uuid_generate_random(u);
+    else
+	uuid_generate(u);
+    uuid_unparse_lower(u, c);
+
+    RNG_END();
+
+    return mkString(c);
+}
+
diff --git a/src/uuid/clear.c b/src/uuid/clear.c
new file mode 100644
index 0000000..ad1f066
--- /dev/null
+++ b/src/uuid/clear.c
@@ -0,0 +1,43 @@
+/*
+ * clear.c -- Clear a UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+
+#include "uuidP.h"
+
+void uuid_clear(uuid_t uu)
+{
+	memset(uu, 0, 16);
+}
+
diff --git a/src/uuid/compare.c b/src/uuid/compare.c
new file mode 100644
index 0000000..8f3437a
--- /dev/null
+++ b/src/uuid/compare.c
@@ -0,0 +1,55 @@
+/*
+ * compare.c --- compare whether or not two UUIDs are the same
+ *
+ * Returns 0 if the two UUIDs are different, and 1 if they are the same.
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+#include <string.h>
+
+#define UUCMP(u1,u2) if (u1 != u2) return((u1 < u2) ? -1 : 1);
+
+int uuid_compare(const uuid_t uu1, const uuid_t uu2)
+{
+	struct uuid	uuid1, uuid2;
+
+	uuid_unpack(uu1, &uuid1);
+	uuid_unpack(uu2, &uuid2);
+
+	UUCMP(uuid1.time_low, uuid2.time_low);
+	UUCMP(uuid1.time_mid, uuid2.time_mid);
+	UUCMP(uuid1.time_hi_and_version, uuid2.time_hi_and_version);
+	UUCMP(uuid1.clock_seq, uuid2.clock_seq);
+	return memcmp(uuid1.node, uuid2.node, 6);
+}
+
diff --git a/src/uuid/config.h.in b/src/uuid/config.h.in
new file mode 100644
index 0000000..b6f72b3
--- /dev/null
+++ b/src/uuid/config.h.in
@@ -0,0 +1,82 @@
+/* src/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `jrand48' function. */
+#undef HAVE_JRAND48
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+#undef HAVE_NET_IF_DL_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define if struct sockaddr contains sa_len */
+#undef HAVE_SA_LEN
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#undef HAVE_SYS_FILE_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+#undef HAVE_SYS_SYSCALL_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
diff --git a/src/uuid/copy.c b/src/uuid/copy.c
new file mode 100644
index 0000000..ead33aa
--- /dev/null
+++ b/src/uuid/copy.c
@@ -0,0 +1,45 @@
+/*
+ * copy.c --- copy UUIDs
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+
+void uuid_copy(uuid_t dst, const uuid_t src)
+{
+	unsigned char		*cp1;
+	const unsigned char	*cp2;
+	int			i;
+
+	for (i=0, cp1 = dst, cp2 = src; i < 16; i++)
+		*cp1++ = *cp2++;
+}
diff --git a/src/uuid/gen_uuid.c b/src/uuid/gen_uuid.c
new file mode 100644
index 0000000..69ad494
--- /dev/null
+++ b/src/uuid/gen_uuid.c
@@ -0,0 +1,575 @@
+/*
+ * gen_uuid.c --- generate a DCE-compatible uuid
+ *
+ * Copyright (C) 1996, 1997, 1998, 1999 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+/*
+ * Force inclusion of SVID stuff since we need it if we're compiling in
+ * gcc-wall wall mode
+ */
+#define _SVID_SOURCE
+
+#include "config.h"
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#include <windows.h>
+#define UUID MYUUID
+#endif
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/stat.h>
+#ifdef HAVE_SYS_FILE_H
+#include <sys/file.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NET_IF_DL_H
+#include <net/if_dl.h>
+#endif
+#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
+#include <sys/syscall.h>
+#endif
+
+#include "uuidP.h"
+#include "uuidd.h"
+
+#ifdef USING_R
+#include "igraph_random.h"
+#define srand(x) ;
+#define rand() RNG_INTEGER(0, RAND_MAX)
+#endif
+
+#ifdef HAVE_TLS
+#define THREAD_LOCAL static __thread
+#else
+#define THREAD_LOCAL static
+#endif
+
+#ifdef _WIN32
+#if 0 /* MinGW has gettimeofday so we don't need this */
+static int gettimeofday (struct timeval *tv, void *dummy)
+{
+	FILETIME	ftime;
+	uint64_t	n;
+
+	GetSystemTimeAsFileTime (&ftime);
+	n = (((uint64_t) ftime.dwHighDateTime << 32)
+	     + (uint64_t) ftime.dwLowDateTime);
+	if (n) {
+		n /= 10;
+		n -= ((369 * 365 + 89) * (uint64_t) 86400) * 1000000;
+	}
+
+	tv->tv_sec = n / 1000000;
+	tv->tv_usec = n % 1000000;
+}
+#endif
+
+#ifdef __MINGW32__
+int gettimeofday (struct timeval *tv, void *dummy);
+#endif
+#ifdef __MINGW64__
+int gettimeofday (struct timeval *tv, void *dummy);
+#endif
+
+static int getuid (void)
+{
+	return 1;
+}
+#endif
+
+/*
+ * Get the ethernet hardware address, if we can find it...
+ *
+ * XXX for a windows version, probably should use GetAdaptersInfo:
+ * http://www.codeguru.com/cpp/i-n/network/networkinformation/article.php/c5451
+ * commenting out get_node_id just to get gen_uuid to compile under windows
+ * is not the right way to go!
+ */
+static int get_node_id(unsigned char *node_id)
+{
+#ifdef HAVE_NET_IF_H
+	int		sd;
+	struct ifreq	ifr, *ifrp;
+	struct ifconf	ifc;
+	char buf[1024];
+	int		n, i;
+	unsigned char	*a;
+#ifdef HAVE_NET_IF_DL_H
+	struct sockaddr_dl *sdlp;
+#endif
+
+/*
+ * BSD 4.4 defines the size of an ifreq to be
+ * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
+ * However, under earlier systems, sa_len isn't present, so the size is
+ * just sizeof(struct ifreq)
+ */
+#ifdef HAVE_SA_LEN
+#define max(x, y) (((x) > (y)) ? (x) : (y))
+#define ifreq_size(i) max(sizeof(struct ifreq),\
+     sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
+#else
+#define ifreq_size(i) sizeof(struct ifreq)
+#endif /* HAVE_SA_LEN */
+
+	sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+	if (sd < 0) {
+		return -1;
+	}
+	memset(buf, 0, sizeof(buf));
+	ifc.ifc_len = sizeof(buf);
+	ifc.ifc_buf = buf;
+	if (ioctl (sd, SIOCGIFCONF, (char *)&ifc) < 0) {
+		close(sd);
+		return -1;
+	}
+	n = ifc.ifc_len;
+	for (i = 0; i < n; i+= ifreq_size(*ifrp) ) {
+		ifrp = (struct ifreq *)((char *) ifc.ifc_buf+i);
+		strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ);
+#ifdef SIOCGIFHWADDR
+		if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0)
+			continue;
+		a = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
+#else
+#ifdef SIOCGENADDR
+		if (ioctl(sd, SIOCGENADDR, &ifr) < 0)
+			continue;
+		a = (unsigned char *) ifr.ifr_enaddr;
+#else
+#ifdef HAVE_NET_IF_DL_H
+		sdlp = (struct sockaddr_dl *) &ifrp->ifr_addr;
+		if ((sdlp->sdl_family != AF_LINK) || (sdlp->sdl_alen != 6))
+			continue;
+		a = (unsigned char *) &sdlp->sdl_data[sdlp->sdl_nlen];
+#else
+		/*
+		 * XXX we don't have a way of getting the hardware
+		 * address
+		 */
+		close(sd);
+		return 0;
+#endif /* HAVE_NET_IF_DL_H */
+#endif /* SIOCGENADDR */
+#endif /* SIOCGIFHWADDR */
+		if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5])
+			continue;
+		if (node_id) {
+			memcpy(node_id, a, 6);
+			close(sd);
+			return 1;
+		}
+	}
+	close(sd);
+#endif
+	return 0;
+}
+
+#if defined(__linux__) && defined(__NR_gettid) && defined(HAVE_JRAND48)
+#define DO_JRAND_MIX
+static unsigned short ul_jrand_seed[3];
+#endif
+
+static int random_get_fd(void)
+{
+    int i, fd = -1;
+    struct timeval  tv;
+
+    gettimeofday(&tv, NULL);
+#ifndef _WIN32
+    fd = open("/dev/urandom", O_RDONLY);
+    if (fd == -1)
+	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+    if (fd >= 0) {
+	i = fcntl(fd, F_GETFD);
+	if (i >= 0)
+	    fcntl(fd, F_SETFD, i | FD_CLOEXEC);
+    }
+#endif
+    srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec);
+
+#ifdef DO_JRAND_MIX
+    ul_jrand_seed[0] = getpid() ^ (tv.tv_sec & 0xFFFF);
+    ul_jrand_seed[1] = getppid() ^ (tv.tv_usec & 0xFFFF);
+    ul_jrand_seed[2] = (tv.tv_sec ^ tv.tv_usec) >> 16;
+#endif
+    /* Crank the random number generator a few times */
+    gettimeofday(&tv, NULL);
+    for (i = (tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--)
+	rand();
+    return fd;
+}
+
+/*
+ * Generate a stream of random nbytes into buf.
+ * Use /dev/urandom if possible, and if not,
+ * use glibc pseudo-random functions.
+ */
+static void random_get_bytes(void *buf, size_t nbytes)
+{
+    size_t i, n = nbytes;
+    int fd = random_get_fd();
+    int lose_counter = 0;
+    unsigned char *cp = (unsigned char *) buf;
+
+    if (fd >= 0) {
+	while (n > 0) {
+	    ssize_t x = read(fd, cp, n);
+	    if (x <= 0) {
+		if (lose_counter++ > 16)
+		    break;
+		continue;
+	    }
+	    n -= x;
+	    cp += x;
+	    lose_counter = 0;
+	}
+
+	close(fd);
+    }
+
+    /*
+     * We do this all the time, but this is the only source of
+     * randomness if /dev/random/urandom is out to lunch.
+     */
+    for (cp = buf, i = 0; i < nbytes; i++)
+	*cp++ ^= (rand() >> 7) & 0xFF;
+
+#ifdef DO_JRAND_MIX
+    {
+	unsigned short tmp_seed[3];
+
+	memcpy(tmp_seed, ul_jrand_seed, sizeof(tmp_seed));
+	ul_jrand_seed[2] = ul_jrand_seed[2] ^ syscall(__NR_gettid);
+	for (cp = buf, i = 0; i < nbytes; i++)
+	    *cp++ ^= (jrand48(tmp_seed) >> 7) & 0xFF;
+	memcpy(ul_jrand_seed, tmp_seed,
+	       sizeof(ul_jrand_seed)-sizeof(unsigned short));
+    }
+#endif
+
+    return;
+}
+
+#ifdef _WIN32 /* compatibility layer */
+#define LOCK_EX 1
+#define LOCK_UN 2
+static int flock(int fd, int op)
+{
+    HANDLE h = (HANDLE) _get_osfhandle(fd);
+    OVERLAPPED offset;
+    if (h < 0)
+	return -1;
+    memset(&offset, 0, sizeof(offset));
+    switch (op) {
+    case LOCK_EX:
+	return (LockFileEx(h, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &offset)) ? 0 : -1;
+    case LOCK_UN:
+	UnlockFileEx(h, 0, 1, 0, &offset);
+	return 0;
+    }
+    return -1;
+}
+#endif
+
+#if !defined(HAVE_FLOCK) && !defined(__sun)
+# define HAVE_FLOCK 1
+#endif
+
+/* Assume that the gettimeofday() has microsecond granularity */
+#define MAX_ADJUSTMENT 10
+
+/*
+ * Get clock from global sequence clock counter.
+ *
+ * Return -1 if the clock counter could not be opened/locked (in this case
+ * pseudorandom value is returned in @ret_clock_seq), otherwise return 0.
+ */
+static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
+		     uint16_t *ret_clock_seq, int *num)
+{
+	THREAD_LOCAL int		adjustment = 0;
+	THREAD_LOCAL struct timeval	last = {0, 0};
+	THREAD_LOCAL int		state_fd = -2;
+	THREAD_LOCAL FILE		*state_f;
+	THREAD_LOCAL uint16_t		clock_seq;
+	struct timeval			tv;
+	uint64_t			clock_reg;
+	mode_t				save_umask;
+	int				len;
+	int				ret = 0;
+
+	if (state_fd == -2) {
+		save_umask = umask(0);
+		state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT, 0660);
+		(void) umask(save_umask);
+		if (state_fd != -1) {
+			state_f = fdopen(state_fd, "r+");
+			if (!state_f) {
+				close(state_fd);
+				state_fd = -1;
+				ret = -1;
+			}
+		}
+		else
+			ret = -1;
+	}
+	if (state_fd >= 0) {
+		rewind(state_f);
+#ifdef HAVE_FLOCK
+		while (flock(state_fd, LOCK_EX) < 0) {
+			if ((errno == EAGAIN) || (errno == EINTR))
+				continue;
+			fclose(state_f);
+			close(state_fd);
+			state_fd = -1;
+			ret = -1;
+			break;
+		}
+#endif
+	}
+	if (state_fd >= 0) {
+		unsigned int cl;
+		unsigned long tv1, tv2;
+		int a;
+
+		if (fscanf(state_f, "clock: %04x tv: %lu %lu adj: %d\n",
+			   &cl, &tv1, &tv2, &a) == 4) {
+			clock_seq = cl & 0x3FFF;
+			last.tv_sec = tv1;
+			last.tv_usec = tv2;
+			adjustment = a;
+		}
+	}
+
+	if ((last.tv_sec == 0) && (last.tv_usec == 0)) {
+		random_get_bytes(&clock_seq, sizeof(clock_seq));
+		clock_seq &= 0x3FFF;
+		gettimeofday(&last, NULL);
+		last.tv_sec--;
+	}
+
+try_again:
+	gettimeofday(&tv, NULL);
+	if ((tv.tv_sec < last.tv_sec) ||
+	    ((tv.tv_sec == last.tv_sec) &&
+	     (tv.tv_usec < last.tv_usec))) {
+		clock_seq = (clock_seq+1) & 0x3FFF;
+		adjustment = 0;
+		last = tv;
+	} else if ((tv.tv_sec == last.tv_sec) &&
+	    (tv.tv_usec == last.tv_usec)) {
+		if (adjustment >= MAX_ADJUSTMENT)
+			goto try_again;
+		adjustment++;
+	} else {
+		adjustment = 0;
+		last = tv;
+	}
+
+	clock_reg = tv.tv_usec*10 + adjustment;
+	clock_reg += ((uint64_t) tv.tv_sec)*10000000;
+	clock_reg += (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
+
+	if (num && (*num > 1)) {
+		adjustment += *num - 1;
+		last.tv_usec += adjustment / 10;
+		adjustment = adjustment % 10;
+		last.tv_sec += last.tv_usec / 1000000;
+		last.tv_usec = last.tv_usec % 1000000;
+	}
+
+	if (state_fd >= 0) {
+		rewind(state_f);
+		len = fprintf(state_f,
+			      "clock: %04x tv: %016lu %08lu adj: %08d\n",
+			      clock_seq, (unsigned long) last.tv_sec, (unsigned long) last.tv_usec, adjustment);
+		fflush(state_f);
+		if (ftruncate(state_fd, len) < 0) {
+			fprintf(state_f, "                   \n");
+			fflush(state_f);
+		}
+		rewind(state_f);
+#ifdef HAVE_FLOCK
+		flock(state_fd, LOCK_UN);
+#endif
+	}
+
+	*clock_high = clock_reg >> 32;
+	*clock_low = clock_reg;
+	*ret_clock_seq = clock_seq;
+	return ret;
+}
+
+
+int __uuid_generate_time(uuid_t out, int *num)
+{
+	static unsigned char node_id[6];
+	static int has_init = 0;
+	struct uuid uu;
+	uint32_t	clock_mid;
+	int ret;
+
+	if (!has_init) {
+		if (get_node_id(node_id) <= 0) {
+			random_get_bytes(node_id, 6);
+			/*
+			 * Set multicast bit, to prevent conflicts
+			 * with IEEE 802 addresses obtained from
+			 * network cards
+			 */
+			node_id[0] |= 0x01;
+		}
+		has_init = 1;
+	}
+	ret = get_clock(&clock_mid, &uu.time_low, &uu.clock_seq, num);
+	uu.clock_seq |= 0x8000;
+	uu.time_mid = (uint16_t) clock_mid;
+	uu.time_hi_and_version = ((clock_mid >> 16) & 0x0FFF) | 0x1000;
+	memcpy(uu.node, node_id, 6);
+	uuid_pack(&uu, out);
+	return ret;
+}
+
+/*
+ * Generate time-based UUID and store it to @out
+ *
+ * Since there is no daemon here, use fall-back right away
+ */
+static int uuid_generate_time_generic(uuid_t out) {
+	return __uuid_generate_time(out, 0);
+}
+
+/*
+ * Generate time-based UUID and store it to @out.
+ *
+ * Discards return value from uuid_generate_time_generic()
+ */
+void uuid_generate_time(uuid_t out)
+{
+	(void)uuid_generate_time_generic(out);
+}
+
+
+int uuid_generate_time_safe(uuid_t out)
+{
+	return uuid_generate_time_generic(out);
+}
+
+
+void __uuid_generate_random(uuid_t out, int *num)
+{
+	uuid_t	buf;
+	struct uuid uu;
+	int i, n;
+
+	if (!num || !*num)
+		n = 1;
+	else
+		n = *num;
+
+	for (i = 0; i < n; i++) {
+		random_get_bytes(buf, sizeof(buf));
+		uuid_unpack(buf, &uu);
+
+		uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+		uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF)
+			| 0x4000;
+		uuid_pack(&uu, out);
+		out += sizeof(uuid_t);
+	}
+}
+
+void uuid_generate_random(uuid_t out)
+{
+	int	num = 1;
+	/* No real reason to use the daemon for random uuid's -- yet */
+
+	__uuid_generate_random(out, &num);
+}
+
+/*
+ * Check whether good random source (/dev/random or /dev/urandom)
+ * is available.
+ */
+static int have_random_source(void)
+{
+	struct stat s;
+
+	return (!stat("/dev/random", &s) || !stat("/dev/urandom", &s));
+}
+
+
+/*
+ * This is the generic front-end to uuid_generate_random and
+ * uuid_generate_time.  It uses uuid_generate_random only if
+ * /dev/urandom is available, since otherwise we won't have
+ * high-quality randomness.
+ */
+void uuid_generate(uuid_t out)
+{
+	if (have_random_source())
+		uuid_generate_random(out);
+	else
+		uuid_generate_time(out);
+}
diff --git a/src/uuid/isnull.c b/src/uuid/isnull.c
new file mode 100644
index 0000000..931e7e7
--- /dev/null
+++ b/src/uuid/isnull.c
@@ -0,0 +1,48 @@
+/*
+ * isnull.c --- Check whether or not the UUID is null
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include "uuidP.h"
+
+/* Returns 1 if the uuid is the NULL uuid */
+int uuid_is_null(const uuid_t uu)
+{
+	const unsigned char 	*cp;
+	int			i;
+
+	for (i=0, cp = uu; i < 16; i++)
+		if (*cp++)
+			return 0;
+	return 1;
+}
+
diff --git a/src/uuid/pack.c b/src/uuid/pack.c
new file mode 100644
index 0000000..6e12476
--- /dev/null
+++ b/src/uuid/pack.c
@@ -0,0 +1,69 @@
+/*
+ * Internal routine for packing UUIDs
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_pack(const struct uuid *uu, uuid_t ptr)
+{
+	uint32_t	tmp;
+	unsigned char	*out = ptr;
+
+	tmp = uu->time_low;
+	out[3] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[2] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[1] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[0] = (unsigned char) tmp;
+
+	tmp = uu->time_mid;
+	out[5] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[4] = (unsigned char) tmp;
+
+	tmp = uu->time_hi_and_version;
+	out[7] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[6] = (unsigned char) tmp;
+
+	tmp = uu->clock_seq;
+	out[9] = (unsigned char) tmp;
+	tmp >>= 8;
+	out[8] = (unsigned char) tmp;
+
+	memcpy(out+10, uu->node, 6);
+}
+
diff --git a/src/uuid/parse.c b/src/uuid/parse.c
new file mode 100644
index 0000000..074383e
--- /dev/null
+++ b/src/uuid/parse.c
@@ -0,0 +1,79 @@
+/*
+ * parse.c --- UUID parsing
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "uuidP.h"
+
+int uuid_parse(const char *in, uuid_t uu)
+{
+	struct uuid	uuid;
+	int 		i;
+	const char	*cp;
+	char		buf[3];
+
+	if (strlen(in) != 36)
+		return -1;
+	for (i=0, cp = in; i <= 36; i++,cp++) {
+		if ((i == 8) || (i == 13) || (i == 18) ||
+		    (i == 23)) {
+			if (*cp == '-')
+				continue;
+			else
+				return -1;
+		}
+		if (i== 36)
+			if (*cp == 0)
+				continue;
+		if (!isxdigit(*cp))
+			return -1;
+	}
+	uuid.time_low = strtoul(in, NULL, 16);
+	uuid.time_mid = strtoul(in+9, NULL, 16);
+	uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
+	uuid.clock_seq = strtoul(in+19, NULL, 16);
+	cp = in+24;
+	buf[2] = 0;
+	for (i=0; i < 6; i++) {
+		buf[0] = *cp++;
+		buf[1] = *cp++;
+		uuid.node[i] = strtoul(buf, NULL, 16);
+	}
+
+	uuid_pack(&uuid, uu);
+	return 0;
+}
diff --git a/src/uuid/unpack.c b/src/uuid/unpack.c
new file mode 100644
index 0000000..beaaff3
--- /dev/null
+++ b/src/uuid/unpack.c
@@ -0,0 +1,63 @@
+/*
+ * Internal routine for unpacking UUID
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <string.h>
+#include "uuidP.h"
+
+void uuid_unpack(const uuid_t in, struct uuid *uu)
+{
+	const uint8_t	*ptr = in;
+	uint32_t		tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_low = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_mid = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->time_hi_and_version = tmp;
+
+	tmp = *ptr++;
+	tmp = (tmp << 8) | *ptr++;
+	uu->clock_seq = tmp;
+
+	memcpy(uu->node, ptr, 6);
+}
+
diff --git a/src/uuid/unparse.c b/src/uuid/unparse.c
new file mode 100644
index 0000000..a95bbb0
--- /dev/null
+++ b/src/uuid/unparse.c
@@ -0,0 +1,76 @@
+/*
+ * unparse.c -- convert a UUID to string
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <stdio.h>
+
+#include "uuidP.h"
+
+static const char *fmt_lower =
+	"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x";
+
+static const char *fmt_upper =
+	"%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X";
+
+#ifdef UUID_UNPARSE_DEFAULT_UPPER
+#define FMT_DEFAULT fmt_upper
+#else
+#define FMT_DEFAULT fmt_lower
+#endif
+
+static void uuid_unparse_x(const uuid_t uu, char *out, const char *fmt)
+{
+	struct uuid uuid;
+
+	uuid_unpack(uu, &uuid);
+	sprintf(out, fmt,
+		uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
+		uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
+		uuid.node[0], uuid.node[1], uuid.node[2],
+		uuid.node[3], uuid.node[4], uuid.node[5]);
+}
+
+void uuid_unparse_lower(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out,	fmt_lower);
+}
+
+void uuid_unparse_upper(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out,	fmt_upper);
+}
+
+void uuid_unparse(const uuid_t uu, char *out)
+{
+	uuid_unparse_x(uu, out, FMT_DEFAULT);
+}
diff --git a/src/uuid/uuid.h b/src/uuid/uuid.h
new file mode 100644
index 0000000..874d65a
--- /dev/null
+++ b/src/uuid/uuid.h
@@ -0,0 +1,104 @@
+/*
+ * Public include file for the UUID library
+ *
+ * Copyright (C) 1996, 1997, 1998 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUID_H
+#define _UUID_UUID_H
+
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+#include <time.h>
+
+typedef unsigned char uuid_t[16];
+
+/* UUID Variant definitions */
+#define UUID_VARIANT_NCS	0
+#define UUID_VARIANT_DCE	1
+#define UUID_VARIANT_MICROSOFT	2
+#define UUID_VARIANT_OTHER	3
+
+/* UUID Type definitions */
+#define UUID_TYPE_DCE_TIME   1
+#define UUID_TYPE_DCE_RANDOM 4
+
+/* Allow UUID constants to be defined */
+#ifdef __GNUC__
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+	static const uuid_t name __attribute__ ((unused)) = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#else
+#define UUID_DEFINE(name,u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15) \
+	static const uuid_t name = {u0,u1,u2,u3,u4,u5,u6,u7,u8,u9,u10,u11,u12,u13,u14,u15}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* clear.c */
+void uuid_clear(uuid_t uu);
+
+/* compare.c */
+int uuid_compare(const uuid_t uu1, const uuid_t uu2);
+
+/* copy.c */
+void uuid_copy(uuid_t dst, const uuid_t src);
+
+/* gen_uuid.c */
+void uuid_generate(uuid_t out);
+void uuid_generate_random(uuid_t out);
+void uuid_generate_time(uuid_t out);
+int uuid_generate_time_safe(uuid_t out);
+
+/* isnull.c */
+int uuid_is_null(const uuid_t uu);
+
+/* parse.c */
+int uuid_parse(const char *in, uuid_t uu);
+
+/* unparse.c */
+void uuid_unparse(const uuid_t uu, char *out);
+void uuid_unparse_lower(const uuid_t uu, char *out);
+void uuid_unparse_upper(const uuid_t uu, char *out);
+
+/* uuid_time.c */
+time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
+int uuid_type(const uuid_t uu);
+int uuid_variant(const uuid_t uu);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UUID_UUID_H */
diff --git a/src/uuid/uuidP.h b/src/uuid/uuidP.h
new file mode 100644
index 0000000..604d8bf
--- /dev/null
+++ b/src/uuid/uuidP.h
@@ -0,0 +1,63 @@
+/*
+ * uuid.h -- private header file for uuids
+ *
+ * Copyright (C) 1996, 1997 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include "config.h"
+
+#include "uuid.h"
+
+#define LIBUUID_CLOCK_FILE	"/var/lib/libuuid/clock.txt"
+
+/*
+ * Offset between 15-Oct-1582 and 1-Jan-70
+ */
+#define TIME_OFFSET_HIGH 0x01B21DD2
+#define TIME_OFFSET_LOW  0x13814000
+
+struct uuid {
+	uint32_t	time_low;
+	uint16_t	time_mid;
+	uint16_t	time_hi_and_version;
+	uint16_t	clock_seq;
+	uint8_t	node[6];
+};
+
+
+/*
+ * prototypes
+ */
+void uuid_pack(const struct uuid *uu, uuid_t ptr);
+void uuid_unpack(const uuid_t in, struct uuid *uu);
diff --git a/src/uuid/uuidd.h b/src/uuid/uuidd.h
new file mode 100644
index 0000000..2f70968
--- /dev/null
+++ b/src/uuid/uuidd.h
@@ -0,0 +1,54 @@
+/*
+ * Definitions used by the uuidd daemon
+ *
+ * Copyright (C) 2007 Theodore Ts'o.
+ *
+ * %Begin-Header%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, and the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * %End-Header%
+ */
+
+#ifndef _UUID_UUIDD_H
+#define _UUID_UUIDD_H
+
+#define UUIDD_DIR		_PATH_LOCALSTATEDIR "/uuidd"
+#define UUIDD_SOCKET_PATH	UUIDD_DIR "/request"
+#define UUIDD_PIDFILE_PATH	UUIDD_DIR "/uuidd.pid"
+#define UUIDD_PATH		"/usr/sbin/uuidd"
+
+#define UUIDD_OP_GETPID			0
+#define UUIDD_OP_GET_MAXOP		1
+#define UUIDD_OP_TIME_UUID		2
+#define UUIDD_OP_RANDOM_UUID		3
+#define UUIDD_OP_BULK_TIME_UUID		4
+#define UUIDD_OP_BULK_RANDOM_UUID	5
+#define UUIDD_MAX_OP			UUIDD_OP_BULK_RANDOM_UUID
+
+extern int __uuid_generate_time(uuid_t out, int *num);
+extern void __uuid_generate_random(uuid_t out, int *num);
+
+#endif /* _UUID_UUID_H */
diff --git a/src/uuid/win32/config.h b/src/uuid/win32/config.h
new file mode 100644
index 0000000..ffb2aba
--- /dev/null
+++ b/src/uuid/win32/config.h
@@ -0,0 +1,84 @@
+/* src/config.h.  Generated from config.h.in by configure.  */
+/* src/config.h.in.  Generated from configure.ac by autoheader.  */
+/* -- reflects MinGW + Win32 -- */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `jrand48' function. */
+/* #undef HAVE_JRAND48 */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+/* #undef HAVE_NETINET_IN_H */
+
+/* Define to 1 if you have the <net/if_dl.h> header file. */
+/* #undef HAVE_NET_IF_DL_H */
+
+/* Define to 1 if you have the <net/if.h> header file. */
+/* #undef HAVE_NET_IF_H */
+
+/* Define if struct sockaddr contains sa_len */
+/* #undef HAVE_SA_LEN */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+/* #undef HAVE_SYS_SOCKET_H */
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/syscall.h> header file. */
+/* #undef HAVE_SYS_SYSCALL_H */
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+/* #undef HAVE_SYS_UN_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "Simon.Urbanek at r-project.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "uuid"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "uuid 0.1"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "uuid"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.1"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
diff --git a/src/vector.c b/src/vector.c
index 577eb8f..4c2297b 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -1,22 +1,22 @@
 /* -*- mode: C -*-  */
-/* 
+/*
    IGraph library.
    Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor at gmail.com>
    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 
+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301 USA
 
 */
@@ -24,6 +24,7 @@
 #include "igraph_types.h"
 #include "igraph_types_internal.h"
 #include "igraph_complex.h"
+#include "bigint.h"
 #include "config.h"
 #include <float.h>
 
@@ -33,6 +34,12 @@
 #include "igraph_pmt_off.h"
 #undef BASE_IGRAPH_REAL
 
+#define BASE_FLOAT
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_FLOAT
+
 #define BASE_LONG
 #include "igraph_pmt.h"
 #include "vector.pmt"
@@ -63,11 +70,17 @@
 #include "igraph_pmt_off.h"
 #undef BASE_COMPLEX
 
+#define BASE_LIMB
+#include "igraph_pmt.h"
+#include "vector.pmt"
+#include "igraph_pmt_off.h"
+#undef BASE_LIMB
+
 #include "igraph_math.h"
 
 int igraph_vector_floor(const igraph_vector_t *from, igraph_vector_long_t *to) {
   long int i, n=igraph_vector_size(from);
-  
+
   IGRAPH_CHECK(igraph_vector_long_resize(to, n));
   for (i=0; i<n; i++) {
     VECTOR(*to)[i] = (long int) floor(VECTOR(*from)[i]);
@@ -77,7 +90,7 @@ int igraph_vector_floor(const igraph_vector_t *from, igraph_vector_long_t *to) {
 
 int igraph_vector_round(const igraph_vector_t *from, igraph_vector_long_t *to) {
   long int i, n=igraph_vector_size(from);
-  
+
   IGRAPH_CHECK(igraph_vector_long_resize(to, n));
   for (i=0; i<n; i++) {
     VECTOR(*to)[i] = (long int) round(VECTOR(*from)[i]);
@@ -88,7 +101,7 @@ int igraph_vector_round(const igraph_vector_t *from, igraph_vector_long_t *to) {
 int igraph_vector_order2(igraph_vector_t *v) {
 
   igraph_indheap_t heap;
-  
+
   igraph_indheap_init_array(&heap, VECTOR(*v), igraph_vector_size(v));
   IGRAPH_FINALLY(igraph_indheap_destroy, &heap);
 
@@ -97,7 +110,7 @@ int igraph_vector_order2(igraph_vector_t *v) {
     IGRAPH_CHECK(igraph_vector_push_back(v, igraph_indheap_max_index(&heap)-1));
     igraph_indheap_delete_max(&heap);
   }
-  
+
   igraph_indheap_destroy(&heap);
   IGRAPH_FINALLY_CLEAN(1);
   return 0;
@@ -110,7 +123,7 @@ int igraph_vector_order2(igraph_vector_t *v) {
  *
  * </para><para>
  * The smallest element will have order zero, the second smallest
- * order one, etc. 
+ * order one, etc.
  * \param v The original \type igraph_vector_t object.
  * \param v2 A secondary key, another \type igraph_vector_t object.
  * \param res An initialized \type igraph_vector_t object, it will be
@@ -119,11 +132,11 @@ int igraph_vector_order2(igraph_vector_t *v) {
  * \param nodes Hint, the largest element in \p v.
  * \return Error code:
  *         \c IGRAPH_ENOMEM: out of memory
- * 
+ *
  * Time complexity: O()
  */
 
-int igraph_vector_order(const igraph_vector_t* v, 
+int igraph_vector_order(const igraph_vector_t* v,
 			const igraph_vector_t *v2,
 			igraph_vector_t* res, igraph_real_t nodes) {
   long int edges=igraph_vector_size(v);
@@ -137,14 +150,14 @@ int igraph_vector_order(const igraph_vector_t* v,
   IGRAPH_VECTOR_INIT_FINALLY(&ptr, (long int) nodes+1);
   IGRAPH_VECTOR_INIT_FINALLY(&rad, edges);
   IGRAPH_CHECK(igraph_vector_resize(res, edges));
-  
+
   for (i=0; i<edges; i++) {
     long int radix=(long int) v2->stor_begin[i];
     if (VECTOR(ptr)[radix]!=0) {
       VECTOR(rad)[i]=VECTOR(ptr)[radix];
     }
     VECTOR(ptr)[radix]=i+1;
-  }  
+  }
 
   j=0;
   for (i=0; i<nodes+1; i++) {
@@ -169,7 +182,7 @@ int igraph_vector_order(const igraph_vector_t* v,
     }
     VECTOR(ptr)[radix]=edge+1;
   }
-  
+
   j=0;
   for (i=0; i<nodes+1; i++) {
     if (VECTOR(ptr)[i] != 0) {
@@ -180,12 +193,12 @@ int igraph_vector_order(const igraph_vector_t* v,
 	res->stor_begin[j++]=next;
       }
     }
-  } 
-  
+  }
+
   igraph_vector_destroy(&ptr);
   igraph_vector_destroy(&rad);
   IGRAPH_FINALLY_CLEAN(2);
-  
+
   return 0;
 }
 
@@ -202,7 +215,7 @@ int igraph_vector_order1(const igraph_vector_t* v,
   IGRAPH_VECTOR_INIT_FINALLY(&ptr, (long int) nodes+1);
   IGRAPH_VECTOR_INIT_FINALLY(&rad, edges);
   IGRAPH_CHECK(igraph_vector_resize(res, edges));
-  
+
   for (i=0; i<edges; i++) {
     long int radix=(long int) v->stor_begin[i];
     if (VECTOR(ptr)[radix]!=0) {
@@ -210,7 +223,7 @@ int igraph_vector_order1(const igraph_vector_t* v,
     }
     VECTOR(ptr)[radix]=i+1;
   }
-  
+
   j=0;
   for (i=0; i<nodes+1; i++) {
     if (VECTOR(ptr)[i] != 0) {
@@ -222,11 +235,11 @@ int igraph_vector_order1(const igraph_vector_t* v,
       }
     }
   }
-  
+
   igraph_vector_destroy(&ptr);
   igraph_vector_destroy(&rad);
   IGRAPH_FINALLY_CLEAN(2);
-  
+
   return 0;
 }
 
@@ -274,25 +287,25 @@ int igraph_vector_order1_int(const igraph_vector_t* v,
 
 int igraph_vector_rank(const igraph_vector_t *v, igraph_vector_t *res,
 		       long int nodes) {
-  
+
   igraph_vector_t rad;
   igraph_vector_t ptr;
   long int edges = igraph_vector_size(v);
   long int i, c=0;
-  
+
   IGRAPH_VECTOR_INIT_FINALLY(&rad, nodes);
   IGRAPH_VECTOR_INIT_FINALLY(&ptr, edges);
   IGRAPH_CHECK(igraph_vector_resize(res, edges));
-	       
+
   for (i=0; i<edges; i++) {
     long int elem=(long int) VECTOR(*v)[i];
     VECTOR(ptr)[i] = VECTOR(rad)[elem];
     VECTOR(rad)[elem] = i+1;
   }
-  
+
   for (i=0; i<nodes; i++) {
     long int p=(long int) VECTOR(rad)[i];
-    while (p != 0) {      
+    while (p != 0) {
       VECTOR(*res)[p-1]=c++;
       p=(long int) VECTOR(ptr)[p-1];
     }
@@ -320,7 +333,7 @@ int igraph_vector_complex_print(const igraph_vector_complex_t *v) {
 }
 #endif
 
-int igraph_vector_complex_fprint(const igraph_vector_complex_t *v, 
+int igraph_vector_complex_fprint(const igraph_vector_complex_t *v,
 				 FILE *file) {
   long int i, n=igraph_vector_complex_size(v);
   if (n!=0) {
@@ -335,7 +348,7 @@ int igraph_vector_complex_fprint(const igraph_vector_complex_t *v,
   return 0;
 }
 
-int igraph_vector_complex_real(const igraph_vector_complex_t *v, 
+int igraph_vector_complex_real(const igraph_vector_complex_t *v,
 			       igraph_vector_t *real) {
   int i, n=(int) igraph_vector_complex_size(v);
   IGRAPH_CHECK(igraph_vector_resize(real, n));
@@ -346,7 +359,7 @@ int igraph_vector_complex_real(const igraph_vector_complex_t *v,
   return 0;
 }
 
-int igraph_vector_complex_imag(const igraph_vector_complex_t *v, 
+int igraph_vector_complex_imag(const igraph_vector_complex_t *v,
 			       igraph_vector_t *imag) {
   int i, n=(int) igraph_vector_complex_size(v);
   IGRAPH_CHECK(igraph_vector_resize(imag, n));
@@ -357,8 +370,8 @@ int igraph_vector_complex_imag(const igraph_vector_complex_t *v,
   return 0;
 }
 
-int igraph_vector_complex_realimag(const igraph_vector_complex_t *v, 
-				   igraph_vector_t *real, 
+int igraph_vector_complex_realimag(const igraph_vector_complex_t *v,
+				   igraph_vector_t *real,
 				   igraph_vector_t *imag) {
   int i, n=(int) igraph_vector_complex_size(v);
   IGRAPH_CHECK(igraph_vector_resize(real, n));
@@ -379,10 +392,10 @@ int igraph_vector_complex_create(igraph_vector_complex_t *v,
   if (n != igraph_vector_size(imag)) {
     IGRAPH_ERROR("Real and imag vector sizes don't match", IGRAPH_EINVAL);
   }
-  
+
   IGRAPH_CHECK(igraph_vector_complex_init(v, n));
   /* FINALLY not needed */
-  
+
   for (i=0; i<n; i++) {
     VECTOR(*v)[i] = igraph_complex(VECTOR(*real)[i], VECTOR(*imag)[i]);
   }
@@ -397,10 +410,10 @@ int igraph_vector_complex_create_polar(igraph_vector_complex_t *v,
   if (n != igraph_vector_size(theta)) {
     IGRAPH_ERROR("'r' and 'theta' vector sizes don't match", IGRAPH_EINVAL);
   }
-  
+
   IGRAPH_CHECK(igraph_vector_complex_init(v, n));
   /* FINALLY not needed */
-  
+
   for (i=0; i<n; i++) {
     VECTOR(*v)[i] = igraph_complex_polar(VECTOR(*r)[i], VECTOR(*theta)[i]);
   }
@@ -430,5 +443,18 @@ igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs,
       }
     }
     return 1;
-  }  
+  }
+}
+
+int igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol) {
+  int i, n=igraph_vector_size(v);
+  if (tol < 0.0) {
+    IGRAPH_ERROR("`tol' tolerance must be non-negative", IGRAPH_EINVAL);
+  }
+  if (tol == 0.0) { tol = sqrt(DBL_EPSILON); }
+  for (i = 0; i < n; i++) {
+    igraph_real_t val=VECTOR(*v)[i];
+    if (val < tol && val > -tol) { VECTOR(*v)[i] = 0.0; }
+  }
+  return 0;
 }
diff --git a/src/visitors.c b/src/visitors.c
index 4fb061f..887b4c1 100644
--- a/src/visitors.c
+++ b/src/visitors.c
@@ -460,12 +460,12 @@ int igraph_dfs(const igraph_t *graph, igraph_integer_t root,
     if (terminate) { FREE_ALL(); return 0; }
   }
 
-  for (actroot=0; actroot<no_of_nodes; actroot++) {
+  for (actroot=0; actroot<no_of_nodes; ) {
 
     /* 'root' first, then all other vertices */
     if (igraph_stack_empty(&stack)) {
       if (!unreachable) { break; }
-      if (VECTOR(added)[actroot]) { continue; }
+      if (VECTOR(added)[actroot]) { actroot++; continue; }
       IGRAPH_CHECK(igraph_stack_push(&stack, actroot));
       VECTOR(added)[actroot] = 1;
       if (father) { VECTOR(*father)[actroot] = -1; }
@@ -477,6 +477,7 @@ int igraph_dfs(const igraph_t *graph, igraph_integer_t root,
 					    0, extra);
 	if (terminate) { FREE_ALL(); return 0; }
       }
+      actroot++;
     }
     
     while (!igraph_stack_empty(&stack)) {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-igraph.git



More information about the debian-med-commit mailing list